/* Mixmaster version 2.9 -- (C) 1999 - 2003 Anonymizer Inc. and others.
Mixmaster may be redistributed and modified under certain conditions.
This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
ANY KIND, either express or implied. See the file COPYRIGHT for
details.
Command-line based frontend
$Id: main.c 665 2003-11-09 01:47:32Z rabbi $ */
#include "mix3.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#ifdef POSIX
#include <unistd.h>
#else /* end of POSIX */
#include <io.h>
#endif /* else if not POSIX */
static char *largopt(char *p, char *opt, char *name, int *error);
static void noarg(char *name, char p);
/** main *****************************************************************/
/* Returns:
0 successful operation
1 command line error
2 client error condition */
#ifdef WIN32SERVICE
int mix_main(int argc, char *argv[])
#else
int main(int argc, char *argv[])
#endif /* WIN32SERVICE */
{
int error = 0, deflt = 1, help = 0, readmail = 0, send = -1, sendpool = 0,
header = 1, maint = 0, keygen = 0, verbose = 2, sign = 0, encrypt = 0;
int daemon = 0, type_list = 0, nodetach = 0;
#ifdef USE_SOCK
int pop3 = 0;
#endif /* USE_SOCK */
char *filename = NULL;
int i;
int ret = 0;
char *p, *q;
char chain[1024] = "";
char nym[LINELEN] = "";
BUFFER *nymopt, *pseudonym, *attachments;
int numcopies = 0; /* default value set in mix.cfg */
BUFFER *msg, *chainlist, *field, *content;
FILE *f;
mix_init(NULL);
msg = buf_new();
chainlist = buf_new();
nymopt = buf_new();
pseudonym = buf_new();
attachments = buf_new();
field = buf_new();
content = buf_new();
#ifdef USE_NCURSES
if (argc == 1) {
if (isatty(fileno(stdin)))
menu_main();
else
menu_folder(0, NULL);
goto end;
}
#endif /* USE_NCURSES */
if (argc > 1 && strleft(argv[1], "-f")) {
menu_folder(strlen(argv[1]) > 2 ? argv[1][2] : 0,
argc < 3 ? NULL : argv[2]);
goto end;
}
for (i = 1; i < argc; i++) {
p = argv[i];
if (p[0] == '-' && p[1] != '\0') {
if (p[1] == '-') {
p += 2;
if (strieq(p, "help"))
help = 1, deflt = 0;
else if (streq(p, "verbose"))
verbose = 1;
else if (streq(p, "type-list"))
type_list = 1;
else if (streq(p, "dummy"))
send = MSG_NULL, deflt = 0;
else if (streq(p, "remailer"))
maint = 1, deflt = 0;
else if (streq(p, "generate-key"))
keygen = 2, deflt = 0;
else if (streq(p, "update-keys"))
keygen = 1, deflt = 0;
else if (streq(p, "send"))
sendpool = 1, deflt = 0;
else if (streq(p, "read-mail"))
readmail = 1, deflt = 0;
else if (streq(p, "store-mail"))
readmail = 2, deflt = 0;
#ifdef USE_SOCK
else if (streq(p, "pop-mail"))
pop3 = 1, deflt = 0;
#endif /* USE_SOCK */
else if (streq(p, "daemon"))
daemon = 1, deflt = 0;
else if (streq(p, "no-detach"))
nodetach = 1;
else if (streq(p, "post"))
send = MSG_POST;
else if (streq(p, "mail"))
send = MSG_MAIL;
else if (streq(p, "sign"))
sign = 1;
else if (streq(p, "encrypt"))
encrypt = 1;
else if ((q = largopt(p, "to", argv[0], &error)) != NULL) {
header = 0;
buf_appendf(msg, "To: %s\n", q);
} else if ((q = largopt(p, "post-to", argv[0], &error)) != NULL) {
send = MSG_POST, header = 0;
buf_appendf(msg, "Newsgroups: %s\n", q);
} else if ((q = largopt(p, "subject", argv[0], &error)) != NULL) {
buf_appendf(msg, "Subject: %s\n", q);
} else if ((q = largopt(p, "header", argv[0], &error)) != NULL) {
buf_appendf(msg, "%s\n", q);
} else if ((q = largopt(p, "chain", argv[0], &error)) != NULL) {
buf_appendf(msg, "Chain: %s\n", q);
}
#ifdef USE_PGP
else if ((q = largopt(p, "reply-chain", argv[0], &error)) != NULL) {
buf_appendf(msg, "Reply-Chain: %s\n", q);
} else if ((q = largopt(p, "latency", argv[0], &error)) != NULL) {
buf_appendf(msg, "Latency: %s\n", q);
} else if ((q = largopt(p, "attachment", argv[0], &error)) != NULL) {
buf_appendf(attachments, "%s\n", q);
} else if ((q = largopt(p, "nym-config", argv[0], &error)) != NULL) {
deflt = 0;
strncpy(nym, q, sizeof(nym));
if (i > argc && strileft(argv[i + 1], "name="))
buf_sets(pseudonym, argv[++i] + 5);
else if (i > argc && strileft(argv[i + 1], "opt="))
buf_appends(nymopt, argv[++i] + 5);
} else if ((q = largopt(p, "nym", argv[0], &error)) != NULL) {
buf_appendf(msg, "Nym: %s\n", q);
}
#endif /* USE_PGP */
else if ((q = largopt(p, "copies", argv[0], &error)) != NULL) {
sscanf(q, "%d", &numcopies);
} else if ((q = largopt(p, "config", argv[0], &error)) != NULL) {
strncpy(MIXCONF, q, PATHMAX);
MIXCONF[PATHMAX-1] = 0;
mix_config(); /* configuration file changed - reread it */
} else if (error == 0 && mix_configline(p) == 0) {
fprintf(stderr, "%s: Invalid option %s\n", argv[0], argv[i]);
error = 1;
}
} else {
while (*++p) {
switch (*p) {
case 'd':
send = MSG_NULL, deflt = 0;
break;
case 'R':
readmail = 1, deflt = 0;
break;
case 'I':
readmail = 2, deflt = 0;
break;
case 'S':
sendpool = 1, deflt = 0;
break;
case 'M':
maint = 1, deflt = 0;
break;
#ifdef USE_SOCK
case 'P':
pop3 = 1, deflt = 0;
break;
#endif /* USE_SOCK */
case 'D':
daemon = 1, deflt = 0;
break;
case 'G':
keygen = 2, deflt = 0;
break;
case 'K':
keygen = 1, deflt = 0;
break;
case 'L': /* backwards compatibility */
break;
case 'v':
verbose = 1;
break;
case 'h':
help = 1, deflt = 0;
break;
case 'T':
type_list = 1;
break;
case 't':
if (*(p + 1) == 'o')
p++;
header = 0;
if (i < argc - 1)
buf_appendf(msg, "To: %s\n", argv[++i]);
else {
fprintf(stderr, "%s: Missing argument for option -to\n",
argv[0]);
error = 1;
}
break;
case 's':
if (i < argc - 1)
buf_appendf(msg, "Subject: %s\n", argv[++i]);
else {
noarg(argv[0], *p);
error = 1;
}
break;
case 'l':
if (i < argc - 1)
buf_appendf(msg, "Chain: %s\n", argv[++i]);
else {
noarg(argv[0], *p);
error = 1;
}
break;
case 'r':
if (i < argc - 1)
buf_appendf(msg, "Reply-Chain: %s\n", argv[++i]);
else {
noarg(argv[0], *p);
error = 1;
}
break;
#ifdef USE_PGP
case 'n':
if (i < argc - 1)
buf_appendf(msg, "Nym: %s\n", argv[++i]);
else {
noarg(argv[0], *p);
error = 1;
}
break;
#endif /* USE_PGP */
case 'c':
if (i < argc - 1)
sscanf(argv[++i], "%d", &numcopies);
else {
noarg(argv[0], *p);
error = 1;
}
break;
case 'p':
send = MSG_POST;
break;
case 'g':
if (i < argc - 1) {
send = MSG_POST, header = 0;
buf_appendf(msg, "Newsgroups: %s\n", argv[++i]);
} else {
noarg(argv[0], *p);
error = 1;
}
break;
case 'a':
if (i < argc - 1)
buf_appendf(attachments, "%s\n", argv[++i]);
else {
noarg(argv[0], *p);
error = 1;
}
break;
case 'm':
send = MSG_MAIL;
break;
default:
fprintf(stderr, "%s: Invalid option -%c\n", argv[0], *p);
error = 1;
break;
}
}
}
} else {
if (strchr(argv[i], '@')) {
header = 0;
buf_appendf(msg, "To: %s\n", argv[i]);
} else {
if (filename == NULL)
filename = argv[i];
else {
fprintf(stderr, "%s: Error in command line: %s\n", argv[0], argv[i]);
error = 1;
}
}
}
}
if (error) {
ret = 1;
goto end;
}
if (type_list) {
BUFFER *type2list;
type2list = buf_new();
if (prepare_type2list(type2list) < 0) {
fprintf(stderr, "Cannot print type2.list.\n");
ret = 2;
} else {
printf("%s", type2list->data);
};
buf_free(type2list);
goto end;
}
if (help || (isatty(fileno(stdin)) && isatty(fileno(stdout))))
fprintf(stderr, "Mixmaster %s (%s) - %s\n", VERSION, SOURCE_REVISION, COPYRIGHT);
if (help) {
printf("Usage: %s [options] [user@host] [filename]\n\n", argv[0]);
printf("Options:\n\
\n\
-h, --help summary of command line options\n\
-T, --type-list list available remailers\n\
-t, --to=user@host the recipient's address(es)\n\
-g, --post-to=newsgroup newsgroup(s) to post to\n\
-p, --post input is a Usenet article\n\
-m, --mail input is a mail message\n\
-s, --subject=subject message subject\n\
--header='header line' arbitrary message headers\n\
-a, --attachment=file attach a file\n"
#ifdef USE_PGP
"-n, --nym=yournym use pseudonym to send the message\n\
--encrypt encrypt the message using the PGP format\n\
--sign sign the message using the PGP format\n"
#endif /* USE_PGP */
"-l, --chain=mix1,mix2,mix3,... specify a remailer chain\n\
-c, --copies=num send num copies to increase reliability\n\
-d, --dummy generate a dummy message\n\
-S, --send send the message(s) in the pool\n"
#ifdef USE_PGP
" --nym-config=yournym generate a new pseudonym\n\
--latency=hours reply chain latency\n\
--reply-chain=rem1,rem2,... reply chain for the pseudonym\n"
#endif /* USE_PGP */
"-v, --verbose output informational messages\n\
-f [file] read a mail folder\n"
#ifndef USE_NCURSES
"\n-fr, -ff, -fg [file] send reply/followup/group reply to a message\n"
#endif /* USE_NCURSES */
"\nThe input file is expected to contain mail headers if no address is\n\
specified in the command line.\n\
\n\
Remailer:\n\
\n\
-R, --read-mail read remailer message from stdin\n\
-I, --store-mail read remailer msg from stdin, do not decrypt\n\
-M, --remailer process the remailer pool\n\
-D, --daemon remailer as background process\n\
--no-detach do not detach from terminal as daemon\n"
#ifdef USE_SOCK
"-S, --send force sending messages from the pool\n"
#endif /* USE_SOCK */
"-P, --pop-mail force getting messages from POP3 servers\n\
-G, --generate-key generate a new remailer key\n\
-K, --update-keys generate remailer keys if necessary\n\
--config=file use alternate configuration file\n"
#ifdef WIN32SERVICE
"\n\
WinNT service:\n\
\n\
--install-svc install the service\n\
--remove-svc remove the service\n\
--run-svc run as a service\n"
#endif /* WIN32SERVICE */
);
ret = 0;
goto end;
}
if (deflt && send == -1)
send = MSG_MAIL;
if (nym[0] != 0)
send = -1;
if ((send == MSG_MAIL || send == MSG_POST) && filename == NULL &&
header == 1 && isatty(fileno(stdin))) {
/* we don't get here if USE_NCURSES is set */
printf("Run `%s -h' to view a summary of the command line options.\n\nEnter the message, complete with headers.\n",
argv[0]);
#ifdef UNIX
printf("When done, press ^D.\n\n");
#else
printf("When done, press ^Z.\n\n");
#endif /* else not UNIX */
}
if (header == 0)
buf_nl(msg);
if (readmail || send == MSG_MAIL || send == MSG_POST) {
if (filename == NULL || streq(filename, "-"))
f = stdin;
else {
f = fopen(filename, "r");
if (f == NULL)
fprintf(stderr, "Can't open %s.\n", filename);
}
if (f && buf_read(msg, f) != -1) {
if (readmail == 1)
mix_decrypt(msg);
else if (readmail == 2)
pool_add(msg, "inf");
if (send == MSG_MAIL || send == MSG_POST) {
BUFFER *sendmsg;
int numdest = 0;
sendmsg = buf_new();
while (buf_getheader(msg, field, content) == 0) {
if (bufieq(field, "nym")) {
strncpy(nym, content->data, sizeof(nym));
} else if (bufieq(field, "chain"))
if (strchr(content->data, ';')) {
i = strchr(content->data, ';') - (char *)content->data;
strncpy(chain, content->data, i);
if (strstr(content->data + i, "copies=") != NULL) {
sscanf(strstr(content->data + i, "copies=") +
sizeof("copies=") - 1, "%d", &numcopies);
}
} else
strncpy(chain, content->data, sizeof(chain));
else { /* line goes into message */
if ((send == MSG_MAIL && bufieq(field, "to"))
|| (send == MSG_POST && bufieq(field, "newsgroups")))
numdest++;
if (bufieq(field, "from"))
fprintf(stderr, "Warning: The message has a From: line.\n");
buf_appendheader(sendmsg, field, content);
}
}
buf_nl(sendmsg);
buf_rest(sendmsg, msg);
while (buf_getline(attachments, field) != -1)
if (attachfile(sendmsg, field) == -1) {
errlog(ERRORMSG, "Can't attach %b!\n", field);
ret = 2;
goto end;
}
#ifdef USE_PGP
if (nym[0] != 0 && strchr(nym, '@') == NULL)
strcatn(nym, "@", sizeof(nym));
if (sign || encrypt) {
BUFFER *pass;
pass = buf_new();
user_pass(pass);
if (pgp_mailenc((encrypt ? PGP_ENCRYPT : 0) |
(nym[0] != 0 && sign ? PGP_SIGN : 0) |
PGP_TEXT | PGP_REMAIL, sendmsg, nym,
pass, NULL, NYMSECRING) != 0) {
fprintf(stderr, "Encryption failed: missing key!");
ret = 2;
goto end;
}
buf_free(pass);
}
if (nym[0] != 0) {
if (nym_encrypt(sendmsg, nym, send) == 0)
send = MSG_MAIL;
else
fprintf(stderr, "Nym error, sending message anonymously.\n");
}
#endif /* USE_PGP */
if (numdest == 0) {
fprintf(stderr, "No destination address given!\n");
ret = 2;
} else if (numcopies < 0 || numcopies > 10) {
fprintf(stderr, "Invalid number of copies!\n");
ret = 2;
} else {
if (mix_encrypt(send, sendmsg, chain, numcopies,
chainlist) == -1) {
ret = 2;
if (chainlist->length)
fprintf(stderr, "%s\n", chainlist->data);
else
fprintf(stderr, "Failed!\n");
} else if (verbose) {
fprintf(stderr, "Chain: ");
buf_write(chainlist, stderr);
}
}
buf_free(sendmsg);
}
if (filename != NULL)
fclose(f);
} else
ret = 2;
}
if (send == MSG_NULL) {
if (msg->length) {
while (buf_getheader(msg, field, content) == 0) {
if (bufieq(field, "chain"))
strncpy(chain, content->data, sizeof(chain));
}
}
if (mix_encrypt(MSG_NULL, NULL, chain, numcopies, chainlist) == -1) {
ret = 2;
if (chainlist->length)
fprintf(stderr, "%s\n", chainlist->data);
else
fprintf(stderr, "Failed!\n");
} else if (verbose) {
fprintf(stderr, "Chain: ");
buf_write(chainlist, stderr);
}
}
#ifdef USE_PGP
if (nym[0] != 0) {
char nymserver[LINELEN] = "*";
BUFFER *chains;
chains = buf_new();
if (numcopies < 1 || numcopies > 10)
numcopies = 1;
while (buf_getheader(msg, field, content) != -1) {
if (bufieq(field, "chain"))
strncpy(chain, content->data, sizeof(chain));
else if (bufieq(field, "reply-chain"))
buf_appendf(chains, "Chain: %b\n", content);
else if (field->length)
buf_appendheader(chains, field, content);
else
buf_nl(chains);
}
if (strrchr(nym, '@')) {
strncpy(nymserver, strrchr(nym, '@'), sizeof(nymserver));
*strrchr(nym, '@') = '\0';
}
if (nym_config(NYM_CREATE, nym, nymserver, pseudonym,
chain, numcopies, chains, nymopt) < 0) {
ret = 2;
fprintf(stderr, "Failed!\n");
}
user_delpass();
buf_free(chains);
}
#endif /* USE_PGP */
if (keygen)
keymgt(keygen);
if (sendpool)
mix_send();
#ifdef USE_SOCK
if (pop3)
pop3get();
#endif /* USE_SOCK */
if (maint)
mix_regular(0);
if (REMAIL == 0)
mix_regular(0); /* check client pool */
end:
buf_free(field);
buf_free(content);
buf_free(chainlist);
buf_free(msg);
buf_free(nymopt);
buf_free(pseudonym);
buf_free(attachments);
if (daemon) {
#ifdef UNIX
if (! nodetach) {
int pid;
fprintf(stderr, "Detaching.\n");
/* Detach as suggested by the Unix Programming FAQ */
pid = fork();
if (pid > 0)
exit(0);
if (setsid() < 0) {
/* This should never happen. */
fprintf(stderr, "setsid() failed.\n");
exit(1);
};
pid = fork();
if (pid > 0)
exit(0);
};
if (chdir(MIXDIR) < 0) {
if (chdir("/") < 0) {
fprintf(stderr, "Cannot chdir to mixdir or /.\n");
exit(1);
};
};
if (write_pidfile(PIDFILE)) {
fprintf(stderr, "Aborting.\n");
exit(1);
}
if (! nodetach) {
freopen ("/dev/null", "r", stdin);
freopen ("/dev/null", "w", stdout);
freopen ("/dev/null", "w", stderr);
}
#endif /* UNIX */
mix_daemon();
#ifdef UNIX
/* ifdef this one to, so that we do not need to export it from windows dll */
clear_pidfile(PIDFILE);
#endif /* UNIX */
}
mix_exit();
return (ret);
}
static char *largopt(char *p, char *opt, char *name, int *error)
{
if (streq(p, opt)) {
fprintf(stderr, "%s: Missing argument for option --%s\n", name, p);
*error = 1;
} else if (strleft(p, opt) && p[strlen(opt)] == '=') {
return (p + strlen(opt) + 1);
}
return (NULL);
}
static void noarg(char *name, char p)
{
fprintf(stderr, "%s: Missing argument for option -%c\n", name, p);
}
syntax highlighted by Code2HTML, v. 0.9.1