xref: /csrg-svn/usr.bin/mail/quit.c (revision 69020)
122464Sdist /*
262083Sbostic  * Copyright (c) 1980, 1993
362083Sbostic  *	The Regents of the University of California.  All rights reserved.
433499Sbostic  *
542741Sbostic  * %sccs.include.redist.c%
622464Sdist  */
722464Sdist 
834905Sbostic #ifndef lint
9*69020Sbostic static char sccsid[] = "@(#)quit.c	8.2 (Berkeley) 04/28/95";
1034905Sbostic #endif /* not lint */
111243Skas 
121243Skas #include "rcv.h"
1354505Sbostic #include <fcntl.h>
1454505Sbostic #include "extern.h"
151243Skas 
161243Skas /*
171243Skas  * Rcv -- receive mail rationally.
181243Skas  *
191243Skas  * Termination processing.
201243Skas  */
211243Skas 
221243Skas /*
2336554Sedward  * The "quit" command.
2436554Sedward  */
2554505Sbostic int
quitcmd()2636554Sedward quitcmd()
2736554Sedward {
2836554Sedward 	/*
2936554Sedward 	 * If we are sourcing, then return 1 so execute() can handle it.
3036554Sedward 	 * Otherwise, return -1 to abort command loop.
3136554Sedward 	 */
3236554Sedward 	if (sourcing)
3336554Sedward 		return 1;
3436554Sedward 	return -1;
3536554Sedward }
3636554Sedward 
3736554Sedward /*
381243Skas  * Save all of the undetermined messages at the top of "mbox"
391243Skas  * Save all untouched messages back in the system mailbox.
401243Skas  * Remove the system mailbox, if none saved there.
411243Skas  */
4254505Sbostic void
quit()431243Skas quit()
441243Skas {
454338Skurt 	int mcount, p, modify, autohold, anystat, holdbit, nohold;
4616733Sralph 	FILE *ibuf, *obuf, *fbuf, *rbuf, *readstat, *abuf;
471243Skas 	register struct message *mp;
481243Skas 	register int c;
491243Skas 	extern char tempQuit[], tempResid[];
501243Skas 	struct stat minfo;
5134753Sedward 	char *mbox;
521243Skas 
531243Skas 	/*
541314Skas 	 * If we are read only, we can't do anything,
551314Skas 	 * so just return quickly.
561314Skas 	 */
571314Skas 	if (readonly)
581314Skas 		return;
591314Skas 	/*
6036554Sedward 	 * If editing (not reading system mail box), then do the work
6136554Sedward 	 * in edstop()
6236554Sedward 	 */
6336554Sedward 	if (edit) {
6436554Sedward 		edstop();
6536554Sedward 		return;
6636554Sedward 	}
6736554Sedward 
6836554Sedward 	/*
691243Skas 	 * See if there any messages to save in mbox.  If no, we
701243Skas 	 * can save copying mbox to /tmp and back.
711243Skas 	 *
721243Skas 	 * Check also to see if any files need to be preserved.
731243Skas 	 * Delete all untouched messages to keep them out of mbox.
741243Skas 	 * If all the messages are to be preserved, just exit with
751243Skas 	 * a message.
761243Skas 	 */
771243Skas 
7843865Sedward 	fbuf = Fopen(mailname, "r");
7916733Sralph 	if (fbuf == NULL)
8016733Sralph 		goto newmail;
8116733Sralph 	flock(fileno(fbuf), LOCK_EX);
821243Skas 	rbuf = NULL;
8316733Sralph 	if (fstat(fileno(fbuf), &minfo) >= 0 && minfo.st_size > mailsize) {
841243Skas 		printf("New mail has arrived.\n");
8543865Sedward 		rbuf = Fopen(tempResid, "w");
861243Skas 		if (rbuf == NULL || fbuf == NULL)
871243Skas 			goto newmail;
881243Skas #ifdef APPEND
8954505Sbostic 		fseek(fbuf, (long)mailsize, 0);
901243Skas 		while ((c = getc(fbuf)) != EOF)
9136554Sedward 			(void) putc(c, rbuf);
921243Skas #else
931243Skas 		p = minfo.st_size - mailsize;
941243Skas 		while (p-- > 0) {
951243Skas 			c = getc(fbuf);
961243Skas 			if (c == EOF)
971243Skas 				goto newmail;
9836554Sedward 			(void) putc(c, rbuf);
991243Skas 		}
1001243Skas #endif
10143865Sedward 		Fclose(rbuf);
10243865Sedward 		if ((rbuf = Fopen(tempResid, "r")) == NULL)
1031243Skas 			goto newmail;
10446349Sedward 		rm(tempResid);
1051243Skas 	}
1061486Skas 
1071486Skas 	/*
1081486Skas 	 * Adjust the message flags in each message.
1091486Skas 	 */
1101486Skas 
1111486Skas 	anystat = 0;
1123322Skas 	autohold = value("hold") != NOSTR;
1133322Skas 	holdbit = autohold ? MPRESERVE : MBOX;
1144338Skurt 	nohold = MBOX|MSAVED|MDELETED|MPRESERVE;
1154338Skurt 	if (value("keepsave") != NOSTR)
1164338Skurt 		nohold &= ~MSAVED;
1171243Skas 	for (mp = &message[0]; mp < &message[msgCount]; mp++) {
1181486Skas 		if (mp->m_flag & MNEW) {
1191486Skas 			mp->m_flag &= ~MNEW;
1201486Skas 			mp->m_flag |= MSTATUS;
1211486Skas 		}
1221486Skas 		if (mp->m_flag & MSTATUS)
1231486Skas 			anystat++;
1241243Skas 		if ((mp->m_flag & MTOUCH) == 0)
1253322Skas 			mp->m_flag |= MPRESERVE;
1264338Skurt 		if ((mp->m_flag & nohold) == 0)
1273322Skas 			mp->m_flag |= holdbit;
1281243Skas 	}
1291243Skas 	modify = 0;
1304020Skurt 	if (Tflag != NOSTR) {
13143865Sedward 		if ((readstat = Fopen(Tflag, "w")) == NULL)
1324020Skurt 			Tflag = NOSTR;
1334020Skurt 	}
1341243Skas 	for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) {
1353322Skas 		if (mp->m_flag & MBOX)
1361243Skas 			c++;
1373322Skas 		if (mp->m_flag & MPRESERVE)
1381243Skas 			p++;
1391243Skas 		if (mp->m_flag & MODIFY)
1401243Skas 			modify++;
1414020Skurt 		if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
14234754Sedward 			char *id;
14334754Sedward 
14434754Sedward 			if ((id = hfield("article-id", mp)) != NOSTR)
1454020Skurt 				fprintf(readstat, "%s\n", id);
1464020Skurt 		}
1471243Skas 	}
1484020Skurt 	if (Tflag != NOSTR)
14943865Sedward 		Fclose(readstat);
1501486Skas 	if (p == msgCount && !modify && !anystat) {
15134754Sedward 		printf("Held %d message%s in %s\n",
15234754Sedward 			p, p == 1 ? "" : "s", mailname);
15343865Sedward 		Fclose(fbuf);
1541243Skas 		return;
1551243Skas 	}
1561243Skas 	if (c == 0) {
1571243Skas 		if (p != 0) {
1581243Skas 			writeback(rbuf);
15943865Sedward 			Fclose(fbuf);
1601243Skas 			return;
1611243Skas 		}
1621243Skas 		goto cream;
1631243Skas 	}
1641243Skas 
1651243Skas 	/*
1661243Skas 	 * Create another temporary file and copy user's mbox file
1671243Skas 	 * darin.  If there is no mbox, copy nothing.
1681243Skas 	 * If he has specified "append" don't copy his mailbox,
1691243Skas 	 * just copy saveable entries at the end.
1701243Skas 	 */
1711243Skas 
17234753Sedward 	mbox = expand("&");
1731243Skas 	mcount = c;
1741243Skas 	if (value("append") == NOSTR) {
17543865Sedward 		if ((obuf = Fopen(tempQuit, "w")) == NULL) {
1761243Skas 			perror(tempQuit);
17743865Sedward 			Fclose(fbuf);
1781243Skas 			return;
1791243Skas 		}
18043865Sedward 		if ((ibuf = Fopen(tempQuit, "r")) == NULL) {
1811243Skas 			perror(tempQuit);
18246349Sedward 			rm(tempQuit);
18343865Sedward 			Fclose(obuf);
18443865Sedward 			Fclose(fbuf);
1851243Skas 			return;
1861243Skas 		}
18746349Sedward 		rm(tempQuit);
18843865Sedward 		if ((abuf = Fopen(mbox, "r")) != NULL) {
18916733Sralph 			while ((c = getc(abuf)) != EOF)
19036554Sedward 				(void) putc(c, obuf);
19143865Sedward 			Fclose(abuf);
1921243Skas 		}
1931243Skas 		if (ferror(obuf)) {
1941243Skas 			perror(tempQuit);
19543865Sedward 			Fclose(ibuf);
19643865Sedward 			Fclose(obuf);
19743865Sedward 			Fclose(fbuf);
1981243Skas 			return;
1991243Skas 		}
20043865Sedward 		Fclose(obuf);
2011243Skas 		close(creat(mbox, 0600));
20243865Sedward 		if ((obuf = Fopen(mbox, "r+")) == NULL) {
2031243Skas 			perror(mbox);
20443865Sedward 			Fclose(ibuf);
20543865Sedward 			Fclose(fbuf);
2061243Skas 			return;
2071243Skas 		}
2081243Skas 	}
20926488Smckusick 	if (value("append") != NOSTR) {
21043865Sedward 		if ((obuf = Fopen(mbox, "a")) == NULL) {
2111243Skas 			perror(mbox);
21243865Sedward 			Fclose(fbuf);
2131243Skas 			return;
2141243Skas 		}
21526488Smckusick 		fchmod(fileno(obuf), 0600);
21626488Smckusick 	}
2171243Skas 	for (mp = &message[0]; mp < &message[msgCount]; mp++)
2183322Skas 		if (mp->m_flag & MBOX)
21934969Sedward 			if (send(mp, obuf, saveignore, NOSTR) < 0) {
2201243Skas 				perror(mbox);
22143865Sedward 				Fclose(ibuf);
22243865Sedward 				Fclose(obuf);
22343865Sedward 				Fclose(fbuf);
2241243Skas 				return;
2251243Skas 			}
2261243Skas 
2271243Skas 	/*
2281243Skas 	 * Copy the user's old mbox contents back
2291243Skas 	 * to the end of the stuff we just saved.
2301243Skas 	 * If we are appending, this is unnecessary.
2311243Skas 	 */
2321243Skas 
2331243Skas 	if (value("append") == NOSTR) {
2341243Skas 		rewind(ibuf);
2351243Skas 		c = getc(ibuf);
2361243Skas 		while (c != EOF) {
23736554Sedward 			(void) putc(c, obuf);
2381243Skas 			if (ferror(obuf))
2391243Skas 				break;
2401243Skas 			c = getc(ibuf);
2411243Skas 		}
24243865Sedward 		Fclose(ibuf);
2431243Skas 	}
244*69020Sbostic 	fflush(obuf);
24512818Sleres 	trunc(obuf);
2461243Skas 	if (ferror(obuf)) {
2471243Skas 		perror(mbox);
24843865Sedward 		Fclose(obuf);
24943865Sedward 		Fclose(fbuf);
2501243Skas 		return;
2511243Skas 	}
25243865Sedward 	Fclose(obuf);
2531243Skas 	if (mcount == 1)
2541243Skas 		printf("Saved 1 message in mbox\n");
2551243Skas 	else
2561243Skas 		printf("Saved %d messages in mbox\n", mcount);
2571243Skas 
2581243Skas 	/*
2591243Skas 	 * Now we are ready to copy back preserved files to
2601243Skas 	 * the system mailbox, if any were requested.
2611243Skas 	 */
2621243Skas 
2631243Skas 	if (p != 0) {
2641243Skas 		writeback(rbuf);
26543865Sedward 		Fclose(fbuf);
2661243Skas 		return;
2671243Skas 	}
2681243Skas 
2691243Skas 	/*
2701243Skas 	 * Finally, remove his /usr/mail file.
2711243Skas 	 * If new mail has arrived, copy it back.
2721243Skas 	 */
2731243Skas 
2741243Skas cream:
2751243Skas 	if (rbuf != NULL) {
27643865Sedward 		abuf = Fopen(mailname, "r+");
27716733Sralph 		if (abuf == NULL)
2781243Skas 			goto newmail;
2791243Skas 		while ((c = getc(rbuf)) != EOF)
28036554Sedward 			(void) putc(c, abuf);
28143865Sedward 		Fclose(rbuf);
28216733Sralph 		trunc(abuf);
28343865Sedward 		Fclose(abuf);
28416733Sralph 		alter(mailname);
28543865Sedward 		Fclose(fbuf);
2861243Skas 		return;
2871243Skas 	}
2881243Skas 	demail();
28943865Sedward 	Fclose(fbuf);
2901243Skas 	return;
2911243Skas 
2921243Skas newmail:
2931243Skas 	printf("Thou hast new mail.\n");
29421092Sserge 	if (fbuf != NULL)
29543865Sedward 		Fclose(fbuf);
2961243Skas }
2971243Skas 
2981243Skas /*
2991243Skas  * Preserve all the appropriate messages back in the system
3001243Skas  * mailbox, and print a nice message indicated how many were
3011243Skas  * saved.  On any error, just return -1.  Else return 0.
3021243Skas  * Incorporate the any new mail that we found.
3031243Skas  */
30454505Sbostic int
writeback(res)3051243Skas writeback(res)
3061243Skas 	register FILE *res;
3071243Skas {
3081243Skas 	register struct message *mp;
3091243Skas 	register int p, c;
3101243Skas 	FILE *obuf;
3111243Skas 
3121243Skas 	p = 0;
31343865Sedward 	if ((obuf = Fopen(mailname, "r+")) == NULL) {
3141243Skas 		perror(mailname);
3151243Skas 		return(-1);
3161243Skas 	}
3171243Skas #ifndef APPEND
3181243Skas 	if (res != NULL)
3191243Skas 		while ((c = getc(res)) != EOF)
32036554Sedward 			(void) putc(c, obuf);
3211243Skas #endif
3221243Skas 	for (mp = &message[0]; mp < &message[msgCount]; mp++)
3231243Skas 		if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) {
3241243Skas 			p++;
32534969Sedward 			if (send(mp, obuf, (struct ignoretab *)0, NOSTR) < 0) {
3261243Skas 				perror(mailname);
32743865Sedward 				Fclose(obuf);
3281243Skas 				return(-1);
3291243Skas 			}
3301243Skas 		}
3311243Skas #ifdef APPEND
3321243Skas 	if (res != NULL)
3331243Skas 		while ((c = getc(res)) != EOF)
33436554Sedward 			(void) putc(c, obuf);
3351243Skas #endif
3361243Skas 	fflush(obuf);
33712818Sleres 	trunc(obuf);
3381243Skas 	if (ferror(obuf)) {
3391243Skas 		perror(mailname);
34043865Sedward 		Fclose(obuf);
3411243Skas 		return(-1);
3421243Skas 	}
3431243Skas 	if (res != NULL)
34443865Sedward 		Fclose(res);
34543865Sedward 	Fclose(obuf);
3461243Skas 	alter(mailname);
3471243Skas 	if (p == 1)
3481243Skas 		printf("Held 1 message in %s\n", mailname);
3491243Skas 	else
3501243Skas 		printf("Held %d messages in %s\n", p, mailname);
3511243Skas 	return(0);
3521243Skas }
35336554Sedward 
35436554Sedward /*
35536554Sedward  * Terminate an editing session by attempting to write out the user's
35636554Sedward  * file from the temporary.  Save any new stuff appended to the file.
35736554Sedward  */
35854505Sbostic void
edstop()35936554Sedward edstop()
36036554Sedward {
36152909Sbostic 	extern char *tmpdir;
36236554Sedward 	register int gotcha, c;
36336554Sedward 	register struct message *mp;
36436554Sedward 	FILE *obuf, *ibuf, *readstat;
36536554Sedward 	struct stat statb;
36636554Sedward 	char tempname[30];
36736554Sedward 	char *mktemp();
36836554Sedward 
36936554Sedward 	if (readonly)
37036554Sedward 		return;
37136554Sedward 	holdsigs();
37236554Sedward 	if (Tflag != NOSTR) {
37343865Sedward 		if ((readstat = Fopen(Tflag, "w")) == NULL)
37436554Sedward 			Tflag = NOSTR;
37536554Sedward 	}
37636554Sedward 	for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) {
37736554Sedward 		if (mp->m_flag & MNEW) {
37836554Sedward 			mp->m_flag &= ~MNEW;
37936554Sedward 			mp->m_flag |= MSTATUS;
38036554Sedward 		}
38136554Sedward 		if (mp->m_flag & (MODIFY|MDELETED|MSTATUS))
38236554Sedward 			gotcha++;
38336554Sedward 		if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
38436554Sedward 			char *id;
38536554Sedward 
38636554Sedward 			if ((id = hfield("article-id", mp)) != NOSTR)
38736554Sedward 				fprintf(readstat, "%s\n", id);
38836554Sedward 		}
38936554Sedward 	}
39036554Sedward 	if (Tflag != NOSTR)
39143865Sedward 		Fclose(readstat);
39236554Sedward 	if (!gotcha || Tflag != NOSTR)
39336554Sedward 		goto done;
39436554Sedward 	ibuf = NULL;
39536554Sedward 	if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) {
39652909Sbostic 		strcpy(tempname, tmpdir);
39738698Sbostic 		strcat(tempname, "mboxXXXXXX");
39836554Sedward 		mktemp(tempname);
39943865Sedward 		if ((obuf = Fopen(tempname, "w")) == NULL) {
40036554Sedward 			perror(tempname);
40136554Sedward 			relsesigs();
40236554Sedward 			reset(0);
40336554Sedward 		}
40443865Sedward 		if ((ibuf = Fopen(mailname, "r")) == NULL) {
40536554Sedward 			perror(mailname);
40643865Sedward 			Fclose(obuf);
40746349Sedward 			rm(tempname);
40836554Sedward 			relsesigs();
40936554Sedward 			reset(0);
41036554Sedward 		}
41154505Sbostic 		fseek(ibuf, (long)mailsize, 0);
41236554Sedward 		while ((c = getc(ibuf)) != EOF)
41336554Sedward 			(void) putc(c, obuf);
41443865Sedward 		Fclose(ibuf);
41543865Sedward 		Fclose(obuf);
41643865Sedward 		if ((ibuf = Fopen(tempname, "r")) == NULL) {
41736554Sedward 			perror(tempname);
41846349Sedward 			rm(tempname);
41936554Sedward 			relsesigs();
42036554Sedward 			reset(0);
42136554Sedward 		}
42246349Sedward 		rm(tempname);
42336554Sedward 	}
42436554Sedward 	printf("\"%s\" ", mailname);
42536554Sedward 	fflush(stdout);
42643865Sedward 	if ((obuf = Fopen(mailname, "r+")) == NULL) {
42736554Sedward 		perror(mailname);
42836554Sedward 		relsesigs();
42936554Sedward 		reset(0);
43036554Sedward 	}
43136554Sedward 	trunc(obuf);
43236554Sedward 	c = 0;
43336554Sedward 	for (mp = &message[0]; mp < &message[msgCount]; mp++) {
43436554Sedward 		if ((mp->m_flag & MDELETED) != 0)
43536554Sedward 			continue;
43636554Sedward 		c++;
43736554Sedward 		if (send(mp, obuf, (struct ignoretab *) NULL, NOSTR) < 0) {
43836554Sedward 			perror(mailname);
43936554Sedward 			relsesigs();
44036554Sedward 			reset(0);
44136554Sedward 		}
44236554Sedward 	}
44336554Sedward 	gotcha = (c == 0 && ibuf == NULL);
44436554Sedward 	if (ibuf != NULL) {
44536554Sedward 		while ((c = getc(ibuf)) != EOF)
44636554Sedward 			(void) putc(c, obuf);
44743865Sedward 		Fclose(ibuf);
44836554Sedward 	}
44936554Sedward 	fflush(obuf);
45036554Sedward 	if (ferror(obuf)) {
45136554Sedward 		perror(mailname);
45236554Sedward 		relsesigs();
45336554Sedward 		reset(0);
45436554Sedward 	}
45543865Sedward 	Fclose(obuf);
45636554Sedward 	if (gotcha) {
45746349Sedward 		rm(mailname);
45836554Sedward 		printf("removed\n");
45936554Sedward 	} else
46036554Sedward 		printf("complete\n");
46136554Sedward 	fflush(stdout);
46236554Sedward 
46336554Sedward done:
46436554Sedward 	relsesigs();
46536554Sedward }
466