1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Termination processing.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2014 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
8 * Copyright (c) 1980, 1993
9 * The Regents of the University of California. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 #ifndef HAVE_AMALGAMATION
49 QUITFLAG_KEEPSAVE
= 002,
50 QUITFLAG_APPEND
= 004,
51 QUITFLAG_EMPTYBOX
= 010
59 static struct quitnames
const _quitnames
[] = {
60 {QUITFLAG_HOLD
, ok_b_hold
},
61 {QUITFLAG_KEEPSAVE
, ok_b_keepsave
},
62 {QUITFLAG_APPEND
, ok_b_append
},
63 {QUITFLAG_EMPTYBOX
, ok_b_emptybox
}
66 static char _mboxname
[PATH_MAX
]; /* Name of mbox */
68 /* Touch the indicated file */
69 static void _alter(char const *name
);
71 /* Preserve all the appropriate messages back in the system mailbox, and print
72 * a nice message indicated how many were saved. On any error, just return -1.
73 * Else return 0. Incorporate the any new mail that we found */
74 static int writeback(FILE *res
, FILE *obuf
);
76 /* Terminate an editing session by attempting to write out the user's file from
77 * the temporary. Save any new stuff appended to the file */
78 static void edstop(void);
81 _alter(char const *name
)
87 if (!stat(name
, &sb
)) {
88 utb
.actime
= time(NULL
) + 1;
89 utb
.modtime
= sb
.st_mtime
;
96 writeback(FILE *res
, FILE *obuf
)
102 if (fseek(obuf
, 0L, SEEK_SET
) == -1)
107 while ((c
= getc(res
)) != EOF
)
111 for (p
= 0, mp
= message
; PTRCMP(mp
, <, message
+ msgCount
); ++mp
)
112 if ((mp
->m_flag
& MPRESERVE
) || !(mp
->m_flag
& MTOUCH
)) {
114 if (sendmp(mp
, obuf
, NULL
, NULL
, SEND_MBOX
, NULL
) < 0) {
123 while ((c
= getc(res
)) != EOF
)
132 fseek(obuf
, 0L, SEEK_SET
);
135 if (fseek(obuf
, 0L, SEEK_SET
) == -1)
140 printf(tr(155, "Held 1 message in %s\n"), displayname
);
142 printf(tr(156, "Held %d messages in %s\n"), p
, displayname
);
152 edstop(void) /* TODO oh my god - and REMOVE that CRAPPY reset(0) jump!! */
156 FILE *obuf
= NULL
, *ibuf
= NULL
;
167 for (mp
= message
, gotcha
= 0; PTRCMP(mp
, <, message
+ msgCount
); ++mp
) {
168 if (mp
->m_flag
& MNEW
) {
170 mp
->m_flag
|= MSTATUS
;
172 if (mp
->m_flag
& (MODIFY
| MDELETED
| MSTATUS
| MFLAG
| MUNFLAG
|
173 MANSWER
| MUNANSWER
| MDRAFT
| MUNDRAFT
))
181 if (stat(mailname
, &statb
) >= 0 && statb
.st_size
> mailsize
) {
182 if ((obuf
= Ftmp(NULL
, "edstop", OF_RDWR
| OF_UNLINK
| OF_REGISTER
,
184 perror(tr(167, "tmpfile"));
187 if ((ibuf
= Zopen(mailname
, "r", &mb
.mb_compressed
)) == NULL
) {
192 fseek(ibuf
, (long)mailsize
, SEEK_SET
);
193 while ((c
= getc(ibuf
)) != EOF
)
200 printf(tr(168, "\"%s\" "), displayname
);
202 if ((obuf
= Zopen(mailname
, "r+", &mb
.mb_compressed
)) == NULL
) {
210 for (mp
= message
; PTRCMP(mp
, <, message
+ msgCount
); ++mp
) {
211 if ((mp
->m_flag
& MDELETED
) != 0)
214 if (sendmp(mp
, obuf
, NULL
, NULL
, SEND_MBOX
, NULL
) < 0) {
223 gotcha
= (c
== 0 && ibuf
== NULL
);
225 while ((c
= getc(ibuf
)) != EOF
)
238 if (gotcha
&& !ok_blook(emptybox
)) {
240 printf((ok_blook(bsdcompat
) || ok_blook(bsdmsgs
))
241 ? tr(169, "removed\n") : tr(211, "removed.\n"));
243 printf((ok_blook(bsdcompat
) || ok_blook(bsdmsgs
))
244 ? tr(170, "complete\n") : tr(212, "updated.\n"));
262 /* If we are sourcing, then return 1 so evaluate() can handle it.
263 * Otherwise return -1 to abort command loop */
264 rv
= sourcing
? 1 : -1;
272 int p
, modify
, anystat
, c
;
273 FILE *fbuf
= NULL
, *rbuf
, *abuf
;
279 /* If we are read only, we can't do anything, so just return quickly. IMAP
280 * can set some flags (e.g. "\\Seen") so imap_quit must be called anyway */
281 if (mb
.mb_perm
== 0 && mb
.mb_type
!= MB_IMAP
)
284 /* TODO lex.c:setfile() has just called hold_sigs(); before it called
285 * TODO us, but this causes uninterruptible hangs due to blocked sigs
286 * TODO anywhere except for MB_FILE (all others install their own
287 * TODO handlers, as it seems, properly); marked YYY */
288 switch (mb
.mb_type
) {
292 rele_sigs(); /* YYY */
294 hold_sigs(); /* YYY */
298 rele_sigs(); /* YYY */
300 hold_sigs(); /* YYY */
306 rele_sigs(); /* YYY */
308 hold_sigs(); /* YYY */
316 /* If editing (not reading system mail box), then do the work in edstop() */
322 /* See if there any messages to save in mbox. If no, we
323 * can save copying mbox to /tmp and back.
325 * Check also to see if any files need to be preserved.
326 * Delete all untouched messages to keep them out of mbox.
327 * If all the messages are to be preserved, just exit with
329 fbuf
= Zopen(mailname
, "r+", &mb
.mb_compressed
);
334 printf(tr(166, "Thou hast new mail.\n"));
338 if (fcntl_lock(fileno(fbuf
), FLOCK_WRITE
) == -1 ||
339 dot_lock(mailname
, fileno(fbuf
), 1, stdout
, ".") == -1) {
340 perror(tr(157, "Unable to lock mailbox"));
347 if (fstat(fileno(fbuf
), &minfo
) >= 0 && minfo
.st_size
> mailsize
) {
348 printf(tr(158, "New mail has arrived.\n"));
349 rbuf
= Ftmp(&tempResid
, "quit", OF_RDWR
| OF_UNLINK
| OF_REGISTER
, 0600);
350 if (rbuf
== NULL
|| fbuf
== NULL
)
353 fseek(fbuf
, (long)mailsize
, SEEK_SET
);
354 while ((c
= getc(fbuf
)) != EOF
)
357 p
= minfo
.st_size
- mailsize
;
368 anystat
= holdbits();
370 for (c
= 0, p
= 0, mp
= message
; PTRCMP(mp
, <, message
+ msgCount
); ++mp
) {
371 if (mp
->m_flag
& MBOX
)
373 if (mp
->m_flag
& MPRESERVE
)
375 if (mp
->m_flag
& MODIFY
)
378 if (p
== msgCount
&& !modify
&& !anystat
) {
380 printf(tr(155, "Held 1 message in %s\n"), displayname
);
382 printf(tr(156, "Held %d messages in %s\n"), p
, displayname
);
387 writeback(rbuf
, fbuf
);
393 if (makembox() == STOP
)
396 /* Now we are ready to copy back preserved files to the system mailbox, if
397 * any were requested */
399 writeback(rbuf
, fbuf
);
403 /* Finally, remove his file. If new mail has arrived, copy it back */
407 fseek(abuf
, 0L, SEEK_SET
);
408 while ((c
= getc(rbuf
)) != EOF
)
419 dot_unlock(mailname
);
428 int anystat
, autohold
, holdbit
, nohold
;
432 autohold
= ok_blook(hold
);
433 holdbit
= autohold
? MPRESERVE
: MBOX
;
434 nohold
= MBOX
| MSAVED
| MDELETED
| MPRESERVE
;
435 if (ok_blook(keepsave
))
437 for (mp
= message
; PTRCMP(mp
, <, message
+ msgCount
); ++mp
) {
438 if (mp
->m_flag
& MNEW
) {
440 mp
->m_flag
|= MSTATUS
;
442 if (mp
->m_flag
& (MSTATUS
| MFLAG
| MUNFLAG
| MANSWER
| MUNANSWER
|
445 if (!(mp
->m_flag
& MTOUCH
))
446 mp
->m_flag
|= MPRESERVE
;
447 if (!(mp
->m_flag
& nohold
))
448 mp
->m_flag
|= holdbit
;
455 makembox(void) /* TODO oh my god */
458 char *mbox
, *tempQuit
;
460 FILE *ibuf
= NULL
, *obuf
, *abuf
;
467 if (!ok_blook(append
)) {
468 if ((obuf
= Ftmp(&tempQuit
, "makembox",
469 OF_WRONLY
| OF_HOLDSIGS
| OF_REGISTER
, 0600)) == NULL
) {
470 perror(tr(163, "temporary mail quit file"));
473 if ((ibuf
= Fopen(tempQuit
, "r")) == NULL
)
475 Ftmp_release(&tempQuit
);
481 if ((abuf
= Zopen(mbox
, "r", NULL
)) != NULL
) {
482 while ((c
= getc(abuf
)) != EOF
)
487 perror(tr(163, "temporary mail quit file"));
494 if ((c
= open(mbox
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0600)) >= 0)
496 if ((obuf
= Zopen(mbox
, "r+", NULL
)) == NULL
) {
502 if ((obuf
= Zopen(mbox
, "a", NULL
)) == NULL
) {
506 fchmod(fileno(obuf
), 0600);
510 prot
= which_protocol(mbox
);
511 for (mp
= message
; PTRCMP(mp
, <, message
+ msgCount
); ++mp
) {
512 if (mp
->m_flag
& MBOX
) {
514 if (prot
== PROTO_IMAP
&&
515 saveignore
[0].i_count
== 0 && saveignore
[1].i_count
== 0
516 #ifdef HAVE_IMAP /* TODO revisit */
517 && imap_thisaccount(mbox
)
521 if (imap_copy(mp
, PTR2SIZE(mp
- message
+ 1), mbox
) == STOP
)
524 } else if (sendmp(mp
, obuf
, saveignore
, NULL
, SEND_MBOX
, NULL
) < 0) {
533 mp
->m_flag
|= MBOXED
;
539 /* Copy the user's old mbox contents back to the end of the stuff we just
540 * saved. If we are appending, this is unnecessary */
541 if (!ok_blook(append
)) {
559 if (Fclose(obuf
) != 0) {
560 if (prot
!= PROTO_IMAP
)
565 printf(tr(164, "Saved 1 message in mbox\n"));
567 printf(tr(165, "Saved %d messages in mbox\n"), mcount
);
575 save_mbox_for_possible_quitstuff(void) /* TODO try to get rid of that */
580 if ((cp
= expand("&")) == NULL
)
582 n_strlcpy(_mboxname
, cp
, sizeof _mboxname
);
589 enum quitflags qf
= 0;
593 for (i
= 0; i
< NELEM(_quitnames
); ++i
)
594 if (_var_oklook(_quitnames
[i
].okey
) != NULL
)
595 qf
|= _quitnames
[i
].flag
;
601 restorequitflags(int qf
)
606 for (i
= 0; i
< NELEM(_quitnames
); ++i
) {
607 char *x
= _var_oklook(_quitnames
[i
].okey
);
608 if (qf
& _quitnames
[i
].flag
) {
610 _var_okset(_quitnames
[i
].okey
, TRU1
);
611 } else if (x
!= NULL
)
612 _var_okclear(_quitnames
[i
].okey
);
617 /* vim:set fenc=utf-8:s-it-mode */