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