2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
7 * Copyright (c) 1980, 1993
8 * The Regents of the University of California. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 static char sccsid
[] = "@(#)quit.c 2.30 (gritter) 11/11/08";
55 * Rcv -- receive mail rationally.
57 * Termination processing.
60 static int writeback(FILE *res
, FILE *obuf
);
61 static void edstop(void);
71 * If we are sourcing, then return 1 so execute() can handle it.
72 * Otherwise, return -1 to abort command loop.
80 * Preserve all the appropriate messages back in the system
81 * mailbox, and print a nice message indicated how many were
82 * saved. On any error, just return -1. Else return 0.
83 * Incorporate the any new mail that we found.
86 writeback(FILE *res
, FILE *obuf
)
92 fseek(obuf
, 0L, SEEK_SET
);
95 while ((c
= getc(res
)) != EOF
)
98 for (mp
= &message
[0]; mp
< &message
[msgCount
]; mp
++)
99 if ((mp
->m_flag
&MPRESERVE
)||(mp
->m_flag
&MTOUCH
)==0) {
101 if (send(mp
, obuf
, NULL
, NULL
, SEND_MBOX
, NULL
) < 0) {
103 fseek(obuf
, 0L, SEEK_SET
);
109 while ((c
= getc(res
)) != EOF
)
116 fseek(obuf
, 0L, SEEK_SET
);
121 fseek(obuf
, 0L, SEEK_SET
);
124 printf(catgets(catd
, CATSET
, 155,
125 "Held 1 message in %s\n"), mailname
);
127 printf(catgets(catd
, CATSET
, 156,
128 "Held %d messages in %s\n"), p
, mailname
);
133 * Save all of the undetermined messages at the top of "mbox"
134 * Save all untouched messages back in the system mailbox.
135 * Remove the system mailbox, if none saved there.
140 int p
, modify
, anystat
;
141 FILE *fbuf
, *rbuf
, *readstat
= NULL
, *abuf
;
148 * If we are read only, we can't do anything,
149 * so just return quickly. IMAP can set some
150 * flags (e.g. "\\Seen") so imap_quit must be
153 if (mb
.mb_perm
== 0 && mb
.mb_type
!= MB_IMAP
)
155 switch (mb
.mb_type
) {
172 * If editing (not reading system mail box), then do the work
181 * See if there any messages to save in mbox. If no, we
182 * can save copying mbox to /tmp and back.
184 * Check also to see if any files need to be preserved.
185 * Delete all untouched messages to keep them out of mbox.
186 * If all the messages are to be preserved, just exit with
190 fbuf
= Zopen(mailname
, "r+", &mb
.mb_compressed
);
196 if (fcntl_lock(fileno(fbuf
), F_WRLCK
) == -1) {
198 perror(catgets(catd
, CATSET
, 157, "Unable to lock mailbox"));
202 if (dot_lock(mailname
, fileno(fbuf
), 1, stdout
, ".") == -1)
205 if (fstat(fileno(fbuf
), &minfo
) >= 0 && minfo
.st_size
> mailsize
) {
206 printf(catgets(catd
, CATSET
, 158, "New mail has arrived.\n"));
207 rbuf
= Ftemp(&tempResid
, "Rq", "w", 0600, 1);
208 if (rbuf
== NULL
|| fbuf
== NULL
)
211 fseek(fbuf
, (long)mailsize
, SEEK_SET
);
212 while ((c
= getc(fbuf
)) != EOF
)
215 p
= minfo
.st_size
- mailsize
;
224 if ((rbuf
= Fopen(tempResid
, "r")) == NULL
)
230 anystat
= holdbits();
233 if ((readstat
= Zopen(Tflag
, "w", NULL
)) == NULL
)
236 for (c
= 0, p
= 0, mp
= &message
[0]; mp
< &message
[msgCount
]; mp
++) {
237 if (mp
->m_flag
& MBOX
)
239 if (mp
->m_flag
& MPRESERVE
)
241 if (mp
->m_flag
& MODIFY
)
243 if (readstat
!= NULL
&& (mp
->m_flag
& (MREAD
|MDELETED
)) != 0) {
246 if ((id
= hfield("message-id", mp
)) != NULL
||
247 (id
= hfield("article-id", mp
)) != NULL
)
248 fprintf(readstat
, "%s\n", id
);
251 if (readstat
!= NULL
)
253 if (p
== msgCount
&& !modify
&& !anystat
) {
255 printf(catgets(catd
, CATSET
, 155,
256 "Held 1 message in %s\n"), mailname
);
258 printf(catgets(catd
, CATSET
, 156,
259 "Held %d messages in %s\n"), p
, mailname
);
261 dot_unlock(mailname
);
266 writeback(rbuf
, fbuf
);
268 dot_unlock(mailname
);
274 if (makembox() == STOP
) {
276 dot_unlock(mailname
);
280 * Now we are ready to copy back preserved files to
281 * the system mailbox, if any were requested.
285 writeback(rbuf
, fbuf
);
287 dot_unlock(mailname
);
292 * Finally, remove his /usr/mail file.
293 * If new mail has arrived, copy it back.
299 fseek(abuf
, 0L, SEEK_SET
);
300 while ((c
= getc(rbuf
)) != EOF
)
306 dot_unlock(mailname
);
311 dot_unlock(mailname
);
315 printf(catgets(catd
, CATSET
, 166, "Thou hast new mail.\n"));
318 dot_unlock(mailname
);
323 * Adjust the message flags in each message.
329 int anystat
, autohold
, holdbit
, nohold
;
332 autohold
= value("hold") != NULL
;
333 holdbit
= autohold
? MPRESERVE
: MBOX
;
334 nohold
= MBOX
|MSAVED
|MDELETED
|MPRESERVE
;
335 if (value("keepsave") != NULL
)
337 for (mp
= &message
[0]; mp
< &message
[msgCount
]; mp
++) {
338 if (mp
->m_flag
& MNEW
) {
340 mp
->m_flag
|= MSTATUS
;
342 if (mp
->m_flag
& (MSTATUS
|MFLAG
|MUNFLAG
|MANSWER
|MUNANSWER
|
345 if ((mp
->m_flag
& MTOUCH
) == 0)
346 mp
->m_flag
|= MPRESERVE
;
347 if ((mp
->m_flag
& nohold
) == 0)
348 mp
->m_flag
|= holdbit
;
354 * Create another temporary file and copy user's mbox file
355 * darin. If there is no mbox, copy nothing.
356 * If he has specified "append" don't copy his mailbox,
357 * just copy saveable entries at the end.
364 char *mbox
, *tempQuit
;
366 FILE *ibuf
= NULL
, *obuf
, *abuf
;
371 if (value("append") == NULL
) {
372 if ((obuf
= Ftemp(&tempQuit
, "Rm", "w", 0600, 1)) == NULL
) {
373 perror(catgets(catd
, CATSET
, 162,
374 "temporary mail quit file"));
377 if ((ibuf
= Fopen(tempQuit
, "r")) == NULL
) {
386 if ((abuf
= Zopen(mbox
, "r", NULL
)) != NULL
) {
387 while ((c
= getc(abuf
)) != EOF
)
392 perror(catgets(catd
, CATSET
, 163,
393 "temporary mail quit file"));
399 close(creat(mbox
, 0600));
400 if ((obuf
= Zopen(mbox
, "r+", NULL
)) == NULL
) {
407 if ((obuf
= Zopen(mbox
, "a", NULL
)) == NULL
) {
411 fchmod(fileno(obuf
), 0600);
413 prot
= which_protocol(mbox
);
414 for (mp
= &message
[0]; mp
< &message
[msgCount
]; mp
++)
415 if (mp
->m_flag
& MBOX
) {
417 if (prot
== PROTO_IMAP
&&
418 saveignore
[0].i_count
== 0 &&
419 saveignore
[1].i_count
== 0 &&
420 imap_thisaccount(mbox
)) {
421 if (imap_copy(mp
, mp
-message
+1, mbox
) == STOP
)
423 } else if (send(mp
, obuf
, saveignore
,
424 NULL
, SEND_MBOX
, NULL
) < 0) {
431 mp
->m_flag
|= MBOXED
;
435 * Copy the user's old mbox contents back
436 * to the end of the stuff we just saved.
437 * If we are appending, this is unnecessary.
440 if (value("append") == NULL
) {
458 if (Fclose(obuf
) != 0) {
459 if (prot
!= PROTO_IMAP
)
464 printf(catgets(catd
, CATSET
, 164, "Saved 1 message in mbox\n"));
466 printf(catgets(catd
, CATSET
, 165,
467 "Saved %d messages in mbox\n"), mcount
);
472 * Terminate an editing session by attempting to write out the user's
473 * file from the temporary. Save any new stuff appended to the file.
480 FILE *obuf
, *ibuf
= NULL
, *readstat
= NULL
;
487 if ((readstat
= Zopen(Tflag
, "w", NULL
)) == NULL
)
490 for (mp
= &message
[0], gotcha
= 0; mp
< &message
[msgCount
]; mp
++) {
491 if (mp
->m_flag
& MNEW
) {
493 mp
->m_flag
|= MSTATUS
;
495 if (mp
->m_flag
& (MODIFY
|MDELETED
|MSTATUS
|MFLAG
|MUNFLAG
|
496 MANSWER
|MUNANSWER
|MDRAFT
|MUNDRAFT
))
498 if (readstat
!= NULL
&& (mp
->m_flag
& (MREAD
|MDELETED
)) != 0) {
501 if ((id
= hfield("message-id", mp
)) != NULL
||
502 (id
= hfield("article-id", mp
)) != NULL
)
503 fprintf(readstat
, "%s\n", id
);
506 if (readstat
!= NULL
)
508 if (!gotcha
|| Tflag
!= NULL
)
511 if (stat(mailname
, &statb
) >= 0 && statb
.st_size
> mailsize
) {
514 if ((obuf
= Ftemp(&tempname
, "mbox.", "w", 0600, 1)) == NULL
) {
515 perror(catgets(catd
, CATSET
, 167, "tmpfile"));
519 if ((ibuf
= Zopen(mailname
, "r", &mb
.mb_compressed
)) == NULL
) {
527 fseek(ibuf
, (long)mailsize
, SEEK_SET
);
528 while ((c
= getc(ibuf
)) != EOF
)
532 if ((ibuf
= Fopen(tempname
, "r")) == NULL
) {
542 printf(catgets(catd
, CATSET
, 168, "\"%s\" "), mailname
);
544 if ((obuf
= Zopen(mailname
, "r+", &mb
.mb_compressed
)) == NULL
) {
551 for (mp
= &message
[0]; mp
< &message
[msgCount
]; mp
++) {
552 if ((mp
->m_flag
& MDELETED
) != 0)
555 if (send(mp
, obuf
, NULL
, NULL
, SEND_MBOX
, NULL
) < 0) {
561 gotcha
= (c
== 0 && ibuf
== NULL
);
563 while ((c
= getc(ibuf
)) != EOF
)
574 if (gotcha
&& value("emptybox") == NULL
) {
576 printf(value("bsdcompat") || value("bsdmsgs") ?
577 catgets(catd
, CATSET
, 169, "removed\n") :
578 catgets(catd
, CATSET
, 211, "removed.\n"));
580 printf(value("bsdcompat") || value("bsdmsgs") ?
581 catgets(catd
, CATSET
, 170, "complete\n") :
582 catgets(catd
, CATSET
, 212, "updated.\n"));
591 QUITFLAG_KEEPSAVE
= 002,
592 QUITFLAG_APPEND
= 004,
593 QUITFLAG_EMPTYBOX
= 010
596 static const struct quitnames
{
600 { QUITFLAG_HOLD
, "hold" },
601 { QUITFLAG_KEEPSAVE
, "keepsave" },
602 { QUITFLAG_APPEND
, "append" },
603 { QUITFLAG_EMPTYBOX
, "emptybox" },
610 enum quitflags qf
= 0;
613 for (i
= 0; quitnames
[i
].name
; i
++)
614 if (value(quitnames
[i
].name
))
615 qf
|= quitnames
[i
].flag
;
620 restorequitflags(int qf
)
624 for (i
= 0; quitnames
[i
].name
; i
++)
625 if (qf
& quitnames
[i
].flag
) {
626 if (value(quitnames
[i
].name
) == NULL
)
627 assign(quitnames
[i
].name
, "");
628 } else if (value(quitnames
[i
].name
))
629 unset_internal(quitnames
[i
].name
);