xref: /original-bsd/usr.bin/mail/quit.c (revision 0842ddeb)
1 /*
2  * Copyright (c) 1980, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)quit.c	8.2 (Berkeley) 04/28/95";
10 #endif /* not lint */
11 
12 #include "rcv.h"
13 #include <fcntl.h>
14 #include "extern.h"
15 
16 /*
17  * Rcv -- receive mail rationally.
18  *
19  * Termination processing.
20  */
21 
22 /*
23  * The "quit" command.
24  */
25 int
26 quitcmd()
27 {
28 	/*
29 	 * If we are sourcing, then return 1 so execute() can handle it.
30 	 * Otherwise, return -1 to abort command loop.
31 	 */
32 	if (sourcing)
33 		return 1;
34 	return -1;
35 }
36 
37 /*
38  * Save all of the undetermined messages at the top of "mbox"
39  * Save all untouched messages back in the system mailbox.
40  * Remove the system mailbox, if none saved there.
41  */
42 void
43 quit()
44 {
45 	int mcount, p, modify, autohold, anystat, holdbit, nohold;
46 	FILE *ibuf, *obuf, *fbuf, *rbuf, *readstat, *abuf;
47 	register struct message *mp;
48 	register int c;
49 	extern char tempQuit[], tempResid[];
50 	struct stat minfo;
51 	char *mbox;
52 
53 	/*
54 	 * If we are read only, we can't do anything,
55 	 * so just return quickly.
56 	 */
57 	if (readonly)
58 		return;
59 	/*
60 	 * If editing (not reading system mail box), then do the work
61 	 * in edstop()
62 	 */
63 	if (edit) {
64 		edstop();
65 		return;
66 	}
67 
68 	/*
69 	 * See if there any messages to save in mbox.  If no, we
70 	 * can save copying mbox to /tmp and back.
71 	 *
72 	 * Check also to see if any files need to be preserved.
73 	 * Delete all untouched messages to keep them out of mbox.
74 	 * If all the messages are to be preserved, just exit with
75 	 * a message.
76 	 */
77 
78 	fbuf = Fopen(mailname, "r");
79 	if (fbuf == NULL)
80 		goto newmail;
81 	flock(fileno(fbuf), LOCK_EX);
82 	rbuf = NULL;
83 	if (fstat(fileno(fbuf), &minfo) >= 0 && minfo.st_size > mailsize) {
84 		printf("New mail has arrived.\n");
85 		rbuf = Fopen(tempResid, "w");
86 		if (rbuf == NULL || fbuf == NULL)
87 			goto newmail;
88 #ifdef APPEND
89 		fseek(fbuf, (long)mailsize, 0);
90 		while ((c = getc(fbuf)) != EOF)
91 			(void) putc(c, rbuf);
92 #else
93 		p = minfo.st_size - mailsize;
94 		while (p-- > 0) {
95 			c = getc(fbuf);
96 			if (c == EOF)
97 				goto newmail;
98 			(void) putc(c, rbuf);
99 		}
100 #endif
101 		Fclose(rbuf);
102 		if ((rbuf = Fopen(tempResid, "r")) == NULL)
103 			goto newmail;
104 		rm(tempResid);
105 	}
106 
107 	/*
108 	 * Adjust the message flags in each message.
109 	 */
110 
111 	anystat = 0;
112 	autohold = value("hold") != NOSTR;
113 	holdbit = autohold ? MPRESERVE : MBOX;
114 	nohold = MBOX|MSAVED|MDELETED|MPRESERVE;
115 	if (value("keepsave") != NOSTR)
116 		nohold &= ~MSAVED;
117 	for (mp = &message[0]; mp < &message[msgCount]; mp++) {
118 		if (mp->m_flag & MNEW) {
119 			mp->m_flag &= ~MNEW;
120 			mp->m_flag |= MSTATUS;
121 		}
122 		if (mp->m_flag & MSTATUS)
123 			anystat++;
124 		if ((mp->m_flag & MTOUCH) == 0)
125 			mp->m_flag |= MPRESERVE;
126 		if ((mp->m_flag & nohold) == 0)
127 			mp->m_flag |= holdbit;
128 	}
129 	modify = 0;
130 	if (Tflag != NOSTR) {
131 		if ((readstat = Fopen(Tflag, "w")) == NULL)
132 			Tflag = NOSTR;
133 	}
134 	for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) {
135 		if (mp->m_flag & MBOX)
136 			c++;
137 		if (mp->m_flag & MPRESERVE)
138 			p++;
139 		if (mp->m_flag & MODIFY)
140 			modify++;
141 		if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
142 			char *id;
143 
144 			if ((id = hfield("article-id", mp)) != NOSTR)
145 				fprintf(readstat, "%s\n", id);
146 		}
147 	}
148 	if (Tflag != NOSTR)
149 		Fclose(readstat);
150 	if (p == msgCount && !modify && !anystat) {
151 		printf("Held %d message%s in %s\n",
152 			p, p == 1 ? "" : "s", mailname);
153 		Fclose(fbuf);
154 		return;
155 	}
156 	if (c == 0) {
157 		if (p != 0) {
158 			writeback(rbuf);
159 			Fclose(fbuf);
160 			return;
161 		}
162 		goto cream;
163 	}
164 
165 	/*
166 	 * Create another temporary file and copy user's mbox file
167 	 * darin.  If there is no mbox, copy nothing.
168 	 * If he has specified "append" don't copy his mailbox,
169 	 * just copy saveable entries at the end.
170 	 */
171 
172 	mbox = expand("&");
173 	mcount = c;
174 	if (value("append") == NOSTR) {
175 		if ((obuf = Fopen(tempQuit, "w")) == NULL) {
176 			perror(tempQuit);
177 			Fclose(fbuf);
178 			return;
179 		}
180 		if ((ibuf = Fopen(tempQuit, "r")) == NULL) {
181 			perror(tempQuit);
182 			rm(tempQuit);
183 			Fclose(obuf);
184 			Fclose(fbuf);
185 			return;
186 		}
187 		rm(tempQuit);
188 		if ((abuf = Fopen(mbox, "r")) != NULL) {
189 			while ((c = getc(abuf)) != EOF)
190 				(void) putc(c, obuf);
191 			Fclose(abuf);
192 		}
193 		if (ferror(obuf)) {
194 			perror(tempQuit);
195 			Fclose(ibuf);
196 			Fclose(obuf);
197 			Fclose(fbuf);
198 			return;
199 		}
200 		Fclose(obuf);
201 		close(creat(mbox, 0600));
202 		if ((obuf = Fopen(mbox, "r+")) == NULL) {
203 			perror(mbox);
204 			Fclose(ibuf);
205 			Fclose(fbuf);
206 			return;
207 		}
208 	}
209 	if (value("append") != NOSTR) {
210 		if ((obuf = Fopen(mbox, "a")) == NULL) {
211 			perror(mbox);
212 			Fclose(fbuf);
213 			return;
214 		}
215 		fchmod(fileno(obuf), 0600);
216 	}
217 	for (mp = &message[0]; mp < &message[msgCount]; mp++)
218 		if (mp->m_flag & MBOX)
219 			if (send(mp, obuf, saveignore, NOSTR) < 0) {
220 				perror(mbox);
221 				Fclose(ibuf);
222 				Fclose(obuf);
223 				Fclose(fbuf);
224 				return;
225 			}
226 
227 	/*
228 	 * Copy the user's old mbox contents back
229 	 * to the end of the stuff we just saved.
230 	 * If we are appending, this is unnecessary.
231 	 */
232 
233 	if (value("append") == NOSTR) {
234 		rewind(ibuf);
235 		c = getc(ibuf);
236 		while (c != EOF) {
237 			(void) putc(c, obuf);
238 			if (ferror(obuf))
239 				break;
240 			c = getc(ibuf);
241 		}
242 		Fclose(ibuf);
243 	}
244 	fflush(obuf);
245 	trunc(obuf);
246 	if (ferror(obuf)) {
247 		perror(mbox);
248 		Fclose(obuf);
249 		Fclose(fbuf);
250 		return;
251 	}
252 	Fclose(obuf);
253 	if (mcount == 1)
254 		printf("Saved 1 message in mbox\n");
255 	else
256 		printf("Saved %d messages in mbox\n", mcount);
257 
258 	/*
259 	 * Now we are ready to copy back preserved files to
260 	 * the system mailbox, if any were requested.
261 	 */
262 
263 	if (p != 0) {
264 		writeback(rbuf);
265 		Fclose(fbuf);
266 		return;
267 	}
268 
269 	/*
270 	 * Finally, remove his /usr/mail file.
271 	 * If new mail has arrived, copy it back.
272 	 */
273 
274 cream:
275 	if (rbuf != NULL) {
276 		abuf = Fopen(mailname, "r+");
277 		if (abuf == NULL)
278 			goto newmail;
279 		while ((c = getc(rbuf)) != EOF)
280 			(void) putc(c, abuf);
281 		Fclose(rbuf);
282 		trunc(abuf);
283 		Fclose(abuf);
284 		alter(mailname);
285 		Fclose(fbuf);
286 		return;
287 	}
288 	demail();
289 	Fclose(fbuf);
290 	return;
291 
292 newmail:
293 	printf("Thou hast new mail.\n");
294 	if (fbuf != NULL)
295 		Fclose(fbuf);
296 }
297 
298 /*
299  * Preserve all the appropriate messages back in the system
300  * mailbox, and print a nice message indicated how many were
301  * saved.  On any error, just return -1.  Else return 0.
302  * Incorporate the any new mail that we found.
303  */
304 int
305 writeback(res)
306 	register FILE *res;
307 {
308 	register struct message *mp;
309 	register int p, c;
310 	FILE *obuf;
311 
312 	p = 0;
313 	if ((obuf = Fopen(mailname, "r+")) == NULL) {
314 		perror(mailname);
315 		return(-1);
316 	}
317 #ifndef APPEND
318 	if (res != NULL)
319 		while ((c = getc(res)) != EOF)
320 			(void) putc(c, obuf);
321 #endif
322 	for (mp = &message[0]; mp < &message[msgCount]; mp++)
323 		if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) {
324 			p++;
325 			if (send(mp, obuf, (struct ignoretab *)0, NOSTR) < 0) {
326 				perror(mailname);
327 				Fclose(obuf);
328 				return(-1);
329 			}
330 		}
331 #ifdef APPEND
332 	if (res != NULL)
333 		while ((c = getc(res)) != EOF)
334 			(void) putc(c, obuf);
335 #endif
336 	fflush(obuf);
337 	trunc(obuf);
338 	if (ferror(obuf)) {
339 		perror(mailname);
340 		Fclose(obuf);
341 		return(-1);
342 	}
343 	if (res != NULL)
344 		Fclose(res);
345 	Fclose(obuf);
346 	alter(mailname);
347 	if (p == 1)
348 		printf("Held 1 message in %s\n", mailname);
349 	else
350 		printf("Held %d messages in %s\n", p, mailname);
351 	return(0);
352 }
353 
354 /*
355  * Terminate an editing session by attempting to write out the user's
356  * file from the temporary.  Save any new stuff appended to the file.
357  */
358 void
359 edstop()
360 {
361 	extern char *tmpdir;
362 	register int gotcha, c;
363 	register struct message *mp;
364 	FILE *obuf, *ibuf, *readstat;
365 	struct stat statb;
366 	char tempname[30];
367 	char *mktemp();
368 
369 	if (readonly)
370 		return;
371 	holdsigs();
372 	if (Tflag != NOSTR) {
373 		if ((readstat = Fopen(Tflag, "w")) == NULL)
374 			Tflag = NOSTR;
375 	}
376 	for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) {
377 		if (mp->m_flag & MNEW) {
378 			mp->m_flag &= ~MNEW;
379 			mp->m_flag |= MSTATUS;
380 		}
381 		if (mp->m_flag & (MODIFY|MDELETED|MSTATUS))
382 			gotcha++;
383 		if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
384 			char *id;
385 
386 			if ((id = hfield("article-id", mp)) != NOSTR)
387 				fprintf(readstat, "%s\n", id);
388 		}
389 	}
390 	if (Tflag != NOSTR)
391 		Fclose(readstat);
392 	if (!gotcha || Tflag != NOSTR)
393 		goto done;
394 	ibuf = NULL;
395 	if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) {
396 		strcpy(tempname, tmpdir);
397 		strcat(tempname, "mboxXXXXXX");
398 		mktemp(tempname);
399 		if ((obuf = Fopen(tempname, "w")) == NULL) {
400 			perror(tempname);
401 			relsesigs();
402 			reset(0);
403 		}
404 		if ((ibuf = Fopen(mailname, "r")) == NULL) {
405 			perror(mailname);
406 			Fclose(obuf);
407 			rm(tempname);
408 			relsesigs();
409 			reset(0);
410 		}
411 		fseek(ibuf, (long)mailsize, 0);
412 		while ((c = getc(ibuf)) != EOF)
413 			(void) putc(c, obuf);
414 		Fclose(ibuf);
415 		Fclose(obuf);
416 		if ((ibuf = Fopen(tempname, "r")) == NULL) {
417 			perror(tempname);
418 			rm(tempname);
419 			relsesigs();
420 			reset(0);
421 		}
422 		rm(tempname);
423 	}
424 	printf("\"%s\" ", mailname);
425 	fflush(stdout);
426 	if ((obuf = Fopen(mailname, "r+")) == NULL) {
427 		perror(mailname);
428 		relsesigs();
429 		reset(0);
430 	}
431 	trunc(obuf);
432 	c = 0;
433 	for (mp = &message[0]; mp < &message[msgCount]; mp++) {
434 		if ((mp->m_flag & MDELETED) != 0)
435 			continue;
436 		c++;
437 		if (send(mp, obuf, (struct ignoretab *) NULL, NOSTR) < 0) {
438 			perror(mailname);
439 			relsesigs();
440 			reset(0);
441 		}
442 	}
443 	gotcha = (c == 0 && ibuf == NULL);
444 	if (ibuf != NULL) {
445 		while ((c = getc(ibuf)) != EOF)
446 			(void) putc(c, obuf);
447 		Fclose(ibuf);
448 	}
449 	fflush(obuf);
450 	if (ferror(obuf)) {
451 		perror(mailname);
452 		relsesigs();
453 		reset(0);
454 	}
455 	Fclose(obuf);
456 	if (gotcha) {
457 		rm(mailname);
458 		printf("removed\n");
459 	} else
460 		printf("complete\n");
461 	fflush(stdout);
462 
463 done:
464 	relsesigs();
465 }
466