xref: /csrg-svn/usr.bin/mail/cmd2.c (revision 5776)
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*5776Skurt static char *SccsId = "@(#)cmd2.c	2.4 02/13/82";
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 /*
95*5776Skurt  * Save a message in a file.  Mark the message as saved
96*5776Skurt  * so we can discard when the user quits.
971224Skas  */
981224Skas save(str)
991224Skas 	char str[];
1001224Skas {
101*5776Skurt 
102*5776Skurt 	return(save1(str, 1));
103*5776Skurt }
104*5776Skurt 
105*5776Skurt /*
106*5776Skurt  * Copy a message to a file without affected its saved-ness
107*5776Skurt  */
108*5776Skurt copycmd(str)
109*5776Skurt 	char str[];
110*5776Skurt {
111*5776Skurt 
112*5776Skurt 	return(save1(str, 0));
113*5776Skurt }
114*5776Skurt 
115*5776Skurt /*
116*5776Skurt  * Save/copy the indicated messages at the end of the passed file name.
117*5776Skurt  * If mark is true, mark the message "saved."
118*5776Skurt  */
119*5776Skurt save1(str, mark)
120*5776Skurt 	char str[];
121*5776Skurt {
1221224Skas 	register int *ip, mesg;
1231224Skas 	register struct message *mp;
124*5776Skurt 	char *file, *disp, *cmd;
1251224Skas 	int f, *msgvec, lc, cc, t;
1261224Skas 	FILE *obuf;
1271224Skas 	struct stat statb;
1281224Skas 
129*5776Skurt 	cmd = mark ? "save" : "copy";
1301224Skas 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
1311224Skas 	if ((file = snarf(str, &f)) == NOSTR)
1321224Skas 		return(1);
1331224Skas 	if (!f) {
1341224Skas 		*msgvec = first(0, MMNORM);
1351224Skas 		if (*msgvec == NULL) {
136*5776Skurt 			printf("No messages to %s.\n", cmd);
1371224Skas 			return(1);
1381224Skas 		}
1391224Skas 		msgvec[1] = NULL;
1401224Skas 	}
1411224Skas 	if (f && getmsglist(str, msgvec, 0) < 0)
1421224Skas 		return(1);
1431224Skas 	if ((file = expand(file)) == NOSTR)
1441224Skas 		return(1);
1451224Skas 	printf("\"%s\" ", file);
1461224Skas 	flush();
1471224Skas 	if (stat(file, &statb) >= 0)
1481224Skas 		disp = "[Appended]";
1491224Skas 	else
1501224Skas 		disp = "[New file]";
1511224Skas 	if ((obuf = fopen(file, "a")) == NULL) {
1521224Skas 		perror(NOSTR);
1531224Skas 		return(1);
1541224Skas 	}
1551224Skas 	cc = lc = 0;
1561224Skas 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
1571224Skas 		mesg = *ip;
1581224Skas 		touch(mesg);
1591224Skas 		mp = &message[mesg-1];
1601224Skas 		if ((t = send(mp, obuf)) < 0) {
1611224Skas 			perror(file);
1621224Skas 			fclose(obuf);
1631224Skas 			return(1);
1641224Skas 		}
1651224Skas 		lc += t;
1661224Skas 		cc += msize(mp);
167*5776Skurt 		if (mark)
168*5776Skurt 			mp->m_flag |= MSAVED;
1691224Skas 	}
1701224Skas 	fflush(obuf);
1711224Skas 	if (ferror(obuf))
1721224Skas 		perror(file);
1731224Skas 	fclose(obuf);
1741224Skas 	printf("%s %d/%d\n", disp, lc, cc);
1751224Skas 	return(0);
1761224Skas }
1771224Skas 
1781224Skas /*
1791224Skas  * Write the indicated messages at the end of the passed
1801224Skas  * file name, minus header and trailing blank line.
1811224Skas  */
1821224Skas 
1831224Skas swrite(str)
1841224Skas 	char str[];
1851224Skas {
1861224Skas 	register int *ip, mesg;
1871224Skas 	register struct message *mp;
1881224Skas 	register char *file, *disp;
1891224Skas 	char linebuf[BUFSIZ];
1901224Skas 	int f, *msgvec, lc, cc, t;
1911224Skas 	FILE *obuf, *mesf;
1921224Skas 	struct stat statb;
1931224Skas 
1941224Skas 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
1951224Skas 	if ((file = snarf(str, &f)) == NOSTR)
1961224Skas 		return(1);
1971224Skas 	if ((file = expand(file)) == NOSTR)
1981224Skas 		return(1);
1991224Skas 	if (!f) {
2001224Skas 		*msgvec = first(0, MMNORM);
2011224Skas 		if (*msgvec == NULL) {
2021224Skas 			printf("No messages to write.\n");
2031224Skas 			return(1);
2041224Skas 		}
2051224Skas 		msgvec[1] = NULL;
2061224Skas 	}
2071224Skas 	if (f && getmsglist(str, msgvec, 0) < 0)
2081224Skas 		return(1);
2091224Skas 	printf("\"%s\" ", file);
2101224Skas 	flush();
2111224Skas 	if (stat(file, &statb) >= 0)
2121224Skas 		disp = "[Appended]";
2131224Skas 	else
2141224Skas 		disp = "[New file]";
2151224Skas 	if ((obuf = fopen(file, "a")) == NULL) {
2161224Skas 		perror(NOSTR);
2171224Skas 		return(1);
2181224Skas 	}
2191224Skas 	cc = lc = 0;
2201224Skas 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
2211224Skas 		mesg = *ip;
2221224Skas 		touch(mesg);
2231224Skas 		mp = &message[mesg-1];
2241224Skas 		mesf = setinput(mp);
2251224Skas 		t = mp->m_lines - 2;
2261224Skas 		readline(mesf, linebuf);
2271224Skas 		while (t-- > 0) {
2281224Skas 			fgets(linebuf, BUFSIZ, mesf);
2291224Skas 			fputs(linebuf, obuf);
2301224Skas 			cc += strlen(linebuf);
2311224Skas 		}
2321224Skas 		lc += mp->m_lines - 2;
2331224Skas 		mp->m_flag |= MSAVED;
2341224Skas 	}
2351224Skas 	fflush(obuf);
2361224Skas 	if (ferror(obuf))
2371224Skas 		perror(file);
2381224Skas 	fclose(obuf);
2391224Skas 	printf("%s %d/%d\n", disp, lc, cc);
2401224Skas 	return(0);
2411224Skas }
2421224Skas 
2431224Skas /*
2441224Skas  * Snarf the file from the end of the command line and
2451224Skas  * return a pointer to it.  If there is no file attached,
2461224Skas  * just return NOSTR.  Put a null in front of the file
2471224Skas  * name so that the message list processing won't see it,
2481224Skas  * unless the file name is the only thing on the line, in
2491224Skas  * which case, return 0 in the reference flag variable.
2501224Skas  */
2511224Skas 
2521224Skas char *
2531224Skas snarf(linebuf, flag)
2541224Skas 	char linebuf[];
2551224Skas 	int *flag;
2561224Skas {
2571224Skas 	register char *cp;
2581224Skas 
2591224Skas 	*flag = 1;
2601224Skas 	cp = strlen(linebuf) + linebuf - 1;
2611224Skas 
2621224Skas 	/*
2631224Skas 	 * Strip away trailing blanks.
2641224Skas 	 */
2651224Skas 
2661224Skas 	while (*cp == ' ' && cp > linebuf)
2671224Skas 		cp--;
2681224Skas 	*++cp = 0;
2691224Skas 
2701224Skas 	/*
2711224Skas 	 * Now search for the beginning of the file name.
2721224Skas 	 */
2731224Skas 
2741224Skas 	while (cp > linebuf && !any(*cp, "\t "))
2751224Skas 		cp--;
2761224Skas 	if (*cp == '\0') {
2771224Skas 		printf("No file specified.\n");
2781224Skas 		return(NOSTR);
2791224Skas 	}
2801224Skas 	if (any(*cp, " \t"))
2811224Skas 		*cp++ = 0;
2821224Skas 	else
2831224Skas 		*flag = 0;
2841224Skas 	return(cp);
2851224Skas }
2861224Skas 
2871224Skas /*
2881224Skas  * Delete messages.
2891224Skas  */
2901224Skas 
2911224Skas delete(msgvec)
2921224Skas 	int msgvec[];
2931224Skas {
2941224Skas 	return(delm(msgvec));
2951224Skas }
2961224Skas 
2971224Skas /*
2981224Skas  * Delete messages, then type the new dot.
2991224Skas  */
3001224Skas 
3011224Skas deltype(msgvec)
3021224Skas 	int msgvec[];
3031224Skas {
3041224Skas 	int list[2];
3054493Skurt 	int lastdot;
3061224Skas 
3074493Skurt 	lastdot = dot - &message[0] + 1;
3081224Skas 	if (delm(msgvec) >= 0) {
3091224Skas 		list[0] = dot - &message[0];
3101224Skas 		list[0]++;
3114493Skurt 		if (list[0] > lastdot) {
3124493Skurt 			touch(list[0]);
3134493Skurt 			list[1] = NULL;
3144493Skurt 			return(type(list));
3154493Skurt 		}
3164493Skurt 		printf("At EOF\n");
3174493Skurt 		return(0);
3181224Skas 	}
3191224Skas 	else {
3201224Skas 		printf("No more messages\n");
3211224Skas 		return(0);
3221224Skas 	}
3231224Skas }
3241224Skas 
3251224Skas /*
3261224Skas  * Delete the indicated messages.
3271224Skas  * Set dot to some nice place afterwards.
3281224Skas  * Internal interface.
3291224Skas  */
3301224Skas 
3311224Skas delm(msgvec)
3321224Skas 	int *msgvec;
3331224Skas {
3341224Skas 	register struct message *mp;
3351224Skas 	register *ip, mesg;
3361224Skas 	int last;
3371224Skas 
3381224Skas 	last = NULL;
3391224Skas 	for (ip = msgvec; *ip != NULL; ip++) {
3401224Skas 		mesg = *ip;
3411224Skas 		touch(mesg);
3421224Skas 		mp = &message[mesg-1];
3433319Skas 		mp->m_flag |= MDELETED|MTOUCH;
3443319Skas 		mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
3451224Skas 		last = mesg;
3461224Skas 	}
3471224Skas 	if (last != NULL) {
3481224Skas 		dot = &message[last-1];
3491224Skas 		last = first(0, MDELETED);
3501224Skas 		if (last != NULL) {
3511224Skas 			dot = &message[last-1];
3521224Skas 			return(0);
3531224Skas 		}
3541224Skas 		else {
3551224Skas 			dot = &message[0];
3561224Skas 			return(-1);
3571224Skas 		}
3581224Skas 	}
3591224Skas 
3601224Skas 	/*
3611224Skas 	 * Following can't happen -- it keeps lint happy
3621224Skas 	 */
3631224Skas 
3641224Skas 	return(-1);
3651224Skas }
3661224Skas 
3671224Skas /*
3681224Skas  * Undelete the indicated messages.
3691224Skas  */
3701224Skas 
3711224Skas undelete(msgvec)
3721224Skas 	int *msgvec;
3731224Skas {
3741224Skas 	register struct message *mp;
3751224Skas 	register *ip, mesg;
3761224Skas 
3771224Skas 	for (ip = msgvec; ip-msgvec < msgCount; ip++) {
3781224Skas 		mesg = *ip;
3791224Skas 		if (mesg == 0)
3801224Skas 			return;
3811224Skas 		touch(mesg);
3821224Skas 		mp = &message[mesg-1];
3831224Skas 		dot = mp;
3841224Skas 		mp->m_flag &= ~MDELETED;
3851224Skas 	}
3861224Skas }
3871224Skas 
3881224Skas /*
3891224Skas  * Interactively dump core on "core"
3901224Skas  */
3911224Skas 
3921224Skas core()
3931224Skas {
3941224Skas 	register int pid;
3951224Skas 	int status;
3961224Skas 
3971224Skas 	if ((pid = vfork()) == -1) {
3981224Skas 		perror("fork");
3991224Skas 		return(1);
4001224Skas 	}
4011224Skas 	if (pid == 0) {
4021224Skas 		abort();
4031224Skas 		_exit(1);
4041224Skas 	}
4051224Skas 	printf("Okie dokie");
4061224Skas 	fflush(stdout);
4071224Skas 	while (wait(&status) != pid)
4081224Skas 		;
4091224Skas 	if (status & 0200)
4101224Skas 		printf(" -- Core dumped\n");
4111224Skas 	else
4121224Skas 		printf("\n");
4131224Skas }
4144340Skurt 
4154340Skurt /*
4164340Skurt  * Clobber as many bytes of stack as the user requests.
4174340Skurt  */
4184340Skurt clobber(argv)
4194340Skurt 	char **argv;
4204340Skurt {
4214340Skurt 	register int times;
4224340Skurt 
4234340Skurt 	if (argv[0] == 0)
4244340Skurt 		times = 1;
4254340Skurt 	else
4264340Skurt 		times = (atoi(argv[0]) + 511) / 512;
4274340Skurt 	clobber1(times);
4284340Skurt }
4294340Skurt 
4304340Skurt /*
4314340Skurt  * Clobber the stack.
4324340Skurt  */
4334340Skurt clobber1(n)
4344340Skurt {
4354340Skurt 	char buf[512];
4364340Skurt 	register char *cp;
4374340Skurt 
4384340Skurt 	if (n <= 0)
4394340Skurt 		return;
4404340Skurt 	for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
4414340Skurt 		;
4424340Skurt 	clobber1(n - 1);
4434340Skurt }
444