]> diplodocus.org Git - nmh/blob - uip/inc.c
7ebb0581c1f206befb1764d3794af17f8313b395
[nmh] / uip / inc.c
1 /* inc.c -- incorporate messages from a maildrop into a folder
2 *
3 * This code is Copyright (c) 2002, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
6 */
7
8 #ifdef MAILGROUP
9 /*
10 * Thu Feb 12 21:00 CST 2015 Marcin Cieslak <saper@saper.info>
11 * Replaced setgid() calls with setegid() so that it works with dot
12 * locking on FreeBSD. setegid() should be supported on modern POSIX
13 * systems.
14 *
15 * Revised: Sat Apr 14 17:08:17 PDT 1990 (marvit@hplabs)
16 * Added hpux hacks to set and reset gid to be "mail" as needed. The reset
17 * is necessary so inc'ed mail is the group of the inc'er, rather than
18 * "mail". We setgid to egid only when [un]locking the mail file. This
19 * is also a major security precaution which will not be explained here.
20 *
21 * Fri Feb 7 16:04:57 PST 1992 John Romine <bug-mh@ics.uci.edu>
22 * NB: I'm not 100% sure that this setgid stuff is secure even now.
23 *
24 * See the *GROUPPRIVS() macros later. I'm reasonably happy with the setgid
25 * attribute. Running setuid root is probably not a terribly good idea, though.
26 * -- Peter Maydell <pmaydell@chiark.greenend.org.uk>, 04/1998
27 *
28 * Peter Maydell's patch slightly modified for nmh 0.28-pre2.
29 * Ruud de Rooij <ruud@debian.org> Wed, 22 Jul 1998 13:24:22 +0200
30 */
31 #endif
32
33 #include "h/mh.h"
34 #include "sbr/fmt_new.h"
35 #include "sbr/dtime.h"
36 #include "scansbr.h"
37 #include "sbr/m_name.h"
38 #include "sbr/m_gmprot.h"
39 #include "sbr/getarguments.h"
40 #include "sbr/concat.h"
41 #include "sbr/seq_setunseen.h"
42 #include "sbr/seq_setcur.h"
43 #include "sbr/seq_save.h"
44 #include "sbr/smatch.h"
45 #include "sbr/getfolder.h"
46 #include "sbr/ext_hook.h"
47 #include "sbr/folder_read.h"
48 #include "sbr/folder_realloc.h"
49 #include "sbr/folder_free.h"
50 #include "sbr/context_save.h"
51 #include "sbr/context_replace.h"
52 #include "sbr/context_find.h"
53 #include "sbr/ambigsw.h"
54 #include "sbr/path.h"
55 #include "sbr/print_version.h"
56 #include "sbr/print_help.h"
57 #include "sbr/error.h"
58 #include "h/utils.h"
59 #include <fcntl.h>
60 #include "h/dropsbr.h"
61 #include "popsbr.h"
62 #include "h/fmt_scan.h"
63 #include "h/signals.h"
64 #include "h/tws.h"
65 #include "h/mts.h"
66 #include "h/done.h"
67 #include "sbr/lock_file.h"
68 #include "sbr/m_maildir.h"
69 #include "sbr/m_mktemp.h"
70 #include "sbr/maildir_read_and_sort.h"
71
72 #ifndef TLS_SUPPORT
73 # define TLSminc(a) (a)
74 #else
75 # define TLSminc(a) 0
76 #endif
77
78 #define INC_SWITCHES \
79 X("audit audit-file", 0, AUDSW) \
80 X("noaudit", 0, NAUDSW) \
81 X("changecur", 0, CHGSW) \
82 X("nochangecur", 0, NCHGSW) \
83 X("file name", 0, FILESW) \
84 X("form formatfile", 0, FORMSW) \
85 X("format string", 5, FMTSW) \
86 X("host hostname", 0, HOSTSW) \
87 X("user username", 0, USERSW) \
88 X("port name/number", 0, PORTSW) \
89 X("silent", 0, SILSW) \
90 X("nosilent", 0, NSILSW) \
91 X("truncate", 0, TRNCSW) \
92 X("notruncate", 0, NTRNCSW) \
93 X("width columns", 0, WIDTHSW) \
94 X("version", 0, VERSIONSW) \
95 X("help", 0, HELPSW) \
96 X("snoop", 0, SNOOPSW) \
97 X("sasl", 0, SASLSW) \
98 X("nosasl", 0, NOSASLSW) \
99 X("saslmech", 0, SASLMECHSW) \
100 X("tls", TLSminc(-3), TLSSW) \
101 X("initialtls", TLSminc(-10), INITTLSSW) \
102 X("notls", TLSminc(-5), NOTLSSW) \
103 X("certverify", TLSminc(-10), CERTVERSW) \
104 X("nocertverify", TLSminc(-12), NOCERTVERSW) \
105 X("authservice", 0, AUTHSERVICESW) \
106 X("proxy command", 0, PROXYSW) \
107
108 #define X(sw, minchars, id) id,
109 DEFINE_SWITCH_ENUM(INC);
110 #undef X
111
112 #define X(sw, minchars, id) { sw, minchars, id },
113 DEFINE_SWITCH_ARRAY(INC, switches);
114 #undef X
115
116 /*
117 * flags for the mail source
118 */
119 #define INC_FILE 0
120 #define INC_POP 1
121
122 static struct Maildir_entry *Maildir;
123 static int num_maildir_entries;
124 static bool snoop;
125
126 typedef struct {
127 FILE *mailout;
128 long written;
129 } pop_closure;
130
131 extern char response[];
132
133 /* This is an attempt to simplify things by putting all the
134 * privilege ops into macros.
135 * *GROUPPRIVS() is related to handling the setgid MAIL property,
136 * and only applies if MAILGROUP is defined.
137 * Basically, SAVEGROUPPRIVS() is called right at the top of main()
138 * to initialise things, and then DROPGROUPPRIVS() and GETGROUPPRIVS()
139 * do the obvious thing.
140 *
141 * There's probably a better implementation if we're allowed to use
142 * BSD-style setreuid() rather than using POSIX saved-ids.
143 * Anyway, if you're euid root it's a bit pointless to drop the group
144 * permissions...
145 *
146 * I'm pretty happy that the security is good provided we aren't setuid root.
147 * The only things we trust with group=mail privilege are lkfopen()
148 * and lkfclose().
149 */
150
151 /*
152 * For setting and returning to "mail" gid
153 */
154 #ifdef MAILGROUP
155 static gid_t return_gid;
156 #define TRYDROPGROUPPRIVS() DROPGROUPPRIVS()
157 #define DROPGROUPPRIVS() \
158 if (setegid(getgid()) != 0) { \
159 adios ("setegid", "unable to restore group to %ld", (long) getgid()); \
160 }
161 #define GETGROUPPRIVS() \
162 if (setegid(return_gid) != 0) { \
163 adios ("setegid", "unable to set group to %ld", (long) return_gid); \
164 }
165 #define SAVEGROUPPRIVS() return_gid = getegid()
166 #else
167 /* define *GROUPPRIVS() as null; this avoids having lots of "#ifdef MAILGROUP"s */
168 #define TRYDROPGROUPPRIVS()
169 #define DROPGROUPPRIVS()
170 #define GETGROUPPRIVS()
171 #define SAVEGROUPPRIVS()
172 #endif /* not MAILGROUP */
173
174 /* these variables have to be globals so that done() can correctly clean up the lockfile */
175 static bool locked;
176 static char *newmail;
177 static FILE *in;
178
179 /*
180 * prototypes
181 */
182 static void inc_done(int) NORETURN;
183 static int pop_action(void *closure, char *);
184
185 int
186 main (int argc, char **argv)
187 {
188 static int inc_type;
189 bool chgflag;
190 int trnflag = 1;
191 bool noisy;
192 int width = -1;
193 int hghnum = 0, msgnum = 0;
194 FILE *pf = NULL;
195 bool sasl, noverify;
196 int tls = 0;
197 int incerr = 0; /* <0 if inc hits an error which means it should not truncate mailspool */
198 char *cp, *maildir = NULL, *folder = NULL;
199 char *format = NULL, *form = NULL;
200 char *host = NULL, *port = NULL, *user = NULL, *proxy = NULL;
201 char *audfile = NULL, *from = NULL, *saslmech = NULL, *auth_svc = NULL;
202 char buf[BUFSIZ], **argp, *nfs, **arguments;
203 struct msgs *mp = NULL;
204 struct stat st, s1;
205 FILE *aud = NULL;
206 char b[PATH_MAX + 1];
207 char *maildir_copy = NULL; /* copy of mail directory because the static gets overwritten */
208 charstring_t scanl = NULL;
209
210 int nmsgs, nbytes;
211 char *MAILHOST_env_variable;
212 set_done(inc_done);
213
214 /* absolutely the first thing we do is save our privileges,
215 * and drop them if we can.
216 */
217 SAVEGROUPPRIVS();
218 TRYDROPGROUPPRIVS();
219
220 if (nmh_init(argv[0], true, true)) { return 1; }
221
222 mts_init ();
223 arguments = getarguments (invo_name, argc, argv, 1);
224 argp = arguments;
225
226 /*
227 * Scheme is:
228 * use MAILHOST environment variable if present,
229 * else try Hesiod.
230 * If that fails, use the default (if any)
231 * provided by mts.conf in mts_init()
232 */
233 if ((MAILHOST_env_variable = getenv("MAILHOST")) != NULL)
234 pophost = MAILHOST_env_variable;
235 /*
236 * If there is a valid "pophost" entry in mts.conf,
237 * then use it as the default host.
238 */
239 if (pophost && *pophost)
240 host = pophost;
241
242 sasl = noverify = false;
243 chgflag = noisy = true;
244 while ((cp = *argp++)) {
245 if (*cp == '-') {
246 switch (smatch (++cp, switches)) {
247 case AMBIGSW:
248 ambigsw (cp, switches);
249 done (1);
250 case UNKWNSW:
251 die("-%s unknown", cp);
252
253 case HELPSW:
254 snprintf (buf, sizeof(buf), "%s [+folder] [switches]", invo_name);
255 print_help (buf, switches, 1);
256 done (0);
257 case VERSIONSW:
258 print_version(invo_name);
259 done (0);
260
261 case AUDSW:
262 if (!(cp = *argp++) || *cp == '-')
263 die("missing argument to %s", argp[-2]);
264 audfile = mh_xstrdup(m_maildir(cp));
265 continue;
266 case NAUDSW:
267 audfile = NULL;
268 continue;
269
270 case CHGSW:
271 chgflag = true;
272 continue;
273 case NCHGSW:
274 chgflag = false;
275 continue;
276
277 /*
278 * The flag `trnflag' has the value:
279 *
280 * 2 if -truncate is given
281 * 1 by default (truncating is default)
282 * 0 if -notruncate is given
283 */
284 case TRNCSW:
285 trnflag = 2;
286 continue;
287 case NTRNCSW:
288 trnflag = 0;
289 continue;
290
291 case FILESW:
292 if (!(cp = *argp++) || *cp == '-')
293 die("missing argument to %s", argp[-2]);
294 from = path (cp, TFILE);
295
296 /*
297 * If the truncate file is in default state,
298 * change to not truncate.
299 */
300 if (trnflag == 1)
301 trnflag = 0;
302 continue;
303
304 case SILSW:
305 noisy = false;
306 continue;
307 case NSILSW:
308 noisy = true;
309 continue;
310
311 case FORMSW:
312 if (!(form = *argp++) || *form == '-')
313 die("missing argument to %s", argp[-2]);
314 format = NULL;
315 continue;
316 case FMTSW:
317 if (!(format = *argp++) || *format == '-')
318 die("missing argument to %s", argp[-2]);
319 form = NULL;
320 continue;
321
322 case WIDTHSW:
323 if (!(cp = *argp++) || *cp == '-')
324 die("missing argument to %s", argp[-2]);
325 width = atoi (cp);
326 continue;
327
328 case HOSTSW:
329 if (!(host = *argp++) || *host == '-')
330 die("missing argument to %s", argp[-2]);
331 continue;
332
333 case PORTSW:
334 if (!(port = *argp++) || *port == '-')
335 die("missing argument to %s", argp[-2]);
336 continue;
337
338 case USERSW:
339 if (!(user = *argp++) || *user == '-')
340 die("missing argument to %s", argp[-2]);
341 continue;
342
343 case SNOOPSW:
344 snoop = true;
345 continue;
346
347 case SASLSW:
348 sasl = true;
349 continue;
350 case NOSASLSW:
351 sasl = false;
352 continue;
353
354 case SASLMECHSW:
355 if (!(saslmech = *argp++) || *saslmech == '-')
356 die("missing argument to %s", argp[-2]);
357 continue;
358
359 case TLSSW:
360 tls = 1;
361 continue;
362
363 case INITTLSSW:
364 tls = 2;
365 continue;
366
367 case NOTLSSW:
368 tls = 0;
369 continue;
370
371 case CERTVERSW:
372 noverify = false;
373 continue;
374
375 case NOCERTVERSW:
376 noverify = true;
377 continue;
378
379 case AUTHSERVICESW:
380 #ifdef OAUTH_SUPPORT
381 if (!(auth_svc = *argp++) || *auth_svc == '-')
382 die("missing argument to %s", argp[-2]);
383 #else
384 die("not built with OAuth support");
385 #endif
386 continue;
387
388 case PROXYSW:
389 if (!(proxy = *argp++) || *proxy == '-')
390 die("missing argument to %s", argp[-2]);
391 continue;
392 }
393 }
394 if (*cp == '+' || *cp == '@') {
395 if (folder)
396 die("only one folder at a time!");
397 folder = pluspath (cp);
398 } else {
399 die("usage: %s [+folder] [switches]", invo_name);
400 }
401 }
402
403 /* NOTE: above this point you should use TRYDROPGROUPPRIVS(),
404 * not DROPGROUPPRIVS().
405 */
406 if (host && !*host)
407 host = NULL;
408
409 /* guarantee dropping group privileges; we might not have done so earlier */
410 DROPGROUPPRIVS();
411
412 /* Source of mail; -from overrides any -host. */
413 inc_type = host && !from ? INC_POP : INC_FILE;
414
415 if (inc_type == INC_POP) {
416 /* Mail from a POP server. */
417 int tlsflag = 0;
418
419 if (auth_svc == NULL) {
420 if (saslmech && ! strcasecmp(saslmech, "xoauth2")) {
421 die("must specify -authservice with -saslmech xoauth2");
422 }
423 } else {
424 if (user == NULL) {
425 die("must specify -user with -saslmech xoauth2");
426 }
427 }
428
429 if (tls == 1)
430 tlsflag = P_STARTTLS;
431 else if (tls == 2)
432 tlsflag = P_INITTLS;
433
434 if (noverify)
435 tlsflag |= P_NOVERIFY;
436
437 /*
438 * initialize POP connection
439 */
440 if (pop_init (host, port, user, proxy, snoop, sasl, saslmech,
441 tlsflag, auth_svc) == NOTOK)
442 die("%s", response);
443
444 /* Check if there are any messages */
445 if (pop_stat (&nmsgs, &nbytes) == NOTOK)
446 die("%s", response);
447
448 if (nmsgs == 0) {
449 pop_quit();
450 die("no mail to incorporate");
451 }
452
453 } else if (inc_type == INC_FILE) {
454 /* Mail from a spool file, or Maildir. */
455 if (from)
456 newmail = from;
457 else if ((newmail = getenv ("MAILDROP")) && *newmail)
458 newmail = m_mailpath (newmail);
459 else if ((newmail = context_find ("maildrop")) && *newmail)
460 newmail = m_mailpath (newmail);
461 else {
462 newmail = concat (MAILDIR, "/", MAILFIL, NULL);
463 }
464 if (stat (newmail, &s1) == NOTOK || s1.st_size == 0)
465 die("no mail to incorporate");
466 if (s1.st_mode & S_IFDIR) {
467 maildir_read_and_sort(newmail, &Maildir, &num_maildir_entries);
468 }
469
470 cp = mh_xstrdup(newmail);
471 newmail = cp;
472 }
473
474 if (!context_find ("path"))
475 free (path ("./", TFOLDER));
476 if (!folder)
477 folder = getfolder (0);
478 maildir = m_maildir (folder);
479 maildir_copy = mh_xstrdup(maildir);
480
481 if (!folder_exists(maildir)) {
482 /* If the folder doesn't exist, and we're given the -silent flag,
483 * just fail.
484 */
485 if (noisy)
486 create_folder(maildir, 0, done);
487 else
488 done (1);
489 }
490
491 if (chdir (maildir) == NOTOK)
492 adios (maildir, "unable to change directory to");
493
494 /* read folder and create message structure */
495 if (!(mp = folder_read (folder, 0)))
496 die("unable to read folder %s", folder);
497
498 if (inc_type == INC_FILE && Maildir == NULL) {
499 /* Mail from a spool file. */
500
501 if (access (newmail, W_OK) != NOTOK) {
502 locked = true;
503 if (trnflag) {
504 SIGNAL (SIGHUP, SIG_IGN);
505 SIGNAL (SIGINT, SIG_IGN);
506 SIGNAL (SIGQUIT, SIG_IGN);
507 SIGNAL (SIGTERM, SIG_IGN);
508 }
509
510 GETGROUPPRIVS(); /* Reset gid to lock mail file */
511 in = lkfopenspool (newmail, "r");
512 DROPGROUPPRIVS();
513 if (in == NULL)
514 die("unable to lock and fopen %s", newmail);
515 fstat (fileno(in), &s1);
516 } else {
517 trnflag = 0;
518 if ((in = fopen (newmail, "r")) == NULL)
519 adios (newmail, "unable to read");
520 }
521 }
522
523 /* This shouldn't be necessary but it can't hurt. */
524 DROPGROUPPRIVS();
525
526 if (audfile) {
527 int i;
528 if ((i = stat (audfile, &st)) == NOTOK)
529 inform("Creating Receive-Audit: %s", audfile);
530 if ((aud = fopen (audfile, "a")) == NULL)
531 adios (audfile, "unable to append to");
532 if (i == NOTOK)
533 chmod (audfile, m_gmprot ());
534
535 if (from)
536 fprintf (aud, "<<inc>> %s -ms %s\n", dtimenow(0), from);
537 else {
538 if (host)
539 fprintf (aud, "<<inc>> %s -host %s -user %s\n", dtimenow(0),
540 host, user);
541 else
542 fprintf (aud, "<<inc>> %s\n", dtimenow (0));
543 }
544 }
545
546 /* Get new format string */
547 nfs = new_fs (form, format, FORMAT);
548
549 if (noisy) {
550 printf ("Incorporating new mail into %s...\n\n", folder);
551 fflush (stdout);
552 }
553
554
555 /*
556 * Get the mail from a POP server
557 */
558 if (inc_type == INC_POP) {
559 /* Mail from a POP server. */
560 int i;
561 pop_closure pc;
562
563 hghnum = msgnum = mp->hghmsg;
564 for (i = 1; i <= nmsgs; i++) {
565
566 msgnum++;
567 cp = mh_xstrdup(m_name (msgnum));
568 if ((pf = fopen (cp, "w+")) == NULL)
569 adios (cp, "unable to write");
570 chmod (cp, m_gmprot ());
571
572 pc.written = 0;
573 pc.mailout = pf;
574 if (pop_retr(i, pop_action, &pc) == NOTOK)
575 die("%s", response);
576
577 if (fflush (pf))
578 adios (cp, "write error on");
579 fseek (pf, 0L, SEEK_SET);
580 switch (incerr = scan (pf, msgnum, 0, nfs, width,
581 msgnum == mp->hghmsg + 1 && chgflag,
582 1, NULL, pc.written, noisy, &scanl)) {
583 case SCNEOF:
584 printf ("%*d empty\n", DMAXFOLDER, msgnum);
585 break;
586
587 case SCNFAT:
588 trnflag = 0;
589 noisy = true;
590 /* advise (cp, "unable to read"); already advised */
591 break;
592
593 case SCNERR:
594 case SCNNUM:
595 break;
596
597 case SCNMSG:
598 default:
599 if (aud)
600 fputs (charstring_buffer (scanl), aud);
601 if (noisy)
602 fflush (stdout);
603 break;
604 }
605
606 if (scanl)
607 charstring_clear (scanl);
608
609 if (ferror(pf) || fclose (pf)) {
610 int e = errno;
611 (void) m_unlink (cp);
612 pop_quit ();
613 errno = e;
614 adios (cp, "write error on");
615 }
616 free (cp);
617
618 if (trnflag && pop_dele (i) == NOTOK)
619 die("%s", response);
620
621 scan_finished();
622 }
623
624 charstring_free (scanl);
625 scanl = NULL;
626
627 if (pop_quit () == NOTOK)
628 die("%s", response);
629
630 } else if (inc_type == INC_FILE && Maildir == NULL) {
631 /* Mail from a spool file. */
632
633 scan_detect_mbox_style (in); /* the MAGIC invocation... */
634 hghnum = msgnum = mp->hghmsg;
635 for (;;) {
636 /* create scanline for new message */
637 switch (incerr = scan (in, msgnum + 1, msgnum + 1, nfs, width,
638 msgnum == hghnum && chgflag, 1, NULL, 0L, noisy,
639 &scanl)) {
640 case SCNFAT:
641 case SCNEOF:
642 break;
643
644 case SCNERR:
645 if (aud)
646 fputs ("inc aborted!\n", aud);
647 inform("aborted!"); /* doesn't clean up locks! */
648 break;
649
650 case SCNNUM:
651 inform("BUG in %s, number out of range", invo_name);
652 break;
653
654 default:
655 inform("BUG in %s, scan() botch (%d)", invo_name, incerr);
656 break;
657
658 case SCNMSG:
659 /*
660 * Run the external program hook on the message.
661 */
662
663 (void)snprintf(b, sizeof (b), "%s/%d", maildir_copy, msgnum + 1);
664 (void)ext_hook("add-hook", b, NULL);
665
666 if (aud)
667 fputs (charstring_buffer (scanl), aud);
668 if (noisy)
669 fflush (stdout);
670
671 charstring_clear (scanl);
672 msgnum++;
673 continue;
674 }
675
676 /* If we get here there was some sort of error from scan(),
677 * so stop processing anything more from the spool.
678 */
679 break;
680 }
681 charstring_free (scanl);
682 scanl = NULL;
683
684 } else {
685 /* Mail from Maildir. */
686 char *sp;
687 FILE *sf;
688 int i;
689
690 hghnum = msgnum = mp->hghmsg;
691 for (i = 0; i < num_maildir_entries; i++) {
692 msgnum++;
693
694 sp = Maildir[i].filename;
695 cp = mh_xstrdup(m_name (msgnum));
696 pf = NULL;
697 if (!trnflag || link(sp, cp) == -1) {
698 static char buf[65536];
699 size_t nrd;
700
701 if ((sf = fopen (sp, "r")) == NULL)
702 adios (sp, "unable to read for copy");
703 if ((pf = fopen (cp, "w+")) == NULL)
704 adios (cp, "unable to write for copy");
705 while ((nrd = fread(buf, 1, sizeof(buf), sf)) > 0)
706 if (fwrite(buf, 1, nrd, pf) != nrd)
707 break;
708 if (ferror(sf) || fflush(pf) || ferror(pf)) {
709 int e = errno;
710 fclose(pf); fclose(sf); (void) m_unlink(cp);
711 errno = e;
712 adios(cp, "copy error %s -> %s", sp, cp);
713 }
714 fclose (sf);
715 sf = NULL;
716 }
717 if (pf == NULL && (pf = fopen (cp, "r")) == NULL)
718 adios (cp, "not available");
719 chmod (cp, m_gmprot ());
720
721 fseek (pf, 0L, SEEK_SET);
722 switch (incerr = scan (pf, msgnum, 0, nfs, width,
723 msgnum == mp->hghmsg + 1 && chgflag,
724 1, NULL, 0, noisy, &scanl)) {
725 case SCNEOF:
726 printf ("%*d empty\n", DMAXFOLDER, msgnum);
727 break;
728
729 case SCNFAT:
730 trnflag = 0;
731 noisy = true;
732 /* advise (cp, "unable to read"); already advised */
733 break;
734
735 case SCNERR:
736 case SCNNUM:
737 break;
738
739 case SCNMSG:
740 default:
741 /*
742 * Run the external program hook on the message.
743 */
744
745 (void)snprintf(b, sizeof (b), "%s/%d", maildir_copy, msgnum + 1);
746 (void)ext_hook("add-hook", b, NULL);
747
748 if (aud)
749 fputs (charstring_buffer (scanl), aud);
750 if (noisy)
751 fflush (stdout);
752 break;
753 }
754 charstring_clear (scanl);
755
756 if (ferror(pf) || fclose (pf)) {
757 int e = errno;
758 (void) m_unlink (cp);
759 errno = e;
760 adios (cp, "write error on");
761 }
762 pf = NULL;
763 free (cp);
764
765 if (trnflag && m_unlink (sp) == NOTOK)
766 adios (sp, "couldn't unlink");
767 free (sp); /* Free Maildir[i]->filename */
768
769 scan_finished();
770 }
771 free (Maildir); /* From now on Maildir is just a flag - don't dref! */
772 charstring_free (scanl);
773 scanl = NULL;
774 }
775
776 scan_finished ();
777
778 if (incerr < 0) { /* error */
779 if (locked) {
780 GETGROUPPRIVS(); /* Be sure we can unlock mail file */
781 (void) lkfclosespool (in, newmail); in = NULL;
782 DROPGROUPPRIVS(); /* And then return us to normal privileges */
783 } else {
784 fclose (in); in = NULL;
785 }
786 die("failed");
787 }
788
789 if (aud)
790 fclose (aud);
791
792 if (noisy)
793 fflush (stdout);
794
795 if (inc_type == INC_FILE && Maildir == NULL) {
796 /* Mail from a spool file; truncate it. */
797
798 if (trnflag) {
799 if (stat (newmail, &st) != NOTOK && s1.st_mtime != st.st_mtime)
800 inform("new messages have arrived!\007");
801 else {
802 int newfd;
803 if ((newfd = creat (newmail, 0600)) != NOTOK)
804 close (newfd);
805 else
806 admonish (newmail, "error zero'ing");
807 }
808 } else {
809 if (noisy)
810 printf ("%s not zero'd\n", newmail);
811 }
812 }
813
814 if (msgnum == hghnum) {
815 inform("no messages incorporated, continuing...");
816 } else {
817 /*
818 * Lock the sequence file now, and loop to set the right flags
819 * in the folder structure
820 */
821
822 struct msgs *mp2;
823 int i;
824
825 context_replace (pfolder, folder); /* update current folder */
826
827 if ((mp2 = folder_read(folder, 1)) == NULL) {
828 inform("Unable to reread folder %s, continuing...", folder);
829 goto skip;
830 }
831
832 /*
833 * Shouldn't happen, but just in case ...
834 */
835
836 if (msgnum >= mp2->hghoff
837 && !(mp2 = folder_realloc (mp2, mp2->lowoff, msgnum + 1))) {
838 inform("unable to reallocate folder storage");
839 goto skip;
840 }
841
842 if (chgflag)
843 mp2->curmsg = hghnum + 1;
844 mp2->hghmsg = msgnum;
845
846 if (mp2->lowmsg == 0)
847 mp2->lowmsg = 1;
848 if (chgflag) /* sigh... */
849 seq_setcur (mp2, mp2->curmsg);
850
851 for (i = hghnum + 1; i <= msgnum; i++) {
852 clear_msg_flags (mp2, i);
853 set_exists (mp2, i);
854 set_unseen (mp2, i);
855 }
856 mp2->msgflags |= SEQMOD;
857 seq_setunseen(mp2, 0); /* Set the Unseen-Sequence */
858 seq_save(mp2); /* Save the sequence file */
859 folder_free(mp2);
860 }
861
862 skip:
863 if (inc_type == INC_FILE && Maildir == NULL) {
864 /* Mail from a spool file; unlock it. */
865
866 if (locked) {
867 GETGROUPPRIVS(); /* Be sure we can unlock mail file */
868 (void) lkfclosespool (in, newmail); in = NULL;
869 DROPGROUPPRIVS(); /* And then return us to normal privileges */
870 } else {
871 fclose (in); in = NULL;
872 }
873 }
874
875 context_save (); /* save the context file */
876 done (0);
877 return 1;
878 }
879
880
881 static void NORETURN
882 inc_done (int status)
883 {
884 set_done(exit);
885 if (locked)
886 {
887 GETGROUPPRIVS();
888 lkfclosespool(in, newmail);
889 DROPGROUPPRIVS();
890 }
891 exit (status);
892 }
893
894 static int
895 pop_action(void *closure, char *s)
896 {
897 pop_closure *pc;
898 int n;
899
900 pc = closure;
901 n = fprintf(pc->mailout, "%s\n", s);
902 if (n < 0)
903 return NOTOK;
904 pc->written += n; /* Count linefeed too. */
905
906 return OK;
907 }