mixmaster

mixmaster 3.0 patched for libressl
git clone git://parazyd.org/mixmaster.git
Log | Files | Refs | README

mix.c (33886B)


      1 /* Mixmaster version 3.0  --  (C) 1999 - 2006 Anonymizer Inc. and others.
      2 
      3    Mixmaster may be redistributed and modified under certain conditions.
      4    This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
      5    ANY KIND, either express or implied. See the file COPYRIGHT for
      6    details.
      7 
      8    Mixmaster initialization, configuration
      9    $Id: mix.c 962 2007-11-19 13:42:41Z zax $ */
     10 
     11 
     12 #include "mix3.h"
     13 #include <stdlib.h>
     14 #include <stdio.h>
     15 #include <string.h>
     16 #include <stdarg.h>
     17 #include <ctype.h>
     18 #include <time.h>
     19 #include <sys/types.h>
     20 #include <sys/stat.h>
     21 #ifdef POSIX
     22 #include <signal.h>
     23 #include <unistd.h>
     24 #include <pwd.h>
     25 #include <sys/utsname.h>
     26 #else /* end of POSIX */
     27 #include <io.h>
     28 #include <direct.h>
     29 #endif /* else if not POSIX */
     30 #ifdef WIN32
     31 #include <windows.h>
     32 #include <shlobj.h>
     33 #include <shlobj.h>
     34 #endif /* WIN32 */
     35 #include <assert.h>
     36 #include "menu.h"
     37 
     38 int buf_vappendf(BUFFER *b, char *fmt, va_list args);
     39 
     40 /** filenames ************************************************************/
     41 char MIXCONF[PATHMAX] = DEFAULT_MIXCONF;
     42 char DISCLAIMFILE[PATHMAX];
     43 char FROMDSCLFILE[PATHMAX];
     44 char MSGFOOTERFILE[PATHMAX];
     45 char POP3CONF[PATHMAX];
     46 char HELPFILE[PATHMAX];
     47 char REQUESTDIR[PATHMAX];
     48 char ABUSEFILE[PATHMAX];
     49 char REPLYFILE[PATHMAX];
     50 char USAGEFILE[PATHMAX];
     51 char USAGELOG[PATHMAX];
     52 char BLOCKFILE[PATHMAX];
     53 char ADMKEYFILE[PATHMAX];
     54 char KEYFILE[PATHMAX];
     55 char PGPKEY[PATHMAX];
     56 char DSAPARAMS[PATHMAX];
     57 char DHPARAMS[PATHMAX];
     58 char MIXRAND[PATHMAX];
     59 char SECRING[PATHMAX];
     60 char PUBRING[PATHMAX];
     61 char IDLOG[PATHMAX];
     62 char STATS[PATHMAX];
     63 char PGPMAXCOUNT[PATHMAX];
     64 char DESTBLOCK[PATHMAX];
     65 char DESTALLOW[PATHMAX];
     66 char DESTALLOW2[PATHMAX];
     67 char SOURCEBLOCK[PATHMAX];
     68 char HDRFILTER[PATHMAX];
     69 char REGULAR[PATHMAX];
     70 char POOL[PATHMAX];
     71 char TYPE1LIST[PATHMAX];
     72 char TYPE2REL[PATHMAX];
     73 char PIDFILE[PATHMAX];
     74 
     75 char PGPREMPUBRING[PATHMAX];
     76 char PGPREMPUBASC[PATHMAX];
     77 char PGPREMSECRING[PATHMAX];
     78 char NYMSECRING[PATHMAX];
     79 char NYMDB[PATHMAX];
     80 char STAREX[PATHMAX];
     81 
     82 /** config ***************************************************************/
     83 
     84 char MIXDIR[PATHMAX];
     85 char POOLDIR[PATHMAX];
     86 
     87 /* programs */
     88 char SENDMAIL[LINELEN];
     89 char SENDANONMAIL[LINELEN];
     90 char NEWS[LINELEN];
     91 char TYPE1[LINELEN];
     92 
     93 /* addresses */
     94 char MAILtoNEWS[LINELEN];
     95 char REMAILERNAME[LINELEN];
     96 char ANONNAME[LINELEN];
     97 char REMAILERADDR[LINELEN];
     98 char ANONADDR[LINELEN];
     99 char COMPLAINTS[LINELEN];
    100 int AUTOREPLY;
    101 char SMTPRELAY[LINELEN];
    102 char SMTPUSERNAME[LINELEN];
    103 char SMTPPASSWORD[LINELEN];
    104 
    105 #ifdef USE_SOCK
    106 char HELONAME[LINELEN];
    107 char ENVFROM[LINELEN];
    108 int POP3DEL;
    109 int POP3SIZELIMIT;
    110 long POP3TIME;
    111 
    112 #endif /* USE_SOCK */
    113 
    114 char SHORTNAME[LINELEN];
    115 char ALLPINGERSURL[BUFSIZE];
    116 char ALLPINGERSFILE[PATHMAX];
    117 char WGET[PATHMAX];
    118 char STATSSRC[PATHMAX];
    119 int  STATSAUTOUPDATE;
    120 long STATSINTERVAL;
    121 
    122 
    123 /* remailer configuration */
    124 int REMAIL;
    125 int MIX;
    126 int PGP;
    127 int UNENCRYPTED;
    128 int REMIX;
    129 int REPGP;
    130 char EXTFLAGS[LINELEN];	/* user-defined capstring flags */
    131 
    132 char PRECEDENCE[LINELEN];	/* default Precedence: header for outgoing mail */
    133 int POOLSIZE;
    134 int RATE;
    135 int INDUMMYP;
    136 int OUTDUMMYP;
    137 int INDUMMYMAXP;
    138 int OUTDUMMYMAXP;
    139 int MIDDLEMAN;
    140 int AUTOBLOCK;
    141 int STATSDETAILS;
    142 char FORWARDTO[LINELEN];
    143 int SIZELIMIT;		/* maximal size of remailed messages */
    144 int INFLATEMAX;		/* maximal size of Inflate: padding */
    145 int MAXRANDHOPS;
    146 int BINFILTER;		/* filter binary attachments? */
    147 int LISTSUPPORTED;	/* list supported remailers in remailer-conf reply? */
    148 long PACKETEXP;		/* Expiration time for old packets */
    149 long IDEXP;		/* 0 = no ID log !! */
    150 long SENDPOOLTIME;	/* frequency for sending pool messages */
    151 long MAILINTIME;	/* frequency for processing MAILIN mail */
    152 
    153 long KEYLIFETIME;
    154 long KEYOVERLAPPERIOD;
    155 long KEYGRACEPERIOD;
    156 
    157 char ERRLOG[LINELEN];
    158 char ADDRESS[LINELEN];
    159 char NAME[LINELEN];
    160 
    161 char ORGANIZATION[LINELEN];
    162 char MID[LINELEN];
    163 
    164 /* client config */
    165 int NUMCOPIES;
    166 char CHAIN[LINELEN];
    167 int VERBOSE;
    168 int DISTANCE;
    169 int MINREL;
    170 int RELFINAL;
    171 long MAXLAT;
    172 long MINLAT;
    173 char PGPPUBRING[PATHMAX];
    174 char PGPSECRING[PATHMAX];
    175 char PASSPHRASE[LINELEN];
    176 char MAILIN[PATHMAX];
    177 char MAILBOX[PATHMAX];
    178 char MAILABUSE[PATHMAX];
    179 char MAILBLOCK[PATHMAX];
    180 char MAILUSAGE[PATHMAX];
    181 char MAILANON[PATHMAX];
    182 char MAILERROR[PATHMAX];
    183 char MAILBOUNCE[PATHMAX];
    184 
    185 int CLIENTAUTOFLUSH;
    186 int MAXRECIPIENTS;
    187 
    188 long TIMESKEW_FORWARD;
    189 long TIMESKEW_BACK;
    190 int TEMP_FAIL;
    191 
    192 char ENTEREDPASSPHRASE[LINELEN] = "";
    193 
    194 static int rereadconfig = 0;
    195 static int terminatedaemon = 0;
    196 
    197 #if defined(S_IFDIR) && !defined(S_ISDIR)
    198 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
    199 #endif /* defined(S_IFDIR) && !defined(S_ISDIR) */
    200 
    201 static int mixdir(char *d, int create)
    202 {
    203   int err;
    204   struct stat buf;
    205 
    206   if (d != MIXDIR)
    207     strncpy(MIXDIR, d, PATHMAX);
    208   if (MIXDIR[strlen(MIXDIR) - 1] == DIRSEP)
    209     MIXDIR[strlen(MIXDIR) - 1] = '\0';
    210   err = stat(MIXDIR, &buf);
    211   if (err == -1) {
    212     if (create) {
    213 #ifndef POSIX
    214       err = mkdir(MIXDIR);
    215 #else /* end of not POSIX */
    216       err = mkdir(MIXDIR, S_IRWXU);
    217 #endif /* else if POSIX */
    218       if (err == 0)
    219 	errlog(NOTICE, "Creating directory %s.\n", MIXDIR);
    220     } else
    221       err = 1;
    222   } else if (!S_ISDIR(buf.st_mode))
    223     err = -1;
    224   if (err == 0)
    225     strcatn(MIXDIR, DIRSEPSTR, PATHMAX);
    226   return (err);
    227 }
    228 
    229 void whoami(char *addr, char *defaultname)
    230 {
    231   char *p = NULL;
    232 
    233 #if defined(HAVE_GETDOMAINNAME) || (defined(HAVE_GETHOSTNAME) && ! defined(HAVE_UNAME))
    234   char line[LINELEN];
    235 
    236 #endif /* defined(HAVE_GETDOMAINNAME) || [...] */
    237 #ifdef HAVE_UNAME
    238   struct utsname uts;
    239 
    240 #endif /* HAVE_UNAME */
    241 #ifdef POSIX
    242   p = getlogin();
    243 #endif /* POSIX */
    244   if (p == NULL)
    245     strcpy(addr, defaultname);
    246   else
    247     strncpy(addr, p, LINELEN);
    248 
    249   strcatn(addr, "@", LINELEN);
    250 #ifdef HAVE_UNAME
    251   if (uname(&uts) != -1)
    252     strcatn(addr, uts.nodename, LINELEN);
    253 #elif defined(HAVE_GETHOSTNAME) /* end of HAVE_UNAME */
    254   if (gethostname(line, LINELEN) == 0)
    255     strcatn(addr, line, LINELEN);
    256 #endif /* defined(HAVE_GETHOSTNAME) */
    257   if (addr[strlen(addr) - 1] == '@')
    258     strcatn(addr, SHORTNAME, LINELEN);
    259 
    260   if (strchr(strchr(addr, '@'), '.') == NULL) {
    261 #ifdef HAVE_GETDOMAINNAME
    262     if (getdomainname(line, LINELEN) == 0 && !streq(line, "(none)")) {
    263       strcatn(addr, ".", LINELEN);
    264       strcatn(addr, line, LINELEN);
    265     }
    266 #endif /* HAVE_GETDOMAINNAME */
    267   }
    268 }
    269 
    270 #define read_conf(t) readconfline(line, #t, sizeof(#t)-1, t)
    271 
    272 static int readconfline(char *line, char *name, int namelen, char *var)
    273 {
    274   if (strncmp(line, name, namelen) == 0 &&
    275       (isspace(line[namelen]) || line[namelen] == '=')) {
    276     line += namelen;
    277     if (*line == '=')
    278       line++;
    279     while (isspace(*line))
    280       line++;
    281     if (line[0] == '\n' || line[0] == '\0')	/* leave default */
    282       return (1);
    283     strncpy(var, line, LINELEN);
    284     if (var[strlen(var) - 1] == '\n')
    285       var[strlen(var) - 1] = '\0';
    286     return (1);
    287   } else
    288     return (0);
    289 }
    290 
    291 #define read_conf_i(t) readiconfline(line, #t, sizeof(#t)-1, &t)
    292 
    293 static int readiconfline(char *line, char *name, int namelen, int *var)
    294 {
    295   if (strncmp(line, name, namelen) == 0 &&
    296       (isspace(line[namelen]) || line[namelen] == '=')) {
    297     line += namelen;
    298     if (*line == '=')
    299       line++;
    300     while (isspace(*line))
    301       line++;
    302     if (line[0] == '\n' || line[0] == '\0')	/* leave default */
    303       return (1);
    304     switch (tolower(line[0])) {
    305     case 'n':
    306       *var = 0;
    307       break;
    308     case 'y':
    309       *var = 1;
    310       break;
    311     case 'x':
    312       *var = 2;
    313       break;
    314     default:
    315       sscanf(line, "%d", var);
    316     }
    317     return (1);
    318   } else
    319     return (0);
    320 }
    321 
    322 #define read_conf_t(t) readtconfline(line, #t, sizeof(#t)-1, &t)
    323 
    324 static int readtconfline(char *line, char *name, int namelen, long *var)
    325 {
    326   char *linenext;
    327   int mod = 0;
    328   long l = 0;
    329   long n;
    330 
    331   if (strncmp(line, name, namelen) == 0 &&
    332       (isspace(line[namelen]) || line[namelen] == '=')) {
    333     line += namelen;
    334     if (*line == '=')
    335       line++;
    336     for (;; line++) {
    337       n = strtol(line, &linenext, 10);
    338       if (linenext == line)
    339 	break;
    340       line = linenext;
    341       mod = 1;
    342       assert(line != NULL);
    343       while (isspace(*line))
    344 	line++;
    345       switch (tolower(*line)) {
    346       case 'y': /* years */
    347 	l += 365 * 24 * 60 * 60 * n;
    348 	break;
    349       case 'b': /* months */
    350 	l += 30 * 24 * 60 * 60 * n;
    351 	break;
    352       case 'w': /* weeks */
    353 	l += 7 * 24 * 60 * 60 * n;
    354 	break;
    355       case 'd': /* days */
    356 	l += 24 * 60 * 60 * n;
    357 	break;
    358       case 's': /* seconds */
    359 	l += n;
    360 	break;
    361       case 'm': /* minutes */
    362 	l += 60 * n;
    363 	break;
    364       case 'h': /* hours - default */
    365       default:
    366 	l += 60 * 60 * n;
    367 	break;
    368       }
    369     }
    370     if (mod)
    371       *var = l;
    372     return (1);
    373   } else
    374     return (0);
    375 }
    376 
    377 static void mix_setdefaults()
    378 {
    379 #define strnncpy(a,b) strncpy(a, b, sizeof(a)); a[sizeof(a)-1] = '\0'
    380 
    381 	strnncpy(DISCLAIMFILE , DEFAULT_DISCLAIMFILE);
    382 	strnncpy(FROMDSCLFILE , DEFAULT_FROMDSCLFILE);
    383 	strnncpy(MSGFOOTERFILE, DEFAULT_MSGFOOTERFILE);
    384 	strnncpy(POP3CONF     , DEFAULT_POP3CONF);
    385 	strnncpy(HELPFILE     , DEFAULT_HELPFILE);
    386 	strnncpy(REQUESTDIR   , DEFAULT_REQUESTDIR);
    387 	strnncpy(ABUSEFILE    , DEFAULT_ABUSEFILE);
    388 	strnncpy(REPLYFILE    , DEFAULT_REPLYFILE);
    389 	strnncpy(USAGEFILE    , DEFAULT_USAGEFILE);
    390 	strnncpy(USAGELOG     , DEFAULT_USAGELOG);
    391 	strnncpy(BLOCKFILE    , DEFAULT_BLOCKFILE);
    392 	strnncpy(ADMKEYFILE   , DEFAULT_ADMKEYFILE);
    393 	strnncpy(KEYFILE      , DEFAULT_KEYFILE);
    394 	strnncpy(PGPKEY       , DEFAULT_PGPKEY);
    395 	strnncpy(DSAPARAMS    , DEFAULT_DSAPARAMS);
    396 	strnncpy(DHPARAMS     , DEFAULT_DHPARAMS);
    397 	strnncpy(MIXRAND      , DEFAULT_MIXRAND);
    398 	strnncpy(SECRING      , DEFAULT_SECRING);
    399 	strnncpy(PUBRING      , DEFAULT_PUBRING);
    400 	strnncpy(IDLOG        , DEFAULT_IDLOG);
    401 	strnncpy(STATS        , DEFAULT_STATS);
    402 	strnncpy(PGPMAXCOUNT  , DEFAULT_PGPMAXCOUNT);
    403 	strnncpy(DESTBLOCK    , DEFAULT_DESTBLOCK);
    404 	strnncpy(DESTALLOW    , DEFAULT_DESTALLOW);
    405 	strnncpy(DESTALLOW2   , DEFAULT_DESTALLOW2);
    406 	strnncpy(SOURCEBLOCK  , DEFAULT_SOURCEBLOCK);
    407 	strnncpy(HDRFILTER    , DEFAULT_HDRFILTER);
    408 	strnncpy(REGULAR      , DEFAULT_REGULAR);
    409 	strnncpy(POOL         , DEFAULT_POOL);
    410 	strnncpy(TYPE1LIST    , DEFAULT_TYPE1LIST);
    411 	strnncpy(TYPE2REL     , DEFAULT_TYPE2REL);
    412 	strnncpy(PIDFILE      , DEFAULT_PIDFILE);
    413 
    414 	strnncpy(PGPREMPUBRING, DEFAULT_PGPREMPUBRING);
    415 	strnncpy(PGPREMPUBASC , DEFAULT_PGPREMPUBASC);
    416 	strnncpy(PGPREMSECRING, DEFAULT_PGPREMSECRING);
    417 	strnncpy(NYMSECRING   , DEFAULT_NYMSECRING);
    418 	strnncpy(NYMDB        , DEFAULT_NYMDB);
    419 	strnncpy(STAREX       , DEFAULT_STAREX);
    420 	strnncpy(ALLPINGERSURL, DEFAULT_ALLPINGERSURL);
    421 	strnncpy(ALLPINGERSFILE, DEFAULT_ALLPINGERSFILE);
    422 	strnncpy(WGET         , DEFAULT_WGET);
    423 	strnncpy(STATSSRC     , DEFAULT_STATSSRC);
    424 
    425 	strnncpy(MIXDIR       , "");
    426 	strnncpy(POOLDIR      , "");
    427 
    428 /* programs */
    429 #ifdef WIN32
    430 	strnncpy(SENDMAIL     , "outfile");
    431 #else /* end of WIN32 */
    432 	strnncpy(SENDMAIL     , "/usr/lib/sendmail -t");
    433 #endif /* else if not WIN32 */
    434 	strnncpy(SENDANONMAIL , "");
    435 	strnncpy(NEWS         , "");
    436 	strnncpy(TYPE1        , "");
    437 
    438 /* addresses */
    439 	strnncpy(MAILtoNEWS   , "mail2news@dizum.com,mail2news@m2n.mixmin.net");
    440 	strnncpy(REMAILERNAME , "Anonymous Remailer");
    441 	strnncpy(ANONNAME     , "Anonymous");
    442 	strnncpy(REMAILERADDR , "");
    443 	strnncpy(ANONADDR     , "");
    444 	strnncpy(COMPLAINTS   , "");
    445 	strnncpy(SMTPRELAY    , "");
    446 	AUTOREPLY             = 0;
    447 
    448 #ifdef USE_SOCK
    449   	strnncpy(HELONAME     , "");
    450 	strnncpy(ENVFROM      , "");
    451 	POP3DEL               = 0;
    452 	POP3SIZELIMIT         = 0;
    453 	POP3TIME              = 60 * 60;
    454 
    455 #endif /* USE_SOCK */
    456 
    457 	strnncpy(SHORTNAME    , "");
    458 
    459 /* 	configuration */
    460 	REMAIL        = 0;
    461 	MIX           = 1;
    462 	PGP           = 1;
    463 	UNENCRYPTED   = 0;
    464 	REMIX         = 1;
    465 	REPGP         = 1;
    466 	STATSAUTOUPDATE = 0;
    467 	STATSINTERVAL = 8 * 60 * 60;
    468 	strnncpy(EXTFLAGS, "");
    469 
    470     strnncpy(PRECEDENCE, "");
    471 	POOLSIZE      = 0;
    472 	RATE          = 100;
    473 	INDUMMYP      = 3;	/* add dummy messages with probability p for each message added to the pool */
    474 	OUTDUMMYP     = 10;	/* add dummy messages with probability p each time we send from the pool */
    475 	INDUMMYMAXP   = 84;	/* for both of the above:  while (rnd < p) { senddummy(); }  */
    476 	OUTDUMMYMAXP  = 96;     /* set max INDUMMYP and OUTDUMMYP such that 24 and 5.25 dummy messages will */
    477 	MIDDLEMAN     = 0;      /* be generated on average. More than this is insane. */
    478 	AUTOBLOCK     = 1;
    479 	STATSDETAILS  = 1;
    480 	strnncpy(FORWARDTO, "*");
    481 	SIZELIMIT     = 0;		/* maximal size of remailed messages */
    482 	INFLATEMAX    = 50;		/* maximal size of Inflate: padding */
    483 	MAXRANDHOPS   = 5;
    484 	BINFILTER     = 0;		/* filter binary attachments? */
    485 	LISTSUPPORTED = 1;		/* list supported remailers in remailer-conf reply? */
    486 	PACKETEXP     = 7 * SECONDSPERDAY;	/* Expiration time for old packets */
    487 	IDEXP         = 7 * SECONDSPERDAY;	/* 0 = no ID log !! */
    488 	SENDPOOLTIME  = 0;              /* frequency for sending pool messages */
    489 	MAILINTIME    = 5 * 60;		/* frequency for processing MAILIN mail */
    490 
    491 	KEYLIFETIME      = 13 * 30 * 24 * 60 * 60;	/* validity period for keys. */
    492 	KEYOVERLAPPERIOD =  1 * 30 * 24 * 60 * 60;	/* when keys have this amount of time */
    493 	                                                /* left before expiration, create  */
    494 	                                        	/* new ones when ./mix -K is run.*/
    495 	KEYGRACEPERIOD   =       7 * 24 * 60 * 60;	/* accept mail to the old key for this */
    496 	                                        	/* amount of time after it has expired. */
    497 
    498 
    499 	strnncpy(ERRLOG      , "");
    500 	strnncpy(ADDRESS     , "");
    501 	strnncpy(NAME        , "");
    502 
    503 	strnncpy(ORGANIZATION, "Anonymous Posting Service");
    504 	strnncpy(MID         , "y");
    505 
    506 /* client config */
    507 	NUMCOPIES = 1;
    508 	strnncpy(CHAIN, "*,*,*,*");
    509 	VERBOSE = 2;
    510 	DISTANCE = 2;
    511 	MINREL = 98;
    512 	RELFINAL = 99;
    513 	MAXLAT = 36 * 60 * 60;
    514 	MINLAT = 5 * 60;
    515 	strnncpy(PGPPUBRING, "");
    516 	strnncpy(PGPSECRING, "");
    517 #ifdef COMPILEDPASS
    518 	strnncpy(PASSPHRASE, COMPILEDPASS);
    519 #else /* end of COMPILEDPASS */
    520 	strnncpy(PASSPHRASE, "");
    521 #endif /* else if not COMPILEDPASS */
    522 	strnncpy(MAILIN    , "");
    523 	strnncpy(MAILBOX   , "mbox");
    524 	strnncpy(MAILABUSE , "");
    525 	strnncpy(MAILBLOCK , "");
    526 #ifdef WIN32
    527 	strnncpy(MAILUSAGE , "nul:");
    528 	strnncpy(MAILANON  , "nul:");
    529 	strnncpy(MAILERROR , "nul:");
    530 #else /* end of WIN32 */
    531 	strnncpy(MAILUSAGE , "/dev/null");
    532 	strnncpy(MAILANON  , "/dev/null");
    533 	strnncpy(MAILERROR , "/dev/null");
    534 #endif /* else if not WIN32 */
    535 	strnncpy(MAILBOUNCE, "");
    536 
    537 	CLIENTAUTOFLUSH = 1;
    538 	MAXRECIPIENTS   = 5;
    539 
    540 	TIMESKEW_FORWARD = 2*7*24*60*60;
    541 	TIMESKEW_BACK = 12*60*60;
    542 	TEMP_FAIL = 75;
    543 }
    544 
    545 int mix_configline(char *line)
    546 {
    547   return (read_conf(ADDRESS) || read_conf(NAME) ||
    548 	  read_conf(SHORTNAME) || read_conf(REMAILERADDR) ||
    549 	  read_conf(ANONADDR) || read_conf(REMAILERNAME) ||
    550 	  read_conf(ANONNAME) || read_conf(COMPLAINTS) ||
    551 	  read_conf_i(AUTOREPLY) || read_conf(SMTPRELAY) ||
    552 	  read_conf(SMTPUSERNAME) || read_conf(SMTPPASSWORD) ||
    553 #ifdef USE_SOCK
    554 	  read_conf(HELONAME) || read_conf(ENVFROM) ||
    555 #endif /* USE_SOCK */
    556 	  read_conf(SENDMAIL) || read_conf(SENDANONMAIL) ||
    557 	  read_conf(PRECEDENCE) ||
    558 	  read_conf_i(REMAIL) || read_conf_i(MIX) ||
    559 	  read_conf_i(PGP) || read_conf_i(UNENCRYPTED) ||
    560 	  read_conf_i(REMIX) || read_conf(NEWS) ||
    561 	  read_conf_i(REPGP) || read_conf(EXTFLAGS) ||
    562 	  read_conf(MAILtoNEWS) || read_conf(ERRLOG) ||
    563 	  read_conf(ORGANIZATION) || read_conf(MID) ||
    564 	  read_conf(TYPE1) || read_conf_i(POOLSIZE) ||
    565 	  read_conf_i(RATE) || read_conf_i(MIDDLEMAN) ||
    566 	  read_conf_i(INDUMMYP) ||
    567 	  read_conf_i(OUTDUMMYP) ||
    568 	  read_conf_i(AUTOBLOCK) || read_conf(FORWARDTO) ||
    569 	  read_conf_i(STATSDETAILS) ||
    570 	  read_conf_i(SIZELIMIT) || read_conf_i(INFLATEMAX) ||
    571 	  read_conf_i(MAXRANDHOPS) || read_conf_i(BINFILTER) ||
    572 	  read_conf_i(LISTSUPPORTED) ||
    573 	  read_conf_t(PACKETEXP) || read_conf_t(IDEXP) ||
    574 	  read_conf_t(SENDPOOLTIME) || read_conf_i(NUMCOPIES) ||
    575 	  read_conf_t(MAILINTIME) ||
    576 	  read_conf(CHAIN) || read_conf_i(VERBOSE) ||
    577 	  read_conf_i(DISTANCE) || read_conf_i(MINREL) ||
    578 	  read_conf_i(RELFINAL) || read_conf_t(MAXLAT) ||
    579 	  read_conf_t(MINLAT) ||
    580 	  read_conf(PGPPUBRING) || read_conf(PGPSECRING) ||
    581 	  read_conf(PASSPHRASE) || read_conf_t(KEYLIFETIME) ||
    582 	  read_conf_t(KEYGRACEPERIOD) || read_conf_t(KEYOVERLAPPERIOD) ||
    583 #ifdef USE_SOCK
    584 	  read_conf_i(POP3DEL) || read_conf_i(POP3SIZELIMIT) ||
    585 	  read_conf_t(POP3TIME) ||
    586 #endif /* USE_SOCK */
    587 	  read_conf(MAILBOX) || read_conf(MAILABUSE) ||
    588 	  read_conf(MAILBLOCK) || read_conf(MAILUSAGE) ||
    589 	  read_conf(MAILANON) || read_conf(MAILERROR) ||
    590 	  read_conf(MAILBOUNCE) || read_conf(MAILIN) ||
    591 
    592 	  read_conf(DISCLAIMFILE) || read_conf(FROMDSCLFILE) ||
    593 	  read_conf(MSGFOOTERFILE) ||
    594 	  read_conf(POP3CONF) || read_conf(HELPFILE) ||
    595 	  read_conf(REQUESTDIR)  ||
    596 	  read_conf(ABUSEFILE) || read_conf(REPLYFILE) ||
    597 	  read_conf(USAGEFILE) || read_conf(USAGELOG) ||
    598 	  read_conf(BLOCKFILE) || read_conf(ADMKEYFILE) ||
    599 	  read_conf(KEYFILE) || read_conf(PGPKEY) ||
    600 	  read_conf(DSAPARAMS) || read_conf(DHPARAMS) ||
    601 	  read_conf(MIXRAND) || read_conf(SECRING) ||
    602 	  read_conf(PUBRING) || read_conf(IDLOG) ||
    603 	  read_conf(STATS) || read_conf(DESTBLOCK) ||
    604 	  read_conf(PGPMAXCOUNT) ||
    605 	  read_conf(DESTALLOW) || read_conf(DESTALLOW2) ||
    606 	  read_conf(SOURCEBLOCK) ||
    607 	  read_conf(STAREX) || read_conf(ALLPINGERSURL) ||
    608 	  read_conf(ALLPINGERSFILE) ||
    609 	  read_conf(HDRFILTER) || read_conf(REGULAR) ||
    610 	  read_conf(POOL) || read_conf(TYPE1LIST) ||
    611 	  read_conf(TYPE2REL) ||
    612 	  read_conf(PGPREMPUBRING) || read_conf(PGPREMPUBASC) ||
    613 	  read_conf(PGPREMSECRING) || read_conf(NYMSECRING) ||
    614 	  read_conf(NYMDB) || read_conf(PIDFILE) ||
    615 	  read_conf(WGET) || read_conf(STATSSRC) ||
    616 	  read_conf_i(STATSAUTOUPDATE) || read_conf_t(STATSINTERVAL) ||
    617 
    618 	  read_conf_i(CLIENTAUTOFLUSH) ||
    619 	  read_conf_i(MAXRECIPIENTS) ||
    620 	  
    621 	  read_conf_t(TIMESKEW_FORWARD) ||
    622 	  read_conf_t(TIMESKEW_BACK) ||
    623 	  read_conf_i(TEMP_FAIL) );
    624 }
    625 
    626 int mix_config(void)
    627 {
    628   char *d;
    629   FILE *f;
    630   char line[PATHMAX];
    631   int err = -1;
    632 #ifdef POSIX
    633   struct passwd *pw;
    634 #endif /* POSIX */
    635   struct stat buf;
    636 #ifdef HAVE_UNAME
    637   struct utsname uts;
    638 #endif /* HAVE_UNAME */
    639 #ifdef WIN32
    640   HKEY regsw, reg, regpgp;
    641   DWORD type, len;
    642   int rkey = 0;
    643 #endif /* WIN32 */
    644 
    645   mix_setdefaults();
    646 
    647 #ifdef POSIX
    648   pw = getpwuid(getuid());
    649 #endif /* POSIX */
    650 
    651  /* find our base directory
    652   *
    653   * first match wins.
    654   *
    655   *  - what the MIXPATH environment variable points to, if it is set.
    656   *  - On WIN32, HKEY_CURRENT_USER\Software\Mixmaster\MixDir, if it exists
    657   *  - whatever is compiled in with -DSPOOL
    658   *  - On Win32 %APPDATA%\Mixmaster
    659   *  - on POSIX, ~/Mix  (or ~/<HOMEMIXDIR>)
    660   *  - the current working directory
    661   */
    662 
    663   if (err == -1 && (d = getenv("MIXPATH")) != NULL)
    664     err = mixdir(d, 1);
    665 
    666 #ifdef WIN32
    667   RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, &regsw);
    668   len=sizeof(line);
    669   if (err == -1 &&
    670       RegOpenKeyEx(regsw, "Mixmaster", 0, KEY_QUERY_VALUE, &reg) == 0) {
    671     if (RegQueryValueEx(reg, "MixDir", 0, &type, line, &len) == 0)
    672       err = mixdir(line, 1);
    673     RegCloseKey(reg);
    674   }
    675 #endif /* WIN32 */
    676 
    677 #ifdef SPOOL
    678   if (err == -1 && strlen(SPOOL) > 0)
    679     err = mixdir(SPOOL, 0);
    680 #endif /* SPOOL */
    681 
    682 #ifdef WIN32
    683     if (err == -1) {
    684       LPMALLOC lpmalloc;
    685       ITEMIDLIST *itemidlist;
    686       if (SUCCEEDED(SHGetMalloc(&lpmalloc)))
    687       {
    688 	SHGetSpecialFolderLocation(0,CSIDL_APPDATA,&itemidlist);
    689 	SHGetPathFromIDList(itemidlist,line);
    690 	lpmalloc->lpVtbl->Free(lpmalloc,&itemidlist);
    691 	lpmalloc->lpVtbl->Release(lpmalloc);
    692 
    693 	strcatn(line, "\\Mixmaster", PATHMAX);
    694 	err = mixdir(line, 1);
    695 
    696       }
    697     }
    698 #endif /* WIN32 */
    699 
    700 #ifdef POSIX
    701   if (err == -1 && pw != NULL) {
    702     strncpy(line, pw->pw_dir, PATHMAX);
    703     line[PATHMAX-1] = '\0';
    704     if (line[strlen(line) - 1] != DIRSEP)
    705       strcatn(line, DIRSEPSTR, PATHMAX);
    706     strcatn(line, HOMEMIXDIR, PATHMAX);
    707     err = mixdir(line, 1);
    708   }
    709 #endif /* POSIX */
    710 
    711   if (err == -1) {
    712     getcwd(MIXDIR, PATHMAX);
    713     mixdir(MIXDIR, 0);
    714   }
    715 
    716 #ifdef GLOBALMIXCONF
    717   f = mix_openfile(GLOBALMIXCONF, "r");
    718   if (f != NULL) {
    719     while (fgets(line, LINELEN, f) != NULL)
    720       if (line[0] > ' ' && line[0] != '#')
    721 	mix_configline(line);
    722     fclose(f);
    723   }
    724 #endif /* GLOBALMIXCONF */
    725   f = mix_openfile(MIXCONF, "r");
    726   if (f != NULL) {
    727     while (fgets(line, LINELEN, f) != NULL)
    728       if (line[0] > ' ' && line[0] != '#')
    729 	mix_configline(line);
    730     fclose(f);
    731   }
    732 
    733   mixfile(POOLDIR, POOL); /* set POOLDIR after reading POOL from cfg file */
    734   if (POOLDIR[strlen(POOLDIR) - 1] == DIRSEP)
    735     POOLDIR[strlen(POOLDIR) - 1] = '\0';
    736   if (stat(POOLDIR, &buf) != 0)
    737     if
    738 #ifndef POSIX
    739       (mkdir(POOLDIR) != 0)
    740 #else /* end of not POSIX */
    741       (mkdir(POOLDIR, S_IRWXU) == -1)
    742 #endif /* else if POSIX */
    743       strncpy(POOLDIR, MIXDIR, PATHMAX);
    744 
    745   if (IDEXP > 0 && IDEXP < 5 * SECONDSPERDAY)
    746     IDEXP = 5 * SECONDSPERDAY;
    747   if (MAXRANDHOPS > 20)
    748     MAXRANDHOPS = 20;
    749   if (INDUMMYP > INDUMMYMAXP)
    750     INDUMMYP = INDUMMYMAXP;
    751   if (OUTDUMMYP > OUTDUMMYMAXP)
    752     OUTDUMMYP = OUTDUMMYMAXP;
    753 
    754   if (strchr(SHORTNAME, '.'))
    755     *strchr(SHORTNAME, '.') = '\0';
    756   if (strchr(SHORTNAME, ' '))
    757     *strchr(SHORTNAME, ' ') = '\0';
    758 #ifdef HAVE_UNAME
    759   if (SHORTNAME[0] == '\0' && uname(&uts) != -1)
    760     strncpy(SHORTNAME, uts.nodename, LINELEN);
    761 #elif defined(HAVE_GETHOSTNAME) /* end of HAVE_UNAME */
    762   if (SHORTNAME[0] == '\0')
    763     gethostname(SHORTNAME, LINELEN);
    764 #endif /* defined(HAVE_GETHOSTNAME) */
    765   if (SHORTNAME[0] == '\0')
    766     strcpy(SHORTNAME, "unknown");
    767 
    768   if (ADDRESS[0] == '\0')
    769     whoami(ADDRESS, "user");
    770 
    771 #ifdef HAVE_GECOS
    772   if (NAME[0] == '\0' && pw != NULL)
    773     strcatn(NAME, pw->pw_gecos, sizeof(NAME));
    774 #endif /* HAVE_GECOS */
    775 
    776   if (REMAILERADDR[0] == '\0')
    777     strncpy(REMAILERADDR, ADDRESS, LINELEN);
    778 
    779   if (COMPLAINTS[0] == '\0')
    780     strncpy(COMPLAINTS, REMAILERADDR, LINELEN);
    781 
    782   if (strchr(REMAILERNAME, '@') == NULL) {
    783     strcatn(REMAILERNAME, " <", LINELEN);
    784     strcatn(REMAILERNAME, REMAILERADDR, LINELEN);
    785     strcatn(REMAILERNAME, ">", LINELEN);
    786   }
    787   if (strchr(ANONNAME, '@') == NULL && ANONADDR[0] != '\0') {
    788     strcatn(ANONNAME, " <", LINELEN);
    789     strcatn(ANONNAME, ANONADDR, LINELEN);
    790     strcatn(ANONNAME, ">", LINELEN);
    791   }
    792   if (strchr(ANONNAME, '@') == NULL) {
    793     strcatn(ANONNAME, " <", LINELEN);
    794     strcatn(ANONNAME, REMAILERADDR, LINELEN);
    795     strcatn(ANONNAME, ">", LINELEN);
    796   }
    797 #ifndef USE_PGP
    798   if (TYPE1[0] == '\0')
    799     PGP = 0;
    800 #endif /* not USE_PGP */
    801 
    802 #ifdef WIN32
    803   if (RegOpenKeyEx(regsw, "PGP", 0, KEY_ALL_ACCESS, &regpgp) == 0)
    804     rkey++;
    805   if (rkey && RegOpenKeyEx(regpgp, "PGPlib", 0, KEY_QUERY_VALUE, &reg) == 0)
    806     rkey++;
    807   if (PGPPUBRING[0] == '\0' && rkey == 2) {
    808     len = PATHMAX;
    809     RegQueryValueEx(reg, "PubRing", 0, &type, PGPPUBRING, &len);
    810   }
    811   if (PGPSECRING[0] == '\0' && rkey == 2) {
    812     len = PATHMAX;
    813     RegQueryValueEx(reg, "SecRing", 0, &type, PGPSECRING, &len);
    814   }
    815   if (rkey == 2)
    816     RegCloseKey(reg);
    817   if (rkey)
    818     RegCloseKey(regpgp);
    819   RegCloseKey(regsw);
    820 #endif /* WIN32 */
    821 
    822   if (PGPPUBRING[0] == '\0') {
    823     char *d;
    824 
    825     if ((d = getenv("HOME")) != NULL) {
    826       strcpy(PGPPUBRING, d);
    827       strcatn(PGPPUBRING, "/.pgp/", PATHMAX);
    828     }
    829     strcatn(PGPPUBRING, "pubring.pkr", PATHMAX);
    830     if (stat(PGPPUBRING, &buf) == -1)
    831       strcpy(strrchr(PGPPUBRING, '.'), ".pgp");
    832   }
    833   if (PGPSECRING[0] == '\0') {
    834     char *d;
    835 
    836     if ((d = getenv("HOME")) != NULL) {
    837       strcpy(PGPSECRING, d);
    838       strcatn(PGPSECRING, "/.pgp/", PATHMAX);
    839     }
    840     strcatn(PGPSECRING, "secring.skr", PATHMAX);
    841     if (stat(PGPSECRING, &buf) == -1)
    842       strcpy(strrchr(PGPSECRING, '.'), ".pgp");
    843   }
    844   if (streq(NEWS, "mail-to-news"))
    845     strncpy(NEWS, MAILtoNEWS, sizeof(NEWS));
    846 
    847   if (f == NULL) {
    848 #ifndef GLOBALMIXCONF
    849     /* Only write the config file in non systemwide installation */
    850     f = mix_openfile(MIXCONF, "w");
    851     if (f == NULL)
    852       errlog(WARNING, "Can't open %s%s!\n", MIXDIR, MIXCONF);
    853     else {
    854       fprintf(f, "# mix.cfg - mixmaster configuration file\n");
    855       fprintf(f, "NAME	        %s\n", NAME);
    856       fprintf(f, "ADDRESS	        %s\n", ADDRESS);
    857       fprintf(f, "\n# edit to set up a remailer:\n");
    858       fprintf(f, "REMAIL          n\n");
    859       fprintf(f, "SHORTNAME	%s\n", SHORTNAME);
    860       fprintf(f, "REMAILERADDR	%s\n", REMAILERADDR);
    861       fprintf(f, "COMPLAINTS	%s\n", COMPLAINTS);
    862       fclose(f);
    863     }
    864 #endif /* not GLOBALMIXCONF */
    865     REMAIL = 0;
    866   }
    867 
    868   if (ENTEREDPASSPHRASE[0] != '\0') {
    869     strncpy(PASSPHRASE, ENTEREDPASSPHRASE, LINELEN);
    870     PASSPHRASE[LINELEN-1] = 0;
    871   };
    872 
    873   return (0);
    874 }
    875 
    876 /** Library initialization: ******************************************/
    877 
    878 static int initialized = 0;
    879 
    880 void mix_check_timeskew() {
    881   FILE *f;
    882   long now, tpool = 0, tpop3 = 0, tdaily = 0, tmailin = 0, latest = 0;
    883 
    884   f = mix_openfile(REGULAR, "r+");
    885   if (f != NULL) {
    886     lock(f);
    887     fscanf(f, "%ld %ld %ld %ld", &tpool, &tpop3, &tdaily, &tmailin);
    888     latest = tpool;
    889     latest = latest > tpop3 ? latest : tpop3;
    890     latest = latest > tdaily ? latest : tdaily;
    891     latest = latest > tmailin ? latest : tmailin;
    892     now = time(NULL);
    893 
    894 
    895     if (( (TIMESKEW_BACK    != 0) && (now < latest - TIMESKEW_BACK   )) ||
    896         ( (TIMESKEW_FORWARD != 0) && (now > latest + TIMESKEW_FORWARD)) ) {
    897       /* Possible timeskew */
    898       errlog(ERRORMSG, "Possible timeskew detected.  Check clock and rm %s\n", REGULAR);
    899       exit(TEMP_FAIL);
    900     }
    901     fclose(f);
    902   } else {
    903     /* shrug */
    904   }
    905 }
    906 
    907 int mix_init(char *mixdir)
    908 {
    909   if (!initialized) {
    910     if (mixdir)
    911       strncpy(MIXDIR, mixdir, LINELEN);
    912     mix_config();
    913 #if defined(USE_SOCK) && defined(WIN32)
    914     sock_init();
    915 #endif /* defined(USE_SOCK) && defined(WIN32) */
    916     /* atexit (mix_exit); */
    917     initialized = 1;
    918   }
    919 
    920   if (rnd_init() == -1)
    921     rnd_seed();
    922   return(0);
    923 }
    924 
    925 void mix_exit(void)
    926 {
    927   if (!initialized)
    928     return;
    929   rnd_final();
    930 #if defined(USE_SOCK) && defined(WIN32)
    931   sock_exit();
    932 #endif /* defined(USE_SOCK) && defined(WIN32) */
    933   initialized=0;
    934 }
    935 
    936 void mix_upd_stats(void)
    937 {
    938   FILE *f;
    939   BUFFER *statssrc;
    940   statssrc = buf_new();
    941   buf_clear(statssrc);
    942   f = mix_openfile(STATSSRC, "r");
    943   if (f != NULL) {
    944     buf_read(statssrc, f);
    945     fclose(f);
    946   }
    947   if (statssrc->length > 0)
    948     download_stats(statssrc->data);
    949   buf_free(statssrc);
    950 }
    951 
    952 int mix_regular(int force)
    953 {
    954   FILE *f;
    955   long now, tpool = 0, tpop3 = 0, tdaily = 0, tmailin = 0, tstats = 0;
    956   int ret = 0;
    957 
    958   mix_init(NULL);
    959   now = time(NULL);
    960 
    961   f = mix_openfile(REGULAR, "r+");
    962   if (f != NULL) {
    963     lock(f);
    964     fscanf(f, "%ld %ld %ld %ld %ld", &tpool, &tpop3, &tdaily, &tmailin, &tstats);
    965     if (now - tpool >= SENDPOOLTIME)
    966       force |= FORCE_POOL | FORCE_MAILIN;
    967 #ifdef USE_SOCK
    968     if (now - tpop3 >= POP3TIME)
    969       force |= FORCE_POP3 | FORCE_MAILIN;
    970 #endif /* USE_SOCK */
    971     if (now - tdaily >= SECONDSPERDAY)
    972       force |= FORCE_DAILY;
    973     if (now - tmailin >= MAILINTIME)
    974       force |= FORCE_MAILIN;
    975     if (now - tstats >= STATSINTERVAL)
    976       force |= FORCE_STATS;
    977     if (force & FORCE_POOL)
    978       tpool = now;
    979     if (force & FORCE_POP3)
    980       tpop3 = now;
    981     if (force & FORCE_DAILY)
    982       tdaily = now;
    983     if (force & FORCE_MAILIN)
    984       tmailin = now;
    985     if (force & FORCE_STATS)
    986       tstats = now;
    987     rewind(f);
    988     fprintf(f, "%ld %ld %ld %ld %ld\n", tpool, tpop3, tdaily, tmailin, tstats);
    989     unlock(f);
    990     fclose(f);
    991   } else {
    992     force = FORCE_POOL | FORCE_POP3 | FORCE_DAILY | FORCE_MAILIN | FORCE_STATS;
    993     f = mix_openfile(REGULAR, "w+");
    994     if (f != NULL) {
    995       lock(f);
    996       fprintf(f, "%ld %ld %ld %ld %ld\n", now, now, now, now, now);
    997       unlock(f);
    998       fclose(f);
    999     } else
   1000       errlog(ERRORMSG, "Can't create %s!\n", REGULAR);
   1001   }
   1002 
   1003   if (force & FORCE_DAILY)
   1004     mix_daily(), ret = 1;
   1005 #ifdef USE_SOCK
   1006   if (force & FORCE_POP3)
   1007     pop3get();
   1008 #endif /* USE_SOCK */
   1009   if (force & FORCE_MAILIN)
   1010     ret = process_mailin();
   1011   if (force & FORCE_POOL)
   1012     ret = pool_send();
   1013   if ((force & FORCE_STATS) && (STATSAUTOUPDATE != 0))
   1014     mix_upd_stats();
   1015 
   1016   return (ret);
   1017 }
   1018 
   1019 int mix_daily(void)
   1020 {
   1021   idexp();
   1022   pgpmaxexp();
   1023   pool_packetexp();
   1024   stats(NULL);
   1025   keymgt(0);
   1026   return (0);
   1027 }
   1028 
   1029 /** Handle signals SIGHUP, SIGINT, and SIGTERM
   1030     This signal handler gets called if the daemon
   1031     process receives one of SIGHUP, SIGINT, or SIGTERM.
   1032     It then sets either rereadconfig of terminatedaemon
   1033     to true depending on the signal received.
   1034 
   1035     @author	PP
   1036     @return	nothing
   1037  */
   1038 #ifdef POSIX
   1039 void sighandler(int signal) {
   1040   if (signal == SIGHUP)
   1041     rereadconfig = 1;
   1042   else if (signal == SIGINT || signal == SIGTERM)
   1043     terminatedaemon = 1;
   1044 };
   1045 #endif /* POSIX */
   1046 
   1047 /** Set the signal handler for SIGHUP, SIGINT and SIGTERM
   1048     This function registers signal handlers so that
   1049     we can react on signals send by the user in daemon
   1050     mode. SIGHUP will instruct mixmaster to reload its
   1051     configuration while SIGINT and SIGTERM will instruct
   1052     it to shut down. Mixmaster will finish the current
   1053     pool run before it terminates.
   1054 
   1055     @param restart  Whether or not system calls should be
   1056                     restarted. Usually we want this, the
   1057                     only excetion is the sleep() in the
   1058                     daemon mail loop.
   1059     @author         PP
   1060     @return         -1 if calling sigaction failed, 0 on
   1061                     no error
   1062   */
   1063 int setsignalhandler(int restart)
   1064 {
   1065 #ifdef POSIX
   1066   struct sigaction hdl;
   1067   int err = 0;
   1068 
   1069   memset(&hdl, 0, sizeof(hdl));
   1070   hdl.sa_handler = sighandler;
   1071   hdl.sa_flags = restart ? SA_RESTART : 0;
   1072 
   1073   if (sigaction(SIGHUP, &hdl, NULL))
   1074     err = -1;
   1075   if (sigaction(SIGINT, &hdl, NULL))
   1076     err = -1;
   1077   if (sigaction(SIGTERM, &hdl, NULL))
   1078     err = -1;
   1079   return (err);
   1080 #else /* POSIX */
   1081   return(0);
   1082 #endif /* POSIX */
   1083 }
   1084 
   1085 #ifdef WIN32
   1086 /* Try to detect if we are the service or not...
   1087    seems there is no easy reliable way        */
   1088 int is_nt_service(void)
   1089 {
   1090     static int issvc = -1;
   1091 #ifdef WIN32SERVICE
   1092     STARTUPINFO StartupInfo;
   1093     OSVERSIONINFO VersionInfo;
   1094     DWORD dwsize;
   1095 
   1096     if (issvc != -1)    /* do it only once */
   1097 	return issvc;
   1098 
   1099     VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
   1100     if (GetVersionEx(&VersionInfo))
   1101 	if (VersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)
   1102 	    return issvc = 0; /* not NT - not the service */
   1103 
   1104     GetStartupInfo(&StartupInfo);
   1105     if (StartupInfo.lpDesktop[0] == 0)
   1106 	return issvc = 1; /* have no desktop - we are the service probably */
   1107 #endif /* WIN32SERVICE */
   1108 
   1109     return issvc = 0; /* assume not the service */
   1110 } /* is_nt_service */
   1111 
   1112 HANDLE hMustTerminate = NULL;
   1113 void set_nt_exit_event(HANDLE h_svc_exit_event)
   1114 {
   1115     hMustTerminate = h_svc_exit_event;
   1116 } /* set_nt_exit_event */
   1117 
   1118 #endif /* WIN32 */
   1119 
   1120 int mix_daemon(void)
   1121 {
   1122   long t, slept;
   1123   t = SENDPOOLTIME;
   1124   if (MAILINTIME < t && (MAILIN != NULL && MAILIN[0] != '\0'))
   1125     t = MAILINTIME;
   1126 #ifdef USE_SOCK
   1127   if (POP3TIME < t)
   1128     t = POP3TIME;
   1129 #endif /* USE_SOCK */
   1130   if (t < 5)
   1131     t = 5; /* Some kind of safety for broken systems */
   1132   slept = t;
   1133 
   1134   setsignalhandler(1); /* set signal handlers and restart any interrupted system calls */
   1135   for(;;) {
   1136     if (terminatedaemon)
   1137       break;
   1138     if (rereadconfig) {
   1139       rereadconfig = 0;
   1140       mix_config();
   1141       t = SENDPOOLTIME;
   1142       if (MAILINTIME < t && (MAILIN != NULL && MAILIN[0] != '\0'))
   1143 	t = MAILINTIME;
   1144 #ifdef USE_SOCK
   1145       if (POP3TIME < t)
   1146 	t = POP3TIME;
   1147       if (t < 5)
   1148 	t = 5; /* Some kind of safety for broken systems */
   1149 #endif /* USE_SOCK */
   1150     }
   1151     if (slept >= t) {
   1152       mix_regular(0);
   1153       slept = 0;
   1154     }
   1155 
   1156 #ifdef WIN32SERVICE
   1157     if (hMustTerminate) {
   1158       if (WaitForSingleObject(hMustTerminate, t * 1000) == WAIT_OBJECT_0) {
   1159 	CloseHandle(hMustTerminate);
   1160 	terminatedaemon = 1;
   1161       }
   1162     }
   1163 #endif /* WIN32SERVICE */
   1164 
   1165     if (!terminatedaemon && !rereadconfig) {
   1166       setsignalhandler(0); /* set signal handlers;  don't restart system calls */
   1167 #ifdef WIN32
   1168       sleep(t); /* how to get the real number of seconds slept? */
   1169       slept = t;
   1170 #else /* end of WIN32 */
   1171       slept += (t - slept) - sleep(t - slept);
   1172 #endif /* else if not WIN32 */
   1173       setsignalhandler(1); /* set signal handlers and restart any interrupted system calls */
   1174     }
   1175   }
   1176   return (0);
   1177 }
   1178 
   1179 /** error ***************************************************************/
   1180 
   1181 void errlog(int type, char *fmt,...)
   1182 {
   1183   va_list args;
   1184   BUFFER *msg;
   1185   FILE *e = NULL;
   1186   time_t t;
   1187   struct tm *tc;
   1188   char line[LINELEN];
   1189   int p;
   1190   char err[6][8] =
   1191   {"", "Error", "Warning", "Notice", "Info", "Info"};
   1192 
   1193   if ((VERBOSE == 0 && type != ERRORMSG) || (type == LOG && VERBOSE < 2)
   1194       || (type == DEBUGINFO && VERBOSE < 3))
   1195     return;
   1196 
   1197   t = time(NULL);
   1198   tc = localtime(&t);
   1199   strftime(line, LINELEN, "[%Y-%m-%d %H:%M:%S] ", tc);
   1200 
   1201   msg = buf_new();
   1202   buf_appends(msg, line);
   1203   p = msg->length;
   1204   buf_appendf(msg, "%s: ", err[type]);
   1205   va_start(args, fmt);
   1206   buf_vappendf(msg, fmt, args);
   1207   va_end(args);
   1208 
   1209   if (streq(ERRLOG, "stdout"))
   1210     e = stdout;
   1211   else if (streq(ERRLOG, "stderr"))
   1212     e = stderr;
   1213 
   1214   if (e == NULL && (ERRLOG[0] == '\0' ||
   1215 		    (e = mix_openfile(ERRLOG, "a")) == NULL))
   1216     mix_status("%s", msg->data + p);
   1217   else {
   1218     buf_write(msg, e);
   1219     if (e != stderr && e != stdout) {
   1220       fclose(e);
   1221       /* duplicate the error message on screen */
   1222       mix_status("%s", msg->data + p);
   1223     }
   1224   }
   1225   buf_free(msg);
   1226 }
   1227 
   1228 static char statusline[BUFSIZE] = "";
   1229 
   1230 void mix_status(char *fmt,...)
   1231 {
   1232   va_list args;
   1233 
   1234   if (fmt != NULL) {
   1235     va_start(args, fmt);
   1236 #ifdef _MSC
   1237     _vsnprintf(statusline, sizeof(statusline) - 1, fmt, args);
   1238 #else /* end of _MSC */
   1239     vsnprintf(statusline, sizeof(statusline) - 1, fmt, args);
   1240 #endif /* else if not _MSC */
   1241     va_end(args);
   1242   }
   1243 #ifdef USE_NCURSES
   1244   if (menu_initialized) {
   1245     cl(LINES - 2, 10);
   1246     printw("%s", statusline);
   1247     refresh();
   1248   } else
   1249 #endif /* USE_NCURSES */
   1250   {
   1251     fprintf(stderr, "%s", statusline);
   1252   }
   1253 }
   1254 
   1255 void mix_genericerror(void)
   1256 {
   1257   if (streq(statusline, "") || strfind(statusline, "...") ||
   1258       strifind(statusline, "generating"))
   1259     mix_status("Failed!");
   1260   else
   1261     mix_status(NULL);
   1262 }