xref: /original-bsd/usr.bin/mail/quit.c (revision f052b07a)
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.10 (Berkeley) 07/07/88";
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  * Save all of the undetermined messages at the top of "mbox"
34  * Save all untouched messages back in the system mailbox.
35  * Remove the system mailbox, if none saved there.
36  */
37 
38 quit()
39 {
40 	int mcount, p, modify, autohold, anystat, holdbit, nohold;
41 	FILE *ibuf, *obuf, *fbuf, *rbuf, *readstat, *abuf;
42 	register struct message *mp;
43 	register int c;
44 	extern char tempQuit[], tempResid[];
45 	struct stat minfo;
46 	char *mbox;
47 
48 	/*
49 	 * If we are read only, we can't do anything,
50 	 * so just return quickly.
51 	 */
52 
53 	if (readonly)
54 		return;
55 	/*
56 	 * See if there any messages to save in mbox.  If no, we
57 	 * can save copying mbox to /tmp and back.
58 	 *
59 	 * Check also to see if any files need to be preserved.
60 	 * Delete all untouched messages to keep them out of mbox.
61 	 * If all the messages are to be preserved, just exit with
62 	 * a message.
63 	 */
64 
65 	fbuf = fopen(mailname, "r");
66 	if (fbuf == NULL)
67 		goto newmail;
68 	flock(fileno(fbuf), LOCK_EX);
69 	rbuf = NULL;
70 	if (fstat(fileno(fbuf), &minfo) >= 0 && minfo.st_size > mailsize) {
71 		printf("New mail has arrived.\n");
72 		rbuf = fopen(tempResid, "w");
73 		if (rbuf == NULL || fbuf == NULL)
74 			goto newmail;
75 #ifdef APPEND
76 		fseek(fbuf, mailsize, 0);
77 		while ((c = getc(fbuf)) != EOF)
78 			putc(c, rbuf);
79 #else
80 		p = minfo.st_size - mailsize;
81 		while (p-- > 0) {
82 			c = getc(fbuf);
83 			if (c == EOF)
84 				goto newmail;
85 			putc(c, rbuf);
86 		}
87 #endif
88 		fclose(rbuf);
89 		if ((rbuf = fopen(tempResid, "r")) == NULL)
90 			goto newmail;
91 		remove(tempResid);
92 	}
93 
94 	/*
95 	 * Adjust the message flags in each message.
96 	 */
97 
98 	anystat = 0;
99 	autohold = value("hold") != NOSTR;
100 	holdbit = autohold ? MPRESERVE : MBOX;
101 	nohold = MBOX|MSAVED|MDELETED|MPRESERVE;
102 	if (value("keepsave") != NOSTR)
103 		nohold &= ~MSAVED;
104 	for (mp = &message[0]; mp < &message[msgCount]; mp++) {
105 		if (mp->m_flag & MNEW) {
106 			mp->m_flag &= ~MNEW;
107 			mp->m_flag |= MSTATUS;
108 		}
109 		if (mp->m_flag & MSTATUS)
110 			anystat++;
111 		if ((mp->m_flag & MTOUCH) == 0)
112 			mp->m_flag |= MPRESERVE;
113 		if ((mp->m_flag & nohold) == 0)
114 			mp->m_flag |= holdbit;
115 	}
116 	modify = 0;
117 	if (Tflag != NOSTR) {
118 		if ((readstat = fopen(Tflag, "w")) == NULL)
119 			Tflag = NOSTR;
120 	}
121 	for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) {
122 		if (mp->m_flag & MBOX)
123 			c++;
124 		if (mp->m_flag & MPRESERVE)
125 			p++;
126 		if (mp->m_flag & MODIFY)
127 			modify++;
128 		if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
129 			char *id;
130 
131 			if ((id = hfield("article-id", mp)) != NOSTR)
132 				fprintf(readstat, "%s\n", id);
133 		}
134 	}
135 	if (Tflag != NOSTR)
136 		fclose(readstat);
137 	if (p == msgCount && !modify && !anystat) {
138 		printf("Held %d message%s in %s\n",
139 			p, p == 1 ? "" : "s", mailname);
140 		fclose(fbuf);
141 		return;
142 	}
143 	if (c == 0) {
144 		if (p != 0) {
145 			writeback(rbuf);
146 			fclose(fbuf);
147 			return;
148 		}
149 		goto cream;
150 	}
151 
152 	/*
153 	 * Create another temporary file and copy user's mbox file
154 	 * darin.  If there is no mbox, copy nothing.
155 	 * If he has specified "append" don't copy his mailbox,
156 	 * just copy saveable entries at the end.
157 	 */
158 
159 	mbox = expand("&");
160 	mcount = c;
161 	if (value("append") == NOSTR) {
162 		if ((obuf = fopen(tempQuit, "w")) == NULL) {
163 			perror(tempQuit);
164 			fclose(fbuf);
165 			return;
166 		}
167 		if ((ibuf = fopen(tempQuit, "r")) == NULL) {
168 			perror(tempQuit);
169 			remove(tempQuit);
170 			fclose(obuf);
171 			fclose(fbuf);
172 			return;
173 		}
174 		remove(tempQuit);
175 		if ((abuf = fopen(mbox, "r")) != NULL) {
176 			while ((c = getc(abuf)) != EOF)
177 				putc(c, obuf);
178 			fclose(abuf);
179 		}
180 		if (ferror(obuf)) {
181 			perror(tempQuit);
182 			fclose(ibuf);
183 			fclose(obuf);
184 			fclose(fbuf);
185 			return;
186 		}
187 		fclose(obuf);
188 		close(creat(mbox, 0600));
189 		if ((obuf = fopen(mbox, "r+")) == NULL) {
190 			perror(mbox);
191 			fclose(ibuf);
192 			fclose(fbuf);
193 			return;
194 		}
195 	}
196 	if (value("append") != NOSTR) {
197 		if ((obuf = fopen(mbox, "a")) == NULL) {
198 			perror(mbox);
199 			fclose(fbuf);
200 			return;
201 		}
202 		fchmod(fileno(obuf), 0600);
203 	}
204 	for (mp = &message[0]; mp < &message[msgCount]; mp++)
205 		if (mp->m_flag & MBOX)
206 			if (send(mp, obuf, saveignore, NOSTR) < 0) {
207 				perror(mbox);
208 				fclose(ibuf);
209 				fclose(obuf);
210 				fclose(fbuf);
211 				return;
212 			}
213 
214 	/*
215 	 * Copy the user's old mbox contents back
216 	 * to the end of the stuff we just saved.
217 	 * If we are appending, this is unnecessary.
218 	 */
219 
220 	if (value("append") == NOSTR) {
221 		rewind(ibuf);
222 		c = getc(ibuf);
223 		while (c != EOF) {
224 			putc(c, obuf);
225 			if (ferror(obuf))
226 				break;
227 			c = getc(ibuf);
228 		}
229 		fclose(ibuf);
230 		fflush(obuf);
231 	}
232 	trunc(obuf);
233 	if (ferror(obuf)) {
234 		perror(mbox);
235 		fclose(obuf);
236 		fclose(fbuf);
237 		return;
238 	}
239 	fclose(obuf);
240 	if (mcount == 1)
241 		printf("Saved 1 message in mbox\n");
242 	else
243 		printf("Saved %d messages in mbox\n", mcount);
244 
245 	/*
246 	 * Now we are ready to copy back preserved files to
247 	 * the system mailbox, if any were requested.
248 	 */
249 
250 	if (p != 0) {
251 		writeback(rbuf);
252 		fclose(fbuf);
253 		return;
254 	}
255 
256 	/*
257 	 * Finally, remove his /usr/mail file.
258 	 * If new mail has arrived, copy it back.
259 	 */
260 
261 cream:
262 	if (rbuf != NULL) {
263 		abuf = fopen(mailname, "r+");
264 		if (abuf == NULL)
265 			goto newmail;
266 		while ((c = getc(rbuf)) != EOF)
267 			putc(c, abuf);
268 		fclose(rbuf);
269 		trunc(abuf);
270 		fclose(abuf);
271 		alter(mailname);
272 		fclose(fbuf);
273 		return;
274 	}
275 	demail();
276 	fclose(fbuf);
277 	return;
278 
279 newmail:
280 	printf("Thou hast new mail.\n");
281 	if (fbuf != NULL)
282 		fclose(fbuf);
283 }
284 
285 /*
286  * Preserve all the appropriate messages back in the system
287  * mailbox, and print a nice message indicated how many were
288  * saved.  On any error, just return -1.  Else return 0.
289  * Incorporate the any new mail that we found.
290  */
291 writeback(res)
292 	register FILE *res;
293 {
294 	register struct message *mp;
295 	register int p, c;
296 	FILE *obuf;
297 
298 	p = 0;
299 	if ((obuf = fopen(mailname, "r+")) == NULL) {
300 		perror(mailname);
301 		return(-1);
302 	}
303 #ifndef APPEND
304 	if (res != NULL)
305 		while ((c = getc(res)) != EOF)
306 			putc(c, obuf);
307 #endif
308 	for (mp = &message[0]; mp < &message[msgCount]; mp++)
309 		if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) {
310 			p++;
311 			if (send(mp, obuf, (struct ignoretab *)0, NOSTR) < 0) {
312 				perror(mailname);
313 				fclose(obuf);
314 				return(-1);
315 			}
316 		}
317 #ifdef APPEND
318 	if (res != NULL)
319 		while ((c = getc(res)) != EOF)
320 			putc(c, obuf);
321 #endif
322 	fflush(obuf);
323 	trunc(obuf);
324 	if (ferror(obuf)) {
325 		perror(mailname);
326 		fclose(obuf);
327 		return(-1);
328 	}
329 	if (res != NULL)
330 		fclose(res);
331 	fclose(obuf);
332 	alter(mailname);
333 	if (p == 1)
334 		printf("Held 1 message in %s\n", mailname);
335 	else
336 		printf("Held %d messages in %s\n", p, mailname);
337 	return(0);
338 }
339