xref: /csrg-svn/usr.bin/mail/cmd2.c (revision 33499)
122445Sdist /*
222445Sdist  * Copyright (c) 1980 Regents of the University of California.
3*33499Sbostic  * All rights reserved.
4*33499Sbostic  *
5*33499Sbostic  * Redistribution and use in source and binary forms are permitted
6*33499Sbostic  * provided that this notice is preserved and that due credit is given
7*33499Sbostic  * to the University of California at Berkeley. The name of the University
8*33499Sbostic  * may not be used to endorse or promote products derived from this
9*33499Sbostic  * software without specific prior written permission. This software
10*33499Sbostic  * is provided ``as is'' without express or implied warranty.
1122445Sdist  */
1222445Sdist 
13*33499Sbostic #ifdef notdef
14*33499Sbostic static char sccsid[] = "@(#)cmd2.c	5.5 (Berkeley) 02/18/88";
15*33499Sbostic #endif /* notdef */
161224Skas 
171224Skas #include "rcv.h"
181224Skas #include <sys/stat.h>
1931142Sedward #include <sys/wait.h>
201224Skas 
211224Skas /*
221224Skas  * Mail -- a mail program
231224Skas  *
241224Skas  * More user commands.
251224Skas  */
261224Skas 
271224Skas /*
281224Skas  * If any arguments were given, go to the next applicable argument
291224Skas  * following dot, otherwise, go to the next applicable message.
301224Skas  * If given as first command with no arguments, print first message.
311224Skas  */
321224Skas 
331224Skas next(msgvec)
341224Skas 	int *msgvec;
351224Skas {
361224Skas 	register struct message *mp;
371224Skas 	register int *ip, *ip2;
381224Skas 	int list[2], mdot;
391224Skas 
401224Skas 	if (*msgvec != NULL) {
411224Skas 
421224Skas 		/*
431224Skas 		 * If some messages were supplied, find the
441224Skas 		 * first applicable one following dot using
451224Skas 		 * wrap around.
461224Skas 		 */
471224Skas 
481224Skas 		mdot = dot - &message[0] + 1;
491470Skas 
501470Skas 		/*
511470Skas 		 * Find the first message in the supplied
521470Skas 		 * message list which follows dot.
531470Skas 		 */
541470Skas 
551224Skas 		for (ip = msgvec; *ip != NULL; ip++)
561224Skas 			if (*ip > mdot)
571224Skas 				break;
581224Skas 		if (*ip == NULL)
591224Skas 			ip = msgvec;
601224Skas 		ip2 = ip;
611224Skas 		do {
621224Skas 			mp = &message[*ip2 - 1];
631224Skas 			if ((mp->m_flag & MDELETED) == 0) {
641224Skas 				dot = mp;
651224Skas 				goto hitit;
661224Skas 			}
671470Skas 			if (*ip2 != NULL)
681470Skas 				ip2++;
691470Skas 			if (*ip2 == NULL)
701470Skas 				ip2 = msgvec;
711224Skas 		} while (ip2 != ip);
721224Skas 		printf("No messages applicable\n");
731224Skas 		return(1);
741224Skas 	}
751224Skas 
761224Skas 	/*
771224Skas 	 * If this is the first command, select message 1.
781224Skas 	 * Note that this must exist for us to get here at all.
791224Skas 	 */
801224Skas 
811481Skas 	if (!sawcom)
821224Skas 		goto hitit;
831224Skas 
841224Skas 	/*
851224Skas 	 * Just find the next good message after dot, no
861224Skas 	 * wraparound.
871224Skas 	 */
881224Skas 
891224Skas 	for (mp = dot+1; mp < &message[msgCount]; mp++)
901224Skas 		if ((mp->m_flag & (MDELETED|MSAVED)) == 0)
911224Skas 			break;
921224Skas 	if (mp >= &message[msgCount]) {
931224Skas 		printf("At EOF\n");
941224Skas 		return(0);
951224Skas 	}
961224Skas 	dot = mp;
971224Skas hitit:
981224Skas 	/*
991224Skas 	 * Print dot.
1001224Skas 	 */
1011224Skas 
1021224Skas 	list[0] = dot - &message[0] + 1;
1031224Skas 	list[1] = NULL;
1041224Skas 	return(type(list));
1051224Skas }
1061224Skas 
1071224Skas /*
1085776Skurt  * Save a message in a file.  Mark the message as saved
1095776Skurt  * so we can discard when the user quits.
1101224Skas  */
1111224Skas save(str)
1121224Skas 	char str[];
1131224Skas {
1145776Skurt 
1155776Skurt 	return(save1(str, 1));
1165776Skurt }
1175776Skurt 
1185776Skurt /*
1195776Skurt  * Copy a message to a file without affected its saved-ness
1205776Skurt  */
1215776Skurt copycmd(str)
1225776Skurt 	char str[];
1235776Skurt {
1245776Skurt 
1255776Skurt 	return(save1(str, 0));
1265776Skurt }
1275776Skurt 
1285776Skurt /*
1295776Skurt  * Save/copy the indicated messages at the end of the passed file name.
1305776Skurt  * If mark is true, mark the message "saved."
1315776Skurt  */
1325776Skurt save1(str, mark)
1335776Skurt 	char str[];
1345776Skurt {
1351224Skas 	register int *ip, mesg;
1361224Skas 	register struct message *mp;
1375776Skurt 	char *file, *disp, *cmd;
1388747Scarl 	int f, *msgvec, lc, t;
1398747Scarl 	long cc;
1401224Skas 	FILE *obuf;
1411224Skas 	struct stat statb;
1421224Skas 
1435776Skurt 	cmd = mark ? "save" : "copy";
1441224Skas 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
1451224Skas 	if ((file = snarf(str, &f)) == NOSTR)
1461224Skas 		return(1);
1471224Skas 	if (!f) {
1481224Skas 		*msgvec = first(0, MMNORM);
1491224Skas 		if (*msgvec == NULL) {
1505776Skurt 			printf("No messages to %s.\n", cmd);
1511224Skas 			return(1);
1521224Skas 		}
1531224Skas 		msgvec[1] = NULL;
1541224Skas 	}
1551224Skas 	if (f && getmsglist(str, msgvec, 0) < 0)
1561224Skas 		return(1);
1571224Skas 	if ((file = expand(file)) == NOSTR)
1581224Skas 		return(1);
1591224Skas 	printf("\"%s\" ", file);
16016859Sralph 	fflush(stdout);
1611224Skas 	if (stat(file, &statb) >= 0)
1621224Skas 		disp = "[Appended]";
1631224Skas 	else
1641224Skas 		disp = "[New file]";
1651224Skas 	if ((obuf = fopen(file, "a")) == NULL) {
1661224Skas 		perror(NOSTR);
1671224Skas 		return(1);
1681224Skas 	}
1698747Scarl 	cc = 0L;
1708747Scarl 	lc = 0;
1711224Skas 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
1721224Skas 		mesg = *ip;
1731224Skas 		touch(mesg);
1741224Skas 		mp = &message[mesg-1];
1757573Skurt 		if ((t = send(mp, obuf, 0)) < 0) {
1761224Skas 			perror(file);
1771224Skas 			fclose(obuf);
1781224Skas 			return(1);
1791224Skas 		}
1801224Skas 		lc += t;
1818747Scarl 		cc += mp->m_size;
1825776Skurt 		if (mark)
1835776Skurt 			mp->m_flag |= MSAVED;
1841224Skas 	}
1851224Skas 	fflush(obuf);
1861224Skas 	if (ferror(obuf))
1871224Skas 		perror(file);
1881224Skas 	fclose(obuf);
1898747Scarl 	printf("%s %d/%ld\n", disp, lc, cc);
1901224Skas 	return(0);
1911224Skas }
1921224Skas 
1931224Skas /*
1941224Skas  * Write the indicated messages at the end of the passed
1951224Skas  * file name, minus header and trailing blank line.
1961224Skas  */
1971224Skas 
1981224Skas swrite(str)
1991224Skas 	char str[];
2001224Skas {
2011224Skas 	register int *ip, mesg;
2021224Skas 	register struct message *mp;
2031224Skas 	register char *file, *disp;
2041224Skas 	char linebuf[BUFSIZ];
2051224Skas 	int f, *msgvec, lc, cc, t;
2061224Skas 	FILE *obuf, *mesf;
2071224Skas 	struct stat statb;
2081224Skas 
2091224Skas 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
2101224Skas 	if ((file = snarf(str, &f)) == NOSTR)
2111224Skas 		return(1);
2121224Skas 	if ((file = expand(file)) == NOSTR)
2131224Skas 		return(1);
2141224Skas 	if (!f) {
2151224Skas 		*msgvec = first(0, MMNORM);
2161224Skas 		if (*msgvec == NULL) {
2171224Skas 			printf("No messages to write.\n");
2181224Skas 			return(1);
2191224Skas 		}
2201224Skas 		msgvec[1] = NULL;
2211224Skas 	}
2221224Skas 	if (f && getmsglist(str, msgvec, 0) < 0)
2231224Skas 		return(1);
2241224Skas 	printf("\"%s\" ", file);
22516859Sralph 	fflush(stdout);
2261224Skas 	if (stat(file, &statb) >= 0)
2271224Skas 		disp = "[Appended]";
2281224Skas 	else
2291224Skas 		disp = "[New file]";
2301224Skas 	if ((obuf = fopen(file, "a")) == NULL) {
2311224Skas 		perror(NOSTR);
2321224Skas 		return(1);
2331224Skas 	}
2341224Skas 	cc = lc = 0;
2351224Skas 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
2361224Skas 		mesg = *ip;
2371224Skas 		touch(mesg);
2381224Skas 		mp = &message[mesg-1];
2391224Skas 		mesf = setinput(mp);
24024681Sserge 		t = mp->m_lines - 1;
2411224Skas 		while (t-- > 0) {
24224681Sserge 			readline(mesf, linebuf);
24324681Sserge 			if (blankline(linebuf))
24424681Sserge 				break;
24524681Sserge 		}
24624681Sserge 		while (t-- > 0) {
2471224Skas 			fgets(linebuf, BUFSIZ, mesf);
2481224Skas 			fputs(linebuf, obuf);
2491224Skas 			cc += strlen(linebuf);
2501224Skas 		}
2511224Skas 		lc += mp->m_lines - 2;
2521224Skas 		mp->m_flag |= MSAVED;
2531224Skas 	}
2541224Skas 	fflush(obuf);
2551224Skas 	if (ferror(obuf))
2561224Skas 		perror(file);
2571224Skas 	fclose(obuf);
2581224Skas 	printf("%s %d/%d\n", disp, lc, cc);
2591224Skas 	return(0);
2601224Skas }
2611224Skas 
2621224Skas /*
2631224Skas  * Snarf the file from the end of the command line and
2641224Skas  * return a pointer to it.  If there is no file attached,
2651224Skas  * just return NOSTR.  Put a null in front of the file
2661224Skas  * name so that the message list processing won't see it,
2671224Skas  * unless the file name is the only thing on the line, in
2681224Skas  * which case, return 0 in the reference flag variable.
2691224Skas  */
2701224Skas 
2711224Skas char *
2721224Skas snarf(linebuf, flag)
2731224Skas 	char linebuf[];
2741224Skas 	int *flag;
2751224Skas {
2761224Skas 	register char *cp;
2771224Skas 
2781224Skas 	*flag = 1;
2791224Skas 	cp = strlen(linebuf) + linebuf - 1;
2801224Skas 
2811224Skas 	/*
2821224Skas 	 * Strip away trailing blanks.
2831224Skas 	 */
2841224Skas 
28531142Sedward 	while (cp > linebuf && isspace(*cp))
2861224Skas 		cp--;
2871224Skas 	*++cp = 0;
2881224Skas 
2891224Skas 	/*
2901224Skas 	 * Now search for the beginning of the file name.
2911224Skas 	 */
2921224Skas 
29331142Sedward 	while (cp > linebuf && !isspace(*cp))
2941224Skas 		cp--;
2951224Skas 	if (*cp == '\0') {
2961224Skas 		printf("No file specified.\n");
2971224Skas 		return(NOSTR);
2981224Skas 	}
29931142Sedward 	if (isspace(*cp))
3001224Skas 		*cp++ = 0;
3011224Skas 	else
3021224Skas 		*flag = 0;
3031224Skas 	return(cp);
3041224Skas }
3051224Skas 
3061224Skas /*
3071224Skas  * Delete messages.
3081224Skas  */
3091224Skas 
3101224Skas delete(msgvec)
3111224Skas 	int msgvec[];
3121224Skas {
3131224Skas 	return(delm(msgvec));
3141224Skas }
3151224Skas 
3161224Skas /*
3171224Skas  * Delete messages, then type the new dot.
3181224Skas  */
3191224Skas 
3201224Skas deltype(msgvec)
3211224Skas 	int msgvec[];
3221224Skas {
3231224Skas 	int list[2];
3244493Skurt 	int lastdot;
3251224Skas 
3264493Skurt 	lastdot = dot - &message[0] + 1;
3271224Skas 	if (delm(msgvec) >= 0) {
3281224Skas 		list[0] = dot - &message[0];
3291224Skas 		list[0]++;
3304493Skurt 		if (list[0] > lastdot) {
3314493Skurt 			touch(list[0]);
3324493Skurt 			list[1] = NULL;
3334493Skurt 			return(type(list));
3344493Skurt 		}
3354493Skurt 		printf("At EOF\n");
3364493Skurt 		return(0);
3371224Skas 	}
3381224Skas 	else {
3391224Skas 		printf("No more messages\n");
3401224Skas 		return(0);
3411224Skas 	}
3421224Skas }
3431224Skas 
3441224Skas /*
3451224Skas  * Delete the indicated messages.
3461224Skas  * Set dot to some nice place afterwards.
3471224Skas  * Internal interface.
3481224Skas  */
3491224Skas 
3501224Skas delm(msgvec)
3511224Skas 	int *msgvec;
3521224Skas {
3531224Skas 	register struct message *mp;
3541224Skas 	register *ip, mesg;
3551224Skas 	int last;
3561224Skas 
3571224Skas 	last = NULL;
3581224Skas 	for (ip = msgvec; *ip != NULL; ip++) {
3591224Skas 		mesg = *ip;
3601224Skas 		touch(mesg);
3611224Skas 		mp = &message[mesg-1];
3623319Skas 		mp->m_flag |= MDELETED|MTOUCH;
3633319Skas 		mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
3641224Skas 		last = mesg;
3651224Skas 	}
3661224Skas 	if (last != NULL) {
3671224Skas 		dot = &message[last-1];
3681224Skas 		last = first(0, MDELETED);
3691224Skas 		if (last != NULL) {
3701224Skas 			dot = &message[last-1];
3711224Skas 			return(0);
3721224Skas 		}
3731224Skas 		else {
3741224Skas 			dot = &message[0];
3751224Skas 			return(-1);
3761224Skas 		}
3771224Skas 	}
3781224Skas 
3791224Skas 	/*
3801224Skas 	 * Following can't happen -- it keeps lint happy
3811224Skas 	 */
3821224Skas 
3831224Skas 	return(-1);
3841224Skas }
3851224Skas 
3861224Skas /*
3871224Skas  * Undelete the indicated messages.
3881224Skas  */
3891224Skas 
3901224Skas undelete(msgvec)
3911224Skas 	int *msgvec;
3921224Skas {
3931224Skas 	register struct message *mp;
3941224Skas 	register *ip, mesg;
3951224Skas 
3961224Skas 	for (ip = msgvec; ip-msgvec < msgCount; ip++) {
3971224Skas 		mesg = *ip;
3981224Skas 		if (mesg == 0)
3991224Skas 			return;
4001224Skas 		touch(mesg);
4011224Skas 		mp = &message[mesg-1];
4021224Skas 		dot = mp;
4031224Skas 		mp->m_flag &= ~MDELETED;
4041224Skas 	}
4051224Skas }
4061224Skas 
4071224Skas /*
4081224Skas  * Interactively dump core on "core"
4091224Skas  */
4101224Skas 
4111224Skas core()
4121224Skas {
4131224Skas 	register int pid;
41431142Sedward 	union wait status;
4151224Skas 
4161224Skas 	if ((pid = vfork()) == -1) {
4171224Skas 		perror("fork");
4181224Skas 		return(1);
4191224Skas 	}
4201224Skas 	if (pid == 0) {
4211224Skas 		abort();
4221224Skas 		_exit(1);
4231224Skas 	}
4241224Skas 	printf("Okie dokie");
4251224Skas 	fflush(stdout);
4261224Skas 	while (wait(&status) != pid)
4271224Skas 		;
42831142Sedward 	if (status.w_coredump)
4291224Skas 		printf(" -- Core dumped\n");
4301224Skas 	else
4311224Skas 		printf("\n");
43231142Sedward 	return 0;
4331224Skas }
4344340Skurt 
4354340Skurt /*
4364340Skurt  * Clobber as many bytes of stack as the user requests.
4374340Skurt  */
4384340Skurt clobber(argv)
4394340Skurt 	char **argv;
4404340Skurt {
4414340Skurt 	register int times;
4424340Skurt 
4434340Skurt 	if (argv[0] == 0)
4444340Skurt 		times = 1;
4454340Skurt 	else
4464340Skurt 		times = (atoi(argv[0]) + 511) / 512;
4477561Skurt 	clob1(times);
4484340Skurt }
4494340Skurt 
4504340Skurt /*
4514340Skurt  * Clobber the stack.
4524340Skurt  */
4537561Skurt clob1(n)
4544340Skurt {
4554340Skurt 	char buf[512];
4564340Skurt 	register char *cp;
4574340Skurt 
4584340Skurt 	if (n <= 0)
4594340Skurt 		return;
4604340Skurt 	for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
4614340Skurt 		;
4627561Skurt 	clob1(n - 1);
4634340Skurt }
4647573Skurt 
4657573Skurt /*
46618662Sserge  * Add the given header fields to the retained list.
46718662Sserge  * If no arguments, print the current list of retained fields.
46818662Sserge  */
46918662Sserge retfield(list)
47018662Sserge 	char *list[];
47118662Sserge {
47218662Sserge 	char field[BUFSIZ];
47318662Sserge 	register int h;
47418662Sserge 	register struct ignore *igp;
47518662Sserge 	char **ap;
47618662Sserge 
47718662Sserge 	if (argcount(list) == 0)
47818662Sserge 		return(retshow());
47918662Sserge 	for (ap = list; *ap != 0; ap++) {
48018662Sserge 		istrcpy(field, *ap);
48118662Sserge 
48218662Sserge 		if (member(field, retain))
48318662Sserge 			continue;
48418662Sserge 
48518662Sserge 		h = hash(field);
48618662Sserge 		igp = (struct ignore *) calloc(1, sizeof (struct ignore));
48731142Sedward 		igp->i_field = calloc((unsigned) strlen(field) + 1,
48831142Sedward 			sizeof (char));
48918662Sserge 		strcpy(igp->i_field, field);
49018662Sserge 		igp->i_link = retain[h];
49118662Sserge 		retain[h] = igp;
49218662Sserge 		nretained++;
49318662Sserge 	}
49418662Sserge 	return(0);
49518662Sserge }
49618662Sserge 
49718662Sserge /*
49818662Sserge  * Print out all currently retained fields.
49918662Sserge  */
50018662Sserge retshow()
50118662Sserge {
50218662Sserge 	register int h, count;
50318662Sserge 	struct ignore *igp;
50418662Sserge 	char **ap, **ring;
50518662Sserge 	int igcomp();
50618662Sserge 
50718662Sserge 	count = 0;
50818662Sserge 	for (h = 0; h < HSHSIZE; h++)
50918662Sserge 		for (igp = retain[h]; igp != 0; igp = igp->i_link)
51018662Sserge 			count++;
51118662Sserge 	if (count == 0) {
51218662Sserge 		printf("No fields currently being retained.\n");
51318662Sserge 		return(0);
51418662Sserge 	}
51518662Sserge 	ring = (char **) salloc((count + 1) * sizeof (char *));
51618662Sserge 	ap = ring;
51718662Sserge 	for (h = 0; h < HSHSIZE; h++)
51818662Sserge 		for (igp = retain[h]; igp != 0; igp = igp->i_link)
51918662Sserge 			*ap++ = igp->i_field;
52018662Sserge 	*ap = 0;
52131142Sedward 	qsort((char *) ring, count, sizeof (char *), igcomp);
52218662Sserge 	for (ap = ring; *ap != 0; ap++)
52318662Sserge 		printf("%s\n", *ap);
52418662Sserge 	return(0);
52518662Sserge }
52618662Sserge 
52718662Sserge /*
5287573Skurt  * Add the given header fields to the ignored list.
5297573Skurt  * If no arguments, print the current list of ignored fields.
5307573Skurt  */
5317573Skurt igfield(list)
5327573Skurt 	char *list[];
5337573Skurt {
5347573Skurt 	char field[BUFSIZ];
5357573Skurt 	register int h;
5367573Skurt 	register struct ignore *igp;
5377573Skurt 	char **ap;
5387573Skurt 
5397573Skurt 	if (argcount(list) == 0)
5407573Skurt 		return(igshow());
5417573Skurt 	for (ap = list; *ap != 0; ap++) {
5427582Skurt 		if (isign(*ap))
5437582Skurt 			continue;
5447573Skurt 		istrcpy(field, *ap);
5457573Skurt 		h = hash(field);
5467573Skurt 		igp = (struct ignore *) calloc(1, sizeof (struct ignore));
54731142Sedward 		igp->i_field = calloc((unsigned) strlen(field) + 1,
54831142Sedward 			sizeof (char));
5497573Skurt 		strcpy(igp->i_field, field);
5507573Skurt 		igp->i_link = ignore[h];
5517573Skurt 		ignore[h] = igp;
5527573Skurt 	}
5537573Skurt 	return(0);
5547573Skurt }
5557573Skurt 
5567573Skurt /*
5577573Skurt  * Print out all currently ignored fields.
5587573Skurt  */
5597573Skurt igshow()
5607573Skurt {
5617582Skurt 	register int h, count;
5627573Skurt 	struct ignore *igp;
5637582Skurt 	char **ap, **ring;
5647582Skurt 	int igcomp();
5657573Skurt 
5667582Skurt 	count = 0;
5677573Skurt 	for (h = 0; h < HSHSIZE; h++)
5687582Skurt 		for (igp = ignore[h]; igp != 0; igp = igp->i_link)
5697582Skurt 			count++;
5707582Skurt 	if (count == 0) {
5717573Skurt 		printf("No fields currently being ignored.\n");
5727582Skurt 		return(0);
5737582Skurt 	}
5747584Skurt 	ring = (char **) salloc((count + 1) * sizeof (char *));
5757582Skurt 	ap = ring;
5767582Skurt 	for (h = 0; h < HSHSIZE; h++)
5777582Skurt 		for (igp = ignore[h]; igp != 0; igp = igp->i_link)
5787582Skurt 			*ap++ = igp->i_field;
5797582Skurt 	*ap = 0;
58031142Sedward 	qsort((char *) ring, count, sizeof (char *), igcomp);
5817582Skurt 	for (ap = ring; *ap != 0; ap++)
5827582Skurt 		printf("%s\n", *ap);
5837573Skurt 	return(0);
5847573Skurt }
5857582Skurt 
5867582Skurt /*
5877582Skurt  * Compare two names for sorting ignored field list.
5887582Skurt  */
5897582Skurt igcomp(l, r)
5907582Skurt 	char **l, **r;
5917582Skurt {
5927582Skurt 
5937582Skurt 	return(strcmp(*l, *r));
5947582Skurt }
595