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
quitcmd()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
quit()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
writeback(res)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
edstop()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