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