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