chiark / gitweb /
update debian version
[inn-innduct.git] / innfeed / main.c
1 /*  $Id: main.c 6956 2004-06-29 22:41:35Z rra $
2 **
3 **  Main routines for the innfeed program.
4 **
5 **  Written by James Brister <brister@vix.com>
6 */
7
8 #include "innfeed.h"
9 #include "config.h"
10 #include "clibrary.h"
11 #include "portable/socket.h"
12 #include "portable/time.h"
13
14 #include <assert.h>
15 #include <ctype.h>
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <math.h>
19 #include <netdb.h>
20 #include <signal.h>
21 #include <sys/stat.h>
22 #include <syslog.h>
23
24 #if defined(HAVE_UNIX_DOMAIN_SOCKETS)
25 # include <sys/un.h>
26 #endif
27
28 #include "inn/innconf.h"
29 #include "inn/messages.h"
30 #include "libinn.h"
31 #include "storage.h"
32
33 #include "article.h"
34 #include "buffer.h"
35 #include "configfile.h"
36 #include "connection.h"
37 #include "endpoint.h"
38 #include "host.h"
39 #include "innlistener.h"
40 #include "misc.h"
41 #include "tape.h"
42
43 #define INHERIT 1
44 #define NO_INHERIT 0
45
46 /* exports */
47 bool talkToSelf ;
48 extern int debugWrites ;
49 bool sigFlag = false ;
50 const char *InputFile ;
51 char *configFile = NULL ;
52 bool RollInputFile = false ;
53 char *pidFile = NULL ;
54 bool useMMap = false ;
55 void (*gPrintInfo) (void) ;
56 char *dflTapeDir;
57 /* these are used by imapfeed */
58 char *deliver_username  = NULL;
59 char *deliver_authname  = NULL;
60 char *deliver_password  = NULL;
61 char *deliver_realm     = NULL;
62 const char *deliver_rcpt_to   = "+%s";
63 char *deliver_to_header = NULL;
64
65 /* imports */
66 extern char *versionInfo ;
67 #if defined (sun)
68 extern char *optarg ;           /* needed for Solaris */
69 extern int optind;
70 #endif
71 extern bool genHtml ;
72
73 extern void openInputFile (void);
74
75 /* privates */
76 static char *logFile ;
77 static char *newsspool ;
78
79 static void sigemt (int sig) ;
80 static void sigalrm (int sig) ;
81 static void sigchld (int sig) ;
82 static void sigint (int sig) ;
83 static void sigquit (int sig) ;
84 static void sighup (int sig) ;
85 static void sigterm (int sig) ;
86 static void sigusr (int sig) ;
87 static void usage (int) ;
88 static void gprintinfo (void) ;
89 static void openLogFile (void) ;
90 static void writePidFile (void) ;
91 static int mainOptionsProcess (void *data) ;
92 static int mainConfigLoadCbk (void *data) ;
93 static void mainCleanup (void) ;
94
95 static char *bopt = NULL ;
96 static char *aopt = NULL ;
97 static char *popt = NULL ;
98 static bool Mopt = false ;
99 static bool Zopt = false ;
100 static bool Dopt = false ;
101 static int debugLevel = 0 ;
102 static unsigned int initialSleep = 2 ;
103 static char *sopt = NULL ;
104 static char *lopt = NULL ;
105 static bool eopt = false ;
106 static int elimit = 0 ;
107
108 int main (int argc, char **argv)
109 {
110   EndPoint ep ;
111   InnListener listener ;
112   int optVal, fd, rval ;
113   const char *subProgram = NULL ;
114   bool seenV = false ;
115   bool dynamicPeers = false ;
116   time_t now = theTime() ;
117   char dateString [30] ;
118   char *copt = NULL ;
119   char *debugFile;
120   bool checkConfig = false ;
121   bool val;
122
123   strlcpy (dateString,ctime(&now),sizeof (dateString)) ;
124
125   message_program_name = strrchr (argv [0],'/');
126   if (message_program_name == NULL)
127     message_program_name = argv [0] ;
128   else
129     message_program_name++;
130
131   gPrintInfo = gprintinfo ;
132
133   openlog (message_program_name,(int)(L_OPENLOG_FLAGS|LOG_PID),LOG_INN_PROG) ;
134   if (!innconf_read(NULL)) {
135       syslog(LOG_ERR, "cant read inn.conf\n");
136       exit(1);
137   }
138
139 #if defined (HAVE_MMAP)
140   useMMap = true ;
141 #else
142   useMMap = false ;
143 #endif
144
145   message_handlers_die (2, error_log_stderr_date, message_log_syslog_err) ;
146   message_handlers_warn (1, message_log_syslog_warning);
147   message_handlers_notice (1, message_log_syslog_notice) ;
148
149 #define OPT_STRING "a:b:c:Cd:e:hl:mMo:p:S:s:vxyz"
150
151   while ((optVal = getopt (argc,argv,OPT_STRING)) != EOF)
152     {
153       switch (optVal) 
154         {
155           case 'a':
156             aopt = optarg ;
157             break ;
158
159           case 'b':
160             if ( !isDirectory (optarg) )
161               logAndExit (1,"Not a directory: %s\n",optarg) ;
162             bopt = optarg ;
163             break ;
164
165           case 'C':
166             checkConfig = true ;
167             break ;
168
169           case 'c':
170             copt = optarg ;
171             break ;
172
173           case 'd':
174             loggingLevel = atoi (optarg) ;
175             debugLevel = loggingLevel ;
176             Dopt = true ;
177             break ;
178
179           case 'e':
180             eopt = true ;
181             elimit = atoi (optarg) ;
182             if (elimit <= 0)
183               {
184                 fprintf (stderr,"Illegal value for -e option\n") ;
185                 usage (1) ;
186               }
187             break ;
188
189           case 'h':
190             usage (0) ;
191
192           case 'l':
193             lopt = optarg ;
194             break ;
195
196           case 'M':
197             Mopt = true ;
198             useMMap = false ;
199             break ;
200
201           case 'm':
202             artLogMissingArticles (true) ;
203             break ;
204
205           case 'o':
206             artSetMaxBytesInUse (atoi (optarg)) ;
207             break ;
208
209           case 'p':
210             popt = optarg ;
211             break ;
212
213           case 's':
214             subProgram = optarg ;
215             break ;
216
217           case 'S':
218             sopt = optarg ;
219             break ;
220
221           case 'v':
222             seenV = true ;
223             break ;
224
225           case 'x':
226             talkToSelf = true ;
227             break ;
228
229           case 'y':
230             dynamicPeers = true ;
231             break ;
232
233           case 'z':
234             Zopt = true ;
235             break ;
236
237           default:
238             usage (1) ; 
239         }
240     }
241
242   argc -= optind;
243   argv += optind;
244
245   if (argc > 1)
246     usage (1) ;
247   else if (argc == 1)
248     InputFile = *argv;
249
250   if (seenV)
251     {
252       warn ("%s version: %s\n",message_program_name, versionInfo) ;
253       exit (0) ;
254     }
255
256   /* make sure we have valid fds 0, 1 & 2 so it is not taken by
257     something else, probably openlog().  fd 0 will be freopen()ed on the
258     inputFile, the subProgram, or ourself.  fd 1 and fd 2 will
259     be freopen()ed on the log file (or will stay pointed at /dev/null).
260     
261     without doing this, if the descriptors were closed then the
262     freopen calls on some systems (like BSDI 2.1) will really close
263     whatever has aquired the stdio descriptors, such as the socket
264     to syslogd.
265     
266     XXX possible problems:  what if fd 0 is closed but no inputFile,
267     XXX subProgram or talkToSelf is true?  it will not be freopen()ed, so
268     XXX innfeed won't have any fresh data (besides, fd 0 is only writable
269     XXX here).  perhaps a warning should be issued.
270     */
271   do
272     {
273       fd = open("/dev/null", O_WRONLY);
274       switch (fd)
275         {
276           case -1:
277             logAndExit (1,"open(\"/dev/null\", O_WRONLY): %s",
278                         strerror (errno));
279             break;
280           case 0:
281           case 1:
282           case 2:
283             /* good, we saved an fd from being trounced */
284             break;
285           default:
286             close(fd);
287         }
288     } while (fd < 2);
289
290   if ( !checkConfig ) 
291     {
292       notice ("ME starting %s at %s", versionInfo, dateString) ;
293     }
294
295   val = true;
296   if (!SMsetup(SM_PREOPEN, (void *)&val)) {
297       syslog(LOG_ERR, "cant setup the storage subsystem\n");
298       exit(1);
299   }
300   if (!SMinit()) {
301       d_printf(0, "Storage manager initialization failed\n");
302       syslog(LOG_ERR, "Storage manager initialization failed\n");
303       exit(1);
304   }
305
306   if (subProgram == NULL && talkToSelf == false)
307     {
308       struct stat buf ;
309
310       if (fstat (0,&buf) < 0)
311         logAndExit (1,"ME oserr fstat stdin: %s", strerror (errno)) ;
312       else if (S_ISREG (buf.st_mode))
313         InputFile = "";
314     }
315
316   /*
317    * set up the config file name and then read the file in. Order is important.
318    */
319   configAddLoadCallback (mainOptionsProcess,(checkConfig ? stderr : NULL)) ;
320   configAddLoadCallback (tapeConfigLoadCbk,(checkConfig ? stderr : NULL)) ;
321
322   configAddLoadCallback (endpointConfigLoadCbk,(checkConfig ? stderr : NULL));
323   configAddLoadCallback (hostConfigLoadCbk,(checkConfig ? stderr : NULL)) ;
324   configAddLoadCallback (cxnConfigLoadCbk,(checkConfig ? stderr : NULL)) ;
325   configAddLoadCallback (mainConfigLoadCbk,(checkConfig ? stderr : NULL)) ;
326   configAddLoadCallback (listenerConfigLoadCbk,(checkConfig ? stderr : NULL));
327
328   if (copt != NULL && *copt == '\0')
329     {
330       logOrPrint (LOG_CRIT,(checkConfig ? stderr : NULL),
331                   "Empty pathname for ``-c'' option") ;
332       exit (1) ;
333     }
334   configFile = buildFilename(innconf->pathetc, copt ? copt : CONFIG_FILE);
335   dflTapeDir = buildFilename(innconf->pathspool, TAPE_DIRECTORY);
336
337   rval = readConfig (configFile,(checkConfig ? stderr : NULL),
338                      checkConfig,loggingLevel > 0);
339
340   if (subProgram != NULL && (talkToSelf == true || InputFile))
341     {
342       d_printf (0,"Cannot specify '-s' with '-x' or an input file\n") ;
343       syslog (LOG_ERR,"Incorrect arguments: '-s' with '-x' or an input file\n");
344       usage (1) ;
345     }
346
347   if (checkConfig)
348     {
349       if (!rval)
350         {
351           fprintf (stderr,"config loading failed.\n") ;
352           exit (1) ;
353         }
354       else
355         {
356           fprintf (stderr,"config loading succeeded.\n") ;
357           exit (0) ;
358         }
359     }
360   else if (!rval)
361     exit (1) ;
362
363   debugFile = buildFilename (innconf->pathlog, DEBUG_FILE);
364   if (loggingLevel == 0 && fileExistsP (debugFile))
365     loggingLevel = 1 ;
366
367   if (logFile == NULL && ! isatty (fileno (stderr)))
368     logFile = buildFilename (innconf->pathlog, LOG_FILE) ;
369
370   if (logFile)
371     openLogFile () ;
372
373   openfds = 4 ;                 /* stdin, stdout, stderr and syslog */
374
375   writePidFile ();
376
377   if (subProgram != NULL)
378     {
379       int fds [2] ;
380       int pid ;
381
382       if (pipe (fds) < 0)
383         sysdie ("ME fatal pipe") ;
384
385       if ((pid = fork ()) < 0)
386         {
387           sysdie ("ME fatal fork") ;
388         }
389       else if (pid == 0)
390         {                       /* child */
391           close (fds[0]) ;
392           close (0) ;
393           close (1) ;
394           close (2) ;
395           dup2 (fds[1],1) ;
396           dup2 (fds[1],2) ;
397           execlp ("sh", "sh", "-c", subProgram, (char *) 0) ;
398           perror ("execlp") ;
399           exit (1) ;
400         }
401       else
402         {                       /* parent */
403           close (0) ;
404           dup2 (fds[0],0) ;
405           close (fds[1]) ;
406           xsignal(SIGCHLD,sigchld) ;
407           openfds++ ;
408         }
409     }
410   else  if (talkToSelf)
411     {
412         /* We're not really getting information from innd or a subprogram,
413            but are just processing backlog files. We set up a pipe to ourself
414            that we never write to, to simulate an idle innd. */
415       int pipefds [2] ;
416
417       if (pipe (pipefds) != 0)
418         sysdie ("ME fatal pipe") ;
419
420       close (0) ;
421       dup2 (pipefds [0], 0) ;
422
423       openfds++ ;
424       openfds++ ;
425     }
426
427   if (chdir (newsspool) != 0)
428     sysdie ("ME fatal chdir %s", newsspool) ;
429
430     /* hook up the endpoint to the source of new article information (usually
431        innd). */
432   ep = newEndPoint (0) ;        /* fd 0, i.e. stdin */
433
434     /* now arrange for this endpoint to always be the first one checked for
435        possible activity. */
436   setMainEndPoint (ep) ;
437
438   listener = newListener (ep, talkToSelf,dynamicPeers) ;
439   mainListener = listener ;
440
441   sleep (initialSleep) ;
442
443   if (innconf->rlimitnofile >= 0)
444     if (setfdlimit (innconf->rlimitnofile) < 0)
445       syswarn ("ME oserr setrlimit(RLIM_NOFILE,%ld)", innconf->rlimitnofile) ;
446
447   if (innconf->timer > 0)
448     TMRinit (TMR_MAX) ;
449
450   configHosts (talkToSelf) ;
451
452   if (InputFile && *InputFile) {
453     openInputFile () ;
454   }
455
456   /* handle signal to shutdown */
457   setSigHandler (SIGTERM,sigterm) ;
458   setSigHandler (SIGQUIT,sigquit) ;
459
460   /* handle signal to reload config */
461   setSigHandler (SIGHUP,sighup) ;
462
463   /* handle signal to print snapshot. */
464   setSigHandler (SIGINT,sigint) ;
465
466   /* handle signal to roll input file */
467   setSigHandler (SIGALRM,sigalrm) ;
468
469   /* handle signal to flush all the backlog files */
470   setSigHandler (SIGCHLD,sigemt) ;
471
472   /* we can increment and decrement logging levels by sending SIGUSR{1,2} */
473   setSigHandler (SIGUSR1,sigusr) ;
474   setSigHandler (SIGUSR2,sigusr) ;
475
476   atexit (mainCleanup) ;
477   
478   Run () ;
479
480   exit (0) ;
481 }
482
483 static void usage (int val)
484 {
485   fprintf (stderr,"usage: %s [ options ] [ file ]\n\n",
486            message_program_name) ;
487   fprintf (stderr,"Version: %s\n\n",versionInfo) ;
488   fprintf (stderr,"Config file: %s\n",CONFIG_FILE) ;
489   fprintf (stderr,"Backlog directory: %s/%s\n", innconf->pathspool, TAPE_DIRECTORY) ;
490   fprintf (stderr,"\nLegal options are:\n") ;
491   fprintf (stderr,"\t-a dir      Use the given directory as the top of the article spool\n") ;
492
493   fprintf (stderr,"\t-b dir      Use the given directory as the the storage\n");
494   fprintf (stderr,"\t            place for backlog files and lock files.\n");
495
496   fprintf (stderr,"\t-c file     Use the given file as the config file instead of the\n");
497   fprintf (stderr,"\t            default of %s\n",CONFIG_FILE);
498
499   fprintf (stderr,"\t-C          Check the config file and then exit.\n") ;
500   fprintf (stderr,"\t-d num      set the logging level to num (an integer).\n");
501   fprintf (stderr,"\t            Larger value means more logging. 0 means no\n");
502   fprintf (stderr,"\t            logging. The default is 0\n");
503
504   fprintf (stderr,"\t-e bytes    Keep the output backlog files to no bigger\n");
505   fprintf (stderr,"\t            than %.2f times this number\n",LIMIT_FUDGE);
506
507   fprintf (stderr,"\t-h          print this message\n");
508
509   fprintf (stderr,"\t-l file     redirect stderr and stdout to the given file.\n");
510   fprintf (stderr,"\t            When run under INN they normally are redirected to\n");
511   fprintf (stderr,"\t            /dev/null. This is needed if using '-d'.\n");
512
513   fprintf (stderr,"\t-m          Log information on all missing articles\n");
514
515   fprintf (stderr,"\t-M          Turn *off* use of mmap\n") ;
516 #if ! defined (HAVE_MMAP)
517   fprintf (stderr,"\t            (a no-op as this excutable has been built without mmap support\n") ;
518 #endif
519
520   fprintf (stderr,"\t-p file     Write the process id to the given file\n") ;
521   fprintf (stderr,"\t            instead of the default of %s\n",PID_FILE);
522   fprintf (stderr,"\t            A relative path is relative to %s\n", innconf->pathrun) ;
523
524   fprintf (stderr,"\t-s command  run the given command in a subprocess and use\n");
525   fprintf (stderr,"\t            its output as article information instead of\n");
526   fprintf (stderr,"\t            running under innd\n");
527
528   fprintf (stderr,"\t-S file     Use the give filename instead of innfeed.status\n") ;
529   fprintf (stderr,"\t            relative pathnames start from %s\n", innconf->pathlog) ;
530
531   fprintf (stderr,"\t-v          print version information\n");
532
533   fprintf (stderr,"\t-x          Do not read any article information off stdin,\n");
534   fprintf (stderr,"\t            but simply process backlog files and then exit\n");
535   fprintf (stderr,"\t            when done\n");
536
537   fprintf (stderr,"\t-y          Add peers dynamically. If an unrecognized peername\n");
538   fprintf (stderr,"\t            is received from innd, then it is presumed to also\n");
539   fprintf (stderr,"\t            be the ip name and a new peer binding is set up\n");
540
541   fprintf (stderr,"\t-z          have each of the connections issue their own stats\n");
542   fprintf (stderr,"\t            whenever they close, or whenever their controller\n");
543   fprintf (stderr,"\t            issues its own stats\n");
544
545   exit (val) ;
546 }
547
548 static void sigterm (int sig UNUSED)
549 {
550   notice ("ME received shutdown signal") ;
551   shutDown (mainListener) ;
552 }
553
554 static void sigquit (int sig UNUSED)
555 {
556   sigterm (0) ;
557 }
558
559 static void sigint (int sig UNUSED)
560 {
561   gprintinfo () ;
562 }
563
564 static void sighup (int sig UNUSED)
565 {
566   notice ("ME reloading config file %s", configFile) ;
567
568   if (!readConfig (configFile,NULL,false,loggingLevel > 0))
569     {
570       die ("ME config aborting, error parsing config file") ;
571     }
572
573   configHosts (talkToSelf) ;
574 }
575
576 static void sigemt (int sig UNUSED)
577 {
578   gFlushTapes () ;
579 }
580
581 static void sigalrm (int sig UNUSED)
582 {
583   if (InputFile == NULL)
584     warn ("ME signal SIGALRM in non-funnel-file mode ignored") ;
585   else 
586     {
587       RollInputFile = true;
588       syslog(LOG_NOTICE, "ME preparing to roll %s", InputFile);
589     }
590 }
591
592 static void sigchld (int sig UNUSED)
593 {
594 #if 0
595   wait (&status) ;              /* we don't care */
596 #endif
597
598   xsignal (sig,sigchld) ;
599 }
600
601   /* SIGUSR1 increments logging level. SIGUSR2 decrements. */
602 static void sigusr (int sig)
603 {
604   if (sig == SIGUSR1) {
605     loggingLevel++ ;
606     notice ("ME increasing logging level to %d", loggingLevel) ;
607   } else if (sig == SIGUSR2 && loggingLevel > 0) {
608     loggingLevel-- ;
609     notice ("ME decreasing logging level to %d", loggingLevel) ;
610   }    
611 }
612
613 static void openLogFile (void)
614 {
615   FILE *fpr ;
616
617   if (logFile)
618     {
619       fpr = freopen (logFile,"a",stdout) ;
620       if (fpr != stdout)
621         logAndExit (1,"freopen (%s, \"a\", stdout): %s",
622                     logFile, strerror (errno)) ;
623       
624       fpr = freopen (logFile,"a",stderr) ;
625       if (fpr != stderr)
626         logAndExit (1,"freopen (%s, \"a\", stderr): %s",
627                     logFile, strerror (errno)) ;
628       
629 #if defined (HAVE_SETBUFFER)
630       setbuffer (stdout, NULL, 0) ;
631       setbuffer (stderr, NULL, 0) ;
632 #else
633       setbuf (stdout, NULL) ;
634       setbuf (stderr, NULL) ;
635 #endif
636     }
637 }
638
639 static void writePidFile (void)
640 {
641   FILE *F;
642   int pid;
643
644   if (pidFile == NULL)
645     logAndExit (1,"NULL pidFile\n") ;
646
647   /* Record our PID. */
648   pid = getpid();
649   if ((F = fopen(pidFile, "w")) == NULL)
650     {
651       syslog(LOG_ERR, "ME cant fopen %s %m", pidFile);
652     }
653   else
654     {
655       if (fprintf(F, "%ld\n", (long)pid) == EOF || ferror(F))
656         {
657           syslog(LOG_ERR, "ME cant fprintf %s %m", pidFile);
658         }
659       if (fclose(F) == EOF)
660         {
661           syslog(LOG_ERR, "ME cant fclose %s %m", pidFile);
662         }
663       if (chmod(pidFile, 0664) < 0)
664         {
665           syslog(LOG_ERR, "ME cant chmod %s %m", pidFile);
666         }
667     }
668 }
669
670 static void gprintinfo (void)
671 {
672   char *snapshotFile;
673   FILE *fp;
674   time_t now = theTime() ;
675
676   snapshotFile = buildFilename(innconf->pathlog, SNAPSHOT_FILE);
677   fp = fopen (snapshotFile,"a") ;
678   if (fp == NULL)
679     {
680       syswarn ("ME fopen %s", snapshotFile) ;
681       free(snapshotFile);
682       return ;
683     }
684   free(snapshotFile);
685
686 #if defined (HAVE_SETBUFFER)
687   setbuffer (fp, NULL, 0) ;
688 #else
689   setbuf (fp, NULL) ;
690 #endif
691
692   fprintf (fp,"----------------------------System snaphot taken at: %s\n",
693            ctime (&now)) ;
694   gPrintListenerInfo (fp,0) ;
695   fprintf (fp,"\n\n\n\n") ;
696   gPrintHostInfo (fp,0) ;
697   fprintf (fp,"\n\n\n\n") ;
698   gPrintCxnInfo (fp,0) ;
699   fprintf (fp,"\n\n\n\n") ;
700   gPrintArticleInfo (fp,0) ;
701   fprintf (fp,"\n\n\n\n") ;
702   gPrintBufferInfo (fp,0) ;
703   fprintf (fp,"\n\n\n\n") ;
704   fclose (fp) ;
705 }
706
707 /* called after the config file is loaded and after the config data has
708   been updated with command line options. */
709 static int mainConfigLoadCbk (void *data)
710 {
711   FILE *fp = (FILE *) data ;
712   char *p ;
713   long ival ;
714   int bval ;
715
716   if (getString (topScope,"news-spool", &p,NO_INHERIT))
717     {
718       if ( !isDirectory (p) && isDirectory (innconf->patharticles) )
719         {
720           logOrPrint (LOG_WARNING,fp,
721                       "ME config: definition of news-spool (%s) is a"
722                       " non-existant directory. Using %s",p,
723                       innconf->patharticles) ;
724           p = xstrdup (innconf->patharticles) ;
725         }
726       else if (!isDirectory (p))
727         logAndExit (1,"Bad spool directories: %s, %s\n",p,innconf->patharticles) ;
728     }
729   else if (!isDirectory (innconf->patharticles))
730     logAndExit (1,"ME config: no definition of news-spool, and %s is no good",
731                 innconf->patharticles);
732   else
733     p = xstrdup (innconf->patharticles) ;
734   newsspool = p ;
735
736   /***************************************************/
737   
738   if (getString (topScope,"input-file",&p,NO_INHERIT))
739     {
740       if (*p != '\0')
741         InputFile = buildFilename (getTapeDirectory(),p) ;
742       else
743         InputFile = "" ;
744       free (p) ;
745     }
746   
747   if (getString (topScope,"pid-file",&p,NO_INHERIT))
748     {
749       pidFile = buildFilename (innconf->pathrun,p) ;
750       free (p) ;
751     }
752   else
753     pidFile = buildFilename (innconf->pathrun,PID_FILE) ;
754   
755   if (getInteger (topScope,"debug-level",&ival,NO_INHERIT))
756     loggingLevel = (unsigned int) ival ;
757   
758   
759   if (getInteger (topScope,"initial-sleep",&ival,NO_INHERIT))
760     initialSleep = (unsigned int) ival ;
761   
762   
763   if (getBool (topScope,"use-mmap",&bval,NO_INHERIT))
764     useMMap = (bval ? true : false) ;
765
766   
767   if (getString (topScope,"log-file",&p,NO_INHERIT))
768     {
769       logFile = buildFilename (innconf->pathlog,p) ;
770       free (p) ;
771     }
772
773    /* For imap/lmtp delivering */
774   if (getString (topScope,"deliver-username",&p, NO_INHERIT))
775     {   
776         deliver_username = p;
777       /* don't need to free */
778     }
779
780   if (getString (topScope,"deliver-authname",&p, NO_INHERIT))
781     {
782       deliver_authname = p;
783       /* don't need to free */
784     }
785
786   if (getString (topScope,"deliver-password",&p, NO_INHERIT))
787     {
788       deliver_password = p;
789       /* don't need to free */
790     }
791
792   if (getString (topScope,"deliver-realm",&p, NO_INHERIT))
793     {
794       deliver_realm = p;
795       /* don't need to free */
796     }
797
798   if (getString (topScope,"deliver-rcpt-to",&p, NO_INHERIT))
799     {
800       deliver_rcpt_to = p;
801       /* don't need to free */
802     }
803
804   if (getString (topScope,"deliver-to-header",&p, NO_INHERIT))
805     {
806       deliver_to_header = p;
807       /* don't need to free */
808     }
809
810   
811
812   return 1 ;
813 }
814
815 /*
816  * called after config file is loaded but before other callbacks, so we
817  * can adjust config file values from options. They will be validated in the
818  * second callback.
819  */
820 static int mainOptionsProcess (void *data UNUSED)
821 {
822   value *v ;
823
824   if (bopt != NULL)
825     {
826       if ((v = findValue (topScope,"backlog-directory",NO_INHERIT)) != NULL) 
827         {
828           free (v->v.charp_val) ;
829           v->v.charp_val = xstrdup (bopt) ;
830         }
831       else
832         addString (topScope,"backlog-directory",xstrdup (bopt)) ;
833     }
834
835   if (aopt != NULL)
836     {
837       if ((v = findValue (topScope,"news-spool",NO_INHERIT)) != NULL)
838         {
839           free (v->v.charp_val) ;
840           v->v.charp_val = xstrdup (aopt) ;
841         }
842       else
843         addString (topScope,"news-spool",xstrdup (aopt)) ;
844     }
845
846   if (sopt != NULL)
847     {
848       if ((v = findValue (topScope,"status-file",NO_INHERIT)) != NULL)
849         {
850           free (v->v.charp_val) ;
851           v->v.charp_val = xstrdup (sopt) ;
852         }
853       else
854         addString (topScope,"status-file",xstrdup (sopt)) ;
855     }
856
857
858   if (Dopt)
859     {
860       if ((v = findValue (topScope,"debug-level",NO_INHERIT)) != NULL)
861         v->v.int_val = debugLevel ;
862       else
863         addInteger (topScope,"debug-level",debugLevel) ;
864     }
865
866   
867   if (eopt || talkToSelf)
868     {
869       if (talkToSelf)
870         elimit = 0 ;
871       
872       if ((v = findValue (topScope,"backlog-limit",NO_INHERIT)) != NULL)
873         v->v.int_val = elimit ;
874       else
875         addInteger (topScope,"backlog-limit",elimit) ;
876     }
877
878   
879   if (Mopt)
880     {
881       if ((v = findValue (topScope,"use-mmap",NO_INHERIT)) != NULL)
882         v->v.bool_val = 0 ;
883       else
884         addBoolean (topScope,"use-mmap",0) ;
885     }
886   
887
888   if (popt != NULL)
889     {
890       if ((v = findValue (topScope,"pid-file",NO_INHERIT)) != NULL)
891         {
892           free (v->v.charp_val) ;
893           v->v.charp_val = xstrdup (popt) ;
894         }
895       else
896         addString (topScope,"pid-file",xstrdup (popt)) ;
897     }
898
899   if (Zopt)
900     {
901       if ((v = findValue (topScope,"connection-stats",NO_INHERIT)) != NULL)
902         v->v.bool_val = 1 ;
903       else
904         addBoolean (topScope,"connection-stats",1) ;
905     }
906
907   if (lopt != NULL)
908     {
909       if ((v = findValue (topScope,"log-file",NO_INHERIT)) != NULL)
910         {
911           free (v->v.charp_val) ;
912           v->v.charp_val = xstrdup (lopt) ;
913         }
914       else
915         addString (topScope,"log-file",xstrdup (lopt)) ;
916     }
917
918   if (InputFile != NULL)
919     {
920       if ((v = findValue (topScope,"input-file",NO_INHERIT)) != NULL)
921         {
922           free (v->v.charp_val) ;
923           v->v.charp_val = xstrdup (InputFile) ;
924         }
925       else
926         addString (topScope,"input-file",xstrdup (InputFile)) ;
927     }
928
929   return 1 ;
930 }
931
932
933
934 static void mainCleanup (void)
935 {
936   free ((void *)configFile) ;
937   free ((void *)pidFile) ;
938   free (logFile) ;
939   free (newsspool) ;
940   configFile = NULL ;
941   pidFile = NULL ;
942   logFile = NULL ;
943   newsspool = NULL ;
944 }
945
946
947 void mainLogStatus (FILE *fp)
948 {
949   fprintf (fp,"%sGlobal configuration parameters:%s\n",
950            genHtml ? "<B>" : "", genHtml ? "</B>" : "") ;
951   fprintf (fp,"          Mode: ") ;
952   if (InputFile != NULL)
953     fprintf (fp,"Funnel file") ;
954   else if (talkToSelf)
955     fprintf (fp,"Batch") ;
956   else
957     fprintf (fp,"Channel") ;
958   if (InputFile != NULL)
959     fprintf (fp,"   (%s)",(*InputFile == '\0' ? "stdin" : InputFile)) ;
960   fprintf (fp,"\n") ;
961   fprintf (fp,"    News spool: %s\n",newsspool) ;
962   fprintf (fp,"      Pid file: %s\n",pidFile) ;
963   fprintf (fp,"      Log file: %s\n",(logFile == NULL ? "(none)" : logFile));
964   fprintf (fp,"   Debug level: %2ld                Mmap: %s\n",
965            (long)loggingLevel,boolToString(useMMap)) ;
966   fprintf (fp,"\n") ;
967 }