4.4BSD snapshot (revision 8.1); add 1993 to copyright
[unix-history] / usr / src / usr.bin / mail / quit.c
CommitLineData
761330fe 1/*
a12ff486
KB
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
0c5f72fb 4 *
f15db449 5 * %sccs.include.redist.c%
761330fe
DF
6 */
7
acfc7e9b 8#ifndef lint
a12ff486 9static char sccsid[] = "@(#)quit.c 8.1 (Berkeley) %G%";
acfc7e9b 10#endif /* not lint */
865dca9a
KS
11
12#include "rcv.h"
a0d23834
KB
13#include <fcntl.h>
14#include "extern.h"
865dca9a
KS
15
16/*
17 * Rcv -- receive mail rationally.
18 *
19 * Termination processing.
20 */
21
2ee3bce2
EW
22/*
23 * The "quit" command.
24 */
a0d23834 25int
2ee3bce2
EW
26quitcmd()
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
865dca9a
KS
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 */
a0d23834 42void
865dca9a
KS
43quit()
44{
c2483c81 45 int mcount, p, modify, autohold, anystat, holdbit, nohold;
4e161d3b 46 FILE *ibuf, *obuf, *fbuf, *rbuf, *readstat, *abuf;
865dca9a
KS
47 register struct message *mp;
48 register int c;
49 extern char tempQuit[], tempResid[];
50 struct stat minfo;
2a0f6531 51 char *mbox;
865dca9a 52
3ecebc0f
KS
53 /*
54 * If we are read only, we can't do anything,
55 * so just return quickly.
56 */
3ecebc0f
KS
57 if (readonly)
58 return;
2ee3bce2
EW
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
865dca9a
KS
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.
865dca9a
KS
76 */
77
07b0d286 78 fbuf = Fopen(mailname, "r");
4e161d3b
RC
79 if (fbuf == NULL)
80 goto newmail;
81 flock(fileno(fbuf), LOCK_EX);
865dca9a 82 rbuf = NULL;
4e161d3b 83 if (fstat(fileno(fbuf), &minfo) >= 0 && minfo.st_size > mailsize) {
865dca9a 84 printf("New mail has arrived.\n");
07b0d286 85 rbuf = Fopen(tempResid, "w");
865dca9a
KS
86 if (rbuf == NULL || fbuf == NULL)
87 goto newmail;
88#ifdef APPEND
a0d23834 89 fseek(fbuf, (long)mailsize, 0);
865dca9a 90 while ((c = getc(fbuf)) != EOF)
2ee3bce2 91 (void) putc(c, rbuf);
865dca9a
KS
92#else
93 p = minfo.st_size - mailsize;
94 while (p-- > 0) {
95 c = getc(fbuf);
96 if (c == EOF)
97 goto newmail;
2ee3bce2 98 (void) putc(c, rbuf);
865dca9a
KS
99 }
100#endif
07b0d286
EW
101 Fclose(rbuf);
102 if ((rbuf = Fopen(tempResid, "r")) == NULL)
865dca9a 103 goto newmail;
a7585c01 104 rm(tempResid);
865dca9a 105 }
63e83a9b
KS
106
107 /*
108 * Adjust the message flags in each message.
109 */
110
111 anystat = 0;
252cba79
KS
112 autohold = value("hold") != NOSTR;
113 holdbit = autohold ? MPRESERVE : MBOX;
c2483c81
KS
114 nohold = MBOX|MSAVED|MDELETED|MPRESERVE;
115 if (value("keepsave") != NOSTR)
116 nohold &= ~MSAVED;
865dca9a 117 for (mp = &message[0]; mp < &message[msgCount]; mp++) {
63e83a9b
KS
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++;
865dca9a 124 if ((mp->m_flag & MTOUCH) == 0)
252cba79 125 mp->m_flag |= MPRESERVE;
c2483c81 126 if ((mp->m_flag & nohold) == 0)
252cba79 127 mp->m_flag |= holdbit;
865dca9a
KS
128 }
129 modify = 0;
f0d15113 130 if (Tflag != NOSTR) {
07b0d286 131 if ((readstat = Fopen(Tflag, "w")) == NULL)
f0d15113
KS
132 Tflag = NOSTR;
133 }
865dca9a 134 for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) {
252cba79 135 if (mp->m_flag & MBOX)
865dca9a 136 c++;
252cba79 137 if (mp->m_flag & MPRESERVE)
865dca9a
KS
138 p++;
139 if (mp->m_flag & MODIFY)
140 modify++;
f0d15113 141 if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
4d20fb09
EW
142 char *id;
143
144 if ((id = hfield("article-id", mp)) != NOSTR)
f0d15113
KS
145 fprintf(readstat, "%s\n", id);
146 }
865dca9a 147 }
f0d15113 148 if (Tflag != NOSTR)
07b0d286 149 Fclose(readstat);
63e83a9b 150 if (p == msgCount && !modify && !anystat) {
4d20fb09
EW
151 printf("Held %d message%s in %s\n",
152 p, p == 1 ? "" : "s", mailname);
07b0d286 153 Fclose(fbuf);
865dca9a
KS
154 return;
155 }
156 if (c == 0) {
157 if (p != 0) {
158 writeback(rbuf);
07b0d286 159 Fclose(fbuf);
865dca9a
KS
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
2a0f6531 172 mbox = expand("&");
865dca9a
KS
173 mcount = c;
174 if (value("append") == NOSTR) {
07b0d286 175 if ((obuf = Fopen(tempQuit, "w")) == NULL) {
865dca9a 176 perror(tempQuit);
07b0d286 177 Fclose(fbuf);
865dca9a
KS
178 return;
179 }
07b0d286 180 if ((ibuf = Fopen(tempQuit, "r")) == NULL) {
865dca9a 181 perror(tempQuit);
a7585c01 182 rm(tempQuit);
07b0d286
EW
183 Fclose(obuf);
184 Fclose(fbuf);
865dca9a
KS
185 return;
186 }
a7585c01 187 rm(tempQuit);
07b0d286 188 if ((abuf = Fopen(mbox, "r")) != NULL) {
4e161d3b 189 while ((c = getc(abuf)) != EOF)
2ee3bce2 190 (void) putc(c, obuf);
07b0d286 191 Fclose(abuf);
865dca9a
KS
192 }
193 if (ferror(obuf)) {
194 perror(tempQuit);
07b0d286
EW
195 Fclose(ibuf);
196 Fclose(obuf);
197 Fclose(fbuf);
865dca9a
KS
198 return;
199 }
07b0d286 200 Fclose(obuf);
865dca9a 201 close(creat(mbox, 0600));
07b0d286 202 if ((obuf = Fopen(mbox, "r+")) == NULL) {
865dca9a 203 perror(mbox);
07b0d286
EW
204 Fclose(ibuf);
205 Fclose(fbuf);
865dca9a
KS
206 return;
207 }
208 }
8fd89bb1 209 if (value("append") != NOSTR) {
07b0d286 210 if ((obuf = Fopen(mbox, "a")) == NULL) {
865dca9a 211 perror(mbox);
07b0d286 212 Fclose(fbuf);
865dca9a
KS
213 return;
214 }
8fd89bb1
KM
215 fchmod(fileno(obuf), 0600);
216 }
865dca9a 217 for (mp = &message[0]; mp < &message[msgCount]; mp++)
252cba79 218 if (mp->m_flag & MBOX)
2de8fc95 219 if (send(mp, obuf, saveignore, NOSTR) < 0) {
865dca9a 220 perror(mbox);
07b0d286
EW
221 Fclose(ibuf);
222 Fclose(obuf);
223 Fclose(fbuf);
865dca9a
KS
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) {
2ee3bce2 237 (void) putc(c, obuf);
865dca9a
KS
238 if (ferror(obuf))
239 break;
240 c = getc(ibuf);
241 }
07b0d286 242 Fclose(ibuf);
865dca9a
KS
243 fflush(obuf);
244 }
ed3b895e 245 trunc(obuf);
865dca9a
KS
246 if (ferror(obuf)) {
247 perror(mbox);
07b0d286
EW
248 Fclose(obuf);
249 Fclose(fbuf);
865dca9a
KS
250 return;
251 }
07b0d286 252 Fclose(obuf);
865dca9a
KS
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);
07b0d286 265 Fclose(fbuf);
865dca9a
KS
266 return;
267 }
268
269 /*
270 * Finally, remove his /usr/mail file.
271 * If new mail has arrived, copy it back.
272 */
273
274cream:
275 if (rbuf != NULL) {
07b0d286 276 abuf = Fopen(mailname, "r+");
4e161d3b 277 if (abuf == NULL)
865dca9a
KS
278 goto newmail;
279 while ((c = getc(rbuf)) != EOF)
2ee3bce2 280 (void) putc(c, abuf);
07b0d286 281 Fclose(rbuf);
4e161d3b 282 trunc(abuf);
07b0d286 283 Fclose(abuf);
865dca9a 284 alter(mailname);
07b0d286 285 Fclose(fbuf);
865dca9a
KS
286 return;
287 }
288 demail();
07b0d286 289 Fclose(fbuf);
865dca9a
KS
290 return;
291
292newmail:
293 printf("Thou hast new mail.\n");
cb674576 294 if (fbuf != NULL)
07b0d286 295 Fclose(fbuf);
865dca9a
KS
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 */
a0d23834 304int
865dca9a
KS
305writeback(res)
306 register FILE *res;
307{
308 register struct message *mp;
309 register int p, c;
310 FILE *obuf;
311
312 p = 0;
07b0d286 313 if ((obuf = Fopen(mailname, "r+")) == NULL) {
865dca9a
KS
314 perror(mailname);
315 return(-1);
316 }
317#ifndef APPEND
318 if (res != NULL)
319 while ((c = getc(res)) != EOF)
2ee3bce2 320 (void) putc(c, obuf);
865dca9a
KS
321#endif
322 for (mp = &message[0]; mp < &message[msgCount]; mp++)
323 if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) {
324 p++;
2de8fc95 325 if (send(mp, obuf, (struct ignoretab *)0, NOSTR) < 0) {
865dca9a 326 perror(mailname);
07b0d286 327 Fclose(obuf);
865dca9a
KS
328 return(-1);
329 }
330 }
331#ifdef APPEND
332 if (res != NULL)
333 while ((c = getc(res)) != EOF)
2ee3bce2 334 (void) putc(c, obuf);
865dca9a
KS
335#endif
336 fflush(obuf);
ed3b895e 337 trunc(obuf);
865dca9a
KS
338 if (ferror(obuf)) {
339 perror(mailname);
07b0d286 340 Fclose(obuf);
865dca9a
KS
341 return(-1);
342 }
343 if (res != NULL)
07b0d286
EW
344 Fclose(res);
345 Fclose(obuf);
865dca9a
KS
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}
2ee3bce2
EW
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 */
a0d23834 358void
2ee3bce2
EW
359edstop()
360{
f629a181 361 extern char *tmpdir;
2ee3bce2
EW
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) {
07b0d286 373 if ((readstat = Fopen(Tflag, "w")) == NULL)
2ee3bce2
EW
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)
07b0d286 391 Fclose(readstat);
2ee3bce2
EW
392 if (!gotcha || Tflag != NOSTR)
393 goto done;
394 ibuf = NULL;
395 if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) {
f629a181 396 strcpy(tempname, tmpdir);
cc28d847 397 strcat(tempname, "mboxXXXXXX");
2ee3bce2 398 mktemp(tempname);
07b0d286 399 if ((obuf = Fopen(tempname, "w")) == NULL) {
2ee3bce2
EW
400 perror(tempname);
401 relsesigs();
402 reset(0);
403 }
07b0d286 404 if ((ibuf = Fopen(mailname, "r")) == NULL) {
2ee3bce2 405 perror(mailname);
07b0d286 406 Fclose(obuf);
a7585c01 407 rm(tempname);
2ee3bce2
EW
408 relsesigs();
409 reset(0);
410 }
a0d23834 411 fseek(ibuf, (long)mailsize, 0);
2ee3bce2
EW
412 while ((c = getc(ibuf)) != EOF)
413 (void) putc(c, obuf);
07b0d286
EW
414 Fclose(ibuf);
415 Fclose(obuf);
416 if ((ibuf = Fopen(tempname, "r")) == NULL) {
2ee3bce2 417 perror(tempname);
a7585c01 418 rm(tempname);
2ee3bce2
EW
419 relsesigs();
420 reset(0);
421 }
a7585c01 422 rm(tempname);
2ee3bce2
EW
423 }
424 printf("\"%s\" ", mailname);
425 fflush(stdout);
07b0d286 426 if ((obuf = Fopen(mailname, "r+")) == NULL) {
2ee3bce2
EW
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);
07b0d286 447 Fclose(ibuf);
2ee3bce2
EW
448 }
449 fflush(obuf);
450 if (ferror(obuf)) {
451 perror(mailname);
452 relsesigs();
453 reset(0);
454 }
07b0d286 455 Fclose(obuf);
2ee3bce2 456 if (gotcha) {
a7585c01 457 rm(mailname);
2ee3bce2
EW
458 printf("removed\n");
459 } else
460 printf("complete\n");
461 fflush(stdout);
462
463done:
464 relsesigs();
465}