/********************************************************
* File: crashecho.c
* Created at Sun Jan 28 22:10:29 MSK 2001 by raorn // raorn@binec.ru
* The CrashEcho itself
* $Id: crashecho.c,v 1.26 2002/10/27 22:47:52 raorn Exp $
*******************************************************/
#include "crashecho.h"
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#else
# include <shared/getopt.h>
#endif
/* Version string to use when writing config */
uchar verstr[] = "CrashEcho/" PLATFORM_NAME " " VERSION;
/*********************************** Global *******************************/
struct jbList PktList;
bool nomem = FALSE;
bool ioerror = FALSE;
bool exitprg = FALSE;
ulong ioerrornum = 0;
ulong toss_total = 0;
ulong toss_bad = 0;
ulong toss_import = 0;
ulong toss_written = 0;
ulong toss_dupes = 0;
ulong toss_cc = 0;
ulong scan_total = 0;
ulong rescan_total = 0;
int nowdoing = DOING_NONE;
struct ConfigNode *RescanNode;
ulong DayStatsWritten; /* The area statistics are updated until
* this day */
struct Config config;
bool ctrlc;
uchar *prinames[] = { "Normal", "Hold", "Normal", "Direct", "Crash" };
/**************************** Local for this file ****************************/
#define SHOWVER 128
bool init_openlog;
bool init_dupebuf;
void Free(void)
{
if (init_dupebuf) {
FreeDupebuf();
init_dupebuf = 0;
}
if (init_openlog) {
CloseLogfile();
init_openlog = FALSE;
}
jbFreeList(&PktList);
}
bool Init(void)
{
struct Area *area;
if (!OpenLogfile(config.cfg_LogFile, config.cfg_LogLevel)) {
Free();
return (FALSE);
}
init_openlog = TRUE;
if (config.cfg_DupeMode != DUPE_IGNORE) {
if (!AllocDupebuf()) {
fprintf(stderr, "No memory for dupe-check buffer\n");
Free();
return (FALSE);
}
init_dupebuf = TRUE;
if (!ReadDupes(config.cfg_DupeFile)) {
Free();
return (FALSE);
}
}
if (!ReadStats(config.cfg_StatsFile))
return (FALSE);
for (area = (struct Area *) config.AreaList.First; area; area = area->Next)
if (area->Messagebase)
area->Messagebase->active = TRUE;
return (TRUE);
}
void AfterScanToss(bool success)
{
struct Area *area;
struct ConfigNode *cnode;
uchar errbuf[200];
ulong day, d, e, i;
LogWrite(6, SYSTEMINFO, "In AfterScanToss(%s)", success ? "TRUE" : "FALSE");
ClosePackets();
if (success) {
if (config.cfg_BeforePack[0]) {
int res, rc;
LogWrite(2, TOSSINGINFO, "Executing BEFOREPACK script %s", config.cfg_BeforePack);
res = Execute(config.cfg_BeforePack, &rc);
if (!res)
LogWrite(3, TOSSINGINFO, "BEFOREPACK script exited with rc = %d", rc);
else
LogWrite(3, TOSSINGINFO, "BEFOREPACK script failed");
}
ArchiveOutbound();
}
for (i = 0; AvailMessagebases[i].name; i++)
if (AvailMessagebases[i].active && AvailMessagebases[i].afterfunc)
(*AvailMessagebases[i].afterfunc) (success);
if (success) {
/* Rotate last8 if needed */
if (DayStatsWritten == 0) /* First time we use this statsfile */
DayStatsWritten = time(NULL) / (24 * 60 * 60);
day = time(NULL) / (24 * 60 * 60);
for (area = (struct Area *) config.AreaList.First; area; area = area->Next)
if (day > DayStatsWritten) {
for (d = DayStatsWritten; d < day; d++) {
for (e = 0; e < 7; e++)
area->Last8Days[7 - e] = area->Last8Days[7 - e - 1];
area->Last8Days[0] = 0;
}
}
DayStatsWritten = day;
/* Areas */
for (area = (struct Area *) config.AreaList.First; area; area = area->Next)
if (area->NewTexts || area->NewDupes) {
area->Texts += area->NewTexts;
area->Last8Days[0] += area->NewTexts;
area->Dupes += area->NewDupes;
if (area->NewTexts)
area->LastTime = time(NULL);
if (area->NewTexts && area->FirstTime == 0)
area->FirstTime = time(NULL);
}
for (cnode = (struct ConfigNode *) config.CNodeList.First; cnode; cnode = cnode->Next) {
if (cnode->FirstTime == 0 && (cnode->GotEchomails != 0 || cnode->GotNetmails != 0 || cnode->SentEchomails != 0 || cnode->SentNetmails) != 0)
cnode->FirstTime = time(NULL);
}
WriteStats(config.cfg_StatsFile);
if (config.cfg_DupeMode != DUPE_IGNORE)
WriteDupes(config.cfg_DupeFile);
if (config.changed) {
LogWrite(2, SYSTEMINFO, "Updating configuration file \"%s\"", config.filename);
if (!UpdateConfig(&config, errbuf, 200))
LogWrite(1, SYSTEMERR, errbuf);
LogWrite(2, SYSTEMINFO, "Updating areas file \"%s\"", config.areafile);
if (!UpdateAreas(&config, errbuf, 200))
LogWrite(1, SYSTEMERR, errbuf);
}
}
jbFreeList(&PktList);
}
bool BeforeScanToss(void)
{
struct Area *area;
struct jbList NewPktFEList;
struct FileEntry *fe;
uchar buf[200];
int i;
toss_total = 0;
toss_bad = 0;
toss_import = 0;
toss_dupes = 0;
toss_written = 0;
toss_cc = 0;
scan_total = 0;
LogWrite(6, SYSTEMINFO, "In BeforeScanToss()");
for (area = (struct Area *) config.AreaList.First; area; area = area->Next) {
area->NewDupes = 0;
area->NewTexts = 0;
}
jbNewList(&PktList); /* Created packets */
/* Find orphan files */
if (!ReadDir(config.cfg_PacketCreate, &NewPktFEList, IsNewPkt)) {
LogWrite(1, SYSTEMERR, "Failed to read directory \"%s\"", config.cfg_PacketCreate);
LogWrite(1, SYSTEMERR, "Error: %s", strerror(errno));
return (FALSE);
}
/* XXX */
for (fe = (struct FileEntry *) NewPktFEList.First; fe; fe = fe->Next) {
uchar buf2[100];
uchar oldname[200];
ulong jbcpos;
struct Pkt *pkttmp;
struct Node4D n4d;
LogWrite(1, SYSTEMINFO, "Found orphan tempfile %s", fe->Name);
/* MakeFullPath(config.cfg_PacketCreate, fe->Name, buf, 200);
unlink(buf); */
if (!(pkttmp = (struct Pkt *) calloc(1, sizeof(struct Pkt)))) {
nomem = TRUE;
return FALSE;
}
pkttmp->Type = PKTS_ECHOMAIL;
mystrncpy(buf, fe->Name, 200);
for (i = 0; buf[i]; i++)
if (buf[i] == '_')
buf[i] = ' ';
jbcpos = 0;
/* Get hexnum */
jbstrcpy(buf2, buf, 100, &jbcpos);
sscanf(buf2, "%lx", &pkttmp->hexnum);
/* Get pktorig */
jbstrcpy(buf2, buf, 100, &jbcpos);
n4d.Zone = atol(buf2);
jbstrcpy(buf2, buf, 100, &jbcpos);
n4d.Net = atol(buf2);
jbstrcpy(buf2, buf, 100, &jbcpos);
n4d.Node = atol(buf2);
jbstrcpy(buf2, buf, 100, &jbcpos);
n4d.Point = atol(buf2);
Copy4D(&pkttmp->Orig, &n4d);
/* Get pktdest */
jbstrcpy(buf2, buf, 100, &jbcpos);
n4d.Zone = atol(buf2);
jbstrcpy(buf2, buf, 100, &jbcpos);
n4d.Net = atol(buf2);
jbstrcpy(buf2, buf, 100, &jbcpos);
n4d.Node = atol(buf2);
jbstrcpy(buf2, buf, 100, &jbcpos);
n4d.Point = atol(buf2);
Copy4D(&pkttmp->Dest, &n4d);
snprintf(buf2, 100, "%08lx.newpkt", pkttmp->hexnum);
MakeFullPath(config.cfg_PacketCreate, fe->Name, oldname, 200);
MakeFullPath(config.cfg_PacketCreate, buf2, buf, 200);
if (rename(oldname, buf)) {
LogWrite(1, SYSTEMERR, "Failed to rename %s to %s", oldname, buf);
LogWrite(1, SYSTEMERR, "Error: %s", strerror(errno));
free(pkttmp);
return FALSE;
}
if (!(pkttmp->fh = fopen(buf, "r+b"))) {
LogWrite(1, SYSTEMERR, "Unable to open packet %s", buf);
LogWrite(1, SYSTEMERR, "Error: %s", strerror(errno));
free(pkttmp);
return FALSE;
}
fseek(pkttmp->fh, -2L, SEEK_END); /* Step 2 bytes backwards */
pkttmp->Len = ftell(pkttmp->fh);
jbAddNode(&PktList, (struct jbNode *) pkttmp);
}
jbFreeList(&NewPktFEList);
for (i = 0; AvailMessagebases[i].name; i++)
if (AvailMessagebases[i].active)
if (AvailMessagebases[i].beforefunc)
if (!(*AvailMessagebases[i].beforefunc) ())
return (FALSE);
return (TRUE);
}
void Version(void)
{
int i;
fprintf(stderr, "%s, compiled %s at %s\n", verstr, __DATE__, __TIME__);
fprintf(stderr, "\n");
fprintf(stderr, "Available messagebase formats:\n");
for (i = 0; AvailMessagebases[i].name; i++)
fprintf(stderr, " %-10.10s %s\n", AvailMessagebases[i].name, AvailMessagebases[i].desc);
fprintf(stderr, "\n");
fprintf(stderr, "Features:\n");
#ifdef USE_SYSLOG
fprintf(stderr, " syslog\n");
#endif
}
bool Rescan(uchar * areaname, uchar * node, ulong max)
{
struct Area *area;
struct ConfigNode *cnode;
struct Node4D n4d;
bool success;
if (!Parse4DTemplate(node, &n4d, &(((struct Aka *) (config.AkaList.First))->Node))) {
LogWrite(1, USERERR, "Invalid node number %s", node);
return (TRUE);
}
for (cnode = (struct ConfigNode *) config.CNodeList.First; cnode; cnode = cnode->Next)
if (Compare4D(&cnode->Node, &n4d) == 0)
break;
if (!cnode) {
LogWrite(1, USERERR, "Unknown node %u:%u/%u.%u", n4d.Zone, n4d.Net, n4d.Node, n4d.Point);
return (TRUE);
}
for (area = (struct Area *) config.AreaList.First; area; area = area->Next)
if (area->AreaType == AREATYPE_ECHOMAIL)
if (stricmp(areaname, area->Tagname) == 0)
break;
if (!area) {
LogWrite(1, USERERR, "Unknown area %s", areaname);
return (TRUE);
}
if (!area->Messagebase) {
LogWrite(1, USERERR, "Can't rescan %s, area is pass-through", areaname);
return (TRUE);
}
if (!area->Messagebase->scanfunc) {
LogWrite(1, USERERR, "Can't rescan %s", areaname);
return (TRUE);
}
RescanNode = cnode;
rescan_total = 0;
success = (*area->Messagebase->scanfunc) (area, FALSE, FALSE, max, NULL, AcceptAny, HandleRescan);
RescanNode = NULL;
if (success)
LogWrite(4, TOSSINGINFO, "Rescanned %lu messages", rescan_total);
return (success);
}
bool SendAFList(uchar * node, short type)
{
struct Node4D n4d;
struct ConfigNode *cnode;
if (stricmp(node, "ALL") == 0) {
for (cnode = (struct ConfigNode *) config.CNodeList.First; cnode; cnode = cnode->Next)
if (cnode->Flags & NODE_NOTIFY)
DoSendAFList(type, cnode);
} else {
if (!Parse4DTemplate(node, &n4d, &(((struct Aka *) (config.AkaList.First))->Node))) {
LogWrite(1, USERERR, "Invalid node number \"%s\"", node);
return (FALSE);
}
for (cnode = (struct ConfigNode *) config.CNodeList.First; cnode; cnode = cnode->Next)
if (Compare4D(&cnode->Node, &n4d) == 0)
break;
if (cnode) {
DoSendAFList(type, cnode);
} else {
LogWrite(1, USERERR, "Unknown node %u:%u/%u.%u", n4d.Zone, n4d.Net, n4d.Node, n4d.Point);
return (FALSE);
}
}
if (nomem || exitprg)
return (FALSE);
return (TRUE);
}
bool RemoveArea(uchar * areaname)
{
struct Area *area;
for (area = (struct Area *) config.AreaList.First; area; area = area->Next)
if (area->AreaType != AREATYPE_NETMAIL)
if (stricmp(areaname, area->Tagname) == 0)
break;
if (!area) {
LogWrite(1, USERERR, "Unknown area %s", areaname);
return (TRUE);
}
LogWrite(1, AREAFIX, "AreaFix: Removing area %s", area->Tagname);
SendRemoveMessages(area);
area->AreaType=AREATYPE_DELETED;
RemoveDeletedAreas();
return (TRUE);
}
bool done_initconfig = FALSE;
bool done_welcomemsg = FALSE;
bool done_init = FALSE;
bool done_lockconfig = FALSE;
bool LockConfig(uchar * file)
{
int i;
bool rc = FALSE;
for (i=0; i < 6 && !(rc=Lock(file, config.cfg_Flags & CFG_LOCKBYLINK, FALSE)); i++) {
fprintf(stderr, "Configuration file %s is already in use, waiting 10 seconds...\n", file);
#ifdef __MINGW32__
sleep(10000);
#else
sleep(10);
#endif
if (ctrlc)
return (FALSE);
}
return rc;
}
void CleanUp(int err)
{
if (done_welcomemsg)
LogWrite(2, SYSTEMINFO, "CrashEcho end");
if (done_lockconfig)
Unlock(config.filename);
if (done_init)
Free();
if (done_initconfig)
FreeConfig(&config);
exit(err);
}
RETSIGTYPE breakfunc(int x)
{
ctrlc = TRUE;
}
bool CmdAreaFix(int argc, char **argv)
{
bool rc, check = FALSE;
static struct option lopts[] = {
{"help", 0, NULL, 'h'},
{"check", 0, NULL, 'c'},
{0, 0, 0, 0}
};
static uchar optstr[] = "+hc";
static uchar helpstr[] =
"Usage: crashecho areafix\n"
"Scan primary netmail area for AreaFix requests\n"
"\n"
" -h, --help display this help and exit\n"
" -c, --check only check for expired requests\n"
"\n";
int ch, lopt_index;
optind = 0;
while((ch=getopt_long(argc, argv, optstr, lopts, &lopt_index)) != -1){
switch(ch){
case 'h':
case '?':
default:
fprintf(stderr, helpstr);
return TRUE;
/* Not reached */
case 'c':
check = TRUE;
break;
}
}
argc -= optind;
argv += optind;
if(argc){
fprintf(stderr, helpstr);
return FALSE;
}
if (!BeforeScanToss())
return FALSE;
nowdoing = DOING_AFIX;
if (check)
rc = CheckAreaFix();
else
rc = ScanAreaFix();
AfterScanToss(rc);
return rc;
}
bool CmdToss(int argc, char **argv)
{
bool no_security = FALSE, tossbad = FALSE;
static struct option lopts[] = {
{"help", 0, NULL, 'h'},
{"bad", 0, NULL, 'b'},
{"no-security", 0, NULL, 's'},
{0, 0, 0, 0}
};
static uchar optstr[] = "+hbs";
static uchar helpstr[] =
"Usage: crashecho toss [OPTION]...\n"
"Toss all .pkt files and bundles in inbound directories\n"
"\n"
" -h, --help display this help and exit\n"
" -b, --bad retoss BAD area\n"
" -s, --no-security process all packets without security checks\n"
"\n";
int ch, lopt_index;
optind = 0;
while((ch=getopt_long(argc, argv, optstr, lopts, &lopt_index)) != -1){
switch(ch){
case 'h':
case '?':
default:
fprintf(stderr, helpstr);
return TRUE;
/* Not reached */
case 'b':
tossbad = TRUE;
break;
case 's':
no_security = TRUE;
break;
}
}
argc -= optind;
argv += optind;
if(argc){
fprintf(stderr, helpstr);
return FALSE;
}
if (no_security)
LogWrite(2, TOSSINGINFO, "Packets will be tossed without security checks");
if (!BeforeScanToss())
return (FALSE);
nowdoing = DOING_TOSS;
if (tossbad) {
struct Area *area;
for (area = (struct Area *) config.AreaList.First; area; area = area->Next)
if (area->Messagebase && area->AreaType == AREATYPE_BAD)
if (area->Messagebase->scanfunc)
break;
if (area) {
LogWrite(2, TOSSINGINFO, "Retossing BAD area...");
nowdoing = DOING_TOSSBAD;
if (!(*area->Messagebase->scanfunc) (area, FALSE, FALSE, 0, NULL, AcceptAny, HandleBad)) {
AfterScanToss(FALSE);
return (FALSE);
}
} else {
LogWrite(2, TOSSINGINFO, "No BAD area configured");
}
} else {
/* Unpack bundles from ProtInbound to TempInbound */
if (!UnpackDir(config.cfg_ProtInbound, config.cfg_TempInbound)) {
AfterScanToss(FALSE);
return FALSE;
}
if (config.cfg_AfterUnpack[0]) {
int res, rc;
LogWrite(2, TOSSINGINFO, "Executing AFTERUNPACK script %s", config.cfg_AfterUnpack);
res = Execute(config.cfg_AfterUnpack, &rc);
if (!res)
LogWrite(3, TOSSINGINFO, "AFTERUNPACK script exited with rc = %d", rc);
else
LogWrite(3, TOSSINGINFO, "AFTERUNPACK script failed");
}
/* Toss packets in LocalInbound without security */
if (!TossDir(config.cfg_LocalInbound, TRUE, FALSE)) {
AfterScanToss(FALSE);
return FALSE;
}
/* Toss packets in ProtInbound */
if (!TossDir(config.cfg_ProtInbound, no_security, FALSE)) {
AfterScanToss(FALSE);
return FALSE;
}
/* Toss packets in TempInbound */
if (!TossDir(config.cfg_TempInbound, no_security, FALSE)) {
AfterScanToss(FALSE);
return FALSE;
}
/* Toss packets in Inbound */
if (!TossDir(config.cfg_Inbound, no_security, TRUE)) {
AfterScanToss(FALSE);
return FALSE;
}
}
LogTossResults();
AfterScanToss(TRUE);
return TRUE;
}
bool CmdScan(int argc, char **argv)
{
uchar *area = NULL, *list = NULL;
bool rc;
bool ignoreflags = FALSE;
static struct option lopts[] = {
{"help", 0, NULL, 'h'},
{"area", required_argument, NULL, 'a'},
{"list", required_argument, NULL, 'l'},
#ifdef MSGBASE_JAM
{"ignore-flags", 0, NULL, 'i'},
#endif
{0, 0, 0, 0}
};
static uchar optstr[] = "+"
"h"
"a:"
"l:"
#ifdef MSGBASE_JAM
"i"
#endif
;
static uchar helpstr[] =
"Usage: crashecho scan [OPTION]...\n"
"Scan areas for messages to export\n"
"\n"
" -h, --help display this help and exit\n"
" -a, --area=NAME scan only specified area\n"
" -l, --list=FILE scan only areas listed in the specified file\n"
#ifdef MSGBASE_JAM
" -i, --ignore-flags ignore netmail.jam/echomail.jam files\n"
#endif
"\n";
int ch, lopt_index;
optind = 0;
while((ch=getopt_long(argc, argv, optstr, lopts, &lopt_index)) != -1){
switch(ch){
case 'h':
case '?':
default:
fprintf(stderr, helpstr);
return TRUE;
/* Not reached */
case 'a':
area = optarg;
break;
case 'l':
list = optarg;
break;
#ifdef MSGBASE_JAM
case 'i':
ignoreflags = TRUE;
break;
#endif
}
}
argc -= optind;
argv += optind;
if(argc){
fprintf(stderr, helpstr);
return FALSE;
}
if (!BeforeScanToss())
return (FALSE);
nowdoing = DOING_SCAN;
if (area)
rc = ScanArea(area);
else if (list)
rc = ScanList(list);
else
rc = Scan(ignoreflags);
if (rc)
LogScanResults();
AfterScanToss(rc);
return rc;
}
bool CmdRescan(int argc, char **argv)
{
ulong num = 0;
bool rc;
static struct option lopts[] = {
{"help", 0, NULL, 'h'},
{"max", required_argument, NULL, 'm'},
{0, 0, 0, 0}
};
static uchar optstr[] = "+hm:";
static uchar helpstr[] =
"Usage: crashecho rescan [OPTION]... AREA NODE\n"
"Rescans the specified area for the specied node\n"
"\n"
" -h, --help display this help and exit\n"
" -m, --max=NUMBER maximum number of messages to rescan\n"
"\n";
int ch, lopt_index;
optind = 0;
while((ch=getopt_long(argc, argv, optstr, lopts, &lopt_index)) != -1){
switch(ch){
case 'h':
case '?':
default:
fprintf(stderr, helpstr);
return TRUE;
/* Not reached */
case 'm':
num = atoi(optarg);
break;
}
}
argc -= optind;
argv += optind;
if(argc != 2){
fprintf(stderr, helpstr);
return FALSE;
}
if (!BeforeScanToss())
return (FALSE);
nowdoing = DOING_RESCAN;
rc = Rescan(argv[0], argv[1], num);
AfterScanToss(rc);
return rc;
}
bool CmdRemove(int argc, char **argv)
{
static struct option lopts[] = {
{"help", 0, NULL, 'h'},
{0, 0, 0, 0}
};
static uchar optstr[] = "+h";
static uchar helpstr[] =
"Usage: crashecho remove AREA [AREA]...\n"
"Remove area(s) and unsubscribe\n"
"\n"
" -h, --help display this help and exit\n"
"\n";
int ch, lopt_index;
optind = 0;
while((ch=getopt_long(argc, argv, optstr, lopts, &lopt_index)) != -1){
switch(ch){
case 'h':
case '?':
default:
fprintf(stderr, helpstr);
return TRUE;
/* Not reached */
}
}
argc -= optind;
argv += optind;
if(argc == 0){
fprintf(stderr, helpstr);
return FALSE;
}
if (!BeforeScanToss())
return (FALSE);
for (; argc > 0; argc--, argv++)
RemoveArea(argv[0]);
AfterScanToss(TRUE);
return TRUE;
}
bool CmdNotify(int argc, char **argv)
{
int list = SENDLIST_INFO;
bool rc = FALSE;
static struct option lopts[] = {
{"help", 0, NULL, 'h'},
{"HELP", 0, NULL, 'H'},
{"INFO", 0, NULL, 'I'},
{"LIST", 0, NULL, 'L'},
{"AVAIL", 0, NULL, 'A'},
{"QUERY", 0, NULL, 'Q'},
{"UNLINKED", 0, NULL, 'U'},
{0, 0, 0, 0}
};
static uchar optstr[] = "+hHILAQU";
static uchar helpstr[] =
"Usage: crashecho notify [OPTION] NODE\n"
"Send AreaFix response to node\n"
"\n"
" -h, --help display this help and exit\n"
" -H, --HELP send response to %%HELP command\n"
" -I, --INFO send response to %%INFO command (default)\n"
" -L, --LIST send response to %%LIST command\n"
" -A, --AVAIL send response to %%AVAIL command\n"
" -Q, --QUERY send response to %%QUERY command\n"
" -U, --UNLINKED send response to %%UNLINKED command\n"
"\n";
int ch, lopt_index;
optind = 0;
while((ch=getopt_long(argc, argv, optstr, lopts, &lopt_index)) != -1){
switch(ch){
case 'h':
case '?':
default:
fprintf(stderr, helpstr);
return TRUE;
/* Not reached */
case 'H':
list = SENDLIST_HELP;
break;
case 'I':
list = SENDLIST_INFO;
break;
case 'L':
list = SENDLIST_FULL;
break;
case 'A':
list = SENDLIST_AVAIL;
break;
case 'Q':
list = SENDLIST_QUERY;
break;
case 'U':
list = SENDLIST_UNLINKED;
break;
}
}
argc -= optind;
argv += optind;
if(argc != 1){
fprintf(stderr, helpstr);
return FALSE;
}
if (!BeforeScanToss())
return FALSE;
rc = SendAFList(argv[0], list);
AfterScanToss(rc);
return rc;
}
static struct cmd {
char *name;
bool (*func)(int, char **);
} cmds[] = {
{"areafix", CmdAreaFix},
{"toss", CmdToss},
{"scan", CmdScan},
{"rescan", CmdRescan},
{"remove", CmdRemove},
{"notify", CmdNotify},
{0, 0}
};
int main(int argc, char **argv)
{
uchar *cfg = CONFIG_NAME;
ulong cfgline;
short seconderr = 0;
uchar errorbuf[500];
static struct option lopts[] = {
{"help", 0, NULL, 'h'},
{"config", required_argument, NULL, 'c'},
{"version", 0, NULL, SHOWVER},
{0, 0, 0, 0}
};
static uchar optstr[] = "+hc:";
static uchar helpstr[] =
"Usage: crashecho [OPTION]... COMMAND [OPTION]...\n"
"\n"
" -h, --help display this help and exit\n"
" --version print version number and information about supported\n"
" messagebases and features\n"
" -c, --config=FILE use this configuration file instead of the default\n"
"\n"
"Valid commands are:\n"
"\n"
" areafix scan primary netmail area for AreaFix requests\n"
" toss toss all .pkt files and bundles in inbound directory\n"
" scan scan all areas for messages to export\n"
" rescan rescans the specied area for the specied node\n"
" remove remove specied area and unsubscribe\n"
" notify send AreaFix response to a node\n"
" lock lock CrashEcho's configuration file and exit\n"
" unlock remove lock on CrashEcho's configuration file and exit\n"
"\n"
"(Specify the --help option for a list of other help options)\n"
"\n";
static uchar helplock[] =
"Usage: crashecho lock\n"
"Lock CrashEcho's configuration file\n"
"\n"
" -h, --help display this help and exit\n"
"\n";
static uchar helpunlock[] =
"Usage: crashecho unlock\n"
"Remove lock on CrashEcho's configuration file\n"
"\n"
" -h, --help display this help and exit\n"
"\n";
int ch, lopt_index;
signal(SIGINT, breakfunc);
while((ch=getopt_long(argc, argv, optstr, lopts, &lopt_index)) != -1){
switch(ch){
case 'h':
case '?':
default:
fprintf(stderr, helpstr);
CleanUp(EXIT_OK);
/* Not reached */
case SHOWVER:
Version();
CleanUp(EXIT_OK);
/* Not reached */
case 'c':
cfg = optarg;
break;
}
}
argc -= optind;
argv += optind;
if (argc < 1) {
fprintf(stderr, helpstr);
CleanUp(EXIT_ERROR);
}
if (!stricmp(argv[0], "lock")) {
if(argc != 1){
fprintf(stderr, helplock);
if(!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))
CleanUp(EXIT_OK);
else
CleanUp(EXIT_ERROR);
}
if (!LockConfig(cfg)) {
fprintf(stderr, "Failed to lock configuration file %s\n", cfg);
CleanUp(EXIT_ERROR);
}
fprintf(stderr, "CrashEcho is now locked, use `crashecho unlock' to unlock\n");
CleanUp(EXIT_OK);
}
if (!stricmp(argv[0], "unlock")) {
if(argc != 1){
fprintf(stderr, helpunlock);
if(!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))
CleanUp(EXIT_OK);
else
CleanUp(EXIT_ERROR);
}
Unlock(cfg);
CleanUp(EXIT_OK);
}
InitConfig(&config);
done_initconfig = TRUE;
if (!(done_lockconfig = LockConfig(cfg))) {
fprintf(stderr, "Failed to lock configuration file %s\n", cfg);
CleanUp(EXIT_ERROR);
}
if (!ReadConfig(cfg, &config, &seconderr, &cfgline, errorbuf, 500)) {
if (seconderr == READCONFIG_INVALID)
fprintf(stderr, "Configuration error in %s on line %ld:\n%s\n", cfg, cfgline, errorbuf);
else if (seconderr == READCONFIG_NO_MEM)
fprintf(stderr, "Out of memory\n");
else
fprintf(stderr, "Failed to read configuration file %s\n", cfg);
CleanUp(EXIT_ERROR);
}
if (config.areafile[0] == 0) {
fprintf(stderr, "AREAFILE not defined in %s\n", cfg);
CleanUp(EXIT_ERROR);
}
if (!ReadAreas(config.areafile, &config, &seconderr, &cfgline, errorbuf, 500)) {
if (seconderr == READCONFIG_INVALID)
fprintf(stderr, "Configuration error in %s on line %ld:\n%s\n", config.areafile, cfgline, errorbuf);
else if (seconderr == READCONFIG_NO_MEM)
fprintf(stderr, "Out of memory\n");
else
fprintf(stderr, "Failed to read configuration file %s\n", config.areafile);
CleanUp(EXIT_ERROR);
}
if (!CheckConfig(&config, errorbuf, 500)) {
fprintf(stderr, "Configuration error:\n%s\n", errorbuf);
CleanUp(EXIT_ERROR);
}
if (!Init())
CleanUp(EXIT_ERROR);
done_init = TRUE;
LogWrite(2, SYSTEMINFO, "%s started successfully!", verstr);
done_welcomemsg = TRUE;
for (ch = 0; cmds[ch].name; ch++)
if (!stricmp(argv[0], cmds[ch].name))
break;
if (!cmds[ch].name) {
fprintf(stderr, helpstr);
CleanUp(EXIT_ERROR);
}
if (!cmds[ch].func) {
fprintf(stderr, "Command %s is not supported yet\n", cmds[ch].name);
CleanUp(EXIT_ERROR);
}
(*cmds[ch].func)(argc, argv);
if (nomem)
LogWrite(1, SYSTEMERR, "Out of memory");
if (ioerror)
LogWrite(1, SYSTEMERR, "I/O error: %s", strerror(ioerrornum));
if (ctrlc)
LogWrite(1, SYSTEMERR, "*** User break ***");
CleanUp(EXIT_OK);
/* The next line is never actually executed.
* It is just there to stop gcc from giving a warning. */
return (0);
}
syntax highlighted by Code2HTML, v. 0.9.1