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