812 lines
21 KiB
C
812 lines
21 KiB
C
/*****************************************************************************
|
|
*
|
|
* $Id$
|
|
* Purpose: Process Fidonet style mail and files.
|
|
*
|
|
*****************************************************************************
|
|
* Copyright (C) 1997-2004
|
|
*
|
|
* 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, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
|
*****************************************************************************/
|
|
|
|
#include "../config.h"
|
|
#include "../lib/libs.h"
|
|
#include "../lib/mbse.h"
|
|
#include "../lib/structs.h"
|
|
#include "../lib/users.h"
|
|
#include "../lib/records.h"
|
|
#include "../lib/common.h"
|
|
#include "../lib/nodelist.h"
|
|
#include "../lib/clcomm.h"
|
|
#include "../lib/dbdupe.h"
|
|
#include "../lib/dbcfg.h"
|
|
#include "../lib/dbnode.h"
|
|
#include "../lib/dbmsgs.h"
|
|
#include "../lib/dbuser.h"
|
|
#include "../lib/dbftn.h"
|
|
#include "../lib/dbtic.h"
|
|
#include "../lib/msg.h"
|
|
#include "../lib/mberrors.h"
|
|
#include "flock.h"
|
|
#include "tosspkt.h"
|
|
#include "unpack.h"
|
|
#include "tic.h"
|
|
#include "fsort.h"
|
|
#include "scan.h"
|
|
#include "mbfido.h"
|
|
#include "tracker.h"
|
|
#include "notify.h"
|
|
#include "rollover.h"
|
|
#include "hatch.h"
|
|
#include "scannews.h"
|
|
#include "maketags.h"
|
|
#include "makestat.h"
|
|
#include "newspost.h"
|
|
#include "rnews.h"
|
|
#include "mgrutil.h"
|
|
#include "backalias.h"
|
|
#include "rfc2ftn.h"
|
|
#include "dirsession.h"
|
|
#include "dirlock.h"
|
|
#include "queue.h"
|
|
|
|
|
|
#define UNPACK_FACTOR 300
|
|
|
|
|
|
int do_areas = FALSE; /* Process area taglists */
|
|
int do_toss = FALSE; /* Toss flag */
|
|
int do_scan = FALSE; /* Scan flag */
|
|
int do_tic = FALSE; /* Process .tic files */
|
|
int do_notify = FALSE; /* Create notify messages */
|
|
int do_roll = FALSE; /* Rollover only */
|
|
int do_full = FALSE; /* Full mailscan */
|
|
int do_tags = FALSE; /* Create taglists */
|
|
int do_stat = FALSE; /* Create statistic HTML pages */
|
|
int do_test = FALSE; /* Test routing */
|
|
int do_news = FALSE; /* Process NNTP news */
|
|
int do_uucp = FALSE; /* Process UUCP newsbatch */
|
|
int do_mail = FALSE; /* Process MTA email message */
|
|
int do_unsec = FALSE; /* Unsecure tossing */
|
|
int do_learn = FALSE; /* News articles learnmode */
|
|
int check_crc = TRUE; /* Check .tic crc values */
|
|
int check_dupe = TRUE; /* Check duplicates */
|
|
int do_flush = FALSE; /* Flush outbound queue */
|
|
int flushed = FALSE; /* If anything was flushed */
|
|
extern int do_quiet; /* Quiet flag */
|
|
extern int e_pid; /* Pid of child process */
|
|
extern int show_log; /* Show logging on screen */
|
|
int do_unprot = FALSE; /* Unprotected inbound flag */
|
|
time_t t_start; /* Start time */
|
|
time_t t_end; /* End time */
|
|
int packets = 0; /* Tossed packets */
|
|
int packets_ok = 0; /* Tossed packets Ok. */
|
|
char *envptr = NULL;
|
|
|
|
extern int net_in, net_imp, net_out, net_bad;
|
|
extern int echo_in, echo_imp, echo_out, echo_bad, echo_dupe;
|
|
extern int email_in, email_imp, email_out, email_bad;
|
|
extern int news_in, news_imp, news_out, news_bad, news_dupe;
|
|
extern int tic_in, tic_imp, tic_out, tic_bad, tic_dup;
|
|
extern int Magics, Hatched;
|
|
extern int notify, filemgr, areamgr;
|
|
|
|
|
|
|
|
/*
|
|
* If we don't know what to type
|
|
*/
|
|
void Help(void)
|
|
{
|
|
do_quiet = FALSE;
|
|
ProgName();
|
|
|
|
colour(LIGHTCYAN, BLACK);
|
|
printf("\nUsage: mbfido [command(s)] <options>\n\n");
|
|
colour(LIGHTBLUE, BLACK);
|
|
printf(" Commands are:\n\n");
|
|
colour(CYAN, BLACK);
|
|
printf(" a areas Process Areas taglists\n");
|
|
printf(" m mail <recipient> ... MTA Mail mode\n");
|
|
printf(" ne news Scan for new news\n");
|
|
printf(" no notify <nodes> Send notify messages\n");
|
|
printf(" r roll Rollover statistic counters\n");
|
|
printf(" s scan Scan outgoing Fido mail\n");
|
|
printf(" ta tag Create taglists\n");
|
|
printf(" te test <node> Do routing test for node\n");
|
|
printf(" ti tic Process .tic files\n");
|
|
printf(" to toss Toss incoming Fido mail\n");
|
|
printf(" u uucp Process UUCP batchfile\n");
|
|
printf(" w web Create WWW statistics\n\n");
|
|
colour(LIGHTBLUE, BLACK);
|
|
printf(" Options are:\n\n");
|
|
colour(CYAN, BLACK);
|
|
printf(" -f -full Full Mailscan\n");
|
|
printf(" -l -learn Learn News dupes\n");
|
|
printf(" -noc -nocrc Skip CRC checking\n");
|
|
printf(" -nod -nodupe Skip dupe checking\n");
|
|
printf(" -q -quiet Quiet mode\n");
|
|
printf(" -uns -unsecure Toss unsecure\n");
|
|
printf(" -unp -unprotect Toss unprotected inbound\n");
|
|
colour(LIGHTGRAY, BLACK);
|
|
ExitClient(MBERR_COMMANDLINE);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Header, only if not quiet.
|
|
*/
|
|
void ProgName(void)
|
|
{
|
|
if (do_quiet)
|
|
return;
|
|
|
|
colour(WHITE, BLACK);
|
|
printf("\nMBFIDO: MBSE BBS %s - Fidonet File and Mail processor\n", VERSION);
|
|
colour(YELLOW, BLACK);
|
|
printf(" %s\n", COPYRIGHT);
|
|
}
|
|
|
|
|
|
|
|
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");
|
|
}
|
|
|
|
if (onsig != MBERR_NO_PROGLOCK)
|
|
CloseDupes();
|
|
|
|
/*
|
|
* Check for locked and open message base.
|
|
*/
|
|
if (MsgBase.Locked)
|
|
Msg_UnLock();
|
|
if (MsgBase.Open)
|
|
Msg_Close();
|
|
|
|
signal(onsig, SIG_IGN);
|
|
deinitnl();
|
|
|
|
if (!do_quiet) {
|
|
show_log = TRUE;
|
|
colour(CYAN, BLACK);
|
|
}
|
|
|
|
if (onsig) {
|
|
if (onsig <= NSIG)
|
|
WriteError("Terminated on signal %d (%s)", onsig, SigName[onsig]);
|
|
else
|
|
WriteError("Terminated with error %d", onsig);
|
|
}
|
|
|
|
if (echo_imp + net_imp + net_out + echo_out)
|
|
CreateSema((char *)"msglink");
|
|
|
|
if ((echo_out + net_out + tic_out) || flushed)
|
|
CreateSema((char *)"scanout");
|
|
|
|
if (tic_imp)
|
|
CreateSema((char *)"reqindex");
|
|
|
|
if (net_in + net_imp + net_out + net_bad)
|
|
Syslog('+', "Netmail [%4d] import [%4d] out [%4d] bad [%4d]", net_in, net_imp, net_out, net_bad);
|
|
if (email_in + email_imp + email_out + email_bad)
|
|
Syslog('+', "Email [%4d] import [%4d] out [%4d] bad [%4d]", email_in, email_imp, email_out, email_bad);
|
|
if (echo_in + echo_imp + echo_out + echo_bad + echo_dupe)
|
|
Syslog('+', "Echomail [%4d] import [%4d] out [%4d] bad [%4d] dupe [%4d]", echo_in, echo_imp, echo_out, echo_bad, echo_dupe);
|
|
if (news_in + news_imp + news_out + news_bad + news_dupe)
|
|
Syslog('+', "News [%4d] import [%4d] out [%4d] bad [%4d] dupe [%4d]", news_in, news_imp, news_out, news_bad, news_dupe);
|
|
if (tic_in + tic_imp + tic_out + tic_bad + tic_dup)
|
|
Syslog('+', "TICfiles [%4d] import [%4d] out [%4d] bad [%4d] dupe [%4d]", tic_in, tic_imp, tic_out, tic_bad, tic_dup);
|
|
if (Magics + Hatched)
|
|
Syslog('+', " Magics [%4d] hatch [%4d]", Magics, Hatched);
|
|
if (notify + areamgr + filemgr)
|
|
Syslog('+', "Notify msgs [%4d] AreaMgr [%4d] FileMgr [%4d]", notify, areamgr, filemgr);
|
|
|
|
/*
|
|
* There should be no locks anymore, but in case of a crash try to unlock
|
|
* all possible directories. Only if onsig <> 110, this was a lock error
|
|
* and there should be no lock. We prevent removing the lock of another
|
|
* mbfido this way.
|
|
*/
|
|
if (onsig != MBERR_NO_PROGLOCK) {
|
|
ulockdir(CFG.inbound);
|
|
ulockdir(CFG.pinbound);
|
|
ulockdir(CFG.out_queue);
|
|
}
|
|
|
|
t_end = time(NULL);
|
|
Syslog(' ', "MBFIDO finished in %s", t_elapsed(t_start, t_end));
|
|
|
|
if (!do_quiet)
|
|
colour(LIGHTGRAY, BLACK);
|
|
ExitClient(onsig);
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int i, Loop, envrecip_count = 0;
|
|
char *p, *cmd, *temp, Options[81];
|
|
struct passwd *pw;
|
|
struct tm *t;
|
|
fa_list **envrecip, *envrecip_start = NULL;
|
|
faddr *taddr = NULL;
|
|
FILE *ofp;
|
|
|
|
|
|
/*
|
|
* The next trick is to supply a fake environment variable
|
|
* MBSE_ROOT in case we are started from UUCP or the MTA.
|
|
* this will setup the variable so InitConfig() will work.
|
|
* The /etc/passwd must point to the correct homedirectory.
|
|
* Some programs can't set uid to mbse, so mbfido is installed
|
|
* setuid mbse.
|
|
*/
|
|
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);
|
|
}
|
|
|
|
InitConfig();
|
|
memset(&Options, 0, sizeof(Options));
|
|
|
|
/*
|
|
* Initialize global variables, data records.
|
|
*/
|
|
InitNode();
|
|
InitMsgs();
|
|
InitTic();
|
|
InitUser();
|
|
InitFidonet();
|
|
TermInit(1);
|
|
t_start = time(NULL);
|
|
t = localtime(&t_start);
|
|
Diw = t->tm_wday;
|
|
Miy = t->tm_mon;
|
|
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))
|
|
signal(i, (void (*))die);
|
|
else if ((i != SIGKILL) && (i != SIGSTOP))
|
|
signal(i, SIG_IGN);
|
|
}
|
|
|
|
if ((p = strrchr(argv[0], '/')))
|
|
p++;
|
|
else
|
|
p = argv[0];
|
|
if (!strcmp(p, "mbmail")) {
|
|
do_quiet = TRUE;
|
|
do_mail = TRUE;
|
|
cmd = xstrcpy((char *)"Cmd: mbmail");
|
|
} else if (!strcmp(p, "mbnews")) {
|
|
do_quiet = TRUE;
|
|
do_uucp = TRUE;
|
|
cmd = xstrcpy((char *)"Cmd: mbnews");
|
|
} else {
|
|
if (argc < 2)
|
|
Help();
|
|
cmd = xstrcpy((char *)"Cmd: mbfido");
|
|
}
|
|
|
|
envrecip = &envrecip_start;
|
|
for (i = 1; i < argc; i++) {
|
|
cmd = xstrcat(cmd, (char *)" ");
|
|
cmd = xstrcat(cmd, argv[i]);
|
|
|
|
if (strncmp(tl(argv[i]), "ne", 2) == 0)
|
|
do_news = TRUE;
|
|
if (strncmp(tl(argv[i]), "no", 2) == 0) {
|
|
do_notify = TRUE;
|
|
if (((i + 1) < argc) &&
|
|
((strchr(argv[i + 1], ':') != NULL) ||
|
|
(atoi(argv[i + 1])) ||
|
|
(strncmp(argv[i + 1], "*", 1) == 0))) {
|
|
sprintf(Options, "%s", argv[i + 1]);
|
|
i++;
|
|
}
|
|
}
|
|
if (strncmp(tl(argv[i]), "r", 1) == 0)
|
|
do_roll = TRUE;
|
|
else if (strncmp(tl(argv[i]), "a", 1) == 0)
|
|
do_areas = TRUE;
|
|
else if (strncmp(tl(argv[i]), "s", 1) == 0)
|
|
do_scan = TRUE;
|
|
else if (strncmp(tl(argv[i]), "ta", 2) == 0)
|
|
do_tags = TRUE;
|
|
else if (strncmp(tl(argv[i]), "ti", 2) == 0)
|
|
do_tic = TRUE;
|
|
else if (strncmp(tl(argv[i]), "te", 2) == 0) {
|
|
do_test = TRUE;
|
|
if ((i + 1) < argc) {
|
|
if ((taddr = parsefaddr(argv[i + 1])) == NULL) {
|
|
Help();
|
|
}
|
|
i++;
|
|
cmd = xstrcat(cmd, (char *)" ");
|
|
cmd = xstrcat(cmd, argv[i]);
|
|
}
|
|
} else if (strncmp(tl(argv[i]), "to", 2) == 0)
|
|
do_toss = TRUE;
|
|
else if (strncmp(tl(argv[i]), "u", 1) == 0)
|
|
do_uucp = TRUE;
|
|
else if (strncmp(tl(argv[i]), "m", 1) == 0)
|
|
do_mail = TRUE;
|
|
else if (strncmp(tl(argv[i]), "w", 1) == 0)
|
|
do_stat = TRUE;
|
|
else if (strncmp(tl(argv[i]), "-f", 2) == 0)
|
|
do_full = TRUE;
|
|
else if (strncmp(tl(argv[i]), "-l", 2) == 0)
|
|
do_learn = TRUE;
|
|
else if (strncmp(tl(argv[i]), "-noc", 4) == 0)
|
|
check_crc = FALSE;
|
|
else if (strncmp(tl(argv[i]), "-nod", 4) == 0)
|
|
check_dupe = FALSE;
|
|
else if (strncmp(tl(argv[i]), "-q", 2) == 0)
|
|
do_quiet = TRUE;
|
|
else if (strncmp(tl(argv[i]), "-a", 2) == 0)
|
|
WriteError("The -a option is obsolete, adjust your setup");
|
|
else if (strncmp(tl(argv[i]), "-unp", 4) == 0)
|
|
do_unprot = TRUE;
|
|
else if (strncmp(tl(argv[i]), "-uns", 4) == 0)
|
|
do_unsec = TRUE;
|
|
else if (do_mail) {
|
|
/*
|
|
* Possible recipient address(es).
|
|
*/
|
|
if ((taddr = parsefaddr(argv[i]))) {
|
|
(*envrecip) = (fa_list*)malloc(sizeof(fa_list));
|
|
(*envrecip)->next = NULL;
|
|
(*envrecip)->addr = taddr;
|
|
envrecip = &((*envrecip)->next);
|
|
envrecip_count++;
|
|
} else {
|
|
cmd = strcat(cmd, (char *)" <- unparsable recipient! ");
|
|
}
|
|
}
|
|
}
|
|
|
|
ProgName();
|
|
pw = getpwuid(getuid());
|
|
InitClient(pw->pw_name, (char *)"mbfido", CFG.location, CFG.logfile,
|
|
CFG.util_loglevel, CFG.error_log, CFG.mgrlog, CFG.debuglog);
|
|
|
|
Syslog(' ', " ");
|
|
Syslog(' ', "MBFIDO v%s", VERSION);
|
|
Syslog(' ', cmd);
|
|
free(cmd);
|
|
|
|
/*
|
|
* Not yet locked, if anything goes wrong, exit with die(MBERR_NO_PROGLOCK)
|
|
*/
|
|
if (!diskfree(CFG.freespace))
|
|
die(MBERR_DISK_FULL);
|
|
|
|
if (do_mail) {
|
|
/*
|
|
* Try to get a lock for a long time, another mbfido may be legally
|
|
* running since mbmail is started by the MTA instead of by mbtask.
|
|
* The timeout is 10 minutes. If mbmail times out, the MTA will
|
|
* bounce the message. What happens during the time we wait is
|
|
* unknown, will the MTA be patient enough?
|
|
*/
|
|
i = 30;
|
|
while (TRUE) {
|
|
if (do_unprot) {
|
|
if (lockdir(CFG.inbound))
|
|
break;
|
|
} else {
|
|
if (lockdir(CFG.pinbound))
|
|
break;
|
|
}
|
|
i--;
|
|
if (! i) {
|
|
WriteError("Lock timeout, aborting");
|
|
die(MBERR_NO_PROGLOCK);
|
|
}
|
|
sleep(20);
|
|
Nopper();
|
|
}
|
|
} else {
|
|
/*
|
|
* Started under control of mbtask, that means if there is a lock then
|
|
* there is something wrong; abort.
|
|
*/
|
|
if (do_unprot) {
|
|
if (! lockdir(CFG.inbound))
|
|
die(MBERR_NO_PROGLOCK);
|
|
} else {
|
|
if (! lockdir(CFG.pinbound))
|
|
die(MBERR_NO_PROGLOCK);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Locking succeeded, no more abort alowed with die(110)
|
|
*/
|
|
|
|
if (initnl())
|
|
die(MBERR_INIT_ERROR);
|
|
if (!do_mail && !do_uucp)
|
|
Rollover();
|
|
if (!do_quiet)
|
|
printf("\n");
|
|
|
|
/*
|
|
* Read alias file
|
|
*/
|
|
cmd = calloc(PATH_MAX, sizeof(char));
|
|
sprintf(cmd, "%s/etc/aliases", getenv("MBSE_ROOT"));
|
|
if ((do_news || do_scan || do_toss || do_mail) && file_exist(cmd, R_OK) == 0)
|
|
readalias(cmd);
|
|
free(cmd);
|
|
|
|
if (do_mail) {
|
|
if (!envrecip_count) {
|
|
WriteError("No valid receipients specified, aborting");
|
|
die(MBERR_NO_RECIPIENTS);
|
|
}
|
|
|
|
umask(066);
|
|
if ((ofp = tmpfile()) == NULL) {
|
|
WriteError("$Can't open tmpfile for RFC message");
|
|
die(MBERR_INIT_ERROR);
|
|
}
|
|
temp = calloc(10240, sizeof(char));
|
|
while (fgets(temp, 10240, stdin))
|
|
fprintf(ofp, temp);
|
|
free(temp);
|
|
|
|
for (envrecip = &envrecip_start; *envrecip; envrecip = &((*envrecip)->next)) {
|
|
Syslog('+', "Message to: %s", ascfnode((*envrecip)->addr, 0x7f));
|
|
rfc2ftn(ofp, (*envrecip)->addr);
|
|
}
|
|
|
|
fclose(ofp);
|
|
flush_queue();
|
|
die(MBERR_OK);
|
|
}
|
|
|
|
InitDupes();
|
|
|
|
if (do_notify)
|
|
if (Notify(Options)) {
|
|
do_flush = TRUE;
|
|
}
|
|
if (do_tic) {
|
|
if (IsSema((char *)"mailin"))
|
|
RemoveSema((char *)"mailin");
|
|
/*
|
|
* Hatch new files and process .tic files
|
|
* until nothing left to do.
|
|
*/
|
|
Loop = TRUE;
|
|
do {
|
|
Hatch();
|
|
switch (Tic()) {
|
|
case -1: die(MBERR_OK);
|
|
break;
|
|
case 0: Loop = FALSE;
|
|
break;
|
|
default: break;
|
|
}
|
|
} while (Loop);
|
|
}
|
|
if (do_news) {
|
|
ScanNews();
|
|
if (IsSema((char *)"newnews"))
|
|
RemoveSema((char *)"newnews");
|
|
}
|
|
if (do_scan)
|
|
ScanMail(do_full);
|
|
if (do_toss) {
|
|
if (IsSema((char *)"mailin"))
|
|
RemoveSema((char *)"mailin");
|
|
if (TossMail() == FALSE)
|
|
die(MBERR_OK);
|
|
}
|
|
if (do_tic || do_toss) {
|
|
/*
|
|
* Do inbound direcory sessions
|
|
*/
|
|
if (dirinbound()) {
|
|
if (do_tic) {
|
|
/*
|
|
* Hatch new files and process .tic files
|
|
* until nothing left to do.
|
|
*/
|
|
Loop = TRUE;
|
|
do {
|
|
Hatch();
|
|
switch (Tic()) {
|
|
case -1: die(MBERR_OK);
|
|
break;
|
|
case 0: Loop = FALSE;
|
|
break;
|
|
default: break;
|
|
}
|
|
} while (Loop);
|
|
}
|
|
if (do_toss) {
|
|
TossMail();
|
|
}
|
|
}
|
|
}
|
|
if (!do_uucp)
|
|
newspost();
|
|
if (do_test) {
|
|
if (taddr == NULL)
|
|
Help();
|
|
TestTracker(taddr);
|
|
tidy_faddr(taddr);
|
|
}
|
|
if (do_tags)
|
|
MakeTags();
|
|
if (do_stat)
|
|
MakeStat();
|
|
if (do_uucp)
|
|
NewsUUCP();
|
|
if (do_areas)
|
|
Areas();
|
|
if (do_flush)
|
|
flush_queue();
|
|
|
|
die(MBERR_OK);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Toss Fidonet mail
|
|
*/
|
|
int TossMail(void)
|
|
{
|
|
char *inbound, *fname;
|
|
DIR *dp;
|
|
struct dirent *de;
|
|
struct stat sbuf;
|
|
int files = 0, files_ok = 0, rc = 0, maxrc = 0;
|
|
fd_list *fdl = NULL;
|
|
|
|
if (do_unprot)
|
|
inbound = xstrcpy(CFG.inbound);
|
|
else
|
|
inbound = xstrcpy(CFG.pinbound);
|
|
|
|
Syslog('+', "Pass: toss netmail (%s)", inbound);
|
|
|
|
if (chdir(inbound) == -1) {
|
|
WriteError("$Can't chdir(%s)", inbound);
|
|
die(MBERR_INIT_ERROR);
|
|
}
|
|
|
|
/*
|
|
* First toss any netmail packets.
|
|
*/
|
|
maxrc = rc = TossPkts();
|
|
chdir(inbound);
|
|
|
|
/*
|
|
* Scan the directory for ARCmail archives. The archive extension
|
|
* numbering doesn't matter, as long as there is something, so
|
|
* all kind of ARCmail naming schemes are recognized.
|
|
*/
|
|
if ((dp = opendir(inbound)) == NULL) {
|
|
WriteError("$Can't opendir(%s)", inbound);
|
|
die(MBERR_INIT_ERROR);
|
|
}
|
|
|
|
Syslog('+', "Pass: toss ARCmail (%s)", inbound);
|
|
|
|
/*
|
|
* Add all ARCmail filenames to the memory array.
|
|
*/
|
|
sync();
|
|
while ((de=readdir(dp)))
|
|
if ((strlen(de->d_name) == 12) && ((strncasecmp(de->d_name+8,".su",3) == 0) ||
|
|
(strncasecmp(de->d_name+8,".mo",3) == 0) || (strncasecmp(de->d_name+8,".tu",3) == 0) ||
|
|
(strncasecmp(de->d_name+8,".we",3) == 0) || (strncasecmp(de->d_name+8,".th",3) == 0) ||
|
|
(strncasecmp(de->d_name+8,".fr",3) == 0) || (strncasecmp(de->d_name+8,".sa",3) == 0))) {
|
|
stat(de->d_name, &sbuf);
|
|
fill_fdlist(&fdl, de->d_name, sbuf.st_mtime);
|
|
}
|
|
|
|
closedir(dp);
|
|
sort_fdlist(&fdl);
|
|
|
|
/*
|
|
* Now process the archives, the oldest first.
|
|
*/
|
|
while ((fname = pull_fdlist(&fdl)) != NULL) {
|
|
files++;
|
|
IsDoing("Unpack arcmail");
|
|
|
|
if (IsSema((char *)"upsalarm")) {
|
|
Syslog('+', "Detected upsalarm semafore, aborting toss");
|
|
break;
|
|
}
|
|
if (!diskfree(CFG.freespace)) {
|
|
rc = MBERR_DISK_FULL;
|
|
break;
|
|
}
|
|
|
|
if (checkspace(inbound, fname, UNPACK_FACTOR))
|
|
if ((rc = unpack(fname)) == 0) {
|
|
files_ok++;
|
|
rc = TossPkts();
|
|
chdir(inbound);
|
|
} else
|
|
WriteError("Error unpacking file %s", fname);
|
|
else
|
|
Syslog('!', "Insufficient space to unpack file %s", fname);
|
|
|
|
if (rc > maxrc)
|
|
maxrc = rc;
|
|
}
|
|
|
|
free(inbound);
|
|
if ((files || packets) && ((files_ok != files) || (packets_ok != packets)))
|
|
Syslog('!', "Processed %d of %d files, %d of %d packets, rc=%d", files_ok, files, packets_ok, packets, maxrc);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Toss all packets currently in the inbound. Tossing is sorted by
|
|
* age of the files.
|
|
*/
|
|
int TossPkts(void)
|
|
{
|
|
char *inbound = NULL, *fname;
|
|
DIR *dp;
|
|
struct dirent *de;
|
|
struct stat sbuf;
|
|
int rc = 0, maxrc = 0;
|
|
fd_list *fdl = NULL;
|
|
|
|
IsDoing("Tossing mail");
|
|
|
|
if (do_unprot)
|
|
inbound = xstrcpy(CFG.inbound);
|
|
else
|
|
inbound = xstrcpy(CFG.pinbound);
|
|
|
|
if ((dp = opendir(inbound)) == NULL) {
|
|
WriteError("$Can't opendir(%s)", inbound);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Read all .pkt filenames, get the timestamp and add them
|
|
* to the memory array for later sort on filedate.
|
|
*/
|
|
while ((de = readdir(dp)))
|
|
if ((strlen(de->d_name) == 12) && (strncasecmp(de->d_name+8,".pkt",4) == 0)) {
|
|
stat(de->d_name, &sbuf);
|
|
fill_fdlist(&fdl, de->d_name, sbuf.st_mtime);
|
|
}
|
|
|
|
closedir(dp);
|
|
sort_fdlist(&fdl);
|
|
|
|
/*
|
|
* Get the filenames, the oldest first until nothing left.
|
|
*/
|
|
while ((fname = pull_fdlist(&fdl)) != NULL) {
|
|
|
|
if (!diskfree(CFG.freespace))
|
|
return FALSE;
|
|
packets++;
|
|
|
|
/*
|
|
* See if "pktdate" from Tobias Ernst (or another preprocessor) is installed.
|
|
*/
|
|
if (strlen(CFG.pktdate)) {
|
|
rc = execute(CFG.pktdate, fname, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null");
|
|
if (rc)
|
|
Syslog('+', "%s preprocessing rc=%d", fname, rc);
|
|
}
|
|
|
|
if ((rc = toss(fname)) == 0)
|
|
packets_ok++;
|
|
else
|
|
WriteError("Error tossing packet %s", fname);
|
|
if (rc > maxrc)
|
|
maxrc = rc;
|
|
}
|
|
|
|
free(inbound);
|
|
do_flush = TRUE;
|
|
return maxrc;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Toss one packet
|
|
*/
|
|
int toss(char *fn)
|
|
{
|
|
int rc = 0, ld;
|
|
char newname[16];
|
|
|
|
/*
|
|
* Lock the packet
|
|
*/
|
|
if ((ld = f_lock(fn)) == -1)
|
|
return 1;
|
|
|
|
rc = TossPkt(fn);
|
|
if (rc == 0) {
|
|
unlink(fn);
|
|
} else {
|
|
strncpy(newname,fn,sizeof(newname)-1);
|
|
strcpy(newname+8,".bad");
|
|
rename(fn,newname);
|
|
}
|
|
|
|
funlock(ld);
|
|
return rc;
|
|
}
|
|
|
|
|