xref: /csrg-svn/usr.bin/mail/cmd2.c (revision 3319)
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*3319Skas static char *SccsId = "@(#)cmd2.c	1.4 03/20/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];
2821224Skas 
2831224Skas 	if (delm(msgvec) >= 0) {
2841224Skas 		list[0] = dot - &message[0];
2851224Skas 		list[0]++;
2861224Skas 		touch(list[0]);
2871224Skas 		list[1] = NULL;
2881224Skas 		return(type(list));
2891224Skas 	}
2901224Skas 	else {
2911224Skas 		printf("No more messages\n");
2921224Skas 		return(0);
2931224Skas 	}
2941224Skas }
2951224Skas 
2961224Skas /*
2971224Skas  * Delete the indicated messages.
2981224Skas  * Set dot to some nice place afterwards.
2991224Skas  * Internal interface.
3001224Skas  */
3011224Skas 
3021224Skas delm(msgvec)
3031224Skas 	int *msgvec;
3041224Skas {
3051224Skas 	register struct message *mp;
3061224Skas 	register *ip, mesg;
3071224Skas 	int last;
3081224Skas 
3091224Skas 	last = NULL;
3101224Skas 	for (ip = msgvec; *ip != NULL; ip++) {
3111224Skas 		mesg = *ip;
3121224Skas 		touch(mesg);
3131224Skas 		mp = &message[mesg-1];
314*3319Skas 		mp->m_flag |= MDELETED|MTOUCH;
315*3319Skas 		mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
3161224Skas 		last = mesg;
3171224Skas 	}
3181224Skas 	if (last != NULL) {
3191224Skas 		dot = &message[last-1];
3201224Skas 		last = first(0, MDELETED);
3211224Skas 		if (last != NULL) {
3221224Skas 			dot = &message[last-1];
3231224Skas 			return(0);
3241224Skas 		}
3251224Skas 		else {
3261224Skas 			dot = &message[0];
3271224Skas 			return(-1);
3281224Skas 		}
3291224Skas 	}
3301224Skas 
3311224Skas 	/*
3321224Skas 	 * Following can't happen -- it keeps lint happy
3331224Skas 	 */
3341224Skas 
3351224Skas 	return(-1);
3361224Skas }
3371224Skas 
3381224Skas /*
3391224Skas  * Undelete the indicated messages.
3401224Skas  */
3411224Skas 
3421224Skas undelete(msgvec)
3431224Skas 	int *msgvec;
3441224Skas {
3451224Skas 	register struct message *mp;
3461224Skas 	register *ip, mesg;
3471224Skas 
3481224Skas 	for (ip = msgvec; ip-msgvec < msgCount; ip++) {
3491224Skas 		mesg = *ip;
3501224Skas 		if (mesg == 0)
3511224Skas 			return;
3521224Skas 		touch(mesg);
3531224Skas 		mp = &message[mesg-1];
3541224Skas 		dot = mp;
3551224Skas 		mp->m_flag &= ~MDELETED;
3561224Skas 	}
3571224Skas }
3581224Skas 
3591224Skas /*
3601224Skas  * Interactively dump core on "core"
3611224Skas  */
3621224Skas 
3631224Skas core()
3641224Skas {
3651224Skas 	register int pid;
3661224Skas 	int status;
3671224Skas 
3681224Skas 	if ((pid = vfork()) == -1) {
3691224Skas 		perror("fork");
3701224Skas 		return(1);
3711224Skas 	}
3721224Skas 	if (pid == 0) {
3731224Skas 		abort();
3741224Skas 		_exit(1);
3751224Skas 	}
3761224Skas 	printf("Okie dokie");
3771224Skas 	fflush(stdout);
3781224Skas 	while (wait(&status) != pid)
3791224Skas 		;
3801224Skas 	if (status & 0200)
3811224Skas 		printf(" -- Core dumped\n");
3821224Skas 	else
3831224Skas 		printf("\n");
3841224Skas }
385