xref: /csrg-svn/usr.bin/mail/cmd2.c (revision 34969)
122445Sdist /*
222445Sdist  * Copyright (c) 1980 Regents of the University of California.
333499Sbostic  * All rights reserved.
433499Sbostic  *
533499Sbostic  * Redistribution and use in source and binary forms are permitted
634905Sbostic  * provided that the above copyright notice and this paragraph are
734905Sbostic  * duplicated in all such forms and that any documentation,
834905Sbostic  * advertising materials, and other materials related to such
934905Sbostic  * distribution and use acknowledge that the software was developed
1034905Sbostic  * by the University of California, Berkeley.  The name of the
1134905Sbostic  * University may not be used to endorse or promote products derived
1234905Sbostic  * from this software without specific prior written permission.
1334905Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434905Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534905Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1622445Sdist  */
1722445Sdist 
1834905Sbostic #ifndef lint
19*34969Sedward static char sccsid[] = "@(#)cmd2.c	5.8 (Berkeley) 07/07/88";
2034905Sbostic #endif /* not lint */
211224Skas 
221224Skas #include "rcv.h"
2331142Sedward #include <sys/wait.h>
241224Skas 
251224Skas /*
261224Skas  * Mail -- a mail program
271224Skas  *
281224Skas  * More user commands.
291224Skas  */
301224Skas 
311224Skas /*
321224Skas  * If any arguments were given, go to the next applicable argument
331224Skas  * following dot, otherwise, go to the next applicable message.
341224Skas  * If given as first command with no arguments, print first message.
351224Skas  */
361224Skas 
371224Skas next(msgvec)
381224Skas 	int *msgvec;
391224Skas {
401224Skas 	register struct message *mp;
411224Skas 	register int *ip, *ip2;
421224Skas 	int list[2], mdot;
431224Skas 
441224Skas 	if (*msgvec != NULL) {
451224Skas 
461224Skas 		/*
471224Skas 		 * If some messages were supplied, find the
481224Skas 		 * first applicable one following dot using
491224Skas 		 * wrap around.
501224Skas 		 */
511224Skas 
521224Skas 		mdot = dot - &message[0] + 1;
531470Skas 
541470Skas 		/*
551470Skas 		 * Find the first message in the supplied
561470Skas 		 * message list which follows dot.
571470Skas 		 */
581470Skas 
591224Skas 		for (ip = msgvec; *ip != NULL; ip++)
601224Skas 			if (*ip > mdot)
611224Skas 				break;
621224Skas 		if (*ip == NULL)
631224Skas 			ip = msgvec;
641224Skas 		ip2 = ip;
651224Skas 		do {
661224Skas 			mp = &message[*ip2 - 1];
671224Skas 			if ((mp->m_flag & MDELETED) == 0) {
681224Skas 				dot = mp;
691224Skas 				goto hitit;
701224Skas 			}
711470Skas 			if (*ip2 != NULL)
721470Skas 				ip2++;
731470Skas 			if (*ip2 == NULL)
741470Skas 				ip2 = msgvec;
751224Skas 		} while (ip2 != ip);
761224Skas 		printf("No messages applicable\n");
771224Skas 		return(1);
781224Skas 	}
791224Skas 
801224Skas 	/*
811224Skas 	 * If this is the first command, select message 1.
821224Skas 	 * Note that this must exist for us to get here at all.
831224Skas 	 */
841224Skas 
851481Skas 	if (!sawcom)
861224Skas 		goto hitit;
871224Skas 
881224Skas 	/*
891224Skas 	 * Just find the next good message after dot, no
901224Skas 	 * wraparound.
911224Skas 	 */
921224Skas 
931224Skas 	for (mp = dot+1; mp < &message[msgCount]; mp++)
941224Skas 		if ((mp->m_flag & (MDELETED|MSAVED)) == 0)
951224Skas 			break;
961224Skas 	if (mp >= &message[msgCount]) {
971224Skas 		printf("At EOF\n");
981224Skas 		return(0);
991224Skas 	}
1001224Skas 	dot = mp;
1011224Skas hitit:
1021224Skas 	/*
1031224Skas 	 * Print dot.
1041224Skas 	 */
1051224Skas 
1061224Skas 	list[0] = dot - &message[0] + 1;
1071224Skas 	list[1] = NULL;
1081224Skas 	return(type(list));
1091224Skas }
1101224Skas 
1111224Skas /*
1125776Skurt  * Save a message in a file.  Mark the message as saved
1135776Skurt  * so we can discard when the user quits.
1141224Skas  */
1151224Skas save(str)
1161224Skas 	char str[];
1171224Skas {
1185776Skurt 
119*34969Sedward 	return save1(str, 1, "save", saveignore);
1205776Skurt }
1215776Skurt 
1225776Skurt /*
1235776Skurt  * Copy a message to a file without affected its saved-ness
1245776Skurt  */
1255776Skurt copycmd(str)
1265776Skurt 	char str[];
1275776Skurt {
1285776Skurt 
129*34969Sedward 	return save1(str, 0, "copy", saveignore);
1305776Skurt }
1315776Skurt 
1325776Skurt /*
1335776Skurt  * Save/copy the indicated messages at the end of the passed file name.
1345776Skurt  * If mark is true, mark the message "saved."
1355776Skurt  */
136*34969Sedward save1(str, mark, cmd, ignore)
1375776Skurt 	char str[];
138*34969Sedward 	char *cmd;
139*34969Sedward 	struct ignoretab *ignore;
1405776Skurt {
1411224Skas 	register int *ip, mesg;
1421224Skas 	register struct message *mp;
143*34969Sedward 	char *file, *disp;
144*34969Sedward 	int f, *msgvec;
1451224Skas 	FILE *obuf;
1461224Skas 
1471224Skas 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
1481224Skas 	if ((file = snarf(str, &f)) == NOSTR)
1491224Skas 		return(1);
1501224Skas 	if (!f) {
1511224Skas 		*msgvec = first(0, MMNORM);
1521224Skas 		if (*msgvec == NULL) {
1535776Skurt 			printf("No messages to %s.\n", cmd);
1541224Skas 			return(1);
1551224Skas 		}
1561224Skas 		msgvec[1] = NULL;
1571224Skas 	}
1581224Skas 	if (f && getmsglist(str, msgvec, 0) < 0)
1591224Skas 		return(1);
1601224Skas 	if ((file = expand(file)) == NOSTR)
1611224Skas 		return(1);
1621224Skas 	printf("\"%s\" ", file);
16316859Sralph 	fflush(stdout);
164*34969Sedward 	if (access(file, 0) >= 0)
1651224Skas 		disp = "[Appended]";
1661224Skas 	else
1671224Skas 		disp = "[New file]";
1681224Skas 	if ((obuf = fopen(file, "a")) == NULL) {
1691224Skas 		perror(NOSTR);
1701224Skas 		return(1);
1711224Skas 	}
1721224Skas 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
1731224Skas 		mesg = *ip;
1741224Skas 		touch(mesg);
1751224Skas 		mp = &message[mesg-1];
176*34969Sedward 		if (send(mp, obuf, ignore, NOSTR) < 0) {
1771224Skas 			perror(file);
1781224Skas 			fclose(obuf);
1791224Skas 			return(1);
1801224Skas 		}
1815776Skurt 		if (mark)
1825776Skurt 			mp->m_flag |= MSAVED;
1831224Skas 	}
1841224Skas 	fflush(obuf);
1851224Skas 	if (ferror(obuf))
1861224Skas 		perror(file);
1871224Skas 	fclose(obuf);
188*34969Sedward 	printf("%s\n", disp);
1891224Skas 	return(0);
1901224Skas }
1911224Skas 
1921224Skas /*
1931224Skas  * Write the indicated messages at the end of the passed
1941224Skas  * file name, minus header and trailing blank line.
1951224Skas  */
1961224Skas 
1971224Skas swrite(str)
1981224Skas 	char str[];
1991224Skas {
2001224Skas 
201*34969Sedward 	return save1(str, 1, "write", ignoreall);
2021224Skas }
2031224Skas 
2041224Skas /*
2051224Skas  * Snarf the file from the end of the command line and
2061224Skas  * return a pointer to it.  If there is no file attached,
2071224Skas  * just return NOSTR.  Put a null in front of the file
2081224Skas  * name so that the message list processing won't see it,
2091224Skas  * unless the file name is the only thing on the line, in
2101224Skas  * which case, return 0 in the reference flag variable.
2111224Skas  */
2121224Skas 
2131224Skas char *
2141224Skas snarf(linebuf, flag)
2151224Skas 	char linebuf[];
2161224Skas 	int *flag;
2171224Skas {
2181224Skas 	register char *cp;
2191224Skas 
2201224Skas 	*flag = 1;
2211224Skas 	cp = strlen(linebuf) + linebuf - 1;
2221224Skas 
2231224Skas 	/*
2241224Skas 	 * Strip away trailing blanks.
2251224Skas 	 */
2261224Skas 
22731142Sedward 	while (cp > linebuf && isspace(*cp))
2281224Skas 		cp--;
2291224Skas 	*++cp = 0;
2301224Skas 
2311224Skas 	/*
2321224Skas 	 * Now search for the beginning of the file name.
2331224Skas 	 */
2341224Skas 
23531142Sedward 	while (cp > linebuf && !isspace(*cp))
2361224Skas 		cp--;
2371224Skas 	if (*cp == '\0') {
2381224Skas 		printf("No file specified.\n");
2391224Skas 		return(NOSTR);
2401224Skas 	}
24131142Sedward 	if (isspace(*cp))
2421224Skas 		*cp++ = 0;
2431224Skas 	else
2441224Skas 		*flag = 0;
2451224Skas 	return(cp);
2461224Skas }
2471224Skas 
2481224Skas /*
2491224Skas  * Delete messages.
2501224Skas  */
2511224Skas 
2521224Skas delete(msgvec)
2531224Skas 	int msgvec[];
2541224Skas {
2551224Skas 	return(delm(msgvec));
2561224Skas }
2571224Skas 
2581224Skas /*
2591224Skas  * Delete messages, then type the new dot.
2601224Skas  */
2611224Skas 
2621224Skas deltype(msgvec)
2631224Skas 	int msgvec[];
2641224Skas {
2651224Skas 	int list[2];
2664493Skurt 	int lastdot;
2671224Skas 
2684493Skurt 	lastdot = dot - &message[0] + 1;
2691224Skas 	if (delm(msgvec) >= 0) {
2701224Skas 		list[0] = dot - &message[0];
2711224Skas 		list[0]++;
2724493Skurt 		if (list[0] > lastdot) {
2734493Skurt 			touch(list[0]);
2744493Skurt 			list[1] = NULL;
2754493Skurt 			return(type(list));
2764493Skurt 		}
2774493Skurt 		printf("At EOF\n");
2784493Skurt 		return(0);
2791224Skas 	}
2801224Skas 	else {
2811224Skas 		printf("No more messages\n");
2821224Skas 		return(0);
2831224Skas 	}
2841224Skas }
2851224Skas 
2861224Skas /*
2871224Skas  * Delete the indicated messages.
2881224Skas  * Set dot to some nice place afterwards.
2891224Skas  * Internal interface.
2901224Skas  */
2911224Skas 
2921224Skas delm(msgvec)
2931224Skas 	int *msgvec;
2941224Skas {
2951224Skas 	register struct message *mp;
2961224Skas 	register *ip, mesg;
2971224Skas 	int last;
2981224Skas 
2991224Skas 	last = NULL;
3001224Skas 	for (ip = msgvec; *ip != NULL; ip++) {
3011224Skas 		mesg = *ip;
3021224Skas 		touch(mesg);
3031224Skas 		mp = &message[mesg-1];
3043319Skas 		mp->m_flag |= MDELETED|MTOUCH;
3053319Skas 		mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
3061224Skas 		last = mesg;
3071224Skas 	}
3081224Skas 	if (last != NULL) {
3091224Skas 		dot = &message[last-1];
3101224Skas 		last = first(0, MDELETED);
3111224Skas 		if (last != NULL) {
3121224Skas 			dot = &message[last-1];
3131224Skas 			return(0);
3141224Skas 		}
3151224Skas 		else {
3161224Skas 			dot = &message[0];
3171224Skas 			return(-1);
3181224Skas 		}
3191224Skas 	}
3201224Skas 
3211224Skas 	/*
3221224Skas 	 * Following can't happen -- it keeps lint happy
3231224Skas 	 */
3241224Skas 
3251224Skas 	return(-1);
3261224Skas }
3271224Skas 
3281224Skas /*
3291224Skas  * Undelete the indicated messages.
3301224Skas  */
3311224Skas 
3321224Skas undelete(msgvec)
3331224Skas 	int *msgvec;
3341224Skas {
3351224Skas 	register struct message *mp;
3361224Skas 	register *ip, mesg;
3371224Skas 
3381224Skas 	for (ip = msgvec; ip-msgvec < msgCount; ip++) {
3391224Skas 		mesg = *ip;
3401224Skas 		if (mesg == 0)
3411224Skas 			return;
3421224Skas 		touch(mesg);
3431224Skas 		mp = &message[mesg-1];
3441224Skas 		dot = mp;
3451224Skas 		mp->m_flag &= ~MDELETED;
3461224Skas 	}
3471224Skas }
3481224Skas 
3491224Skas /*
3501224Skas  * Interactively dump core on "core"
3511224Skas  */
3521224Skas 
3531224Skas core()
3541224Skas {
3551224Skas 	register int pid;
35631142Sedward 	union wait status;
3571224Skas 
3581224Skas 	if ((pid = vfork()) == -1) {
3591224Skas 		perror("fork");
3601224Skas 		return(1);
3611224Skas 	}
3621224Skas 	if (pid == 0) {
3631224Skas 		abort();
3641224Skas 		_exit(1);
3651224Skas 	}
3661224Skas 	printf("Okie dokie");
3671224Skas 	fflush(stdout);
3681224Skas 	while (wait(&status) != pid)
3691224Skas 		;
37031142Sedward 	if (status.w_coredump)
3711224Skas 		printf(" -- Core dumped\n");
3721224Skas 	else
3731224Skas 		printf("\n");
37431142Sedward 	return 0;
3751224Skas }
3764340Skurt 
3774340Skurt /*
3784340Skurt  * Clobber as many bytes of stack as the user requests.
3794340Skurt  */
3804340Skurt clobber(argv)
3814340Skurt 	char **argv;
3824340Skurt {
3834340Skurt 	register int times;
3844340Skurt 
3854340Skurt 	if (argv[0] == 0)
3864340Skurt 		times = 1;
3874340Skurt 	else
3884340Skurt 		times = (atoi(argv[0]) + 511) / 512;
3897561Skurt 	clob1(times);
3904340Skurt }
3914340Skurt 
3924340Skurt /*
3934340Skurt  * Clobber the stack.
3944340Skurt  */
3957561Skurt clob1(n)
3964340Skurt {
3974340Skurt 	char buf[512];
3984340Skurt 	register char *cp;
3994340Skurt 
4004340Skurt 	if (n <= 0)
4014340Skurt 		return;
4024340Skurt 	for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
4034340Skurt 		;
4047561Skurt 	clob1(n - 1);
4054340Skurt }
4067573Skurt 
4077573Skurt /*
40818662Sserge  * Add the given header fields to the retained list.
40918662Sserge  * If no arguments, print the current list of retained fields.
41018662Sserge  */
41118662Sserge retfield(list)
41218662Sserge 	char *list[];
41318662Sserge {
41418662Sserge 
41534692Sedward 	return ignore1(list, ignore + 1, "retained");
41618662Sserge }
41718662Sserge 
41818662Sserge /*
41934692Sedward  * Add the given header fields to the ignored list.
42034692Sedward  * If no arguments, print the current list of ignored fields.
42118662Sserge  */
42234692Sedward igfield(list)
42334692Sedward 	char *list[];
42418662Sserge {
42518662Sserge 
42634692Sedward 	return ignore1(list, ignore, "ignored");
42718662Sserge }
42818662Sserge 
42934692Sedward saveretfield(list)
4307573Skurt 	char *list[];
4317573Skurt {
43234692Sedward 
43334692Sedward 	return ignore1(list, saveignore + 1, "retained");
43434692Sedward }
43534692Sedward 
43634692Sedward saveigfield(list)
43734692Sedward 	char *list[];
43834692Sedward {
43934692Sedward 
44034692Sedward 	return ignore1(list, saveignore, "ignored");
44134692Sedward }
44234692Sedward 
44334692Sedward ignore1(list, tab, which)
44434692Sedward 	char *list[];
44534692Sedward 	struct ignoretab *tab;
44634692Sedward 	char *which;
44734692Sedward {
4487573Skurt 	char field[BUFSIZ];
4497573Skurt 	register int h;
4507573Skurt 	register struct ignore *igp;
4517573Skurt 	char **ap;
4527573Skurt 
4537573Skurt 	if (argcount(list) == 0)
45434692Sedward 		return igshow(tab, which);
4557573Skurt 	for (ap = list; *ap != 0; ap++) {
45634692Sedward 		istrcpy(field, *ap);
45734692Sedward 		if (member(field, tab))
4587582Skurt 			continue;
4597573Skurt 		h = hash(field);
4607573Skurt 		igp = (struct ignore *) calloc(1, sizeof (struct ignore));
46131142Sedward 		igp->i_field = calloc((unsigned) strlen(field) + 1,
46231142Sedward 			sizeof (char));
4637573Skurt 		strcpy(igp->i_field, field);
46434692Sedward 		igp->i_link = tab->i_head[h];
46534692Sedward 		tab->i_head[h] = igp;
46634692Sedward 		tab->i_count++;
4677573Skurt 	}
46834692Sedward 	return 0;
4697573Skurt }
4707573Skurt 
4717573Skurt /*
47234692Sedward  * Print out all currently retained fields.
4737573Skurt  */
47434692Sedward igshow(tab, which)
47534692Sedward 	struct ignoretab *tab;
47634692Sedward 	char *which;
4777573Skurt {
47834692Sedward 	register int h;
4797573Skurt 	struct ignore *igp;
4807582Skurt 	char **ap, **ring;
4817582Skurt 	int igcomp();
4827573Skurt 
48334692Sedward 	if (tab->i_count == 0) {
48434692Sedward 		printf("No fields currently being %s.\n", which);
48534692Sedward 		return 0;
4867582Skurt 	}
48734692Sedward 	ring = (char **) salloc((tab->i_count + 1) * sizeof (char *));
4887582Skurt 	ap = ring;
4897582Skurt 	for (h = 0; h < HSHSIZE; h++)
49034692Sedward 		for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link)
4917582Skurt 			*ap++ = igp->i_field;
4927582Skurt 	*ap = 0;
49334692Sedward 	qsort((char *) ring, tab->i_count, sizeof (char *), igcomp);
4947582Skurt 	for (ap = ring; *ap != 0; ap++)
4957582Skurt 		printf("%s\n", *ap);
49634692Sedward 	return 0;
4977573Skurt }
4987582Skurt 
4997582Skurt /*
5007582Skurt  * Compare two names for sorting ignored field list.
5017582Skurt  */
5027582Skurt igcomp(l, r)
5037582Skurt 	char **l, **r;
5047582Skurt {
5057582Skurt 
50634692Sedward 	return strcmp(*l, *r);
5077582Skurt }
508