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