]> diplodocus.org Git - nmh/blob - uip/inc.c
Add back missing include of <sys/wait.h>
[nmh] / uip / inc.c
1
2 /*
3 * inc.c -- incorporate messages from a maildrop into a folder
4 *
5 * This code is Copyright (c) 2002, by the authors of nmh. See the
6 * COPYRIGHT file in the root directory of the nmh distribution for
7 * complete copyright information.
8 */
9
10 #ifdef MAILGROUP
11 /* Revised: Sat Apr 14 17:08:17 PDT 1990 (marvit@hplabs)
12 * Added hpux hacks to set and reset gid to be "mail" as needed. The reset
13 * is necessary so inc'ed mail is the group of the inc'er, rather than
14 * "mail". We setgid to egid only when [un]locking the mail file. This
15 * is also a major security precaution which will not be explained here.
16 *
17 * Fri Feb 7 16:04:57 PST 1992 John Romine <bug-mh@ics.uci.edu>
18 * NB: I'm not 100% sure that this setgid stuff is secure even now.
19 *
20 * See the *GROUPPRIVS() macros later. I'm reasonably happy with the setgid
21 * attribute. Running setuid root is probably not a terribly good idea, though.
22 * -- Peter Maydell <pmaydell@chiark.greenend.org.uk>, 04/1998
23 *
24 * Peter Maydell's patch slightly modified for nmh 0.28-pre2.
25 * Ruud de Rooij <ruud@debian.org> Wed, 22 Jul 1998 13:24:22 +0200
26 */
27 #endif
28
29 #include <h/mh.h>
30 #include <h/utils.h>
31 #include <fcntl.h>
32
33 #ifdef POP
34 # include <h/dropsbr.h>
35 # include <h/popsbr.h>
36 #endif
37
38 #include <h/fmt_scan.h>
39 #include <h/scansbr.h>
40 #include <h/signals.h>
41 #include <h/tws.h>
42 #include <h/mts.h>
43 #include <errno.h>
44 #include <signal.h>
45
46 #ifndef POP
47 # define POPminc(a) (a)
48 #else
49 # define POPminc(a) 0
50 #endif
51
52 #ifndef CYRUS_SASL
53 # define SASLminc(a) (a)
54 #else
55 # define SASLminc(a) 0
56 #endif
57
58 static struct swit switches[] = {
59 #define AUDSW 0
60 { "audit audit-file", 0 },
61 #define NAUDSW 1
62 { "noaudit", 0 },
63 #define CHGSW 2
64 { "changecur", 0 },
65 #define NCHGSW 3
66 { "nochangecur", 0 },
67 #define FILESW 4
68 { "file name", 0 },
69 #define FORMSW 5
70 { "form formatfile", 0 },
71 #define FMTSW 6
72 { "format string", 5 },
73 #define HOSTSW 7
74 { "host hostname", POPminc (-4) },
75 #define USERSW 8
76 { "user username", POPminc (-4) },
77 #define PACKSW 9
78 { "pack file", POPminc (-4) },
79 #define NPACKSW 10
80 { "nopack", POPminc (-6) },
81 #define PORTSW 11
82 { "port name/number", POPminc (-4) },
83 #define SILSW 12
84 { "silent", 0 },
85 #define NSILSW 13
86 { "nosilent", 0 },
87 #define TRNCSW 14
88 { "truncate", 0 },
89 #define NTRNCSW 15
90 { "notruncate", 0 },
91 #define WIDTHSW 16
92 { "width columns", 0 },
93 #define VERSIONSW 17
94 { "version", 0 },
95 #define HELPSW 18
96 { "help", 0 },
97 #define SNOOPSW 19
98 { "snoop", -5 },
99 #define SASLSW 20
100 { "sasl", SASLminc(-4) },
101 #define SASLMECHSW 21
102 { "saslmech", SASLminc(-8) },
103 #define PROXYSW 22
104 { "proxy command", POPminc(-5) },
105 { NULL, 0 }
106 };
107
108 /*
109 * flags for the mail source
110 */
111 #define INC_FILE 0
112 #define INC_POP 1
113
114 static int inc_type;
115 static struct Maildir_entry {
116 char *filename;
117 time_t mtime;
118 } *Maildir = NULL;
119 static int num_maildir_entries = 0;
120 static int snoop = 0;
121
122 #ifdef POP
123 extern char response[];
124
125 static int size;
126 static long pos;
127
128 static int mbx_style = MMDF_FORMAT;
129 static int pd = NOTOK;
130 #endif /* POP */
131
132 static long start;
133 static long stop;
134
135 static char *packfile = NULL;
136 static FILE *pf = NULL;
137
138 /* This is an attempt to simplify things by putting all the
139 * privilege ops into macros.
140 * *GROUPPRIVS() is related to handling the setgid MAIL property,
141 * and only applies if MAILGROUP is defined.
142 * *USERPRIVS() is related to handling the setuid root property,
143 * and only applies if POP is defined [why does POP => setuid root?]
144 * Basically, SAVEGROUPPRIVS() is called right at the top of main()
145 * to initialise things, and then DROPGROUPPRIVS() and GETGROUPPRIVS()
146 * do the obvious thing. TRYDROPGROUPPRIVS() has to be safe to call
147 * before DROPUSERPRIVS() is called [this is needed because setgid()
148 * sets both effective and real uids if euid is root.]
149 *
150 * There's probably a better implementation if we're allowed to use
151 * BSD-style setreuid() rather than using POSIX saved-ids.
152 * Anyway, if you're euid root it's a bit pointless to drop the group
153 * permissions...
154 *
155 * I'm pretty happy that the security is good provided we aren't setuid root.
156 * The only things we trust with group=mail privilege are lkfopen()
157 * and lkfclose().
158 */
159
160 /*
161 * For setting and returning to "mail" gid
162 */
163 #ifdef MAILGROUP
164 static int return_gid;
165 #ifndef POP
166 /* easy case; we're not setuid root, so can drop group privs
167 * immediately.
168 */
169 #define TRYDROPGROUPPRIVS() DROPGROUPPRIVS()
170 #else /* POP ie we are setuid root */
171 #define TRYDROPGROUPPRIVS() \
172 if (geteuid() != 0) DROPGROUPPRIVS()
173 #endif
174 #define DROPGROUPPRIVS() setgid(getgid())
175 #define GETGROUPPRIVS() setgid(return_gid)
176 #define SAVEGROUPPRIVS() return_gid = getegid()
177 #else
178 /* define *GROUPPRIVS() as null; this avoids having lots of "#ifdef MAILGROUP"s */
179 #define TRYDROPGROUPPRIVS()
180 #define DROPGROUPPRIVS()
181 #define GETGROUPPRIVS()
182 #define SAVEGROUPPRIVS()
183 #endif /* not MAILGROUP */
184
185 /* these variables have to be globals so that done() can correctly clean up the lockfile */
186 static int locked = 0;
187 static char *newmail;
188 static FILE *in;
189
190 /*
191 * prototypes
192 */
193 char *map_name(char *);
194
195 static void inc_done(int) NORETURN;
196 #ifdef POP
197 static int pop_action(char *);
198 static int pop_pack(char *);
199 static int map_count(void);
200 #endif
201
202 int
203 maildir_srt(const void *va, const void *vb)
204 {
205 const struct Maildir_entry *a = va, *b = vb;
206 if (a->mtime > b->mtime)
207 return 1;
208 else if (a->mtime < b->mtime)
209 return -1;
210 else
211 return 0;
212 }
213
214 int
215 main (int argc, char **argv)
216 {
217 int chgflag = 1, trnflag = 1;
218 int noisy = 1, width = 0;
219 int hghnum = 0, msgnum = 0;
220 int sasl = 0;
221 int incerr = 0; /* <0 if inc hits an error which means it should not truncate mailspool */
222 char *cp, *maildir = NULL, *folder = NULL;
223 char *format = NULL, *form = NULL;
224 char *host = NULL, *port = NULL, *user = NULL, *proxy = NULL;
225 char *audfile = NULL, *from = NULL, *saslmech = NULL;
226 char buf[BUFSIZ], **argp, *nfs, **arguments;
227 struct msgs *mp = NULL;
228 struct stat st, s1;
229 FILE *aud = NULL;
230 char b[MAXPATHLEN + 1];
231 char *maildir_copy = NULL; /* copy of mail directory because the static gets overwritten */
232
233 #ifdef POP
234 int nmsgs, nbytes;
235 char *pass = NULL;
236 char *MAILHOST_env_variable;
237 #endif
238
239 #ifdef MHE
240 FILE *mhe = NULL;
241 #endif
242
243 done=inc_done;
244
245 /* absolutely the first thing we do is save our privileges,
246 * and drop them if we can.
247 */
248 SAVEGROUPPRIVS();
249 TRYDROPGROUPPRIVS();
250
251 #ifdef LOCALE
252 setlocale(LC_ALL, "");
253 #endif
254 invo_name = r1bindex (argv[0], '/');
255
256 /* read user profile/context */
257 context_read();
258
259 mts_init (invo_name);
260 arguments = getarguments (invo_name, argc, argv, 1);
261 argp = arguments;
262
263 #ifdef POP
264 /*
265 * Scheme is:
266 * use MAILHOST environment variable if present,
267 * else try Hesiod.
268 * If that fails, use the default (if any)
269 * provided by mts.conf in mts_init()
270 */
271 if ((MAILHOST_env_variable = getenv("MAILHOST")) != NULL)
272 pophost = MAILHOST_env_variable;
273 /*
274 * If there is a valid "pophost" entry in mts.conf,
275 * then use it as the default host.
276 */
277 if (pophost && *pophost)
278 host = pophost;
279
280 if ((cp = getenv ("MHPOPDEBUG")) && *cp)
281 snoop++;
282 #endif /* POP */
283
284 while ((cp = *argp++)) {
285 if (*cp == '-') {
286 switch (smatch (++cp, switches)) {
287 case AMBIGSW:
288 ambigsw (cp, switches);
289 done (1);
290 case UNKWNSW:
291 adios (NULL, "-%s unknown", cp);
292
293 case HELPSW:
294 snprintf (buf, sizeof(buf), "%s [+folder] [switches]", invo_name);
295 print_help (buf, switches, 1);
296 done (1);
297 case VERSIONSW:
298 print_version(invo_name);
299 done (1);
300
301 case AUDSW:
302 if (!(cp = *argp++) || *cp == '-')
303 adios (NULL, "missing argument to %s", argp[-2]);
304 audfile = getcpy (m_maildir (cp));
305 continue;
306 case NAUDSW:
307 audfile = NULL;
308 continue;
309
310 case CHGSW:
311 chgflag++;
312 continue;
313 case NCHGSW:
314 chgflag = 0;
315 continue;
316
317 /*
318 * The flag `trnflag' has the value:
319 *
320 * 2 if -truncate is given
321 * 1 by default (truncating is default)
322 * 0 if -notruncate is given
323 */
324 case TRNCSW:
325 trnflag = 2;
326 continue;
327 case NTRNCSW:
328 trnflag = 0;
329 continue;
330
331 case FILESW:
332 if (!(cp = *argp++) || *cp == '-')
333 adios (NULL, "missing argument to %s", argp[-2]);
334 from = path (cp, TFILE);
335
336 /*
337 * If the truncate file is in default state,
338 * change to not truncate.
339 */
340 if (trnflag == 1)
341 trnflag = 0;
342 continue;
343
344 case SILSW:
345 noisy = 0;
346 continue;
347 case NSILSW:
348 noisy++;
349 continue;
350
351 case FORMSW:
352 if (!(form = *argp++) || *form == '-')
353 adios (NULL, "missing argument to %s", argp[-2]);
354 format = NULL;
355 continue;
356 case FMTSW:
357 if (!(format = *argp++) || *format == '-')
358 adios (NULL, "missing argument to %s", argp[-2]);
359 form = NULL;
360 continue;
361
362 case WIDTHSW:
363 if (!(cp = *argp++) || *cp == '-')
364 adios (NULL, "missing argument to %s", argp[-2]);
365 width = atoi (cp);
366 continue;
367
368 case HOSTSW:
369 if (!(host = *argp++) || *host == '-')
370 adios (NULL, "missing argument to %s", argp[-2]);
371 continue;
372
373 case PORTSW:
374 if (!(host = *argp++) || *port == '-')
375 adios (NULL, "missing argument to %s", argp[-2]);
376 continue;
377
378 case USERSW:
379 if (!(user = *argp++) || *user == '-')
380 adios (NULL, "missing argument to %s", argp[-2]);
381 continue;
382
383 case PACKSW:
384 #ifndef POP
385 if (!(cp = *argp++) || *cp == '-')
386 adios (NULL, "missing argument to %s", argp[-2]);
387 #else /* POP */
388 if (!(packfile = *argp++) || *packfile == '-')
389 adios (NULL, "missing argument to %s", argp[-2]);
390 #endif /* POP */
391 continue;
392 case NPACKSW:
393 #ifdef POP
394 packfile = NULL;
395 #endif /* POP */
396 continue;
397
398 case SNOOPSW:
399 snoop++;
400 continue;
401
402 case SASLSW:
403 sasl++;
404 continue;
405
406 case SASLMECHSW:
407 if (!(saslmech = *argp++) || *saslmech == '-')
408 adios (NULL, "missing argument to %s", argp[-2]);
409 continue;
410 case PROXYSW:
411 if (!(proxy = *argp++) || *proxy == '-')
412 adios (NULL, "missing argument to %s", argp[-2]);
413 continue;
414 }
415 }
416 if (*cp == '+' || *cp == '@') {
417 if (folder)
418 adios (NULL, "only one folder at a time!");
419 else
420 folder = pluspath (cp);
421 } else {
422 adios (NULL, "usage: %s [+folder] [switches]", invo_name);
423 }
424 }
425
426 /* NOTE: above this point you should use TRYDROPGROUPPRIVS(),
427 * not DROPGROUPPRIVS().
428 */
429 #ifdef POP
430 if (host && !*host)
431 host = NULL;
432 #endif /* POP */
433
434 /* guarantee dropping group priveleges; we might not have done so earlier */
435 DROPGROUPPRIVS();
436
437 /*
438 * Where are we getting the new mail?
439 */
440 if (from)
441 inc_type = INC_FILE;
442 #ifdef POP
443 else if (host)
444 inc_type = INC_POP;
445 #endif
446 else
447 inc_type = INC_FILE;
448
449 #ifdef POP
450 /*
451 * Are we getting the mail from
452 * a POP server?
453 */
454 if (inc_type == INC_POP) {
455 if (user == NULL)
456 user = getusername ();
457 if (sasl)
458 pass = getusername ();
459 else
460 ruserpass (host, &user, &pass);
461
462 /*
463 * initialize POP connection
464 */
465 if (pop_init (host, port, user, pass, proxy, snoop, sasl,
466 saslmech) == NOTOK)
467 adios (NULL, "%s", response);
468
469 /* Check if there are any messages */
470 if (pop_stat (&nmsgs, &nbytes) == NOTOK)
471 adios (NULL, "%s", response);
472
473 if (nmsgs == 0) {
474 pop_quit();
475 adios (NULL, "no mail to incorporate");
476 }
477 }
478 #endif /* POP */
479
480 /*
481 * We will get the mail from a file
482 * (typically the standard maildrop)
483 */
484
485 if (inc_type == INC_FILE) {
486 if (from)
487 newmail = from;
488 else if ((newmail = getenv ("MAILDROP")) && *newmail)
489 newmail = m_mailpath (newmail);
490 else if ((newmail = context_find ("maildrop")) && *newmail)
491 newmail = m_mailpath (newmail);
492 else {
493 newmail = concat (MAILDIR, "/", MAILFIL, NULL);
494 }
495 if (stat (newmail, &s1) == NOTOK || s1.st_size == 0)
496 adios (NULL, "no mail to incorporate");
497 if (s1.st_mode & S_IFDIR) {
498 DIR *md;
499 struct dirent *de;
500 struct stat ms;
501 int i;
502 i = 0;
503 cp = concat (newmail, "/new", NULL);
504 if ((md = opendir(cp)) == NULL)
505 adios (NULL, "unable to open %s", cp);
506 while ((de = readdir (md)) != NULL) {
507 if (de->d_name[0] == '.')
508 continue;
509 if (i >= num_maildir_entries) {
510 if ((Maildir = realloc(Maildir, sizeof(*Maildir) * (2*i+16))) == NULL)
511 adios(NULL, "not enough memory for %d messages", 2*i+16);
512 num_maildir_entries = 2*i+16;
513 }
514 Maildir[i].filename = concat (cp, "/", de->d_name, NULL);
515 if (stat(Maildir[i].filename, &ms) != 0)
516 adios (Maildir[i].filename, "couldn't get delivery time");
517 Maildir[i].mtime = ms.st_mtime;
518 i++;
519 }
520 free (cp);
521 closedir (md);
522 cp = concat (newmail, "/cur", NULL);
523 if ((md = opendir(cp)) == NULL)
524 adios (NULL, "unable to open %s", cp);
525 while ((de = readdir (md)) != NULL) {
526 if (de->d_name[0] == '.')
527 continue;
528 if (i >= num_maildir_entries) {
529 if ((Maildir = realloc(Maildir, sizeof(*Maildir) * (2*i+16))) == NULL)
530 adios(NULL, "not enough memory for %d messages", 2*i+16);
531 num_maildir_entries = 2*i+16;
532 }
533 Maildir[i].filename = concat (cp, "/", de->d_name, NULL);
534 if (stat(Maildir[i].filename, &ms) != 0)
535 adios (Maildir[i].filename, "couldn't get delivery time");
536 Maildir[i].mtime = ms.st_mtime;
537 i++;
538 }
539 free (cp);
540 closedir (md);
541 if (i == 0)
542 adios (NULL, "no mail to incorporate");
543 num_maildir_entries = i;
544 qsort (Maildir, num_maildir_entries, sizeof(*Maildir), maildir_srt);
545 }
546
547 if ((cp = strdup(newmail)) == (char *)0)
548 adios (NULL, "error allocating memory to copy newmail");
549
550 newmail = cp;
551 }
552
553 #ifdef POP
554 /* skip the folder setup */
555 if ((inc_type == INC_POP) && packfile)
556 goto go_to_it;
557 #endif /* POP */
558
559 if (!context_find ("path"))
560 free (path ("./", TFOLDER));
561 if (!folder)
562 folder = getfolder (0);
563 maildir = m_maildir (folder);
564
565 if ((maildir_copy = strdup(maildir)) == (char *)0)
566 adios (maildir, "error allocating memory to copy maildir");
567
568 if (!folder_exists(maildir)) {
569 /* If the folder doesn't exist, and we're given the -silent flag,
570 * just fail.
571 */
572 if (noisy)
573 create_folder(maildir, 0, done);
574 else
575 done (1);
576 }
577
578 if (chdir (maildir) == NOTOK)
579 adios (maildir, "unable to change directory to");
580
581 /* read folder and create message structure */
582 if (!(mp = folder_read (folder)))
583 adios (NULL, "unable to read folder %s", folder);
584
585 #ifdef POP
586 go_to_it:
587 #endif /* POP */
588
589 if (inc_type == INC_FILE && Maildir == NULL) {
590 if (access (newmail, W_OK) != NOTOK) {
591 locked++;
592 if (trnflag) {
593 SIGNAL (SIGHUP, SIG_IGN);
594 SIGNAL (SIGINT, SIG_IGN);
595 SIGNAL (SIGQUIT, SIG_IGN);
596 SIGNAL (SIGTERM, SIG_IGN);
597 }
598
599 GETGROUPPRIVS(); /* Reset gid to lock mail file */
600 in = lkfopen (newmail, "r");
601 DROPGROUPPRIVS();
602 if (in == NULL)
603 adios (NULL, "unable to lock and fopen %s", newmail);
604 fstat (fileno(in), &s1);
605 } else {
606 trnflag = 0;
607 if ((in = fopen (newmail, "r")) == NULL)
608 adios (newmail, "unable to read");
609 }
610 }
611
612 /* This shouldn't be necessary but it can't hurt. */
613 DROPGROUPPRIVS();
614
615 if (audfile) {
616 int i;
617 if ((i = stat (audfile, &st)) == NOTOK)
618 advise (NULL, "Creating Receive-Audit: %s", audfile);
619 if ((aud = fopen (audfile, "a")) == NULL)
620 adios (audfile, "unable to append to");
621 else if (i == NOTOK)
622 chmod (audfile, m_gmprot ());
623
624 #ifdef POP
625 fprintf (aud, from ? "<<inc>> %s -ms %s\n"
626 : host ? "<<inc>> %s -host %s -user %s\n"
627 : "<<inc>> %s\n",
628 dtimenow (0), from ? from : host, user);
629 #else /* POP */
630 fprintf (aud, from ? "<<inc>> %s -ms %s\n" : "<<inc>> %s\n",
631 dtimenow (0), from);
632 #endif /* POP */
633 }
634
635 #ifdef MHE
636 if (context_find ("mhe")) {
637 int i;
638 cp = concat (maildir, "/++", NULL);
639 i = stat (cp, &st);
640 if ((mhe = fopen (cp, "a")) == NULL)
641 admonish (cp, "unable to append to");
642 else
643 if (i == NOTOK)
644 chmod (cp, m_gmprot ());
645 free (cp);
646 }
647 #endif /* MHE */
648
649 /* Get new format string */
650 nfs = new_fs (form, format, FORMAT);
651
652 if (noisy) {
653 printf ("Incorporating new mail into %s...\n\n", folder);
654 fflush (stdout);
655 }
656
657 #ifdef POP
658 /*
659 * Get the mail from a POP server
660 */
661 if (inc_type == INC_POP) {
662 int i;
663 if (packfile) {
664 packfile = path (packfile, TFILE);
665 if (stat (packfile, &st) == NOTOK) {
666 if (errno != ENOENT)
667 adios (packfile, "error on file");
668 cp = concat ("Create file \"", packfile, "\"? ", NULL);
669 if (noisy && !getanswer (cp))
670 done (1);
671 free (cp);
672 }
673 msgnum = map_count ();
674 if ((pd = mbx_open (packfile, mbx_style, getuid(), getgid(), m_gmprot()))
675 == NOTOK)
676 adios (packfile, "unable to open");
677 if ((pf = fdopen (pd, "w+")) == NULL)
678 adios (NULL, "unable to fdopen %s", packfile);
679 } else {
680 hghnum = msgnum = mp->hghmsg;
681 /*
682 * Check if we have enough message space for all the new
683 * messages. If not, then realloc the folder and add enough
684 * space for all new messages plus 10 additional slots.
685 */
686 if (mp->hghmsg + nmsgs >= mp->hghoff
687 && !(mp = folder_realloc (mp, mp->lowoff, mp->hghmsg + nmsgs + 10)))
688 adios (NULL, "unable to allocate folder storage");
689 }
690
691 for (i = 1; i <= nmsgs; i++) {
692 msgnum++;
693 if (packfile) {
694 fseek (pf, 0L, SEEK_CUR);
695 pos = ftell (pf);
696 size = 0;
697 fwrite (mmdlm1, 1, strlen (mmdlm1), pf);
698 start = ftell (pf);
699
700 if (pop_retr (i, pop_pack) == NOTOK)
701 adios (NULL, "%s", response);
702
703 fseek (pf, 0L, SEEK_CUR);
704 stop = ftell (pf);
705 if (fflush (pf))
706 adios (packfile, "write error on");
707 fseek (pf, start, SEEK_SET);
708 } else {
709 cp = getcpy (m_name (msgnum));
710 if ((pf = fopen (cp, "w+")) == NULL)
711 adios (cp, "unable to write");
712 chmod (cp, m_gmprot ());
713 start = stop = 0L;
714
715 if (pop_retr (i, pop_action) == NOTOK)
716 adios (NULL, "%s", response);
717
718 if (fflush (pf))
719 adios (cp, "write error on");
720 fseek (pf, 0L, SEEK_SET);
721 }
722 switch (incerr = scan (pf, msgnum, 0, nfs, width,
723 packfile ? 0 : msgnum == mp->hghmsg + 1 && chgflag,
724 1, NULL, stop - start, noisy)) {
725 case SCNEOF:
726 printf ("%*d empty\n", DMAXFOLDER, msgnum);
727 break;
728
729 case SCNFAT:
730 trnflag = 0;
731 noisy++;
732 /* advise (cp, "unable to read"); already advised */
733 /* fall thru */
734
735 case SCNERR:
736 case SCNNUM:
737 break;
738
739 case SCNMSG:
740 case SCNENC:
741 default:
742 if (aud)
743 fputs (scanl, aud);
744 # ifdef MHE
745 if (mhe)
746 fputs (scanl, mhe);
747 # endif /* MHE */
748 if (noisy)
749 fflush (stdout);
750 if (!packfile) {
751 clear_msg_flags (mp, msgnum);
752 set_exists (mp, msgnum);
753 set_unseen (mp, msgnum);
754 mp->msgflags |= SEQMOD;
755 }
756 break;
757 }
758 if (packfile) {
759 fseek (pf, stop, SEEK_SET);
760 fwrite (mmdlm2, 1, strlen (mmdlm2), pf);
761 if (fflush (pf) || ferror (pf)) {
762 int e = errno;
763 pop_quit ();
764 errno = e;
765 adios (packfile, "write error on");
766 }
767 map_write (packfile, pd, 0, 0L, start, stop, pos, size, noisy);
768 } else {
769 if (ferror(pf) || fclose (pf)) {
770 int e = errno;
771 unlink (cp);
772 pop_quit ();
773 errno = e;
774 adios (cp, "write error on");
775 }
776 free (cp);
777 }
778
779 if (trnflag && pop_dele (i) == NOTOK)
780 adios (NULL, "%s", response);
781 }
782
783 if (pop_quit () == NOTOK)
784 adios (NULL, "%s", response);
785 if (packfile) {
786 mbx_close (packfile, pd);
787 pd = NOTOK;
788 }
789 }
790 #endif /* POP */
791
792 /*
793 * Get the mail from file (usually mail spool)
794 */
795 if (inc_type == INC_FILE && Maildir == NULL) {
796 m_unknown (in); /* the MAGIC invocation... */
797 hghnum = msgnum = mp->hghmsg;
798 for (;;) {
799 /*
800 * Check if we need to allocate more space for message status.
801 * If so, then add space for an additional 100 messages.
802 */
803 if (msgnum >= mp->hghoff
804 && !(mp = folder_realloc (mp, mp->lowoff, mp->hghoff + 100))) {
805 advise (NULL, "unable to allocate folder storage");
806 incerr = NOTOK;
807 break;
808 }
809
810 #if 0
811 /* copy file from spool to tmp file */
812 tmpfilenam = m_scratch ("", invo_name);
813 if ((fd = creat (tmpfilenam, m_gmprot ())) == NOTOK)
814 adios (tmpfilenam, "unable to create");
815 chmod (tmpfilenam, m_gmprot ());
816 if (!(in2 = fdopen (fd, "r+")))
817 adios (tmpfilenam, "unable to access");
818 cpymsg (in, in2);
819
820 /* link message into folder */
821 newmsg = folder_addmsg(mp, tmpfilenam);
822 #endif
823 /* create scanline for new message */
824 switch (incerr = scan (in, msgnum + 1, msgnum + 1, nfs, width,
825 msgnum == hghnum && chgflag, 1, NULL, 0L, noisy)) {
826 case SCNFAT:
827 case SCNEOF:
828 break;
829
830 case SCNERR:
831 if (aud)
832 fputs ("inc aborted!\n", aud);
833 advise (NULL, "aborted!"); /* doesn't clean up locks! */
834 break;
835
836 case SCNNUM:
837 advise (NULL, "BUG in %s, number out of range", invo_name);
838 break;
839
840 default:
841 advise (NULL, "BUG in %s, scan() botch (%d)", invo_name, incerr);
842 break;
843
844 case SCNMSG:
845 case SCNENC:
846 /*
847 * Run the external program hook on the message.
848 */
849
850 (void)snprintf(b, sizeof (b), "%s/%d", maildir_copy, msgnum + 1);
851 (void)ext_hook("add-hook", b, (char *)0);
852
853 if (aud)
854 fputs (scanl, aud);
855 #ifdef MHE
856 if (mhe)
857 fputs (scanl, mhe);
858 #endif /* MHE */
859 if (noisy)
860 fflush (stdout);
861
862 msgnum++;
863 mp->hghmsg++;
864 mp->nummsg++;
865 if (mp->lowmsg == 0) mp->lowmsg = 1;
866
867 clear_msg_flags (mp, msgnum);
868 set_exists (mp, msgnum);
869 set_unseen (mp, msgnum);
870 mp->msgflags |= SEQMOD;
871 continue;
872 }
873 /* If we get here there was some sort of error from scan(),
874 * so stop processing anything more from the spool.
875 */
876 break;
877 }
878 } else if (inc_type == INC_FILE) { /* Maildir inbox to process */
879 char *sp;
880 FILE *sf;
881 int i;
882
883 hghnum = msgnum = mp->hghmsg;
884 for (i = 0; i < num_maildir_entries; i++) {
885 msgnum++;
886 /*
887 * Check if we need to allocate more space for message status.
888 * If so, then add space for an additional 100 messages.
889 */
890 if (msgnum >= mp->hghoff
891 && !(mp = folder_realloc (mp, mp->lowoff, mp->hghoff + 100))) {
892 advise (NULL, "unable to allocate folder storage");
893 incerr = NOTOK;
894 break;
895 }
896
897 sp = Maildir[i].filename;
898 cp = getcpy (m_name (msgnum));
899 pf = NULL;
900 if (!trnflag || link(sp, cp) == -1) {
901 static char buf[65536];
902 size_t nrd;
903
904 if ((sf = fopen (sp, "r")) == NULL)
905 adios (sp, "unable to read for copy");
906 if ((pf = fopen (cp, "w+")) == NULL)
907 adios (cp, "unable to write for copy");
908 while ((nrd = fread(buf, 1, sizeof(buf), sf)) > 0)
909 if (fwrite(buf, 1, nrd, pf) != nrd)
910 break;
911 if (ferror(sf) || fflush(pf) || ferror(pf)) {
912 int e = errno;
913 fclose(pf); fclose(sf); unlink(cp);
914 errno = e;
915 adios(cp, "copy error %s -> %s", sp, cp);
916 }
917 fclose (sf);
918 sf = NULL;
919 }
920 if (pf == NULL && (pf = fopen (cp, "r")) == NULL)
921 adios (cp, "not available");
922 chmod (cp, m_gmprot ());
923
924 fseek (pf, 0L, SEEK_SET);
925 switch (incerr = scan (pf, msgnum, 0, nfs, width,
926 msgnum == mp->hghmsg + 1 && chgflag,
927 1, NULL, stop - start, noisy)) {
928 case SCNEOF:
929 printf ("%*d empty\n", DMAXFOLDER, msgnum);
930 break;
931
932 case SCNFAT:
933 trnflag = 0;
934 noisy++;
935 /* advise (cp, "unable to read"); already advised */
936 /* fall thru */
937
938 case SCNERR:
939 case SCNNUM:
940 break;
941
942 case SCNMSG:
943 case SCNENC:
944 default:
945 /*
946 * Run the external program hook on the message.
947 */
948
949 (void)snprintf(b, sizeof (b), "%s/%d", maildir_copy, msgnum + 1);
950 (void)ext_hook("add-hook", b, (char *)0);
951
952 if (aud)
953 fputs (scanl, aud);
954 # ifdef MHE
955 if (mhe)
956 fputs (scanl, mhe);
957 # endif /* MHE */
958 if (noisy)
959 fflush (stdout);
960 if (!packfile) {
961 clear_msg_flags (mp, msgnum);
962 set_exists (mp, msgnum);
963 set_unseen (mp, msgnum);
964 mp->msgflags |= SEQMOD;
965 }
966 break;
967 }
968 if (ferror(pf) || fclose (pf)) {
969 int e = errno;
970 unlink (cp);
971 errno = e;
972 adios (cp, "write error on");
973 }
974 pf = NULL;
975 free (cp);
976
977 if (trnflag && unlink (sp) == NOTOK)
978 adios (sp, "couldn't unlink");
979 free (sp); /* Free Maildir[i]->filename */
980 }
981 free (Maildir); /* From now on Maildir is just a flag - don't dref! */
982 }
983
984 if (incerr < 0) { /* error */
985 if (locked) {
986 GETGROUPPRIVS(); /* Be sure we can unlock mail file */
987 (void) lkfclose (in, newmail); in = NULL;
988 DROPGROUPPRIVS(); /* And then return us to normal privileges */
989 } else {
990 fclose (in); in = NULL;
991 }
992 adios (NULL, "failed");
993 }
994
995 if (aud)
996 fclose (aud);
997
998 #ifdef MHE
999 if (mhe)
1000 fclose (mhe);
1001 #endif /* MHE */
1002
1003 if (noisy)
1004 fflush (stdout);
1005
1006 #ifdef POP
1007 if ((inc_type == INC_POP) && packfile)
1008 done (0);
1009 #endif /* POP */
1010
1011 /*
1012 * truncate file we are incorporating from
1013 */
1014 if (inc_type == INC_FILE && Maildir == NULL) {
1015 if (trnflag) {
1016 if (stat (newmail, &st) != NOTOK && s1.st_mtime != st.st_mtime)
1017 advise (NULL, "new messages have arrived!\007");
1018 else {
1019 int newfd;
1020 if ((newfd = creat (newmail, 0600)) != NOTOK)
1021 close (newfd);
1022 else
1023 admonish (newmail, "error zero'ing");
1024 unlink(map_name(newmail));
1025 }
1026 } else {
1027 if (noisy)
1028 printf ("%s not zero'd\n", newmail);
1029 }
1030 }
1031
1032 if (msgnum == hghnum) {
1033 admonish (NULL, "no messages incorporated");
1034 } else {
1035 context_replace (pfolder, folder); /* update current folder */
1036 if (chgflag)
1037 mp->curmsg = hghnum + 1;
1038 mp->hghmsg = msgnum;
1039 if (mp->lowmsg == 0)
1040 mp->lowmsg = 1;
1041 if (chgflag) /* sigh... */
1042 seq_setcur (mp, mp->curmsg);
1043 }
1044
1045 /*
1046 * unlock the mail spool
1047 */
1048 if (inc_type == INC_FILE && Maildir == NULL) {
1049 if (locked) {
1050 GETGROUPPRIVS(); /* Be sure we can unlock mail file */
1051 (void) lkfclose (in, newmail); in = NULL;
1052 DROPGROUPPRIVS(); /* And then return us to normal privileges */
1053 } else {
1054 fclose (in); in = NULL;
1055 }
1056 }
1057
1058 seq_setunseen (mp, 0); /* set the Unseen-Sequence */
1059 seq_save (mp); /* synchronize sequences */
1060 context_save (); /* save the context file */
1061 done (0);
1062 return 1;
1063 }
1064
1065
1066 #if 0
1067
1068 /*
1069 * Copy message message from spool into
1070 * temporary file. Massage the "From " line
1071 * while copying.
1072 */
1073
1074 cpymsg (FILE *in, FILE *out)
1075 {
1076 int state;
1077 char *tmpbuf, name[NAMESZ];
1078
1079 for (;;) {
1080 state = m_getfld (state, name, tmpbuf, rlwidth, in);
1081 switch (state) {
1082 case FLD:
1083 case FLDPLUS:
1084 break;
1085 case BODY:
1086 break;
1087 case LENERR:
1088 case FMTERR:
1089 break;
1090 case FILEEOF:
1091 break;
1092 default:
1093 }
1094 }
1095 }
1096 #endif /* if 0 */
1097
1098
1099 static void
1100 inc_done (int status)
1101 {
1102 #ifdef POP
1103 if (packfile && pd != NOTOK)
1104 mbx_close (packfile, pd);
1105 #endif /* POP */
1106 if (locked)
1107 {
1108 GETGROUPPRIVS();
1109 lkfclose(in, newmail);
1110 DROPGROUPPRIVS();
1111 }
1112 exit (status);
1113 }
1114
1115 #ifdef POP
1116 static int
1117 pop_action (char *s)
1118 {
1119 fprintf (pf, "%s\n", s);
1120 stop += strlen (s) + 1;
1121 return 0; /* Is return value used? This was missing before 1999-07-15. */
1122 }
1123
1124 static int
1125 pop_pack (char *s)
1126 {
1127 int j;
1128 char buffer[BUFSIZ];
1129
1130 snprintf (buffer, sizeof(buffer), "%s\n", s);
1131 for (j = 0; (j = stringdex (mmdlm1, buffer)) >= 0; buffer[j]++)
1132 continue;
1133 for (j = 0; (j = stringdex (mmdlm2, buffer)) >= 0; buffer[j]++)
1134 continue;
1135 fputs (buffer, pf);
1136 size += strlen (buffer) + 1;
1137 return 0; /* Is return value used? This was missing before 1999-07-15. */
1138 }
1139
1140 static int
1141 map_count (void)
1142 {
1143 int md;
1144 char *cp;
1145 struct drop d;
1146 struct stat st;
1147
1148 if (stat (packfile, &st) == NOTOK)
1149 return 0;
1150 if ((md = open (cp = map_name (packfile), O_RDONLY)) == NOTOK
1151 || map_chk (cp, md, &d, (long) st.st_size, 1)) {
1152 if (md != NOTOK)
1153 close (md);
1154 return 0;
1155 }
1156 close (md);
1157 return (d.d_id);
1158 }
1159 #endif /* POP */