mixmaster

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

main.c (22681B)


      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    Command-line based frontend
      9    $Id: main.c 937 2006-06-24 15:52:20Z colin $ */
     10 
     11 
     12 #include "mix3.h"
     13 #include "pgp.h"
     14 #include <stdio.h>
     15 #include <string.h>
     16 #include <ctype.h>
     17 #include <stdlib.h>
     18 #ifdef POSIX
     19 #include <unistd.h>
     20 #else /* end of POSIX */
     21 #include <io.h>
     22 #endif /* else if not POSIX */
     23 #include <assert.h>
     24 
     25 static char *largopt(char *p, char *opt, char *name, int *error);
     26 static void noarg(char *name, char p);
     27 static int check_get_pass(int force, int never_ask_for_passphrase);
     28 
     29 /** main *****************************************************************/
     30 
     31 /* Returns:
     32  0 successful operation
     33  1 command line error
     34  2 client error condition */
     35 
     36 #ifdef WIN32SERVICE
     37 int mix_main(int argc, char *argv[])
     38 #else
     39 int main(int argc, char *argv[])
     40 #endif /* WIN32SERVICE */
     41 {
     42   int error = 0, deflt = 1, help = 0, readmail = 0, send = -1, sendpool = 0,
     43   header = 1, maint = 0, keygen = 0, verbose = 0, sign = 0, encrypt = 0,
     44   redirect_mail = 0, about=0, version=0;
     45   int daemon = 0, type_list = 0, nodetach = 0;
     46   int update_stats = 0, update_pingerlist = 0;
     47   int never_ask_for_passphrase = 0;
     48 
     49 #ifdef USE_SOCK
     50   int pop3 = 0;
     51 
     52 #endif /* USE_SOCK */
     53   char *filename = NULL;
     54   int i;
     55   int ret = 0;
     56   char *p, *q;
     57   char chain[1024] = "";
     58   char nym[LINELEN] = "";
     59   BUFFER *nymopt, *pseudonym, *attachments, *statssrc;
     60   int numcopies = 0;		/* default value set in mix.cfg */
     61   BUFFER *msg, *chainlist, *field, *content;
     62   FILE *f;
     63   char pingpath[PATHMAX];
     64 
     65   /* Check if parse_yearmonthday works */
     66   assert(parse_yearmonthday("2003-04-01") == 1049155200);
     67 
     68   mix_init(NULL);
     69 
     70   msg = buf_new();
     71   chainlist = buf_new();
     72   nymopt = buf_new();
     73   pseudonym = buf_new();
     74   attachments = buf_new();
     75   field = buf_new();
     76   content = buf_new();
     77   statssrc = buf_new();
     78 
     79 #ifdef USE_NCURSES
     80   if (argc == 1) {
     81     if (isatty(fileno(stdin)))
     82       menu_main();
     83     else
     84       menu_folder(0, NULL);
     85     goto clientpool;
     86   }
     87 #endif /* USE_NCURSES */
     88   if (argc > 1 && strleft(argv[1], "-f")) {
     89     menu_folder(strlen(argv[1]) > 2 ? argv[1][2] : 0, argc < 3 ? NULL : argv[2]);
     90     goto clientpool;
     91   }
     92   for (i = 1; i < argc; i++) {
     93     p = argv[i];
     94     if (p[0] == '-' && p[1] != '\0') {
     95       if (p[1] == '-') {
     96 	p += 2;
     97 	if (strieq(p, "help"))
     98 	  help = 1, deflt = 0;
     99 	else if (streq(p, "version"))
    100 	  version = 1, deflt = 0;
    101 	else if (streq(p, "about"))
    102 	  about = 1, deflt = 0;
    103 	else if (streq(p, "verbose"))
    104 	  verbose = 1;
    105 	else if (streq(p, "type-list"))
    106 	  type_list = 1;
    107 	else if (streq(p, "dummy"))
    108 	  send = MSG_NULL, deflt = 0;
    109 	else if (streq(p, "remailer"))
    110 	  maint = 1, deflt = 0;
    111 	else if (streq(p, "generate-key"))
    112 	  keygen = 2, deflt = 0;
    113 	else if (streq(p, "update-keys"))
    114 	  keygen = 1, deflt = 0;
    115 	else if (streq(p, "send"))
    116 	  sendpool = 1, deflt = 0;
    117 	else if (streq(p, "read-mail"))
    118 	  readmail = 1, deflt = 0;
    119 	else if (streq(p, "redirect"))
    120 	  redirect_mail = 1, deflt = 0;
    121 	else if (streq(p, "store-mail"))
    122 	  readmail = 2, deflt = 0;
    123 #ifdef USE_SOCK
    124 	else if (streq(p, "pop-mail"))
    125 	  pop3 = 1, deflt = 0;
    126 #endif /* USE_SOCK */
    127 	else if (streq(p, "daemon"))
    128 	  daemon = 1, deflt = 0;
    129 	else if (streq(p, "no-detach"))
    130 	  nodetach = 1;
    131 	else if (streq(p, "post"))
    132 	  send = MSG_POST;
    133 	else if (streq(p, "mail"))
    134 	  send = MSG_MAIL;
    135 	else if (streq(p, "sign"))
    136 	  sign = 1;
    137 	else if (streq(p, "encrypt"))
    138 	  encrypt = 1;
    139 	else if (streq(p, "no-ask-passphrase"))
    140 	  never_ask_for_passphrase = 1;
    141 	else if (streq(p, "update-pinger-list"))
    142 	  update_pingerlist = 1;
    143 	else if (streq(p, "update-stats")) {
    144 	  buf_clear(statssrc);
    145 	  f = mix_openfile(STATSSRC, "r");
    146 	  if (f != NULL) {
    147 	    buf_read(statssrc, f);
    148 	    fclose(f);
    149 	  }
    150 	  if (statssrc->length > 0) {
    151 	    update_stats = 1;
    152 	  } else {
    153 	    deflt = 0;
    154 	    fprintf(stderr, "%s: No current stats source --%s\n", argv[0], p);
    155 	  }
    156 	} else if (strleft(p, "update-stats") && p[strlen("update-stats")] == '=') {
    157 	  buf_clear(statssrc);
    158 	  buf_appendf(statssrc, "%s", (p + strlen("update-stats") + 1));
    159 	  if (statssrc->length > 0) {
    160 	    update_stats = 1;
    161 	  } else {
    162 	    fprintf(stderr, "%s: No stats source specified --%s\n", argv[0], p);
    163 	  }
    164 	} else if ((q = largopt(p, "to", argv[0], &error)) != NULL) {
    165 	  header = 0;
    166 	  buf_appendf(msg, "To: %s\n", q);
    167 	} else if ((q = largopt(p, "post-to", argv[0], &error)) != NULL) {
    168 	  send = MSG_POST, header = 0;
    169 	  buf_appendf(msg, "Newsgroups: %s\n", q);
    170 	} else if ((q = largopt(p, "subject", argv[0], &error)) != NULL) {
    171 	  buf_appendf(msg, "Subject: %s\n", q);
    172 	} else if ((q = largopt(p, "header", argv[0], &error)) != NULL) {
    173 	  buf_appendf(msg, "%s\n", q);
    174 	} else if ((q = largopt(p, "chain", argv[0], &error)) != NULL) {
    175 	  buf_appendf(msg, "Chain: %s\n", q);
    176 	}
    177 #ifdef USE_PGP
    178 	else if ((q = largopt(p, "reply-chain", argv[0], &error)) != NULL) {
    179 	  buf_appendf(msg, "Reply-Chain: %s\n", q);
    180 	} else if ((q = largopt(p, "latency", argv[0], &error)) != NULL) {
    181 	  buf_appendf(msg, "Latency: %s\n", q);
    182 	} else if ((q = largopt(p, "attachment", argv[0], &error)) != NULL) {
    183 	  buf_appendf(attachments, "%s\n", q);
    184 #ifdef NYMSUPPORT
    185 	} else if ((q = largopt(p, "nym-config", argv[0], &error)) != NULL) {
    186 	  deflt = 0;
    187 	  strncpy(nym, q, sizeof(nym));
    188 	  if (i > argc && strileft(argv[i + 1], "name="))
    189 	    buf_sets(pseudonym, argv[++i] + 5);
    190 	  else if (i > argc && strileft(argv[i + 1], "opt="))
    191 	    buf_appends(nymopt, argv[++i] + 5);
    192 	} else if ((q = largopt(p, "nym", argv[0], &error)) != NULL) {
    193 	  buf_appendf(msg, "Nym: %s\n", q);
    194 #endif /* NYMSUPPORT */
    195 	}
    196 #endif /* USE_PGP */
    197 	else if ((q = largopt(p, "copies", argv[0], &error)) != NULL) {
    198 	  sscanf(q, "%d", &numcopies);
    199 	} else if ((q = largopt(p, "config", argv[0], &error)) != NULL) {
    200 	  strncpy(MIXCONF, q, PATHMAX);
    201 	  MIXCONF[PATHMAX-1] = 0;
    202 	  mix_config(); /* configuration file changed - reread it */
    203 	} else if (error == 0 && mix_configline(p) == 0) {
    204 	  fprintf(stderr, "%s: Invalid option %s\n", argv[0], argv[i]);
    205 	  error = 1;
    206 	}
    207       } else {
    208 	while (*++p) {
    209 	  switch (*p) {
    210 	  case 'd':
    211 	    send = MSG_NULL, deflt = 0;
    212 	    break;
    213 	  case 'R':
    214 	    readmail = 1, deflt = 0;
    215 	    break;
    216 	  case 'I':
    217 	    readmail = 2, deflt = 0;
    218 	    break;
    219 	  case 'S':
    220 	    sendpool = 1, deflt = 0;
    221 	    break;
    222 	  case 'M':
    223 	    maint = 1, deflt = 0;
    224 	    break;
    225 #ifdef USE_SOCK
    226 	  case 'P':
    227 	    pop3 = 1, deflt = 0;
    228 	    break;
    229 #endif /* USE_SOCK */
    230 	  case 'D':
    231 	    daemon = 1, deflt = 0;
    232 	    break;
    233 	  case 'G':
    234 	    keygen = 2, deflt = 0;
    235 	    break;
    236 	  case 'K':
    237 	    keygen = 1, deflt = 0;
    238 	    break;
    239 	  case 'L':		/* backwards compatibility */
    240 	    break;
    241 	  case 'v':
    242 	    verbose = 1;
    243 	    break;
    244 	  case 'h':
    245 	    help = 1, deflt = 0;
    246 	    break;
    247 	  case 'T':
    248 	    type_list = 1;
    249 	    break;
    250 	  case 'V':
    251 	    version = 1, deflt = 0;
    252 	    break;
    253 	  case 't':
    254 	    if (*(p + 1) == 'o')
    255 	      p++;
    256 	    header = 0;
    257 	    if (i < argc - 1)
    258 	      buf_appendf(msg, "To: %s\n", argv[++i]);
    259 	    else {
    260 	      fprintf(stderr, "%s: Missing argument for option -to\n", argv[0]);
    261 	      error = 1;
    262 	    }
    263 	    break;
    264 	  case 's':
    265 	    if (i < argc - 1)
    266 	      buf_appendf(msg, "Subject: %s\n", argv[++i]);
    267 	    else {
    268 	      noarg(argv[0], *p);
    269 	      error = 1;
    270 	    }
    271 	    break;
    272 	  case 'l':
    273 	    if (i < argc - 1)
    274 	      buf_appendf(msg, "Chain: %s\n", argv[++i]);
    275 	    else {
    276 	      noarg(argv[0], *p);
    277 	      error = 1;
    278 	    }
    279 	    break;
    280 	  case 'r':
    281 	    if (i < argc - 1)
    282 	      buf_appendf(msg, "Reply-Chain: %s\n", argv[++i]);
    283 	    else {
    284 	      noarg(argv[0], *p);
    285 	      error = 1;
    286 	    }
    287 	    break;
    288 #ifdef USE_PGP
    289 	  case 'n':
    290 	    if (i < argc - 1)
    291 	      buf_appendf(msg, "Nym: %s\n", argv[++i]);
    292 	    else {
    293 	      noarg(argv[0], *p);
    294 	      error = 1;
    295 	    }
    296 	    break;
    297 #endif /* USE_PGP */
    298 	  case 'c':
    299 	    if (i < argc - 1)
    300 	      sscanf(argv[++i], "%d", &numcopies);
    301 	    else {
    302 	      noarg(argv[0], *p);
    303 	      error = 1;
    304 	    }
    305 	    break;
    306 	  case 'p':
    307 	    send = MSG_POST;
    308 	    break;
    309 	  case 'g':
    310 	    if (i < argc - 1) {
    311 	      send = MSG_POST, header = 0;
    312 	      buf_appendf(msg, "Newsgroups: %s\n", argv[++i]);
    313 	    } else {
    314 	      noarg(argv[0], *p);
    315 	      error = 1;
    316 	    }
    317 	    break;
    318 	  case 'a':
    319 	    if (i < argc - 1)
    320 	      buf_appendf(attachments, "%s\n", argv[++i]);
    321 	    else {
    322 	      noarg(argv[0], *p);
    323 	      error = 1;
    324 	    }
    325 	    break;
    326 	  case 'm':
    327 	    send = MSG_MAIL;
    328 	    break;
    329 	  default:
    330 	    fprintf(stderr, "%s: Invalid option -%c\n", argv[0], *p);
    331 	    error = 1;
    332 	    break;
    333 	  }
    334 	}
    335       }
    336     } else {
    337       if (strchr(argv[i], '@')) {
    338 	header = 0;
    339 	buf_appendf(msg, "To: %s\n", argv[i]);
    340       } else {
    341 	if (filename == NULL)
    342 	  filename = argv[i];
    343 	else {
    344 	  fprintf(stderr, "%s: Error in command line: %s\n", argv[0], argv[i]);
    345 	  error = 1;
    346 	}
    347       }
    348     }
    349   }
    350 
    351   if (error) {
    352     ret = 1;
    353     goto end;
    354   }
    355 
    356   if (type_list) {
    357     BUFFER *type2list;
    358     type2list = buf_new();
    359     if (prepare_type2list(type2list) < 0) {
    360       fprintf(stderr, "Cannot print type2.list.\n");
    361       ret = 2;
    362     } else {
    363       printf("%s", type2list->data);
    364     };
    365     buf_free(type2list);
    366     goto end;
    367   }
    368 
    369   if (version) {
    370     printf("Mixmaster %s\n", VERSION);
    371     ret = 0;
    372     goto end;
    373   }
    374 
    375   if (update_pingerlist) {
    376     mixfile(pingpath, ALLPINGERSFILE);
    377     if (verbose) printf ("downloading %s...\n", ALLPINGERSURL);
    378     if (url_download(ALLPINGERSURL, pingpath) < 0) {
    379       printf("    Download failed... Try again later.\n");
    380       errlog(ERRORMSG, "All Pingers File Download failed.\n");
    381     } else {
    382       if (verbose) printf("    Done.\n");
    383       errlog(LOG, "All Pingers File Downloaded OK.\n");
    384     }
    385     ret = 0;
    386     goto end;
    387   }
    388   
    389   if (update_stats) {
    390     ret = download_stats(statssrc->data);
    391     if (ret == -3) {
    392       fprintf(stderr, "Stats source does not include all required files.\n");
    393     } else if (ret == -2) {
    394       fprintf(stderr, "Could not open stats source file for writing\n");
    395     } else if (ret == -1) {
    396       fprintf(stderr, "Stats source download failed.\n");
    397     }
    398     ret = 0;
    399     goto end;
    400   }
    401 
    402 #ifdef USE_NCURSES
    403 /* If we get here then it's possible we still want to use the NCURSES interface */
    404     if (deflt && (send == -1) && isatty(fileno(stdin))) {
    405       menu_main();
    406       goto clientpool;
    407     }
    408 #endif /* USE_NCURSES */
    409   
    410   if (help ||about ||(isatty(fileno(stdin)) && isatty(fileno(stdout))))
    411     fprintf(stderr, "Mixmaster %s\n", VERSION);
    412   if (help ||about)
    413     printf("\n\n");
    414   if (about) {
    415     printf("Many people have contributed to the source code for Mixmaster.\n");
    416     printf("These contributors include:\n\n");
    417     printf("Lance Cottrell\n");
    418     printf("Janis Jagars\n");
    419     printf("Ulf Moeller\n");
    420     printf("Peter Palfrader\n");
    421     printf("Len Sassaman\n");
    422     printf("\nand others. For full information on copyright and license issues,\n");
    423     printf("read the bundled file COPYRIGHT.\n\n");
    424     ret = 0;
    425     goto end;
    426   }
    427   
    428   if (help) {
    429     printf("Usage: %s [options] [user@host] [filename]\n\n", argv[0]);
    430     printf("Options:\n\
    431 \n\
    432 -h, --help                        summary of command line options\n\
    433 -V, --version                     print version information\n\
    434     --about                       print authorship information\n\
    435 -T, --type-list                   list available remailers\n\
    436 -t, --to=user@host                the recipient's address(es)\n\
    437 -g, --post-to=newsgroup           newsgroup(s) to post to\n\
    438 -p, --post                        input is a Usenet article\n\
    439 -m, --mail                        input is a mail message\n\
    440 -s, --subject=subject             message subject\n\
    441     --header='header line'        arbitrary message headers\n\
    442 -a, --attachment=file             attach a file\n"
    443 #ifdef USE_PGP
    444 #ifdef NYMSUPPORT
    445 	   "-n, --nym=yournym                 use pseudonym to send the message\n"
    446 #endif /* NYMSUPPORT */
    447 "    --encrypt                     encrypt the message using the PGP format\n\
    448     --sign                        sign the message using the PGP format\n"
    449 #endif /* USE_PGP */
    450 	   "-l, --chain=mix1,mix2,mix3,...    specify a remailer chain\n\
    451 -c, --copies=num                  send num copies to increase reliability\n\
    452 -d, --dummy                       generate a dummy message\n\
    453 -S, --send                        send the message(s) in the pool\n"
    454 #ifdef USE_PGP
    455 #ifdef NYMSUPPORT
    456 	   "    --nym-config=yournym          generate a new pseudonym\n\
    457     --latency=hours               reply chain latency\n\
    458     --reply-chain=rem1,rem2,...   reply chain for the pseudonym\n"
    459 #endif /* NYMSUPPORT */
    460 #endif /* USE_PGP */
    461 	   "-v, --verbose                     output informational messages\n\
    462 -f [file]                         read a mail folder\n\
    463     --update-pinger-list          Download an updated all pingers list file\n\
    464     --update-stats[=source]       Download updated stats\n"
    465 
    466 #ifndef USE_NCURSES
    467 	   "\n-fr, -ff, -fg [file]              send reply/followup/group reply to a message\n"
    468 #endif /* USE_NCURSES */
    469 	   "\nThe input file is expected to contain mail headers if no address is\n\
    470 specified in the command line.\n\
    471 \n\
    472 Remailer:\n\
    473 \n\
    474 -R, --read-mail                   read remailer message from stdin\n\
    475 -I, --store-mail                  read remailer msg from stdin, do not decrypt\n\
    476 -M, --remailer                    process the remailer pool\n\
    477 -D, --daemon                      remailer as background process\n\
    478     --no-detach                   do not detach from terminal as daemon\n"
    479 #ifdef USE_SOCK
    480 	   "-S, --send                        force sending messages from the pool\n"
    481 #endif /* USE_SOCK */
    482 	   "-P, --pop-mail                    force getting messages from POP3 servers\n\
    483 -G, --generate-key                generate a new remailer key\n\
    484 -K, --update-keys                 generate remailer keys if necessary\n\
    485     --config=file                 use alternate configuration file\n"
    486 #ifdef WIN32SERVICE
    487 	   "\n\
    488 WinNT service:\n\
    489 \n\
    490     --install-svc                 install the service\n\
    491     --remove-svc                  remove the service\n\
    492     --run-svc                     run as a service\n"
    493 #endif /* WIN32SERVICE */
    494     );
    495 
    496     ret = 0;
    497     goto end;
    498   }
    499 
    500   if (deflt && send == -1)
    501     send = MSG_MAIL;
    502   if (nym[0] != 0)
    503     send = -1;
    504   if ((send == MSG_MAIL || send == MSG_POST) && filename == NULL &&
    505       header == 1 && isatty(fileno(stdin))) {
    506     /* we don't get here if USE_NCURSES is set */
    507     printf("Run `%s -h' to view a summary of the command line options.\n\nEnter the message, complete with headers.\n",
    508 	   argv[0]);
    509 #ifdef UNIX
    510     printf("When done, press ^D.\n\n");
    511 #else
    512     printf("When done, press ^Z.\n\n");
    513 #endif /* else not UNIX */
    514   }
    515   if (header == 0)
    516     buf_nl(msg);
    517 
    518   /* timeskew check */
    519   if (REMAIL == 1)
    520     mix_check_timeskew();
    521 
    522   if (readmail || redirect_mail || send == MSG_MAIL || send == MSG_POST) {
    523     if (filename == NULL || streq(filename, "-"))
    524       f = stdin;
    525     else {
    526       f = fopen(filename, "r");
    527       if (f == NULL)
    528 	fprintf(stderr, "Can't open %s.\n", filename);
    529     }
    530 
    531     if (f && buf_read(msg, f) != -1) {
    532       if (readmail == 1) {
    533 	check_get_pass(1, never_ask_for_passphrase);
    534 	mix_decrypt(msg);
    535       } else if (readmail == 2)
    536 	pool_add(msg, "inf");
    537       if (send == MSG_MAIL || send == MSG_POST || redirect_mail) {
    538 	BUFFER *sendmsg;
    539 	int numdest = 0;
    540 
    541 	sendmsg = buf_new();
    542 
    543 	while (buf_getheader(msg, field, content) == 0) {
    544 	  if (bufieq(field, "nym")) {
    545 	    strncpy(nym, content->data, sizeof(nym));
    546 	  } else if (bufieq(field, "chain"))
    547 	    if (strchr(content->data, ';')) {
    548 	      i = strchr(content->data, ';') - (char *)content->data;
    549 	      strncpy(chain, content->data, i);
    550 	      if (strstr(content->data + i, "copies=") != NULL) {
    551 		sscanf(strstr(content->data + i, "copies=") +
    552 		       sizeof("copies=") - 1, "%d", &numcopies);
    553 	      }
    554 	    } else
    555 	      strncpy(chain, content->data, sizeof(chain));
    556 	  else {		/* line goes into message */
    557 	    if (((redirect_mail || send == MSG_MAIL) && bufieq(field, "to"))
    558 		|| (send == MSG_POST && bufieq(field, "newsgroups")))
    559 	      numdest++;
    560 	    if (bufieq(field, "from") && !redirect_mail)
    561 	      fprintf(stderr, "Warning: The message has a From: line.\n");
    562 	    buf_appendheader(sendmsg, field, content);
    563 	  }
    564 	}
    565 	buf_nl(sendmsg);
    566 	buf_rest(sendmsg, msg);
    567 
    568 	while (buf_getline(attachments, field) != -1)
    569 	  if (attachfile(sendmsg, field) == -1) {
    570 	    errlog(ERRORMSG, "Can't attach %b!\n", field);
    571 	    ret = 2;
    572 	    goto end;
    573 	  }
    574 
    575 #ifdef USE_PGP
    576 	if (nym[0] != 0 && strchr(nym, '@') == NULL)
    577 	  strcatn(nym, "@", sizeof(nym));
    578 	if (sign || encrypt) {
    579 	  BUFFER *pass;
    580 
    581 	  pass = buf_new();
    582 	  user_pass(pass);
    583 	  if (pgp_mailenc((encrypt ? PGP_ENCRYPT : 0) |
    584 			  (nym[0] != 0 && sign ? PGP_SIGN : 0) |
    585 			  PGP_TEXT | PGP_REMAIL, sendmsg, nym,
    586 			  pass, NULL, NYMSECRING) != 0) {
    587 	    fprintf(stderr, "Encryption failed: missing key!");
    588 	    ret = 2;
    589 	    goto end;
    590 	  }
    591 	  buf_free(pass);
    592 	}
    593 	if (nym[0] != 0) {
    594 #ifdef NYMSUPPORT
    595 	  if (nym_encrypt(sendmsg, nym, send) == 0)
    596 	    send = MSG_MAIL;
    597 	  else
    598 #endif /* NYMSUPPORT */
    599 	    fprintf(stderr, "Nym error, sending message anonymously.\n");
    600 	}
    601 #endif /* USE_PGP */
    602 	if (numdest == 0) {
    603 	  fprintf(stderr, "No destination address given!\n");
    604 	  ret = 2;
    605 	} else if (numcopies < 0 || numcopies > 10) {
    606 	  fprintf(stderr, "Invalid number of copies!\n");
    607 	  ret = 2;
    608 	} else {
    609 	  if ( ( redirect_mail ?
    610 		redirect_message(sendmsg, chain, numcopies, chainlist) :
    611 		mix_encrypt(send, sendmsg, chain, numcopies, chainlist)
    612 		) == -1) {
    613 	    ret = 2;
    614 	    if (chainlist->length)
    615 	      fprintf(stderr, "%s\n", chainlist->data);
    616 	    else
    617 	      fprintf(stderr, "Failed!\n");
    618 	  } else if (verbose) {
    619 	    fprintf(stderr, "Chain: ");
    620 	    buf_write(chainlist, stderr);
    621 	  }
    622 	}
    623 
    624 	buf_free(sendmsg);
    625       }
    626       if (filename != NULL)
    627 	fclose(f);
    628     } else
    629       ret = 2;
    630   }
    631   if (send == MSG_NULL) {
    632     if (msg->length) {
    633       while (buf_getheader(msg, field, content) == 0) {
    634 	if (bufieq(field, "chain"))
    635 	  strncpy(chain, content->data, sizeof(chain));
    636       }
    637     }
    638     if (mix_encrypt(MSG_NULL, NULL, chain, numcopies, chainlist) == -1) {
    639       ret = 2;
    640       if (chainlist->length)
    641 	printf("%s\n", chainlist->data);
    642       else
    643 	fprintf(stderr, "Failed!\n");
    644     } else if (verbose) {
    645       printf("Chain: ");
    646       buf_write(chainlist, stdout);
    647     }
    648   }
    649 #ifdef USE_PGP
    650 #ifdef NYMSUPPORT
    651   if (nym[0] != 0) {
    652     char nymserver[LINELEN] = "*";
    653     BUFFER *chains;
    654 
    655     chains = buf_new();
    656     if (numcopies < 1 || numcopies > 10)
    657       numcopies = 1;
    658     while (buf_getheader(msg, field, content) != -1) {
    659       if (bufieq(field, "chain"))
    660 	strncpy(chain, content->data, sizeof(chain));
    661       else if (bufieq(field, "reply-chain"))
    662 	buf_appendf(chains, "Chain: %b\n", content);
    663       else if (field->length)
    664 	buf_appendheader(chains, field, content);
    665       else
    666 	buf_nl(chains);
    667     }
    668     if (strrchr(nym, '@')) {
    669       strncpy(nymserver, strrchr(nym, '@'), sizeof(nymserver));
    670       *strrchr(nym, '@') = '\0';
    671     }
    672     if (nym_config(NYM_CREATE, nym, nymserver, pseudonym,
    673 		   chain, numcopies, chains, nymopt) < 0) {
    674       ret = 2;
    675       fprintf(stderr, "Failed!\n");
    676     }
    677     user_delpass();
    678     buf_free(chains);
    679   }
    680 #endif /* NYMSUPPORT */
    681 #endif /* USE_PGP */
    682 
    683   if (keygen) {
    684     check_get_pass(0, never_ask_for_passphrase);
    685     keymgt(keygen);
    686   }
    687   if (sendpool)
    688     mix_send();
    689 #ifdef USE_SOCK
    690   if (pop3)
    691     pop3get();
    692 #endif /* USE_SOCK */
    693   if (maint) {
    694     check_get_pass(1, never_ask_for_passphrase);
    695     mix_regular(0);
    696   }
    697 
    698 clientpool:
    699   if ((REMAIL == 0) && (CLIENTAUTOFLUSH == 1)) {
    700     SENDPOOLTIME = 0;
    701     RATE = 100;
    702     mix_send();
    703   };
    704 
    705 end:
    706   buf_free(field);
    707   buf_free(content);
    708   buf_free(chainlist);
    709   buf_free(msg);
    710   buf_free(nymopt);
    711   buf_free(pseudonym);
    712   buf_free(attachments);
    713   buf_free(statssrc);
    714 
    715   if (daemon) {
    716     check_get_pass(1, never_ask_for_passphrase);
    717 #ifdef UNIX
    718     if (! nodetach) {
    719       int pid;
    720 
    721       fprintf(stderr, "Detaching.\n");
    722       /* Detach as suggested by the Unix Programming FAQ */
    723       pid = fork();
    724       if (pid > 0)
    725 	exit(0);
    726       if (setsid() < 0) {
    727 	/* This should never happen. */
    728 	fprintf(stderr, "setsid() failed.\n");
    729 	exit(1);
    730       };
    731       pid = fork();
    732       if (pid > 0)
    733 	exit(0);
    734     };
    735     if (chdir(MIXDIR) < 0) {
    736       if (chdir("/") < 0) {
    737 	fprintf(stderr, "Cannot chdir to mixdir or /.\n");
    738 	exit(1);
    739       };
    740     };
    741     if (write_pidfile(PIDFILE)) {
    742       fprintf(stderr, "Aborting.\n");
    743       exit(1);
    744     }
    745     if (! nodetach) {
    746       freopen ("/dev/null", "r", stdin);
    747       freopen ("/dev/null", "w", stdout);
    748       freopen ("/dev/null", "w", stderr);
    749     }
    750 #endif /* UNIX */
    751     mix_daemon();
    752 #ifdef UNIX
    753 /* ifdef this one too, so that we do not need to export it from windows dll */
    754     clear_pidfile(PIDFILE);
    755 #endif /* UNIX */
    756   }
    757   mix_exit();
    758   return (ret);
    759 }
    760 
    761 static char *largopt(char *p, char *opt, char *name, int *error)
    762 {
    763   if (streq(p, opt)) {
    764     fprintf(stderr, "%s: Missing argument for option --%s\n", name, p);
    765     *error = 1;
    766   } else if (strleft(p, opt) && p[strlen(opt)] == '=') {
    767     return (p + strlen(opt) + 1);
    768   }
    769   return (NULL);
    770 }
    771 
    772 static void noarg(char *name, char p)
    773 {
    774   fprintf(stderr, "%s: Missing argument for option -%c\n", name, p);
    775 }
    776 
    777 static int check_get_pass(int force, int never_ask_for_passphrase)
    778 /* get a passphrase and check against keys
    779  * if force != 0 passphrase must match with some key */
    780 {
    781     BUFFER *pass, *pass2, *key;
    782     int n = 0;
    783 
    784     if (PASSPHRASE[0] == '\0' && isatty(fileno(stdin)) && ! never_ask_for_passphrase) {
    785       pass = buf_new();
    786       pass2 = buf_new();
    787       key = buf_new();
    788       buf_sets(pass, PASSPHRASE);
    789       while (
    790 #ifdef USE_PGP
    791 	     pgpdb_getkey(PK_DECRYPT, PGP_ES_RSA, NULL, NULL, NULL, NULL, NULL,
    792 			   NULL, NULL, NULL, pass) < 0 &&
    793 	     pgpdb_getkey(PK_DECRYPT, PGP_E_ELG,  NULL, NULL, NULL, NULL, NULL,
    794 			   NULL, NULL, NULL, pass) < 0 &&
    795 #endif /* USE_PGP */
    796 	     getv2seckey(NULL, key) < 0)
    797       {
    798 	user_delpass();
    799 	if (n)
    800 	  fprintf(stderr, "re-");
    801 	user_pass(pass);
    802 	strncpy(PASSPHRASE, pass->data, LINELEN);
    803 	PASSPHRASE[LINELEN-1] = 0;
    804 	if (!force) {
    805 	  if (n && buf_eq(pass, pass2))
    806 	    break;
    807 	  buf_set(pass2, pass);
    808 	}
    809 	n=1;
    810       }
    811       user_delpass();
    812       buf_free(pass);
    813       buf_free(pass2);
    814       buf_free(key);
    815 
    816       strncpy(ENTEREDPASSPHRASE, PASSPHRASE, LINELEN);
    817       ENTEREDPASSPHRASE[LINELEN-1] = 0;
    818     }
    819     return 1;
    820 }