DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T m

⟦a4377d734⟧ TextFile

    Length: 31264 (0x7a20)
    Types: TextFile
    Names: »mlist.c«

Derivation

└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
    └─⟦dc59850a2⟧ »EurOpenD22/pp5.0/pp-5.tar.Z« 
        └─⟦e5a54fb17⟧ 
            └─⟦this⟧ »pp-5.0/Tools/mlist/mlist.c« 

TextFile

/* mlist: list maintaining and viewing tool */

# ifndef lint
static char Rcsid[] = "@(#)$Header: /cs/research/pp/hubris/pp-beta/Tools/mlist/RCS/mlist.c,v 5.0 90/09/20 16:27:43 pp Exp Locker: pp $";
# endif

/*
 * $Header: /cs/research/pp/hubris/pp-beta/Tools/mlist/RCS/mlist.c,v 5.0 90/09/20 16:27:43 pp Exp Locker: pp $
 *
 * $Log:	mlist.c,v $
 * Revision 5.0  90/09/20  16:27:43  pp
 * rcsforce : 5.0 public release
 * 
 */



#include	"head.h"
#include	"adr.h"
#include	"or.h"
#include	"dl.h"
#include 	"alias.h"
#include	"chan.h"
#include 	"retcode.h"
#include	"ap.h"
#include	<pwd.h>
#include	<sys/stat.h>
#include	<sys/file.h>
#include	<signal.h>

int (*work_proc) ();
int (*menu_proc) ();

static int init();
static void user_init();
static int display();
static int display_menu();
static int modify();
static int modify_menu();
static int verifyList();
static int verifyUser();
static int inList();
static int addUser();
static int isPP();
static int removeUser();
static int findUser();
static void openpager();
static FILE *myopen();
static int myclose();
static void closepager();
static int m_createList();
static int m_alterInLine();
static int m_addReq();
static int m_delReq();
static int m_createListFile();
static int m_alterExpansion();
static int permission();
static void listLists();
static int isModerator();
static int listOnLocal();
static void master_modify();
static void restrict_modify();
static char *lowerfy ();
extern int errno;
extern Name	*new_Name();
extern char	*loc_dom_site,
		*loc_dom_mta,
		*loc_dist_prefix,
		*list_tbl_comment,
		*ad_getlocal();
extern char	*tbldfldir;
char	*pager;
FILE	*out;
char	*list_table_file, *userAlias;
int	haveUid, userId;
int	superUser,
	curmode,
	menudriven,
	pipeopen = 0;

typedef	struct _desc {
	char	*name;
	char	*desc;
} Desc;

Desc	*Descriptions = NULL;
int	noLists = 0;
static void init_descs();

main (argc, argv)
int	argc;
char	**argv;
{
	int i;

	init(argv[0]);

	superUser = FALSE;
	menudriven = TRUE;

	if (strcmp(argv[0], "malias") == 0) {
		work_proc = display;
		menu_proc = display_menu;
	} else {
		work_proc = modify;
		menu_proc = modify_menu;
	}
	i = 1;
	userAlias = NULLCP;
	haveUid = NOTOK;
	
	if (argc > 1 && lexequ(argv[1], "-help") == 0) {
		printf("%s [-user 'username'] [-uid 'user Id'] [listname ...]\n",
		       argv[0]);
		exit(0);
	}
		       
	if (argc >= 3) {
		if (lexequ(argv[1], "-user") == 0) {
			/* run as -user foo */
			if (isPP() == NOTOK) {
				fprintf(stderr,
					"You are not a mail superuser and so cannot use the '%s' flag\n",
					argv[1]);
				exit(1);
			}
			userAlias = argv[2];
			i = 3;

		} else if (lexequ(argv[1], "-uid") == 0) {
			/* run as -uid 6 */
			if (isPP() == NOTOK) {
				fprintf(stderr,
					"You are not a mail superuser and so cannot use the '%s' flag\n",
					argv[1]);
				exit(1);
			}
			haveUid = OK;
			userId = atoi(argv[2]);
			i = 3;
		}
	}
	user_init();
		
	if (i == argc)
		(*menu_proc)();
	else {
		menudriven = FALSE;
		for (; i < argc; i++)
			(*work_proc) (argv[i]);
	}
}

/* \f

 */
/* initialisation routines */
static Table	*List = NULLTBL;

extern	char	*list_tbl;

static int init(myname)
char	*myname;
{
	char	buf[BUFSIZ];
	sys_init(myname);
	or_myinit();
	if ((pager = getenv("PAGER")) == NULL)
		pager = "more";
	if ((List = tb_nm2struct(list_tbl)) == NULLTBL) {
		fprintf(stderr, "Cannot initialise table 'list'\n");
		exit(1);
	}
	if (List->tb_file[0] == '/')
		strcpy(buf, List->tb_file);
	else
		sprintf(buf,"%s/%s",tbldfldir,List->tb_file);
	list_table_file = strdup(buf);
}

struct passwd	*pwd;
ADDR		*adr;
extern char	*postmaster,
		*pplogin;


static int isPP()
{
	RP_Buf	rp;
	int	uid;
	struct passwd	*tmp;
	ADDR	*tmpadr;

	if ((uid = getuid()) == 0)
		/* super user */
		return OK;
	if ((tmp = getpwuid(uid)) == NULL) {
		fprintf(stderr, "Cannot get your passwd entry\n");
		exit(1);
	}
	tmpadr = adr_new(tmp->pw_name, AD_ANY_TYPE, 0);

	if (rp_isbad(ad_parse(tmpadr, &rp, CH_UK_PREF))) {
		fprintf(stderr,
			"Cannot parse your mail address\nReason : %s\n",
			rp.rp_line);
		exit(1);
	}

	if ((strcmp(tmp->pw_name, pplogin) == 0)
	    || (strcmp(tmpadr->ad_r822adr, postmaster) == 0)) {
		adr_free(tmpadr);
		return OK;
	}
	adr_free(tmpadr);
	return NOTOK;
}
	
static void user_init ()
{
	RP_Buf	rp;
	if (userAlias != NULLCP) {
		if ((pwd = getpwnam(userAlias)) == NULL) {
			fprintf(stderr,
				"Cannot get passwd entry for user '%s'\n",
				userAlias);
			exit (1);
		}
		printf("Running as user '%s'\n", userAlias);
	} else if (haveUid == OK) {
		if ((pwd = getpwuid(userId)) == NULL) {
			fprintf (stderr,
				 "Cannot get passwd entry for uid '%d'\n",
				 userId);
			exit (1);
		}
		printf("Running as uid '%d'\n", userId);
	} else {
		if ((pwd = getpwuid(getuid())) == NULL) {
			fprintf(stderr, "Cannot get your passwd entry\n");
			exit(1);
		}
	}
	adr = adr_new(pwd->pw_name, AD_ANY_TYPE, 0);

	if (rp_isbad(ad_parse(adr, &rp, CH_UK_PREF))) {
		fprintf(stderr,
			"Cannot parse your mail address\nReason : %s\n",
			rp.rp_line);
		exit(1);
	}
	if ((strcmp(pwd->pw_name, pplogin) == 0)
	    || (strcmp(adr->ad_r822adr, postmaster) == 0)) {
		printf ("You are a mail super-user\n");
		superUser = TRUE;
	}
}
	
/* \f

 */
/* display mode routines */

static char *getx400name(name)
char	*name;
{
	OR_ptr	or;
	char	buf[BUFSIZ];

	or = or_buildpn(name);
	or = or_default(or);
	or_or2std(or, buf, 0);
	or_free(or);
	return strdup(buf);
}

static dl *readList(name)
char	*name;
{
	dl *list;
	char	newname[BUFSIZ], *x400name, *local;
	
	if (tb_getdl(name,&list,OK) == OK) 
		return list;

	/* try local variant of list */
	if ((local = ad_getlocal(name,(name[0] == '/') ? AD_X400_TYPE : AD_822_TYPE)) != NULLCP) {
		if (tb_getdl(local, &list,OK) == OK) {
			free(local);
			return list;
		}
		free(local);
	}

	/* try various conversion on name */

	/* with locdomsite */
	sprintf(newname, "%s@%s",name,loc_dom_site);
	if (tb_getdl(newname,&list,OK) == OK) 
		return list;

	/* with locdommta */
	sprintf(newname, "%s@%s",name,loc_dom_mta);
	if (tb_getdl(newname,&list,OK) == OK) 
		return list;

	/* x400 type address */
	x400name = getx400name(name);
	if (tb_getdl(x400name, &list,OK) == OK) {
		free(x400name);
		return list;
	}
	free(x400name);
	return NULL;
}

static int writeList(list)
dl	*list;
{
	Name	*ix;

	openpager();

	if (strncmp(list->dl_listname, loc_dist_prefix, strlen(loc_dist_prefix)) == 0) {
		char	*ix2 = list->dl_listname + strlen(loc_dist_prefix);
		if (pipeopen)
			fprintf(out, "Local Expansion of List: %s\t%s\n-------------------------\n",
				ix2, list->dl_desc);
	} else {
		if (pipeopen)
			fprintf(out,"List: %s\t%s\n-----\n",list->dl_listname,list->dl_desc);
	}
	if (pipeopen)
		fprintf(out,"Moderator's mail address: %s\n",
			(list -> dl_moderator == NULL) ? postmaster : list -> dl_moderator);
	if (isModerator(list)) {
		if ((ix = list -> dl_uids) != NULL) {
			if (pipeopen)
				fprintf(out,"Moderator%s uids: ",
					(ix -> next == NULL) ? "" : "s");
			while (ix != NULL) {
				if (pipeopen)
					fprintf(out,"%*s%s\n",
						(ix == list -> dl_uids) ? 0 : strlen("Moderators uids: "),
						"",
						ix -> name);
				ix = ix -> next;
			}
		}
	}

	ix = list -> dl_list;
	if (pipeopen)
		fprintf(out,"Expands to -> ");
	while (ix != NULL && pipeopen) {
		if (pipeopen)
			fprintf(out,"%*s%s\t%s\n",
				(ix == list -> dl_list) ? 0 : strlen("Expands to -> "),
				"",
				ix -> name,
				(ix -> file == NULL) ? "{inline-member}" : "");
		ix = ix -> next;
	}
	if (pipeopen)
		fprintf(out,"\n");
	closepager();
}
		
static int display(name)
char	*name;
{
	dl	*list;
	char	distList[BUFSIZ];

	(void) sprintf(distList, "%s%s", loc_dist_prefix, name);

	if ((list = readList(name)) != NULL
	    || (list = readList(distList)) != NULL) {
	    if (permission(list) != SECRMODE) {
		    writeList(list);
		    dl_free(list);
	    } else
		    printf("You do not have permission to read this list\n");
	} else
		printf("unknown list '%s'\n",name);
}

static int display_menu()
{
	int	quit = FALSE;
	char	buf[BUFSIZ];

	while (quit == FALSE) {
		printf("\n> ");
		fflush (stdout);
		if (gets (buf) == NULL)
			exit(OK);
		compress (buf, buf);
		if (buf[0] == NULL || strlen(buf) == 0) {
			printf("\nType 'h' or '?' for help\n");
			continue;
		}
		if (strlen(buf) == 1)
			switch (buf[0])
			{
			    case '\0':
			    case '\n':
				printf("\nType 'h' or '?' for help\n");
				continue;
			    case 'q':
				printf("\nBye...\n");
				quit = TRUE;
				continue;
			    case 'h':
			    case '?':
				fprintf(stdout,
					"\nOptions are:\n'l' ist the lists,\n'q' uit,\n\nor the name of the list you wish to view\n");
				continue;
			    case 'l':
				listLists();
				continue;
			    default:
				break;
			}
		display(buf);
	}
}

/* \f

 */
/* modify mode routines */

static int modify(name)
char	*name;
{
	dl		*list;
	char		distList[BUFSIZ];
	struct stat	statbuf;
	int 		fd;
	char	buf[BUFSIZ], *inListname;

	(void) sprintf(distList, "%s%s", loc_dist_prefix, name);
	if ((list = readList(name)) == NULL
	    && (list = readList(distList)) == NULL) {
		fprintf(stderr, "Unknown list '%s'\n",name);
		return NOTOK;
	}
	
	/* check in line or in file */
	if (list->dl_file == NULLCP) {
		if (confirm("This list is an in-line list\nThis program is unable to modify in-line lists\nDo you want to send a request to change this ?") == TRUE)
			m_alterInLine(list);
		dl_free(list);
		return NOTOK;
	}

/*	if (listOnLocal(list -> dl_listname, hostname) == FALSE) {
		printf("List '%s' is expanded on machine '%s'\n",name,hostname);
		if (isModerator(list) == TRUE) {
			if (confirm("do you wish to mail a request to change the expansion point ?") == TRUE)
				m_alterExpansion(list);
		} else
			printf("This tool can not modify remotely expanded lists\n");
		dl_free(list);
		return NOTOK;
	}*/

	if (stat(list->dl_file, &statbuf) < 0) {
		if (isModerator(list) == FALSE) {
			sprintf(buf, "File for list '%s' can only be created by a moderator\nDo you wish to send a message to the list moderator ?",name);
			if (confirm(buf) == TRUE)
				m_createListFile(list);
			dl_free(list);
			return NOTOK;
		}
		
		/* work out modes for creation of file */
		printf("Creating file for list '%s'\n",name);
		printf("Do you want other users to be able to add / remove their own names ?");
		if (confirm (NULLCP) == TRUE) {
			printf("Do you want them to be able to add / remove anyone else's name ?");
			if (confirm(NULLCP) == TRUE)
				curmode = FREEMODE;
			else
				curmode = PUBMODE;
		} else {
			printf("Do you want others to be able to see who is on the list ?");
			if (confirm (NULLCP))
				curmode = PRIVMODE;
			else
				curmode = SECRMODE;
		}
		
		printf ("Creating file '%s' with list mode ", list->dl_file);
		switch (curmode) {
		    case FREEMODE:
			printf("free\n");
			break;
		    case PUBMODE:
			printf("public\n");
			break;
		    case PRIVMODE:
			printf("private\n");
			break;
		    case SECRMODE:
			printf("secret\n");
			break;
		}
		if ((fd = creat(list->dl_file, curmode)) < 0) {
			printf("Unable to create file '%s'\n",list->dl_file);
			dl_free(list);
			return NOTOK;
		}
		(void) fchmod(fd, curmode);
		
	} else {
		curmode = (int) statbuf.st_mode;
		curmode = curmode & 0777;
		
		if (!(isModerator(list)
		      || curmode == PUBMODE
		      || curmode == FREEMODE)) {
			printf ("list '%s' can only be updated by it's moderators\n",name);
			if (curmode != SECRMODE) {
				printf("Do you want to see who is on the list ? ");
				if (confirm (NULLCP)) 
					display(name);
			}
			
			if (inList(pwd -> pw_name, list -> dl_list, &inListname) == TRUE) {
				printf("You (%s) are already in this list\nDo you wish to mail a request to be removed",inListname);
				if (confirm(NULLCP) == TRUE)
					m_delReq(list);
			} else {
				printf ("Do you wish to mail a request to be added");
				if (confirm(NULLCP) == TRUE)
					m_addReq(list);
			}
			dl_free(list);
			return NOTOK;
		}
	}

	/* all prelimarys done */
	printf("Modifying list '%s'\n",name);
	if (isModerator(list) || curmode == FREEMODE)
		master_modify(list);
	else
		restrict_modify(list);
	return OK;
}
				
static int modify_menu()
{
	int	quit = FALSE;
	char	buf[BUFSIZ],
	*margv[20],
	ch;
	int	margc;

	while (quit == FALSE) {
		printf("\n> ");
		fflush (stdout);
		if (gets (buf) == NULL)
			exit(OK);
		compress (buf, buf);
		if (buf[0] == NULL || strlen(buf) == 0) {
			printf("\nType 'h' or '?' for help\n");
			continue;
		}
		margc = sstr2arg(buf, 20, margv, " \t");
		if (strlen(margv[0]) > 1)
			ch = 'A';
		else if (margv[0][0] == '?')
			ch = '?';
		else
			ch = uptolow(margv[0][0]);
		switch (ch)
		{
		    case '\0':
		    case '\n':
			printf("\nType 'h' or '?' for help\n");
			continue;
		    case 'h':
		    case '?':
			printf("\nOptions are:\n'l' ist the lists,\n'c' reate a list,\n");
			printf("'p' rint 'listname' to view a list,\n'q' uit,\n\nor the name of the list you wish to modify\n");
			continue;
		    case 'q':
			printf("\nBye...\n");
			quit = TRUE;
			continue;
		    case 'l':
			listLists();
			continue;
		    case 'c':
			m_createList();
			continue;
		    case 'p':
			if (margc > 1)
				display(margv[1]);
			continue;
		    default:
			break;
		}
		if (modify(margv[0]) == NOTOK)
			printf("\nType 'h' or '?' for help\n");
	}

}

/* \f

 */
/* routines to send messages to postmaster or moderators */

char	input[BUFSIZ];

static int getinput()
{
	RP_Buf	rp;
	fflush(stdout);
	if (gets (input) == NULL) {
		exit (1);
	}
	compress (input, input);
	if ((strlen(input) == 0)
	    || ((strlen(input) == 1) && (input[0] == '\n'))) {
		printf("\t-> ");
		return getinput();
	}
	return OK;
}

static int error_user()
{
	RP_Buf	rp;
	pps_end(NOTOK, &rp);
}

static int error_pps(rp)
RP_Buf	*rp;
{
	fprintf(stderr, "pps_error: %s\n",rp->rp_line);
	fflush(stderr);
}

static int m_createList()
{
	dl	*list;
	RP_Buf	rp;
	printf("Please wait while I initialise things ...");
	fflush(stdout);
	
	if (pps_1adr("Distribution/mailing List creation request",
		     postmaster,
		     &rp) != OK)
		return error_pps(&rp);
	printf("done\n");
	printf("Name of new list -> ");
	if (getinput() == NOTOK)
		return error_user();
	if ((list = readList(input)) != NULL) {
		printf("'%s' list already exists ('%s')\n",
		       input,
		       list -> dl_listname);
		dl_free(list);
		return error_user();
	}
	if (pps_txt("\nName of new list: ",&rp) != OK)
		return error_pps(&rp);
	if (pps_txt(input,&rp) != OK)
		return error_pps(&rp);
	printf("\nDescription of list (one line only) -> ");
	if (getinput() == NOTOK)
		return error_user();
	if (pps_txt("\nFunction: ",&rp) != OK)
		return error_pps(&rp);
	if (pps_txt(input,&rp) != OK)
		return error_pps(&rp);
	printf("\nModerators login names (separated by , again one line only)\n\t-> ");
	if (getinput() == NOTOK)
		return error_user();
	if (pps_txt("\nModerators: ",&rp) != OK)
		return error_pps(&rp);
	if (pps_txt(input,&rp) != OK)
		return error_pps(&rp);
	if (pps_txt("\n",&rp) != OK)
		return error_pps(&rp);

	printf("\nDo you want to pass this message on to the postmaster ?");
	if (confirm (NULLCP) == FALSE) {
		pps_end(NOTOK,&rp);
		return 0;
	}
	printf("Please wait while I tidy things up ...");
	fflush(stdout);
	if (pps_end(OK,&rp) != OK)
		return error_pps(&rp);
	printf("done\n");
	fflush(stdout);
	printf ("Your request has been passed to an administrator\n");
	printf ("You will be notified in a short time when the list has been created\n");
	printf ("You can then use this program to enter names into the list\n\n");
	fflush (stdout);
	return 0;
}

static int m_alterInLine(list)
dl	*list;
{
	RP_Buf	rp;
	printf("Sending message to postmaster...");
	fflush(stdout);
	if (pps_1adr("Distribution/mailing list alteration request",
		     postmaster,
		     &rp) != OK)
		return error_pps(&rp);
	if (pps_txt("\nPlease could you change the list ",&rp) != OK)
		return error_pps(&rp);
	if (pps_txt(list->dl_listname,&rp) != OK)
		return error_pps(&rp);
	if (pps_txt("\nfrom being inline to being contained within a file\n\nThank you\n",&rp) != OK)
		return error_pps(&rp);
	if (pps_end(OK,&rp) != OK)
		return error_pps(&rp);
	printf("sent\n");
	fflush(stdout);
	return 0;
}

static int m_addReq(list)
dl	*list;
{
	RP_Buf	rp;
	printf("Sending request message to moderator...");
	fflush(stdout);
	if (pps_1adr("List addition request",
		     (list -> dl_moderator == NULL) ? postmaster : list -> dl_moderator,
		     &rp) != OK) 
		return error_pps(&rp);

	if (pps_txt("\nPlease add me to the list ",&rp) != OK) 
		return error_pps(&rp);
	if (pps_txt(list -> dl_listname,&rp) != OK)
		return error_pps(&rp);
	if (pps_txt("\n\nThank you.\n",&rp) != OK)
		return error_pps(&rp);
	if (pps_end(OK,&rp) != OK)
		return error_pps(&rp);
	printf("sent\n");
	fflush(stdout);
	return 0;
}

static int m_delReq(list)
dl	*list;
{
	RP_Buf	rp;
	printf("Sending request message to moderator...");
	fflush(stdout);
	if (pps_1adr("Deletion from list request",
		     (list -> dl_moderator == NULL) ? postmaster : list -> dl_moderator,
		     &rp) != OK) 
		return error_pps(&rp);

	if (pps_txt("\nPlease remove me from the list ",&rp) != OK) 
		return error_pps(&rp);
	if (pps_txt(list -> dl_listname,&rp) != OK)
		return error_pps(&rp);
	if (pps_txt("\n\nThank you.\n",&rp) != OK)
		return error_pps(&rp);
	if (pps_end(OK,&rp) != OK)
		return error_pps(&rp);
	printf("sent\n");
	fflush(stdout);
	return 0;
}

static int m_createListFile(list)
dl	*list;
{
	RP_Buf	rp;
	printf("Sending request message to moderator...");
	fflush(stdout);
	if (pps_1adr("List file creation request",
		     (list -> dl_moderator == NULL) ? postmaster : list -> dl_moderator,
		     &rp) != OK) 
		return error_pps(&rp);

	if (pps_txt("Please create the file for the list ",&rp) != OK) 
		return error_pps(&rp);
	if (pps_txt(list -> dl_listname,&rp) != OK)
		return error_pps(&rp);
	if (pps_txt("\n\nThank you.\n",&rp) != OK)
		return error_pps(&rp);
	if (pps_end(OK,&rp) != OK)
		return error_pps(&rp);
	printf("sent\n");
	fflush(stdout);
	return 0;
}

static int m_alterExpansion(list)
dl	*list;
{
	RP_Buf	rp;
	printf("Please wait while I initialise things ...");
	fflush(stdout);
	if (pps_1adr("List expansion alteration request",
		     postmaster,
		     &rp) != OK)
		return error_pps(&rp);

	if (pps_txt("\nPlease change the host the list ",&rp) != OK) 
		return error_pps(&rp);
	if (pps_txt(list -> dl_listname,&rp) != OK)
		return error_pps(&rp);
	if (pps_txt(" is distributed from\nto ->",&rp) != OK)
		return error_pps(&rp);
	printf("done\n");
	printf("Please input the host the list should be distrubuted from ->");
	if (getinput() == NOTOK)
		return error_user();
	if (pps_txt(input,&rp) != OK)
		return error_pps(&rp);
	if (pps_txt("\n\nThank you.\n",&rp) != OK)
		return error_pps(&rp);

	printf("Please wait while I tidy things up ...");
	fflush(stdout);
	if (pps_end(OK,&rp) != OK)
		return error_pps(&rp);
	printf("done\n");
	fflush(stdout);
	return 0; 
}

/* \f

 */
/* general routines */
#define	INC	3

static void init_descs()
{
	int	size = INC;
	char	buf[BUFSIZ],
		*temp,
		*name,
		*ix;
	FILE	*fd;

	if ((fd = fopen(list_table_file, "r")) == NULL) {
		fprintf(stderr,
			"Unable to open list of list file '%s' : %s\n",
			list_table_file, sys_errname (errno));
		return;
	}

	Descriptions = (Desc *) calloc((unsigned int) size, sizeof(Desc));
	
	while (fgets(buf, BUFSIZ, fd) != NULLCP) {
		temp = strdup(buf);
		if (temp[0] == '\n') {
			free(temp);
			continue;
		}
		
		if (temp[0] != '#') {
			if (strncmp(temp,loc_dist_prefix,strlen(loc_dist_prefix)) == 0)
				name = temp+strlen(loc_dist_prefix);
			else
				name = temp;
			ix = index(name, ':');
			if (ix == NULL) {
				printf("unknown syntax line in list table '%s'\n",temp);
				free(temp);
				continue;
			}
			*ix++ = '\0';
			ix = rindex(ix, ',');
			if (ix != NULL)
				ix++;
		} else {
			if (strncmp(&temp[1], 
				    list_tbl_comment, 
				    strlen(list_tbl_comment)) == 0) {
				name = temp+strlen(list_tbl_comment)+1;
				ix = NULL;
			} else
				continue;
		}
		if (noLists >= size) {
			size += INC;
			Descriptions = (Desc *) realloc((char *) Descriptions, 
							(unsigned int)(size*sizeof(Desc)));
		}

		Descriptions[noLists].name = strdup(name);
		if (ix == NULLCP)
			Descriptions[noLists].desc = NULLCP;
		else
			Descriptions[noLists].desc = strdup(ix);
		noLists++;
		free(temp);
	}
	Descriptions = (Desc *) realloc((char *) Descriptions,
					(unsigned int) (noLists*sizeof(Desc)));
}

static void listLists()
{
	int	i;

	openpager();
	
	if (Descriptions == NULL)
		init_descs();
	for (i = 0; i < noLists && pipeopen; i++) {	
		if (Descriptions[i].desc == NULLCP)
			fprintf(out, "%s", Descriptions[i].name);
		else
			fprintf(out, "%-30s: %s",
				Descriptions[i].name,Descriptions[i].desc);
	}
	closepager();
}

/* \f

 */
/* pager routines */

SFP	oldpipe;

static void piped()
{
	pipeopen = 0;
}

static void openpager()
{
	oldpipe = signal(SIGPIPE, piped);
	if (isatty(1) == 0)
		out = stdout;
	else if ((out = popen(pager,"w")) == NULL) {
		fprintf(stderr, "unable to start pager '%s': %s\n",
			pager, sys_errname (errno));
		out = stdout;
	}
	pipeopen = 1;
}	

static void closepager()
{
	if (out != stdout) {
		pclose(out);
		out = stdout;
	}
	pipeopen = 0;
	signal(SIGPIPE, oldpipe);
}

/*\f

*/

confirm (str)
char	*str;
{
    register char   c;

    if (str != NULL) {
	    fputs (str, stdout);
	    fflush(stdout);
    }
    printf (" [y/n] ");
    fflush (stdout);

    c = ttychar ();

    switch (c)
    {
	case 'Y':
	case 'y':
	    printf ("yes\r\n");
	    fflush (stdout);
	    return (TRUE);

	case 'N':
	case 'n':
	    printf ("no\r\n");
	    fflush(stdout);
	    return (FALSE);
	default:
	    printf ("Type y or n\n");
	    fflush(stdout);
	    return (confirm (NULLCP));
    }
}


ttychar ()
{
    register int	c;
    char		buf[LINESIZE];

    fflush (stdout);
    if (fgets (buf, LINESIZE,  stdin) == NULL)
	    exit (1);
    c = buf[0];

    c = toascii (c);    /* get rid of high bit */

    if (c == '\r')
	c = '\n';

    return (c);
}

/* \f

 */
static int permission(list)
dl *list;
{
	struct stat	statbuf;
	int		mode;

	if (isModerator(list) == TRUE)
		/* allowed to do anything */
		return FREEMODE;
	if (list->dl_file == NULLCP
	    || stat(list->dl_file, &statbuf) < 0)
		/* no file so can't do anything */
		return TOPMODE;

	mode = (int) statbuf.st_mode;
	mode = mode & 0777;

	return mode;
}

/* \f

 */
static int listOnLocal(name, host)
char	*name,
	host[];
{
	char	*p;

	if ((p = index(name, '@')) == NULL) {
		/* do x400 */
		sprintf(host,"unknown");
		return FALSE;
	}
	p++;
	sprintf(host,"%s",p);
	if (strcmp(p, loc_dom_mta) == 0
	    || strcmp(p, loc_dom_site) == 0)
		return TRUE;

	/* do x400 */
	return FALSE;
}
		
static int isModerator(list)
dl	*list;
{
	Name	*ix = list -> dl_uids;

	if (superUser == TRUE)
		return TRUE;

	while (ix != NULL && (strcmp(ix -> name, pwd -> pw_name) != 0))
		ix = ix -> next;

	return (ix == NULL) ? FALSE : TRUE;
}

/* \f

 */
/* main modify work routines */
static char	*ix;

static int	getbufchar()
{
	char	ret = *ix;
	if (ret != 0) ix++;
	return (ret == 0) ? EOF : ret;
}

static void master_modify(list)
dl	*list;
{
	FILE	*curfp;
	int	quit = FALSE,
		done;
	char	tmpbuf[LINESIZE],
		buf[BUFSIZ],
		*adrstr, *orig_line, ch, *inListname;

	if ((curfp = flckopen(list->dl_file, "r+")) == NULL) {
		fprintf (stderr, "Can't open %s: %s\n",
			 list -> dl_file, sys_errname (errno));
		return;
	}
	
	flckclose(curfp);

	while (quit == FALSE) {
		fprintf(stdout, "\n%s%s", 
			list->dl_listname,	
			(menudriven == TRUE) ? ">> " : "> ");
		fflush(stdout);
		if (gets(tmpbuf) == NULL) {
			exit(0);
		}
		compress (tmpbuf, tmpbuf);
		if (tmpbuf[1] != '\0'
		    && !isspace(tmpbuf[1])) {
			/* assume no command given */
			ix = &(tmpbuf[0]);
			ch = 'A';
		} else {
			/* get past command */
			ix = &(tmpbuf[1]);
			while (isspace(*ix)) ix++;
			if (tmpbuf[0] == '?')
				ch = '?';
			else
				ch = uptolow(tmpbuf[0]);
		}	
		switch (ch)
		{
		    case '\0':
		    case '\n':
			printf("\nType 'h' or '?' for help\n");
			continue;

		    case 'p':
			display(list -> dl_listname);
			break;

		    case 'v':
			verifyList(list);
			break;
			
		    case 'h':
		    case '?':
			fprintf(stdout,
				"\nOptions are:\n'p' rint list,\n'v' erify list,\n'a' dd user,\n'f' ind user,\n'r' emove users,\n'l' ist the lists,\n'c' reate a new list,\n");
			if (menudriven == TRUE)
				fprintf(stdout, "'q' uit and return to top menu.\n\n");
			else
				fprintf(stdout, "'q' uit.\n\n");
			fprintf(stdout, "If the input is none of the above options,\nit is assumed to be a user name to be added\n");
			fflush (stdout);
			break;

		    case 'l':
			listLists();
			break;
			
		    case 'c':
			m_createList();
			break;

		    case 'q':
			quit = TRUE;
			break;

		    case 'r':
			if (*ix == '\0') {
				printf ("give username to be removed (regex): ");
				if (gets(tmpbuf) == NULL) 
					exit(0);
				compress (tmpbuf, tmpbuf);
				ix = &(tmpbuf[0]);
			} 
			removeUser(ix, list);

			break;

		    case 'f':
			if (*ix == '\0') {
				printf ("give username to search for (regex): ");
				if (gets(tmpbuf) == NULL) 
					exit(0);
				compress (tmpbuf, tmpbuf);
				ix = &(tmpbuf[0]);
			} 
			findUser(ix, list);
			break;

		    case 'a':
			if (*ix == '\0') {
				printf("give username to be added: ");
				if (gets(tmpbuf) == NULL)
					exit(0);
				compress (tmpbuf, tmpbuf);
				ix = &(tmpbuf[0]);
			} 
		    default:
			done = FALSE;

			while (done == FALSE) {
				orig_line = ix;
				if (ap_pinit(getbufchar) == BADAP) {
					printf("Cannot parse '%s'\n",
					       orig_line);
					done = FALSE;
				} else {
					switch (ap_1adr()) {
					    case DONE:
						done = TRUE;
						break;
					    case NOTOK:
						break;
					    default:
						if (ap_t2s(ap_pstrt, &adrstr) != BADAP) {
							if (rp_isbad(verifyUser(adrstr, buf)))
								printf("Illegal address '%s'\n",
								       adrstr);
							else {
								if (inList(adrstr, list -> dl_list, &inListname) == TRUE) {
									printf("User '%s' already in list",
									       adrstr);
									if (lexequ(inListname, adrstr) != 0) 
										printf(" as '%s'", inListname);
									printf("\n");
								} else 
									addUser(adrstr, list);
								ap_sqdelete(ap_pstrt, NULLAP);
								ap_free(ap_pstrt);
								ap_pstrt = NULLAP;
							}
							free(adrstr);
						}
						break;
					}
				}
			}
			break;
			
		}

	}
	if (menudriven == FALSE) 
		printf("\nBye...\n");
		
}

static void restrict_modify(list)
dl	*list;
{
	char	buf[LINESIZE],
		adr[BUFSIZ],
		*nameinlist;

	printf("Would you like to see who's in the list ?");
	if (confirm(NULLCP) == TRUE) 
		display(list -> dl_listname);
	if (!rp_isbad(verifyUser(pwd->pw_name, adr))) {
		if (inList(adr, list -> dl_list, &nameinlist) == TRUE) {
	   
			printf("You (%s) are already in this list\nDo you wish to be removed ?",pwd -> pw_name);
			if (confirm(NULLCP) == TRUE) {
				sprintf(buf, "^%s$",adr);
				removeUser(buf, list);
			} else 
				printf("You only have permission to add or remove yourself from this list\n");
		} else {
			printf ("You (%s) are not in this list\nDo you wish to be added ?", pwd -> pw_name);
			if (confirm(NULLCP) == TRUE)
				addUser(adr, list);
			else
				printf("You only have permission to add or remove yourself from this list\n");
		}
	}
			
}

/* \f

 */
/* checking routines */

static int verifyUser(name, addr)
char	*name,
	*addr;
{
	RP_Buf	rp;
	ADDR	*temp;
	int	ret,
		type;
	
	if (name[0] == '/')
		/* assume x400 address */
		type = AD_X400_TYPE;
	else
		type = AD_ANY_TYPE;

	temp = adr_new(name, type, 0);
	
	if (rp_isbad(ret = ad_parse(temp, &rp, CH_UK_PREF)))
		fprintf(stderr, "Failed to parse '%s' (%s)\n",
			name,
			rp.rp_line);
	if (temp -> ad_r400adr != NULL 
	    && temp->ad_type == AD_X400_TYPE)
		sprintf(addr, temp->ad_r400adr);
	else if (temp -> ad_r822adr != NULL)
		sprintf(addr, temp->ad_r822adr);
	adr_free(temp);
	
	return ret;
}

static int verifyList(list)
dl	*list;
{
	char	*name,
		buf[BUFSIZ];

	
	Name	*ix = list -> dl_list;
	while (ix != NULL) {
		printf("Checking '%s'...",ix -> name);
		if (!rp_isbad(verifyUser(ix -> name, buf))) {
			printf("ok\n");
			ix = ix -> next;
		} else {
			name = strdup(ix -> name);
			ix = ix -> next;
			removeUser(name,list);
			free(name);
		}
/*		if (temp != NULL) *temp = '@';*/
	}
}

static int inList(name, list, plistname)
char	*name;
Name	*list;
char	**plistname;
{
	while (list != NULL 
	       && ap_equ(list -> name, name) != TRUE)
		list = list -> next;
	if (list != NULL)
		*plistname = list->name;
	return (list != NULL) ? TRUE : FALSE;
}

/* \f

 */
/* list maintaince routines */
extern char *re_comp();
extern int re_exec();

static int findUser  (name, list)
char	*name;
dl	*list;
{
	char	*diag;
	Name	*ix;

	if ((diag = re_comp(name)) != 0) {
		fprintf(stderr,
			"re_comp error for '%s' [%s]\n", name, diag);
		return;
	}
	ix = list -> dl_list;
	openpager();
	while (ix != NULL && pipeopen) {
		if (re_exec(lowerfy(ix -> name)) == 1) {
			fprintf(out, "%s\n", ix -> name);
			fflush(stdout);
		}
		ix = ix -> next;
	}
 	closepager();
}
	
static int removeUser(name, list)
char	*name;
dl	*list;
{
	char   	*diag;
	Name    *ix,
		*temp;
	char	buf[BUFSIZ];
	int	len = 0,
		found;
	FILE	*curfp;

	if ((diag = re_comp(name)) != 0) {
		fprintf (stderr,
			 "re_comp error for '%s' [%s]\n",name,diag);
		return;
	}
	if ((curfp = flckopen (list->dl_file, "r+")) == NULL) {
		fprintf (stderr, "Can't open %s: %s\n",
			 list -> dl_file, sys_errname (errno));
		return;
	}

	rewind(curfp);
	ix = list -> dl_list;
	found = FALSE;
	while (ix != NULL) {
		temp = NULL;
		sprintf(buf, "Remove user '%s' ?", ix -> name);
		if (re_exec(lowerfy(ix -> name)) == 1 
		    && confirm(buf) == TRUE) {
			/* remove from list -> dl_list */
			if (ix -> file == NULL) 
				printf("User '%s' specified in-line, cannot remove\n",ix->name);
			else {
				found = TRUE;
				temp = list -> dl_list;
				if (ix == list -> dl_list) {
					list -> dl_list = temp -> next;
				} else {
					while (temp -> next != ix)
						temp = temp -> next;
					temp -> next = ix -> next;
					temp = ix;
				}
			}
		} else if (ix -> file != NULL) {
			/* put it out again */
			fputs (ix -> name, curfp);
			fputc('\n', curfp);
			len += strlen(ix -> name) + 1;
		}
		ix = ix -> next;
		if (temp != NULL) {
			temp -> next = NULL;
			name_free(temp);
		}
	}
	ftruncate(fileno(curfp), (off_t) len);
	flckclose(curfp);
	if (found == FALSE)
		printf("No matches\n");
}

static int addUser(name, list)
char	*name;
dl	*list;
{
	FILE	*curfp;
	Name	*temp,
		*ix;

	if ((curfp = flckopen(list->dl_file, "a")) == NULL) {
		fprintf (stderr, "Can't open file %s: %s\n",
			 list -> dl_file, sys_errname (errno));
		return;
	}
	
	printf ("adding user '%s'\n", name);
	fputs (name, curfp);
	fputc ('\n', curfp);
	flckclose (curfp);
	temp = new_Name(name, list->dl_file);
	if (list -> dl_list == NULL)
		list -> dl_list = temp;
	else {
		ix = list -> dl_list;

		while (ix -> next != NULL)
			ix = ix -> next;
		ix -> next = temp;
	}
}

static char *lowerfy (s)
char	*s;
{
	static char	buf[BUFSIZ];
	char	*cp;

	for (cp = buf; *s; s++)
		if (isascii (*s) && isupper (*s))
			*cp++ = tolower (*s);
		else
			*cp ++ = *s;
	*cp = NULL;
	return buf;
}