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, ®sw); 668 len=sizeof(line); 669 if (err == -1 && 670 RegOpenKeyEx(regsw, "Mixmaster", 0, KEY_QUERY_VALUE, ®) == 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, ®pgp) == 0) 804 rkey++; 805 if (rkey && RegOpenKeyEx(regpgp, "PGPlib", 0, KEY_QUERY_VALUE, ®) == 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 }