xref: /csrg-svn/usr.bin/mail/cmd2.c (revision 34987)
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*34987Sedward static char sccsid[] = "@(#)cmd2.c	5.10 (Berkeley) 07/08/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 
11934969Sedward 	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 
12934969Sedward 	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  */
13634969Sedward save1(str, mark, cmd, ignore)
1375776Skurt 	char str[];
13834969Sedward 	char *cmd;
13934969Sedward 	struct ignoretab *ignore;
1405776Skurt {
141*34987Sedward 	register int *ip;
1421224Skas 	register struct message *mp;
14334969Sedward 	char *file, *disp;
14434969Sedward 	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);
16434969Sedward 	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++) {
173*34987Sedward 		mp = &message[*ip - 1];
174*34987Sedward 		touch(mp);
17534969Sedward 		if (send(mp, obuf, ignore, NOSTR) < 0) {
1761224Skas 			perror(file);
1771224Skas 			fclose(obuf);
1781224Skas 			return(1);
1791224Skas 		}
1805776Skurt 		if (mark)
1815776Skurt 			mp->m_flag |= MSAVED;
1821224Skas 	}
1831224Skas 	fflush(obuf);
1841224Skas 	if (ferror(obuf))
1851224Skas 		perror(file);
1861224Skas 	fclose(obuf);
18734969Sedward 	printf("%s\n", disp);
1881224Skas 	return(0);
1891224Skas }
1901224Skas 
1911224Skas /*
1921224Skas  * Write the indicated messages at the end of the passed
1931224Skas  * file name, minus header and trailing blank line.
1941224Skas  */
1951224Skas 
1961224Skas swrite(str)
1971224Skas 	char str[];
1981224Skas {
1991224Skas 
20034969Sedward 	return save1(str, 1, "write", ignoreall);
2011224Skas }
2021224Skas 
2031224Skas /*
2041224Skas  * Snarf the file from the end of the command line and
2051224Skas  * return a pointer to it.  If there is no file attached,
2061224Skas  * just return NOSTR.  Put a null in front of the file
2071224Skas  * name so that the message list processing won't see it,
2081224Skas  * unless the file name is the only thing on the line, in
2091224Skas  * which case, return 0 in the reference flag variable.
2101224Skas  */
2111224Skas 
2121224Skas char *
2131224Skas snarf(linebuf, flag)
2141224Skas 	char linebuf[];
2151224Skas 	int *flag;
2161224Skas {
2171224Skas 	register char *cp;
2181224Skas 
2191224Skas 	*flag = 1;
2201224Skas 	cp = strlen(linebuf) + linebuf - 1;
2211224Skas 
2221224Skas 	/*
2231224Skas 	 * Strip away trailing blanks.
2241224Skas 	 */
2251224Skas 
22631142Sedward 	while (cp > linebuf && isspace(*cp))
2271224Skas 		cp--;
2281224Skas 	*++cp = 0;
2291224Skas 
2301224Skas 	/*
2311224Skas 	 * Now search for the beginning of the file name.
2321224Skas 	 */
2331224Skas 
23431142Sedward 	while (cp > linebuf && !isspace(*cp))
2351224Skas 		cp--;
2361224Skas 	if (*cp == '\0') {
2371224Skas 		printf("No file specified.\n");
2381224Skas 		return(NOSTR);
2391224Skas 	}
24031142Sedward 	if (isspace(*cp))
2411224Skas 		*cp++ = 0;
2421224Skas 	else
2431224Skas 		*flag = 0;
2441224Skas 	return(cp);
2451224Skas }
2461224Skas 
2471224Skas /*
2481224Skas  * Delete messages.
2491224Skas  */
2501224Skas 
2511224Skas delete(msgvec)
2521224Skas 	int msgvec[];
2531224Skas {
2541224Skas 	return(delm(msgvec));
2551224Skas }
2561224Skas 
2571224Skas /*
2581224Skas  * Delete messages, then type the new dot.
2591224Skas  */
2601224Skas 
2611224Skas deltype(msgvec)
2621224Skas 	int msgvec[];
2631224Skas {
2641224Skas 	int list[2];
2654493Skurt 	int lastdot;
2661224Skas 
2674493Skurt 	lastdot = dot - &message[0] + 1;
2681224Skas 	if (delm(msgvec) >= 0) {
269*34987Sedward 		list[0] = dot - &message[0] + 1;
2704493Skurt 		if (list[0] > lastdot) {
271*34987Sedward 			touch(dot);
2724493Skurt 			list[1] = NULL;
2734493Skurt 			return(type(list));
2744493Skurt 		}
2754493Skurt 		printf("At EOF\n");
2764493Skurt 		return(0);
2771224Skas 	}
2781224Skas 	else {
2791224Skas 		printf("No more messages\n");
2801224Skas 		return(0);
2811224Skas 	}
2821224Skas }
2831224Skas 
2841224Skas /*
2851224Skas  * Delete the indicated messages.
2861224Skas  * Set dot to some nice place afterwards.
2871224Skas  * Internal interface.
2881224Skas  */
2891224Skas 
2901224Skas delm(msgvec)
2911224Skas 	int *msgvec;
2921224Skas {
2931224Skas 	register struct message *mp;
294*34987Sedward 	register *ip;
2951224Skas 	int last;
2961224Skas 
2971224Skas 	last = NULL;
2981224Skas 	for (ip = msgvec; *ip != NULL; ip++) {
299*34987Sedward 		mp = &message[*ip - 1];
300*34987Sedward 		touch(mp);
3013319Skas 		mp->m_flag |= MDELETED|MTOUCH;
3023319Skas 		mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
303*34987Sedward 		last = *ip;
3041224Skas 	}
3051224Skas 	if (last != NULL) {
3061224Skas 		dot = &message[last-1];
3071224Skas 		last = first(0, MDELETED);
3081224Skas 		if (last != NULL) {
3091224Skas 			dot = &message[last-1];
3101224Skas 			return(0);
3111224Skas 		}
3121224Skas 		else {
3131224Skas 			dot = &message[0];
3141224Skas 			return(-1);
3151224Skas 		}
3161224Skas 	}
3171224Skas 
3181224Skas 	/*
3191224Skas 	 * Following can't happen -- it keeps lint happy
3201224Skas 	 */
3211224Skas 
3221224Skas 	return(-1);
3231224Skas }
3241224Skas 
3251224Skas /*
3261224Skas  * Undelete the indicated messages.
3271224Skas  */
3281224Skas 
3291224Skas undelete(msgvec)
3301224Skas 	int *msgvec;
3311224Skas {
3321224Skas 	register struct message *mp;
333*34987Sedward 	register *ip;
3341224Skas 
335*34987Sedward 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
336*34987Sedward 		mp = &message[*ip - 1];
337*34987Sedward 		touch(mp);
3381224Skas 		dot = mp;
3391224Skas 		mp->m_flag &= ~MDELETED;
3401224Skas 	}
3411224Skas }
3421224Skas 
3431224Skas /*
3441224Skas  * Interactively dump core on "core"
3451224Skas  */
3461224Skas 
3471224Skas core()
3481224Skas {
34934976Sedward 	int pid;
35034976Sedward 	extern union wait wait_status;
3511224Skas 
35234976Sedward 	switch (pid = vfork()) {
35334976Sedward 	case -1:
3541224Skas 		perror("fork");
3551224Skas 		return(1);
35634976Sedward 	case 0:
3571224Skas 		abort();
3581224Skas 		_exit(1);
3591224Skas 	}
3601224Skas 	printf("Okie dokie");
3611224Skas 	fflush(stdout);
36234976Sedward 	wait_child(pid);
36334976Sedward 	if (wait_status.w_coredump)
36434976Sedward 		printf(" -- Core dumped.\n");
3651224Skas 	else
36634976Sedward 		printf(" -- Can't dump core.\n");
36731142Sedward 	return 0;
3681224Skas }
3694340Skurt 
3704340Skurt /*
3714340Skurt  * Clobber as many bytes of stack as the user requests.
3724340Skurt  */
3734340Skurt clobber(argv)
3744340Skurt 	char **argv;
3754340Skurt {
3764340Skurt 	register int times;
3774340Skurt 
3784340Skurt 	if (argv[0] == 0)
3794340Skurt 		times = 1;
3804340Skurt 	else
3814340Skurt 		times = (atoi(argv[0]) + 511) / 512;
3827561Skurt 	clob1(times);
3834340Skurt }
3844340Skurt 
3854340Skurt /*
3864340Skurt  * Clobber the stack.
3874340Skurt  */
3887561Skurt clob1(n)
3894340Skurt {
3904340Skurt 	char buf[512];
3914340Skurt 	register char *cp;
3924340Skurt 
3934340Skurt 	if (n <= 0)
3944340Skurt 		return;
3954340Skurt 	for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
3964340Skurt 		;
3977561Skurt 	clob1(n - 1);
3984340Skurt }
3997573Skurt 
4007573Skurt /*
40118662Sserge  * Add the given header fields to the retained list.
40218662Sserge  * If no arguments, print the current list of retained fields.
40318662Sserge  */
40418662Sserge retfield(list)
40518662Sserge 	char *list[];
40618662Sserge {
40718662Sserge 
40834692Sedward 	return ignore1(list, ignore + 1, "retained");
40918662Sserge }
41018662Sserge 
41118662Sserge /*
41234692Sedward  * Add the given header fields to the ignored list.
41334692Sedward  * If no arguments, print the current list of ignored fields.
41418662Sserge  */
41534692Sedward igfield(list)
41634692Sedward 	char *list[];
41718662Sserge {
41818662Sserge 
41934692Sedward 	return ignore1(list, ignore, "ignored");
42018662Sserge }
42118662Sserge 
42234692Sedward saveretfield(list)
4237573Skurt 	char *list[];
4247573Skurt {
42534692Sedward 
42634692Sedward 	return ignore1(list, saveignore + 1, "retained");
42734692Sedward }
42834692Sedward 
42934692Sedward saveigfield(list)
43034692Sedward 	char *list[];
43134692Sedward {
43234692Sedward 
43334692Sedward 	return ignore1(list, saveignore, "ignored");
43434692Sedward }
43534692Sedward 
43634692Sedward ignore1(list, tab, which)
43734692Sedward 	char *list[];
43834692Sedward 	struct ignoretab *tab;
43934692Sedward 	char *which;
44034692Sedward {
4417573Skurt 	char field[BUFSIZ];
4427573Skurt 	register int h;
4437573Skurt 	register struct ignore *igp;
4447573Skurt 	char **ap;
4457573Skurt 
446*34987Sedward 	if (*list == NOSTR)
44734692Sedward 		return igshow(tab, which);
4487573Skurt 	for (ap = list; *ap != 0; ap++) {
44934692Sedward 		istrcpy(field, *ap);
45034692Sedward 		if (member(field, tab))
4517582Skurt 			continue;
4527573Skurt 		h = hash(field);
4537573Skurt 		igp = (struct ignore *) calloc(1, sizeof (struct ignore));
45431142Sedward 		igp->i_field = calloc((unsigned) strlen(field) + 1,
45531142Sedward 			sizeof (char));
4567573Skurt 		strcpy(igp->i_field, field);
45734692Sedward 		igp->i_link = tab->i_head[h];
45834692Sedward 		tab->i_head[h] = igp;
45934692Sedward 		tab->i_count++;
4607573Skurt 	}
46134692Sedward 	return 0;
4627573Skurt }
4637573Skurt 
4647573Skurt /*
46534692Sedward  * Print out all currently retained fields.
4667573Skurt  */
46734692Sedward igshow(tab, which)
46834692Sedward 	struct ignoretab *tab;
46934692Sedward 	char *which;
4707573Skurt {
47134692Sedward 	register int h;
4727573Skurt 	struct ignore *igp;
4737582Skurt 	char **ap, **ring;
4747582Skurt 	int igcomp();
4757573Skurt 
47634692Sedward 	if (tab->i_count == 0) {
47734692Sedward 		printf("No fields currently being %s.\n", which);
47834692Sedward 		return 0;
4797582Skurt 	}
48034692Sedward 	ring = (char **) salloc((tab->i_count + 1) * sizeof (char *));
4817582Skurt 	ap = ring;
4827582Skurt 	for (h = 0; h < HSHSIZE; h++)
48334692Sedward 		for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link)
4847582Skurt 			*ap++ = igp->i_field;
4857582Skurt 	*ap = 0;
48634692Sedward 	qsort((char *) ring, tab->i_count, sizeof (char *), igcomp);
4877582Skurt 	for (ap = ring; *ap != 0; ap++)
4887582Skurt 		printf("%s\n", *ap);
48934692Sedward 	return 0;
4907573Skurt }
4917582Skurt 
4927582Skurt /*
4937582Skurt  * Compare two names for sorting ignored field list.
4947582Skurt  */
4957582Skurt igcomp(l, r)
4967582Skurt 	char **l, **r;
4977582Skurt {
4987582Skurt 
49934692Sedward 	return strcmp(*l, *r);
5007582Skurt }
501