386BSD 0.1 development
[unix-history] / usr / src / usr.bin / mail / quit.c
CommitLineData
4f4122db
WJ
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * 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
35static char sccsid[] = "@(#)quit.c 5.16 (Berkeley) 2/9/91";
36#endif /* not lint */
37
38#include "rcv.h"
39#include <sys/stat.h>
40#include <sys/file.h>
41
42/*
43 * Rcv -- receive mail rationally.
44 *
45 * Termination processing.
46 */
47
48/*
49 * The "quit" command.
50 */
51quitcmd()
52{
53 /*
54 * If we are sourcing, then return 1 so execute() can handle it.
55 * Otherwise, return -1 to abort command loop.
56 */
57 if (sourcing)
58 return 1;
59 return -1;
60}
61
62/*
63 * Save all of the undetermined messages at the top of "mbox"
64 * Save all untouched messages back in the system mailbox.
65 * Remove the system mailbox, if none saved there.
66 */
67
68quit()
69{
70 int mcount, p, modify, autohold, anystat, holdbit, nohold;
71 FILE *ibuf, *obuf, *fbuf, *rbuf, *readstat, *abuf;
72 register struct message *mp;
73 register int c;
74 extern char tempQuit[], tempResid[];
75 struct stat minfo;
76 char *mbox;
77
78 /*
79 * If we are read only, we can't do anything,
80 * so just return quickly.
81 */
82 if (readonly)
83 return;
84 /*
85 * If editing (not reading system mail box), then do the work
86 * in edstop()
87 */
88 if (edit) {
89 edstop();
90 return;
91 }
92
93 /*
94 * See if there any messages to save in mbox. If no, we
95 * can save copying mbox to /tmp and back.
96 *
97 * Check also to see if any files need to be preserved.
98 * Delete all untouched messages to keep them out of mbox.
99 * If all the messages are to be preserved, just exit with
100 * a message.
101 */
102
103 fbuf = Fopen(mailname, "r");
104 if (fbuf == NULL)
105 goto newmail;
106 flock(fileno(fbuf), LOCK_EX);
107 rbuf = NULL;
108 if (fstat(fileno(fbuf), &minfo) >= 0 && minfo.st_size > mailsize) {
109 printf("New mail has arrived.\n");
110 rbuf = Fopen(tempResid, "w");
111 if (rbuf == NULL || fbuf == NULL)
112 goto newmail;
113#ifdef APPEND
114 fseek(fbuf, mailsize, 0);
115 while ((c = getc(fbuf)) != EOF)
116 (void) putc(c, rbuf);
117#else
118 p = minfo.st_size - mailsize;
119 while (p-- > 0) {
120 c = getc(fbuf);
121 if (c == EOF)
122 goto newmail;
123 (void) putc(c, rbuf);
124 }
125#endif
126 Fclose(rbuf);
127 if ((rbuf = Fopen(tempResid, "r")) == NULL)
128 goto newmail;
129 rm(tempResid);
130 }
131
132 /*
133 * Adjust the message flags in each message.
134 */
135
136 anystat = 0;
137 autohold = value("hold") != NOSTR;
138 holdbit = autohold ? MPRESERVE : MBOX;
139 nohold = MBOX|MSAVED|MDELETED|MPRESERVE;
140 if (value("keepsave") != NOSTR)
141 nohold &= ~MSAVED;
142 for (mp = &message[0]; mp < &message[msgCount]; mp++) {
143 if (mp->m_flag & MNEW) {
144 mp->m_flag &= ~MNEW;
145 mp->m_flag |= MSTATUS;
146 }
147 if (mp->m_flag & MSTATUS)
148 anystat++;
149 if ((mp->m_flag & MTOUCH) == 0)
150 mp->m_flag |= MPRESERVE;
151 if ((mp->m_flag & nohold) == 0)
152 mp->m_flag |= holdbit;
153 }
154 modify = 0;
155 if (Tflag != NOSTR) {
156 if ((readstat = Fopen(Tflag, "w")) == NULL)
157 Tflag = NOSTR;
158 }
159 for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) {
160 if (mp->m_flag & MBOX)
161 c++;
162 if (mp->m_flag & MPRESERVE)
163 p++;
164 if (mp->m_flag & MODIFY)
165 modify++;
166 if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
167 char *id;
168
169 if ((id = hfield("article-id", mp)) != NOSTR)
170 fprintf(readstat, "%s\n", id);
171 }
172 }
173 if (Tflag != NOSTR)
174 Fclose(readstat);
175 if (p == msgCount && !modify && !anystat) {
176 printf("Held %d message%s in %s\n",
177 p, p == 1 ? "" : "s", mailname);
178 Fclose(fbuf);
179 return;
180 }
181 if (c == 0) {
182 if (p != 0) {
183 writeback(rbuf);
184 Fclose(fbuf);
185 return;
186 }
187 goto cream;
188 }
189
190 /*
191 * Create another temporary file and copy user's mbox file
192 * darin. If there is no mbox, copy nothing.
193 * If he has specified "append" don't copy his mailbox,
194 * just copy saveable entries at the end.
195 */
196
197 mbox = expand("&");
198 mcount = c;
199 if (value("append") == NOSTR) {
200 if ((obuf = Fopen(tempQuit, "w")) == NULL) {
201 perror(tempQuit);
202 Fclose(fbuf);
203 return;
204 }
205 if ((ibuf = Fopen(tempQuit, "r")) == NULL) {
206 perror(tempQuit);
207 rm(tempQuit);
208 Fclose(obuf);
209 Fclose(fbuf);
210 return;
211 }
212 rm(tempQuit);
213 if ((abuf = Fopen(mbox, "r")) != NULL) {
214 while ((c = getc(abuf)) != EOF)
215 (void) putc(c, obuf);
216 Fclose(abuf);
217 }
218 if (ferror(obuf)) {
219 perror(tempQuit);
220 Fclose(ibuf);
221 Fclose(obuf);
222 Fclose(fbuf);
223 return;
224 }
225 Fclose(obuf);
226 close(creat(mbox, 0600));
227 if ((obuf = Fopen(mbox, "r+")) == NULL) {
228 perror(mbox);
229 Fclose(ibuf);
230 Fclose(fbuf);
231 return;
232 }
233 }
234 if (value("append") != NOSTR) {
235 if ((obuf = Fopen(mbox, "a")) == NULL) {
236 perror(mbox);
237 Fclose(fbuf);
238 return;
239 }
240 fchmod(fileno(obuf), 0600);
241 }
242 for (mp = &message[0]; mp < &message[msgCount]; mp++)
243 if (mp->m_flag & MBOX)
244 if (send(mp, obuf, saveignore, NOSTR) < 0) {
245 perror(mbox);
246 Fclose(ibuf);
247 Fclose(obuf);
248 Fclose(fbuf);
249 return;
250 }
251
252 /*
253 * Copy the user's old mbox contents back
254 * to the end of the stuff we just saved.
255 * If we are appending, this is unnecessary.
256 */
257
258 if (value("append") == NOSTR) {
259 rewind(ibuf);
260 c = getc(ibuf);
261 while (c != EOF) {
262 (void) putc(c, obuf);
263 if (ferror(obuf))
264 break;
265 c = getc(ibuf);
266 }
267 Fclose(ibuf);
268 fflush(obuf);
269 }
270 trunc(obuf);
271 if (ferror(obuf)) {
272 perror(mbox);
273 Fclose(obuf);
274 Fclose(fbuf);
275 return;
276 }
277 Fclose(obuf);
278 if (mcount == 1)
279 printf("Saved 1 message in mbox\n");
280 else
281 printf("Saved %d messages in mbox\n", mcount);
282
283 /*
284 * Now we are ready to copy back preserved files to
285 * the system mailbox, if any were requested.
286 */
287
288 if (p != 0) {
289 writeback(rbuf);
290 Fclose(fbuf);
291 return;
292 }
293
294 /*
295 * Finally, remove his /usr/mail file.
296 * If new mail has arrived, copy it back.
297 */
298
299cream:
300 if (rbuf != NULL) {
301 abuf = Fopen(mailname, "r+");
302 if (abuf == NULL)
303 goto newmail;
304 while ((c = getc(rbuf)) != EOF)
305 (void) putc(c, abuf);
306 Fclose(rbuf);
307 trunc(abuf);
308 Fclose(abuf);
309 alter(mailname);
310 Fclose(fbuf);
311 return;
312 }
313 demail();
314 Fclose(fbuf);
315 return;
316
317newmail:
318 printf("Thou hast new mail.\n");
319 if (fbuf != NULL)
320 Fclose(fbuf);
321}
322
323/*
324 * Preserve all the appropriate messages back in the system
325 * mailbox, and print a nice message indicated how many were
326 * saved. On any error, just return -1. Else return 0.
327 * Incorporate the any new mail that we found.
328 */
329writeback(res)
330 register FILE *res;
331{
332 register struct message *mp;
333 register int p, c;
334 FILE *obuf;
335
336 p = 0;
337 if ((obuf = Fopen(mailname, "r+")) == NULL) {
338 perror(mailname);
339 return(-1);
340 }
341#ifndef APPEND
342 if (res != NULL)
343 while ((c = getc(res)) != EOF)
344 (void) putc(c, obuf);
345#endif
346 for (mp = &message[0]; mp < &message[msgCount]; mp++)
347 if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) {
348 p++;
349 if (send(mp, obuf, (struct ignoretab *)0, NOSTR) < 0) {
350 perror(mailname);
351 Fclose(obuf);
352 return(-1);
353 }
354 }
355#ifdef APPEND
356 if (res != NULL)
357 while ((c = getc(res)) != EOF)
358 (void) putc(c, obuf);
359#endif
360 fflush(obuf);
361 trunc(obuf);
362 if (ferror(obuf)) {
363 perror(mailname);
364 Fclose(obuf);
365 return(-1);
366 }
367 if (res != NULL)
368 Fclose(res);
369 Fclose(obuf);
370 alter(mailname);
371 if (p == 1)
372 printf("Held 1 message in %s\n", mailname);
373 else
374 printf("Held %d messages in %s\n", p, mailname);
375 return(0);
376}
377
378/*
379 * Terminate an editing session by attempting to write out the user's
380 * file from the temporary. Save any new stuff appended to the file.
381 */
382edstop()
383{
384 register int gotcha, c;
385 register struct message *mp;
386 FILE *obuf, *ibuf, *readstat;
387 struct stat statb;
388 char tempname[30];
389 char *mktemp();
390
391 if (readonly)
392 return;
393 holdsigs();
394 if (Tflag != NOSTR) {
395 if ((readstat = Fopen(Tflag, "w")) == NULL)
396 Tflag = NOSTR;
397 }
398 for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) {
399 if (mp->m_flag & MNEW) {
400 mp->m_flag &= ~MNEW;
401 mp->m_flag |= MSTATUS;
402 }
403 if (mp->m_flag & (MODIFY|MDELETED|MSTATUS))
404 gotcha++;
405 if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
406 char *id;
407
408 if ((id = hfield("article-id", mp)) != NOSTR)
409 fprintf(readstat, "%s\n", id);
410 }
411 }
412 if (Tflag != NOSTR)
413 Fclose(readstat);
414 if (!gotcha || Tflag != NOSTR)
415 goto done;
416 ibuf = NULL;
417 if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) {
418 strcpy(tempname, _PATH_TMP);
419 strcat(tempname, "mboxXXXXXX");
420 mktemp(tempname);
421 if ((obuf = Fopen(tempname, "w")) == NULL) {
422 perror(tempname);
423 relsesigs();
424 reset(0);
425 }
426 if ((ibuf = Fopen(mailname, "r")) == NULL) {
427 perror(mailname);
428 Fclose(obuf);
429 rm(tempname);
430 relsesigs();
431 reset(0);
432 }
433 fseek(ibuf, mailsize, 0);
434 while ((c = getc(ibuf)) != EOF)
435 (void) putc(c, obuf);
436 Fclose(ibuf);
437 Fclose(obuf);
438 if ((ibuf = Fopen(tempname, "r")) == NULL) {
439 perror(tempname);
440 rm(tempname);
441 relsesigs();
442 reset(0);
443 }
444 rm(tempname);
445 }
446 printf("\"%s\" ", mailname);
447 fflush(stdout);
448 if ((obuf = Fopen(mailname, "r+")) == NULL) {
449 perror(mailname);
450 relsesigs();
451 reset(0);
452 }
453 trunc(obuf);
454 c = 0;
455 for (mp = &message[0]; mp < &message[msgCount]; mp++) {
456 if ((mp->m_flag & MDELETED) != 0)
457 continue;
458 c++;
459 if (send(mp, obuf, (struct ignoretab *) NULL, NOSTR) < 0) {
460 perror(mailname);
461 relsesigs();
462 reset(0);
463 }
464 }
465 gotcha = (c == 0 && ibuf == NULL);
466 if (ibuf != NULL) {
467 while ((c = getc(ibuf)) != EOF)
468 (void) putc(c, obuf);
469 Fclose(ibuf);
470 }
471 fflush(obuf);
472 if (ferror(obuf)) {
473 perror(mailname);
474 relsesigs();
475 reset(0);
476 }
477 Fclose(obuf);
478 if (gotcha) {
479 rm(mailname);
480 printf("removed\n");
481 } else
482 printf("complete\n");
483 fflush(stdout);
484
485done:
486 relsesigs();
487}