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