xref: /csrg-svn/usr.bin/mail/cmd2.c (revision 4493)
11224Skas #
21224Skas 
31224Skas #include "rcv.h"
41224Skas #include <sys/stat.h>
51224Skas 
61224Skas /*
71224Skas  * Mail -- a mail program
81224Skas  *
91224Skas  * More user commands.
101224Skas  */
111224Skas 
12*4493Skurt static char *SccsId = "@(#)cmd2.c	2.3 10/13/81";
131224Skas 
141224Skas /*
151224Skas  * If any arguments were given, go to the next applicable argument
161224Skas  * following dot, otherwise, go to the next applicable message.
171224Skas  * If given as first command with no arguments, print first message.
181224Skas  */
191224Skas 
201224Skas next(msgvec)
211224Skas 	int *msgvec;
221224Skas {
231224Skas 	register struct message *mp;
241224Skas 	register int *ip, *ip2;
251224Skas 	int list[2], mdot;
261224Skas 
271224Skas 	if (*msgvec != NULL) {
281224Skas 
291224Skas 		/*
301224Skas 		 * If some messages were supplied, find the
311224Skas 		 * first applicable one following dot using
321224Skas 		 * wrap around.
331224Skas 		 */
341224Skas 
351224Skas 		mdot = dot - &message[0] + 1;
361470Skas 
371470Skas 		/*
381470Skas 		 * Find the first message in the supplied
391470Skas 		 * message list which follows dot.
401470Skas 		 */
411470Skas 
421224Skas 		for (ip = msgvec; *ip != NULL; ip++)
431224Skas 			if (*ip > mdot)
441224Skas 				break;
451224Skas 		if (*ip == NULL)
461224Skas 			ip = msgvec;
471224Skas 		ip2 = ip;
481224Skas 		do {
491224Skas 			mp = &message[*ip2 - 1];
501224Skas 			if ((mp->m_flag & MDELETED) == 0) {
511224Skas 				dot = mp;
521224Skas 				goto hitit;
531224Skas 			}
541470Skas 			if (*ip2 != NULL)
551470Skas 				ip2++;
561470Skas 			if (*ip2 == NULL)
571470Skas 				ip2 = msgvec;
581224Skas 		} while (ip2 != ip);
591224Skas 		printf("No messages applicable\n");
601224Skas 		return(1);
611224Skas 	}
621224Skas 
631224Skas 	/*
641224Skas 	 * If this is the first command, select message 1.
651224Skas 	 * Note that this must exist for us to get here at all.
661224Skas 	 */
671224Skas 
681481Skas 	if (!sawcom)
691224Skas 		goto hitit;
701224Skas 
711224Skas 	/*
721224Skas 	 * Just find the next good message after dot, no
731224Skas 	 * wraparound.
741224Skas 	 */
751224Skas 
761224Skas 	for (mp = dot+1; mp < &message[msgCount]; mp++)
771224Skas 		if ((mp->m_flag & (MDELETED|MSAVED)) == 0)
781224Skas 			break;
791224Skas 	if (mp >= &message[msgCount]) {
801224Skas 		printf("At EOF\n");
811224Skas 		return(0);
821224Skas 	}
831224Skas 	dot = mp;
841224Skas hitit:
851224Skas 	/*
861224Skas 	 * Print dot.
871224Skas 	 */
881224Skas 
891224Skas 	list[0] = dot - &message[0] + 1;
901224Skas 	list[1] = NULL;
911224Skas 	return(type(list));
921224Skas }
931224Skas 
941224Skas /*
951224Skas  * Save the indicated messages at the end of the passed file name.
961224Skas  */
971224Skas 
981224Skas save(str)
991224Skas 	char str[];
1001224Skas {
1011224Skas 	register int *ip, mesg;
1021224Skas 	register struct message *mp;
1031224Skas 	char *file, *disp;
1041224Skas 	int f, *msgvec, lc, cc, t;
1051224Skas 	FILE *obuf;
1061224Skas 	struct stat statb;
1071224Skas 
1081224Skas 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
1091224Skas 	if ((file = snarf(str, &f)) == NOSTR)
1101224Skas 		return(1);
1111224Skas 	if (!f) {
1121224Skas 		*msgvec = first(0, MMNORM);
1131224Skas 		if (*msgvec == NULL) {
1141224Skas 			printf("No messages to save.\n");
1151224Skas 			return(1);
1161224Skas 		}
1171224Skas 		msgvec[1] = NULL;
1181224Skas 	}
1191224Skas 	if (f && getmsglist(str, msgvec, 0) < 0)
1201224Skas 		return(1);
1211224Skas 	if ((file = expand(file)) == NOSTR)
1221224Skas 		return(1);
1231224Skas 	printf("\"%s\" ", file);
1241224Skas 	flush();
1251224Skas 	if (stat(file, &statb) >= 0)
1261224Skas 		disp = "[Appended]";
1271224Skas 	else
1281224Skas 		disp = "[New file]";
1291224Skas 	if ((obuf = fopen(file, "a")) == NULL) {
1301224Skas 		perror(NOSTR);
1311224Skas 		return(1);
1321224Skas 	}
1331224Skas 	cc = lc = 0;
1341224Skas 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
1351224Skas 		mesg = *ip;
1361224Skas 		touch(mesg);
1371224Skas 		mp = &message[mesg-1];
1381224Skas 		if ((t = send(mp, obuf)) < 0) {
1391224Skas 			perror(file);
1401224Skas 			fclose(obuf);
1411224Skas 			return(1);
1421224Skas 		}
1431224Skas 		lc += t;
1441224Skas 		cc += msize(mp);
1451224Skas 		mp->m_flag |= MSAVED;
1461224Skas 	}
1471224Skas 	fflush(obuf);
1481224Skas 	if (ferror(obuf))
1491224Skas 		perror(file);
1501224Skas 	fclose(obuf);
1511224Skas 	printf("%s %d/%d\n", disp, lc, cc);
1521224Skas 	return(0);
1531224Skas }
1541224Skas 
1551224Skas /*
1561224Skas  * Write the indicated messages at the end of the passed
1571224Skas  * file name, minus header and trailing blank line.
1581224Skas  */
1591224Skas 
1601224Skas swrite(str)
1611224Skas 	char str[];
1621224Skas {
1631224Skas 	register int *ip, mesg;
1641224Skas 	register struct message *mp;
1651224Skas 	register char *file, *disp;
1661224Skas 	char linebuf[BUFSIZ];
1671224Skas 	int f, *msgvec, lc, cc, t;
1681224Skas 	FILE *obuf, *mesf;
1691224Skas 	struct stat statb;
1701224Skas 
1711224Skas 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
1721224Skas 	if ((file = snarf(str, &f)) == NOSTR)
1731224Skas 		return(1);
1741224Skas 	if ((file = expand(file)) == NOSTR)
1751224Skas 		return(1);
1761224Skas 	if (!f) {
1771224Skas 		*msgvec = first(0, MMNORM);
1781224Skas 		if (*msgvec == NULL) {
1791224Skas 			printf("No messages to write.\n");
1801224Skas 			return(1);
1811224Skas 		}
1821224Skas 		msgvec[1] = NULL;
1831224Skas 	}
1841224Skas 	if (f && getmsglist(str, msgvec, 0) < 0)
1851224Skas 		return(1);
1861224Skas 	printf("\"%s\" ", file);
1871224Skas 	flush();
1881224Skas 	if (stat(file, &statb) >= 0)
1891224Skas 		disp = "[Appended]";
1901224Skas 	else
1911224Skas 		disp = "[New file]";
1921224Skas 	if ((obuf = fopen(file, "a")) == NULL) {
1931224Skas 		perror(NOSTR);
1941224Skas 		return(1);
1951224Skas 	}
1961224Skas 	cc = lc = 0;
1971224Skas 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
1981224Skas 		mesg = *ip;
1991224Skas 		touch(mesg);
2001224Skas 		mp = &message[mesg-1];
2011224Skas 		mesf = setinput(mp);
2021224Skas 		t = mp->m_lines - 2;
2031224Skas 		readline(mesf, linebuf);
2041224Skas 		while (t-- > 0) {
2051224Skas 			fgets(linebuf, BUFSIZ, mesf);
2061224Skas 			fputs(linebuf, obuf);
2071224Skas 			cc += strlen(linebuf);
2081224Skas 		}
2091224Skas 		lc += mp->m_lines - 2;
2101224Skas 		mp->m_flag |= MSAVED;
2111224Skas 	}
2121224Skas 	fflush(obuf);
2131224Skas 	if (ferror(obuf))
2141224Skas 		perror(file);
2151224Skas 	fclose(obuf);
2161224Skas 	printf("%s %d/%d\n", disp, lc, cc);
2171224Skas 	return(0);
2181224Skas }
2191224Skas 
2201224Skas /*
2211224Skas  * Snarf the file from the end of the command line and
2221224Skas  * return a pointer to it.  If there is no file attached,
2231224Skas  * just return NOSTR.  Put a null in front of the file
2241224Skas  * name so that the message list processing won't see it,
2251224Skas  * unless the file name is the only thing on the line, in
2261224Skas  * which case, return 0 in the reference flag variable.
2271224Skas  */
2281224Skas 
2291224Skas char *
2301224Skas snarf(linebuf, flag)
2311224Skas 	char linebuf[];
2321224Skas 	int *flag;
2331224Skas {
2341224Skas 	register char *cp;
2351224Skas 
2361224Skas 	*flag = 1;
2371224Skas 	cp = strlen(linebuf) + linebuf - 1;
2381224Skas 
2391224Skas 	/*
2401224Skas 	 * Strip away trailing blanks.
2411224Skas 	 */
2421224Skas 
2431224Skas 	while (*cp == ' ' && cp > linebuf)
2441224Skas 		cp--;
2451224Skas 	*++cp = 0;
2461224Skas 
2471224Skas 	/*
2481224Skas 	 * Now search for the beginning of the file name.
2491224Skas 	 */
2501224Skas 
2511224Skas 	while (cp > linebuf && !any(*cp, "\t "))
2521224Skas 		cp--;
2531224Skas 	if (*cp == '\0') {
2541224Skas 		printf("No file specified.\n");
2551224Skas 		return(NOSTR);
2561224Skas 	}
2571224Skas 	if (any(*cp, " \t"))
2581224Skas 		*cp++ = 0;
2591224Skas 	else
2601224Skas 		*flag = 0;
2611224Skas 	return(cp);
2621224Skas }
2631224Skas 
2641224Skas /*
2651224Skas  * Delete messages.
2661224Skas  */
2671224Skas 
2681224Skas delete(msgvec)
2691224Skas 	int msgvec[];
2701224Skas {
2711224Skas 	return(delm(msgvec));
2721224Skas }
2731224Skas 
2741224Skas /*
2751224Skas  * Delete messages, then type the new dot.
2761224Skas  */
2771224Skas 
2781224Skas deltype(msgvec)
2791224Skas 	int msgvec[];
2801224Skas {
2811224Skas 	int list[2];
282*4493Skurt 	int lastdot;
2831224Skas 
284*4493Skurt 	lastdot = dot - &message[0] + 1;
2851224Skas 	if (delm(msgvec) >= 0) {
2861224Skas 		list[0] = dot - &message[0];
2871224Skas 		list[0]++;
288*4493Skurt 		if (list[0] > lastdot) {
289*4493Skurt 			touch(list[0]);
290*4493Skurt 			list[1] = NULL;
291*4493Skurt 			return(type(list));
292*4493Skurt 		}
293*4493Skurt 		printf("At EOF\n");
294*4493Skurt 		return(0);
2951224Skas 	}
2961224Skas 	else {
2971224Skas 		printf("No more messages\n");
2981224Skas 		return(0);
2991224Skas 	}
3001224Skas }
3011224Skas 
3021224Skas /*
3031224Skas  * Delete the indicated messages.
3041224Skas  * Set dot to some nice place afterwards.
3051224Skas  * Internal interface.
3061224Skas  */
3071224Skas 
3081224Skas delm(msgvec)
3091224Skas 	int *msgvec;
3101224Skas {
3111224Skas 	register struct message *mp;
3121224Skas 	register *ip, mesg;
3131224Skas 	int last;
3141224Skas 
3151224Skas 	last = NULL;
3161224Skas 	for (ip = msgvec; *ip != NULL; ip++) {
3171224Skas 		mesg = *ip;
3181224Skas 		touch(mesg);
3191224Skas 		mp = &message[mesg-1];
3203319Skas 		mp->m_flag |= MDELETED|MTOUCH;
3213319Skas 		mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
3221224Skas 		last = mesg;
3231224Skas 	}
3241224Skas 	if (last != NULL) {
3251224Skas 		dot = &message[last-1];
3261224Skas 		last = first(0, MDELETED);
3271224Skas 		if (last != NULL) {
3281224Skas 			dot = &message[last-1];
3291224Skas 			return(0);
3301224Skas 		}
3311224Skas 		else {
3321224Skas 			dot = &message[0];
3331224Skas 			return(-1);
3341224Skas 		}
3351224Skas 	}
3361224Skas 
3371224Skas 	/*
3381224Skas 	 * Following can't happen -- it keeps lint happy
3391224Skas 	 */
3401224Skas 
3411224Skas 	return(-1);
3421224Skas }
3431224Skas 
3441224Skas /*
3451224Skas  * Undelete the indicated messages.
3461224Skas  */
3471224Skas 
3481224Skas undelete(msgvec)
3491224Skas 	int *msgvec;
3501224Skas {
3511224Skas 	register struct message *mp;
3521224Skas 	register *ip, mesg;
3531224Skas 
3541224Skas 	for (ip = msgvec; ip-msgvec < msgCount; ip++) {
3551224Skas 		mesg = *ip;
3561224Skas 		if (mesg == 0)
3571224Skas 			return;
3581224Skas 		touch(mesg);
3591224Skas 		mp = &message[mesg-1];
3601224Skas 		dot = mp;
3611224Skas 		mp->m_flag &= ~MDELETED;
3621224Skas 	}
3631224Skas }
3641224Skas 
3651224Skas /*
3661224Skas  * Interactively dump core on "core"
3671224Skas  */
3681224Skas 
3691224Skas core()
3701224Skas {
3711224Skas 	register int pid;
3721224Skas 	int status;
3731224Skas 
3741224Skas 	if ((pid = vfork()) == -1) {
3751224Skas 		perror("fork");
3761224Skas 		return(1);
3771224Skas 	}
3781224Skas 	if (pid == 0) {
3791224Skas 		abort();
3801224Skas 		_exit(1);
3811224Skas 	}
3821224Skas 	printf("Okie dokie");
3831224Skas 	fflush(stdout);
3841224Skas 	while (wait(&status) != pid)
3851224Skas 		;
3861224Skas 	if (status & 0200)
3871224Skas 		printf(" -- Core dumped\n");
3881224Skas 	else
3891224Skas 		printf("\n");
3901224Skas }
3914340Skurt 
3924340Skurt /*
3934340Skurt  * Clobber as many bytes of stack as the user requests.
3944340Skurt  */
3954340Skurt clobber(argv)
3964340Skurt 	char **argv;
3974340Skurt {
3984340Skurt 	register int times;
3994340Skurt 
4004340Skurt 	if (argv[0] == 0)
4014340Skurt 		times = 1;
4024340Skurt 	else
4034340Skurt 		times = (atoi(argv[0]) + 511) / 512;
4044340Skurt 	clobber1(times);
4054340Skurt }
4064340Skurt 
4074340Skurt /*
4084340Skurt  * Clobber the stack.
4094340Skurt  */
4104340Skurt clobber1(n)
4114340Skurt {
4124340Skurt 	char buf[512];
4134340Skurt 	register char *cp;
4144340Skurt 
4154340Skurt 	if (n <= 0)
4164340Skurt 		return;
4174340Skurt 	for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
4184340Skurt 		;
4194340Skurt 	clobber1(n - 1);
4204340Skurt }
421