419 lines
11 KiB
C
419 lines
11 KiB
C
/*****************************************************************************
|
|
*
|
|
* File ..................: mbmail/mbmail.c
|
|
* Purpose ...............: MBSE BBS Mail Gate
|
|
* Last modification date : 28-May-2001
|
|
*
|
|
*****************************************************************************
|
|
* Copyright (C) 1997-2001
|
|
*
|
|
* Michiel Broek FIDO: 2:280/2802
|
|
* Beekmansbos 10
|
|
* 1971 BV IJmuiden
|
|
* the Netherlands
|
|
*
|
|
* This file is part of MBSE BBS.
|
|
*
|
|
* This BBS is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2, or (at your option) any
|
|
* later version.
|
|
*
|
|
* MBSE BBS is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with MBSE BBS; see the file COPYING. If not, write to the Free
|
|
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*****************************************************************************/
|
|
|
|
#include "../lib/libs.h"
|
|
#include "../lib/structs.h"
|
|
#include "../lib/records.h"
|
|
#include "../lib/common.h"
|
|
#include "../lib/clcomm.h"
|
|
#include "../lib/dbftn.h"
|
|
#include "../lib/dbcfg.h"
|
|
#include "../lib/dbnode.h"
|
|
#include "../lib/dbmsgs.h"
|
|
#include "../lib/dbuser.h"
|
|
#include "hash.h"
|
|
#include "mkftnhdr.h"
|
|
#include "message.h"
|
|
|
|
|
|
/* ### Modified by P.Saratxaga on 9 Aug 1995 ###
|
|
* - added a line so if fmsg->to->name is greater than MAXNAME (35),
|
|
* and "@" or "%" or "!" is in it; then UUCP is used instead. So we can
|
|
* send messages to old style fido->email gates (that is, using another
|
|
* soft than mbmail ;-) ) with long adresses.
|
|
*/
|
|
|
|
extern int most_debug;
|
|
extern int addrerror;
|
|
extern int defaultrfcchar;
|
|
extern int defaultftnchar;
|
|
extern int do_quiet; /* Quiet flag */
|
|
extern int e_pid; /* Pid of child process */
|
|
extern int show_log; /* Show logging on screen */
|
|
time_t t_start; /* Start time */
|
|
time_t t_end; /* End time */
|
|
extern int usetmp;
|
|
int pgpsigned;
|
|
extern char *configname;
|
|
extern char passwd[];
|
|
int net_in = 0, net_imp = 0, net_out = 0, net_bad = 0;
|
|
int dirtyoutcode = CHRS_NOTSET;
|
|
|
|
|
|
void ProgName(void)
|
|
{
|
|
if (do_quiet)
|
|
return;
|
|
|
|
colour(15, 0);
|
|
printf("\nMBMAIL: MBSE BBS %s - Internet Fidonet mail gate\n", VERSION);
|
|
colour(14, 0);
|
|
printf(" %s\n", Copyright);
|
|
}
|
|
|
|
|
|
|
|
void Help(void)
|
|
{
|
|
do_quiet = FALSE;
|
|
ProgName();
|
|
|
|
colour(11, 0);
|
|
printf("\nUsage: mbmail -r<addr> -g<grade> <recip> ...\n\n");
|
|
colour(9, 0);
|
|
printf(" Commands are:\n\n");
|
|
colour(3, 0);
|
|
printf(" -r<addr> address to route packet\n");
|
|
printf(" -g<grade> [ n | c | h ] \"flavor\" of packet\n");
|
|
printf(" -c<charset> force the given charset\n");
|
|
printf(" <recip> list of receipient addresses\n");
|
|
colour(7, 0);
|
|
ExitClient(0);
|
|
}
|
|
|
|
|
|
|
|
void die(int onsig)
|
|
{
|
|
/*
|
|
* First check if there is a child running, if so, kill it.
|
|
*/
|
|
if (e_pid) {
|
|
if ((kill(e_pid, SIGTERM)) == 0)
|
|
Syslog('+', "SIGTERM to pid %d succeeded", e_pid);
|
|
else {
|
|
if ((kill(e_pid, SIGKILL)) == 0)
|
|
Syslog('+', "SIGKILL to pid %d succeeded", e_pid);
|
|
else
|
|
WriteError("Failed to kill pid %d", e_pid);
|
|
}
|
|
|
|
/*
|
|
* In case the child had the tty in raw mode, reset the tty.
|
|
*/
|
|
system("stty sane");
|
|
}
|
|
|
|
signal(onsig, SIG_IGN);
|
|
|
|
if (!do_quiet) {
|
|
show_log = TRUE;
|
|
colour(3, 0);
|
|
}
|
|
|
|
if (onsig) {
|
|
if (onsig <= NSIG)
|
|
WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]);
|
|
else
|
|
WriteError("Terminated with error %d", onsig);
|
|
}
|
|
|
|
Syslog('+', "Msgs in [%4d] imp [%4d] out [%4d] bad [%4d]", net_in, net_imp, net_out, net_bad);
|
|
|
|
if (net_out)
|
|
CreateSema((char *)"scanout");
|
|
|
|
|
|
time(&t_end);
|
|
Syslog(' ', "MBMAIL finished in %s", t_elapsed(t_start, t_end));
|
|
|
|
if (!do_quiet)
|
|
colour(7, 0);
|
|
ExitClient(onsig);
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
char *cmd, *envptr;
|
|
struct passwd *pw;
|
|
int i, c, rc;
|
|
char *routec = NULL;
|
|
faddr *route = NULL;
|
|
char *p;
|
|
char buf[BUFSIZ];
|
|
FILE *fp;
|
|
fa_list **envrecip, *envrecip_start = NULL;
|
|
int envrecip_count = 0;
|
|
rfcmsg *msg=NULL;
|
|
ftnmsg *fmsg=NULL;
|
|
faddr *taddr;
|
|
char cflavor = '\0', flavor;
|
|
fa_list *sbl = NULL;
|
|
int incode, outcode;
|
|
|
|
#ifdef MEMWATCH
|
|
mwInit();
|
|
#endif
|
|
|
|
/*
|
|
* The next trick is to supply a fake environment variable
|
|
* MBSE_ROOT in case we are started from the MTA.
|
|
* Some MTA's can't change uid to mbse, so if that's the
|
|
* case we will try it ourself.
|
|
* This will setup the variable so InitConfig() will work.
|
|
* The /etc/passwd must point to the correct homedirectory.
|
|
*/
|
|
pw = getpwuid(getuid());
|
|
if (getenv("MBSE_ROOT") == NULL) {
|
|
pw = getpwuid(getuid());
|
|
if (strcmp(pw->pw_name, "mbse")) {
|
|
/*
|
|
* We are not running as user mbse.
|
|
*/
|
|
pw = getpwnam("mbse");
|
|
if (setuid(pw->pw_uid)) {
|
|
printf("Fatal error: can't set uid to user mbse\n");
|
|
}
|
|
}
|
|
envptr = xstrcpy((char *)"MBSE_ROOT=");
|
|
envptr = xstrcat(envptr, pw->pw_dir);
|
|
putenv(envptr);
|
|
}
|
|
|
|
do_quiet = TRUE;
|
|
InitConfig();
|
|
InitFidonet();
|
|
InitNode();
|
|
InitMsgs();
|
|
InitUser();
|
|
TermInit(1);
|
|
time(&t_start);
|
|
umask(002);
|
|
|
|
/*
|
|
* Catch all the signals we can, and ignore the rest.
|
|
*/
|
|
for(i = 0; i < NSIG; i++) {
|
|
|
|
if ((i == SIGINT) || (i == SIGBUS) || (i == SIGILL) ||
|
|
(i == SIGSEGV) || (i == SIGTERM) || (i == SIGKILL))
|
|
signal(i, (void (*))die);
|
|
else
|
|
signal(i, SIG_IGN);
|
|
}
|
|
|
|
if (argc < 2)
|
|
Help();
|
|
|
|
cmd = xstrcpy((char *)"Cmd line: mbmail");
|
|
|
|
while ((c = getopt(argc, argv, "g:r:c:h")) != -1) {
|
|
cmd = xstrcat(cmd, (char *)" - ");
|
|
cmd[strlen(cmd) -1] = c;
|
|
switch (c) {
|
|
case 'h': Help();
|
|
case 'g': if (optarg && ((*optarg == 'n') || (*optarg == 'c') || (*optarg == 'h'))) {
|
|
cflavor = *optarg;
|
|
cmd = xstrcat(cmd, optarg);
|
|
} else {
|
|
Help();
|
|
}
|
|
break;
|
|
case 'r': routec = optarg; cmd = xstrcat(cmd, optarg); break;
|
|
case 'c': dirtyoutcode = readchrs(optarg);
|
|
cmd = xstrcat(cmd, optarg);
|
|
if (dirtyoutcode == CHRS_NOTSET)
|
|
dirtyoutcode = getcode(optarg);
|
|
break;
|
|
default: Help();
|
|
}
|
|
}
|
|
|
|
ProgName();
|
|
InitClient(pw->pw_name, (char *)"mbmail", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log);
|
|
|
|
Syslog(' ', " ");
|
|
Syslog(' ', "MBMAIL v%s", VERSION);
|
|
most_debug = TRUE;
|
|
|
|
if (!diskfree(CFG.freespace))
|
|
die(101);
|
|
|
|
|
|
if (cflavor == 'n')
|
|
cflavor='o';
|
|
|
|
if ((routec) && ((route=parsefaddr(routec)) == NULL))
|
|
WriteError("unparsable route address \"%s\" (%s)", MBSE_SS(routec),addrerrstr(addrerror));
|
|
|
|
if ((p=strrchr(argv[0],'/')))
|
|
p++;
|
|
else
|
|
p=argv[0];
|
|
|
|
envrecip = &envrecip_start;
|
|
while (argv[optind]) {
|
|
cmd = xstrcat(cmd, (char *)" ");
|
|
cmd = xstrcat(cmd, argv[optind]);
|
|
if ((taddr = parsefaddr(argv[optind++]))) {
|
|
(*envrecip)=(fa_list*)malloc(sizeof(fa_list));
|
|
(*envrecip)->next=NULL;
|
|
(*envrecip)->addr=taddr;
|
|
envrecip=&((*envrecip)->next);
|
|
envrecip_count++;
|
|
} else
|
|
WriteError("unparsable recipient \"%s\" (%s), ignored", argv[optind-1], addrerrstr(addrerror));
|
|
}
|
|
Syslog(' ', cmd);
|
|
free(cmd);
|
|
|
|
if (!envrecip_count) {
|
|
WriteError("No valid receipients specified, aborting");
|
|
die(105);
|
|
}
|
|
|
|
for (envrecip = &envrecip_start; *envrecip; envrecip = &((*envrecip)->next))
|
|
Syslog('+', "envrecip: %s",ascfnode((*envrecip)->addr,0x7f));
|
|
Syslog('+', "route: %s",ascfnode(route,0x1f));
|
|
|
|
umask(066); /* packets may contain confidential information */
|
|
|
|
while (!feof(stdin)) {
|
|
usetmp = 0;
|
|
tidyrfc(msg);
|
|
msg = parsrfc(stdin);
|
|
|
|
incode = outcode = CHRS_NOTSET;
|
|
pgpsigned = 0;
|
|
|
|
p = hdr((char *)"Content-Type",msg);
|
|
if (p)
|
|
incode = readcharset(p);
|
|
if (incode == CHRS_NOTSET) {
|
|
p = hdr((char *)"X-FTN-CHRS",msg);
|
|
if (p == NULL)
|
|
p = hdr((char *)"X-FTN-CHARSET",msg);
|
|
if (p == NULL)
|
|
p = hdr((char *)"X-FTN-CODEPAGE",msg);
|
|
if (p)
|
|
incode = readchrs(p);
|
|
if ((p = hdr((char *)"Message-ID",msg)) && (chkftnmsgid(p)))
|
|
incode = defaultftnchar;
|
|
else
|
|
incode = defaultrfcchar;
|
|
}
|
|
if ((p = hdr((char *)"Content-Type",msg)) && ((strcasestr(p, (char *)"multipart/signed")) ||
|
|
(strcasestr(p,(char *)"application/pgp")))) {
|
|
pgpsigned = 1;
|
|
outcode = incode;
|
|
} else if ((p=hdr((char *)"X-FTN-ORIGCHRS",msg)))
|
|
outcode = readchrs(p);
|
|
else if (dirtyoutcode != CHRS_NOTSET)
|
|
outcode = dirtyoutcode;
|
|
else
|
|
outcode = getoutcode(incode);
|
|
|
|
flavor = cflavor;
|
|
|
|
if ((p = hdr((char *)"X-FTN-FLAGS",msg))) {
|
|
if (!flavor) {
|
|
if (flag_on((char *)"CRS",p))
|
|
flavor = 'c';
|
|
else if (flag_on((char *)"HLD",p))
|
|
flavor = 'h';
|
|
else
|
|
flavor = 'o';
|
|
}
|
|
if (flag_on((char *)"ATT",p))
|
|
attach(*route, hdr((char *)"Subject",msg), 0, flavor);
|
|
if (flag_on((char *)"TFS",p))
|
|
attach(*route, hdr((char *)"Subject",msg), 1, flavor);
|
|
if (flag_on((char *)"KFS",p))
|
|
attach(*route, hdr((char *)"Subject",msg), 2, flavor);
|
|
}
|
|
if ((!flavor) && ((p = hdr((char *)"Priority",msg)) ||
|
|
(p = hdr((char *)"Precedence",msg)) || (p = hdr((char *)"X-Class",msg)))) {
|
|
while (isspace(*p))
|
|
p++;
|
|
if ((strncasecmp(p,"fast",4) == 0) || (strncasecmp(p,"high",4) == 0) ||
|
|
(strncasecmp(p,"crash",5) == 0) || (strncasecmp(p,"airmail",5) == 0) ||
|
|
(strncasecmp(p,"special-delivery",5) == 0) || (strncasecmp(p,"first-class",5) == 0))
|
|
flavor='c';
|
|
else if ((strncasecmp(p,"slow",4) == 0) || (strncasecmp(p,"low",3) == 0) ||
|
|
(strncasecmp(p,"hold",4) == 0) || (strncasecmp(p,"news",4) == 0) ||
|
|
(strncasecmp(p,"bulk",4) == 0) || (strncasecmp(p,"junk",4) == 0))
|
|
flavor='h';
|
|
}
|
|
if (!flavor)
|
|
flavor='o';
|
|
|
|
if (envrecip_count > 1) {
|
|
if ((fp = tmpfile()) == NULL) {
|
|
WriteError("$Cannot open temporary file");
|
|
die(102);
|
|
}
|
|
while (bgets(buf, sizeof(buf)-1, stdin))
|
|
fputs(buf, fp);
|
|
rewind(fp);
|
|
usetmp = 1;
|
|
} else {
|
|
fp = stdin;
|
|
usetmp = 0;
|
|
}
|
|
|
|
tidy_ftnmsg(fmsg);
|
|
if ((fmsg = mkftnhdr(msg, incode, outcode, FALSE)) == NULL) {
|
|
WriteError("Unable to create FTN headers from RFC ones, aborting");
|
|
die(103);
|
|
}
|
|
|
|
for (envrecip = &envrecip_start; *envrecip; envrecip = &((*envrecip)->next)) {
|
|
fmsg->to = (*envrecip)->addr;
|
|
if ((!fmsg->to->name) || ((strlen(fmsg->to->name) > MAXNAME)
|
|
&& ((strstr(fmsg->to->name,"@")) || (strstr(fmsg->to->name,"%"))
|
|
|| (strstr(fmsg->to->name,"!")))))
|
|
fmsg->to->name = (char *)"UUCP";
|
|
rc = putmessage(msg, fmsg, fp, route, flavor, &sbl, incode, outcode);
|
|
if (rc == 1) {
|
|
WriteError("Unable to put netmail message into the packet, aborting");
|
|
die(104);
|
|
}
|
|
if (rc == 2) {
|
|
WriteError("Unable to import netmail messages into the messabe base");
|
|
die(105);
|
|
}
|
|
if (usetmp)
|
|
rewind(fp);
|
|
fmsg->to = NULL;
|
|
}
|
|
net_in++;
|
|
if (usetmp)
|
|
fclose(fp);
|
|
}
|
|
|
|
closepkt();
|
|
die(0);
|
|
return 0;
|
|
}
|
|
|