xref: /csrg-svn/usr.bin/mail/cmd2.c (revision 62083)
122445Sdist /*
2*62083Sbostic  * Copyright (c) 1980, 1993
3*62083Sbostic  *	The Regents of the University of California.  All rights reserved.
433499Sbostic  *
542741Sbostic  * %sccs.include.redist.c%
622445Sdist  */
722445Sdist 
834905Sbostic #ifndef lint
9*62083Sbostic static char sccsid[] = "@(#)cmd2.c	8.1 (Berkeley) 06/06/93";
1034905Sbostic #endif /* not lint */
111224Skas 
121224Skas #include "rcv.h"
1331142Sedward #include <sys/wait.h>
1454505Sbostic #include "extern.h"
151224Skas 
161224Skas /*
171224Skas  * Mail -- a mail program
181224Skas  *
191224Skas  * More user commands.
201224Skas  */
211224Skas 
221224Skas /*
231224Skas  * If any arguments were given, go to the next applicable argument
241224Skas  * following dot, otherwise, go to the next applicable message.
251224Skas  * If given as first command with no arguments, print first message.
261224Skas  */
2754505Sbostic int
next(msgvec)281224Skas next(msgvec)
291224Skas 	int *msgvec;
301224Skas {
311224Skas 	register struct message *mp;
321224Skas 	register int *ip, *ip2;
331224Skas 	int list[2], mdot;
341224Skas 
351224Skas 	if (*msgvec != NULL) {
361224Skas 
371224Skas 		/*
381224Skas 		 * If some messages were supplied, find the
391224Skas 		 * first applicable one following dot using
401224Skas 		 * wrap around.
411224Skas 		 */
421224Skas 
431224Skas 		mdot = dot - &message[0] + 1;
441470Skas 
451470Skas 		/*
461470Skas 		 * Find the first message in the supplied
471470Skas 		 * message list which follows dot.
481470Skas 		 */
491470Skas 
501224Skas 		for (ip = msgvec; *ip != NULL; ip++)
511224Skas 			if (*ip > mdot)
521224Skas 				break;
531224Skas 		if (*ip == NULL)
541224Skas 			ip = msgvec;
551224Skas 		ip2 = ip;
561224Skas 		do {
571224Skas 			mp = &message[*ip2 - 1];
581224Skas 			if ((mp->m_flag & MDELETED) == 0) {
591224Skas 				dot = mp;
601224Skas 				goto hitit;
611224Skas 			}
621470Skas 			if (*ip2 != NULL)
631470Skas 				ip2++;
641470Skas 			if (*ip2 == NULL)
651470Skas 				ip2 = msgvec;
661224Skas 		} while (ip2 != ip);
671224Skas 		printf("No messages applicable\n");
681224Skas 		return(1);
691224Skas 	}
701224Skas 
711224Skas 	/*
721224Skas 	 * If this is the first command, select message 1.
731224Skas 	 * Note that this must exist for us to get here at all.
741224Skas 	 */
751224Skas 
761481Skas 	if (!sawcom)
771224Skas 		goto hitit;
781224Skas 
791224Skas 	/*
801224Skas 	 * Just find the next good message after dot, no
811224Skas 	 * wraparound.
821224Skas 	 */
831224Skas 
841224Skas 	for (mp = dot+1; mp < &message[msgCount]; mp++)
851224Skas 		if ((mp->m_flag & (MDELETED|MSAVED)) == 0)
861224Skas 			break;
871224Skas 	if (mp >= &message[msgCount]) {
881224Skas 		printf("At EOF\n");
891224Skas 		return(0);
901224Skas 	}
911224Skas 	dot = mp;
921224Skas hitit:
931224Skas 	/*
941224Skas 	 * Print dot.
951224Skas 	 */
961224Skas 
971224Skas 	list[0] = dot - &message[0] + 1;
981224Skas 	list[1] = NULL;
991224Skas 	return(type(list));
1001224Skas }
1011224Skas 
1021224Skas /*
1035776Skurt  * Save a message in a file.  Mark the message as saved
1045776Skurt  * so we can discard when the user quits.
1051224Skas  */
10654505Sbostic int
save(str)1071224Skas save(str)
1081224Skas 	char str[];
1091224Skas {
1105776Skurt 
11134969Sedward 	return save1(str, 1, "save", saveignore);
1125776Skurt }
1135776Skurt 
1145776Skurt /*
1155776Skurt  * Copy a message to a file without affected its saved-ness
1165776Skurt  */
11754505Sbostic int
copycmd(str)1185776Skurt copycmd(str)
1195776Skurt 	char str[];
1205776Skurt {
1215776Skurt 
12234969Sedward 	return save1(str, 0, "copy", saveignore);
1235776Skurt }
1245776Skurt 
1255776Skurt /*
1265776Skurt  * Save/copy the indicated messages at the end of the passed file name.
1275776Skurt  * If mark is true, mark the message "saved."
1285776Skurt  */
12954505Sbostic int
save1(str,mark,cmd,ignore)13034969Sedward save1(str, mark, cmd, ignore)
1315776Skurt 	char str[];
13254505Sbostic 	int mark;
13334969Sedward 	char *cmd;
13434969Sedward 	struct ignoretab *ignore;
1355776Skurt {
13634987Sedward 	register int *ip;
1371224Skas 	register struct message *mp;
13834969Sedward 	char *file, *disp;
13934969Sedward 	int f, *msgvec;
1401224Skas 	FILE *obuf;
1411224Skas 
1421224Skas 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
1431224Skas 	if ((file = snarf(str, &f)) == NOSTR)
1441224Skas 		return(1);
1451224Skas 	if (!f) {
1461224Skas 		*msgvec = first(0, MMNORM);
1471224Skas 		if (*msgvec == NULL) {
1485776Skurt 			printf("No messages to %s.\n", cmd);
1491224Skas 			return(1);
1501224Skas 		}
1511224Skas 		msgvec[1] = NULL;
1521224Skas 	}
1531224Skas 	if (f && getmsglist(str, msgvec, 0) < 0)
1541224Skas 		return(1);
1551224Skas 	if ((file = expand(file)) == NOSTR)
1561224Skas 		return(1);
1571224Skas 	printf("\"%s\" ", file);
15816859Sralph 	fflush(stdout);
15934969Sedward 	if (access(file, 0) >= 0)
1601224Skas 		disp = "[Appended]";
1611224Skas 	else
1621224Skas 		disp = "[New file]";
16343865Sedward 	if ((obuf = Fopen(file, "a")) == NULL) {
1641224Skas 		perror(NOSTR);
1651224Skas 		return(1);
1661224Skas 	}
1671224Skas 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
16834987Sedward 		mp = &message[*ip - 1];
16934987Sedward 		touch(mp);
17034969Sedward 		if (send(mp, obuf, ignore, NOSTR) < 0) {
1711224Skas 			perror(file);
17243865Sedward 			Fclose(obuf);
1731224Skas 			return(1);
1741224Skas 		}
1755776Skurt 		if (mark)
1765776Skurt 			mp->m_flag |= MSAVED;
1771224Skas 	}
1781224Skas 	fflush(obuf);
1791224Skas 	if (ferror(obuf))
1801224Skas 		perror(file);
18143865Sedward 	Fclose(obuf);
18234969Sedward 	printf("%s\n", disp);
1831224Skas 	return(0);
1841224Skas }
1851224Skas 
1861224Skas /*
1871224Skas  * Write the indicated messages at the end of the passed
1881224Skas  * file name, minus header and trailing blank line.
1891224Skas  */
19054505Sbostic int
swrite(str)1911224Skas swrite(str)
1921224Skas 	char str[];
1931224Skas {
1941224Skas 
19534969Sedward 	return save1(str, 1, "write", ignoreall);
1961224Skas }
1971224Skas 
1981224Skas /*
1991224Skas  * Snarf the file from the end of the command line and
2001224Skas  * return a pointer to it.  If there is no file attached,
2011224Skas  * just return NOSTR.  Put a null in front of the file
2021224Skas  * name so that the message list processing won't see it,
2031224Skas  * unless the file name is the only thing on the line, in
2041224Skas  * which case, return 0 in the reference flag variable.
2051224Skas  */
2061224Skas 
2071224Skas char *
snarf(linebuf,flag)2081224Skas snarf(linebuf, flag)
2091224Skas 	char linebuf[];
2101224Skas 	int *flag;
2111224Skas {
2121224Skas 	register char *cp;
2131224Skas 
2141224Skas 	*flag = 1;
2151224Skas 	cp = strlen(linebuf) + linebuf - 1;
2161224Skas 
2171224Skas 	/*
2181224Skas 	 * Strip away trailing blanks.
2191224Skas 	 */
2201224Skas 
22131142Sedward 	while (cp > linebuf && isspace(*cp))
2221224Skas 		cp--;
2231224Skas 	*++cp = 0;
2241224Skas 
2251224Skas 	/*
2261224Skas 	 * Now search for the beginning of the file name.
2271224Skas 	 */
2281224Skas 
22931142Sedward 	while (cp > linebuf && !isspace(*cp))
2301224Skas 		cp--;
2311224Skas 	if (*cp == '\0') {
2321224Skas 		printf("No file specified.\n");
2331224Skas 		return(NOSTR);
2341224Skas 	}
23531142Sedward 	if (isspace(*cp))
2361224Skas 		*cp++ = 0;
2371224Skas 	else
2381224Skas 		*flag = 0;
2391224Skas 	return(cp);
2401224Skas }
2411224Skas 
2421224Skas /*
2431224Skas  * Delete messages.
2441224Skas  */
24554505Sbostic int
delete(msgvec)2461224Skas delete(msgvec)
2471224Skas 	int msgvec[];
2481224Skas {
24936554Sedward 	delm(msgvec);
25036554Sedward 	return 0;
2511224Skas }
2521224Skas 
2531224Skas /*
2541224Skas  * Delete messages, then type the new dot.
2551224Skas  */
25654505Sbostic int
deltype(msgvec)2571224Skas deltype(msgvec)
2581224Skas 	int msgvec[];
2591224Skas {
2601224Skas 	int list[2];
2614493Skurt 	int lastdot;
2621224Skas 
2634493Skurt 	lastdot = dot - &message[0] + 1;
2641224Skas 	if (delm(msgvec) >= 0) {
26534987Sedward 		list[0] = dot - &message[0] + 1;
2664493Skurt 		if (list[0] > lastdot) {
26734987Sedward 			touch(dot);
2684493Skurt 			list[1] = NULL;
2694493Skurt 			return(type(list));
2704493Skurt 		}
2714493Skurt 		printf("At EOF\n");
27236554Sedward 	} else
2731224Skas 		printf("No more messages\n");
27436554Sedward 	return(0);
2751224Skas }
2761224Skas 
2771224Skas /*
2781224Skas  * Delete the indicated messages.
2791224Skas  * Set dot to some nice place afterwards.
2801224Skas  * Internal interface.
2811224Skas  */
28254505Sbostic int
delm(msgvec)2831224Skas delm(msgvec)
2841224Skas 	int *msgvec;
2851224Skas {
2861224Skas 	register struct message *mp;
28734987Sedward 	register *ip;
2881224Skas 	int last;
2891224Skas 
2901224Skas 	last = NULL;
2911224Skas 	for (ip = msgvec; *ip != NULL; ip++) {
29234987Sedward 		mp = &message[*ip - 1];
29334987Sedward 		touch(mp);
2943319Skas 		mp->m_flag |= MDELETED|MTOUCH;
2953319Skas 		mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
29634987Sedward 		last = *ip;
2971224Skas 	}
2981224Skas 	if (last != NULL) {
2991224Skas 		dot = &message[last-1];
3001224Skas 		last = first(0, MDELETED);
3011224Skas 		if (last != NULL) {
3021224Skas 			dot = &message[last-1];
3031224Skas 			return(0);
3041224Skas 		}
3051224Skas 		else {
3061224Skas 			dot = &message[0];
3071224Skas 			return(-1);
3081224Skas 		}
3091224Skas 	}
3101224Skas 
3111224Skas 	/*
3121224Skas 	 * Following can't happen -- it keeps lint happy
3131224Skas 	 */
3141224Skas 
3151224Skas 	return(-1);
3161224Skas }
3171224Skas 
3181224Skas /*
3191224Skas  * Undelete the indicated messages.
3201224Skas  */
32154505Sbostic int
undelete(msgvec)3221224Skas undelete(msgvec)
3231224Skas 	int *msgvec;
3241224Skas {
3251224Skas 	register struct message *mp;
32634987Sedward 	register *ip;
3271224Skas 
32834987Sedward 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
32934987Sedward 		mp = &message[*ip - 1];
33034987Sedward 		touch(mp);
3311224Skas 		dot = mp;
3321224Skas 		mp->m_flag &= ~MDELETED;
3331224Skas 	}
33436687Sedward 	return 0;
3351224Skas }
3361224Skas 
3371224Skas /*
3381224Skas  * Interactively dump core on "core"
3391224Skas  */
34054505Sbostic int
core()3411224Skas core()
3421224Skas {
34334976Sedward 	int pid;
34434976Sedward 	extern union wait wait_status;
3451224Skas 
34634976Sedward 	switch (pid = vfork()) {
34734976Sedward 	case -1:
3481224Skas 		perror("fork");
3491224Skas 		return(1);
35034976Sedward 	case 0:
3511224Skas 		abort();
3521224Skas 		_exit(1);
3531224Skas 	}
3541224Skas 	printf("Okie dokie");
3551224Skas 	fflush(stdout);
35634976Sedward 	wait_child(pid);
35734976Sedward 	if (wait_status.w_coredump)
35834976Sedward 		printf(" -- Core dumped.\n");
3591224Skas 	else
36034976Sedward 		printf(" -- Can't dump core.\n");
36131142Sedward 	return 0;
3621224Skas }
3634340Skurt 
3644340Skurt /*
3654340Skurt  * Clobber as many bytes of stack as the user requests.
3664340Skurt  */
36754505Sbostic int
clobber(argv)3684340Skurt clobber(argv)
3694340Skurt 	char **argv;
3704340Skurt {
3714340Skurt 	register int times;
3724340Skurt 
3734340Skurt 	if (argv[0] == 0)
3744340Skurt 		times = 1;
3754340Skurt 	else
3764340Skurt 		times = (atoi(argv[0]) + 511) / 512;
3777561Skurt 	clob1(times);
37836687Sedward 	return 0;
3794340Skurt }
3804340Skurt 
3814340Skurt /*
3824340Skurt  * Clobber the stack.
3834340Skurt  */
38454505Sbostic void
clob1(n)3857561Skurt clob1(n)
38654505Sbostic 	int n;
3874340Skurt {
3884340Skurt 	char buf[512];
3894340Skurt 	register char *cp;
3904340Skurt 
3914340Skurt 	if (n <= 0)
3924340Skurt 		return;
3934340Skurt 	for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
3944340Skurt 		;
3957561Skurt 	clob1(n - 1);
3964340Skurt }
3977573Skurt 
3987573Skurt /*
39918662Sserge  * Add the given header fields to the retained list.
40018662Sserge  * If no arguments, print the current list of retained fields.
40118662Sserge  */
40254505Sbostic int
retfield(list)40318662Sserge retfield(list)
40418662Sserge 	char *list[];
40518662Sserge {
40618662Sserge 
40734692Sedward 	return ignore1(list, ignore + 1, "retained");
40818662Sserge }
40918662Sserge 
41018662Sserge /*
41134692Sedward  * Add the given header fields to the ignored list.
41234692Sedward  * If no arguments, print the current list of ignored fields.
41318662Sserge  */
41454505Sbostic int
igfield(list)41534692Sedward igfield(list)
41634692Sedward 	char *list[];
41718662Sserge {
41818662Sserge 
41934692Sedward 	return ignore1(list, ignore, "ignored");
42018662Sserge }
42118662Sserge 
42254505Sbostic int
saveretfield(list)42334692Sedward saveretfield(list)
4247573Skurt 	char *list[];
4257573Skurt {
42634692Sedward 
42734692Sedward 	return ignore1(list, saveignore + 1, "retained");
42834692Sedward }
42934692Sedward 
43054505Sbostic int
saveigfield(list)43134692Sedward saveigfield(list)
43234692Sedward 	char *list[];
43334692Sedward {
43434692Sedward 
43534692Sedward 	return ignore1(list, saveignore, "ignored");
43634692Sedward }
43734692Sedward 
43854505Sbostic int
ignore1(list,tab,which)43934692Sedward ignore1(list, tab, which)
44034692Sedward 	char *list[];
44134692Sedward 	struct ignoretab *tab;
44234692Sedward 	char *which;
44334692Sedward {
4447573Skurt 	char field[BUFSIZ];
4457573Skurt 	register int h;
4467573Skurt 	register struct ignore *igp;
4477573Skurt 	char **ap;
4487573Skurt 
44934987Sedward 	if (*list == NOSTR)
45034692Sedward 		return igshow(tab, which);
4517573Skurt 	for (ap = list; *ap != 0; ap++) {
45234692Sedward 		istrcpy(field, *ap);
45334692Sedward 		if (member(field, tab))
4547582Skurt 			continue;
4557573Skurt 		h = hash(field);
4567573Skurt 		igp = (struct ignore *) calloc(1, sizeof (struct ignore));
45731142Sedward 		igp->i_field = calloc((unsigned) strlen(field) + 1,
45831142Sedward 			sizeof (char));
4597573Skurt 		strcpy(igp->i_field, field);
46034692Sedward 		igp->i_link = tab->i_head[h];
46134692Sedward 		tab->i_head[h] = igp;
46234692Sedward 		tab->i_count++;
4637573Skurt 	}
46434692Sedward 	return 0;
4657573Skurt }
4667573Skurt 
4677573Skurt /*
46834692Sedward  * Print out all currently retained fields.
4697573Skurt  */
47054505Sbostic int
igshow(tab,which)47134692Sedward igshow(tab, which)
47234692Sedward 	struct ignoretab *tab;
47334692Sedward 	char *which;
4747573Skurt {
47534692Sedward 	register int h;
4767573Skurt 	struct ignore *igp;
4777582Skurt 	char **ap, **ring;
4787582Skurt 	int igcomp();
4797573Skurt 
48034692Sedward 	if (tab->i_count == 0) {
48134692Sedward 		printf("No fields currently being %s.\n", which);
48234692Sedward 		return 0;
4837582Skurt 	}
48434692Sedward 	ring = (char **) salloc((tab->i_count + 1) * sizeof (char *));
4857582Skurt 	ap = ring;
4867582Skurt 	for (h = 0; h < HSHSIZE; h++)
48734692Sedward 		for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link)
4887582Skurt 			*ap++ = igp->i_field;
4897582Skurt 	*ap = 0;
49054505Sbostic 	qsort(ring, tab->i_count, sizeof (char *), igcomp);
4917582Skurt 	for (ap = ring; *ap != 0; ap++)
4927582Skurt 		printf("%s\n", *ap);
49334692Sedward 	return 0;
4947573Skurt }
4957582Skurt 
4967582Skurt /*
4977582Skurt  * Compare two names for sorting ignored field list.
4987582Skurt  */
49954505Sbostic int
igcomp(l,r)5007582Skurt igcomp(l, r)
50154505Sbostic 	const void *l, *r;
5027582Skurt {
50354505Sbostic 	return (strcmp(*(char **)l, *(char **)r));
5047582Skurt }
505