/[pkg-mixmaster]/trunk/Mix/Src/mix.c
ViewVC logotype

Contents of /trunk/Mix/Src/mix.c

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:keywords Id

  ViewVC Help
Powered by ViewVC 1.1.5