/********************************************************
* File: handle.c
* Created at Sun Jan 28 22:10:29 MSK 2001 by raorn // raorn@binec.ru
* Message handling
* $Id: handle.c,v 1.23 2002/05/12 22:18:36 raorn Exp $
*******************************************************/
#include "crashecho.h"
bool WriteBad(struct MemMessage * mm, uchar * reason);
bool HandleMessage(struct MemMessage *mm, bool no_echomail)
{
LogWrite(6, DEBUG, "Is in HandleMessage()");
if (nowdoing == DOING_TOSS || nowdoing == DOING_TOSSBAD)
toss_total++;
if (mm->Area[0] == 0)
return HandleNetmail(mm);
else if (mm->no_security || !no_echomail)
return HandleEchomail(mm);
else {
LogWrite(3, TOSSINGERR, "Refusing echomail message from insecure inbound");
toss_bad++;
return WriteBad(mm, "Echomail message from insecure inbound");
}
}
/**************************** auto-add *****************************/
bool GetDescription(uchar * area, struct ConfigNode * node, uchar * desc)
{
struct Arealist *arealist;
uchar buf[200];
ulong c, d;
FILE *fh;
for (arealist = (struct Arealist *) config.ArealistList.First; arealist; arealist = arealist->Next) {
if (arealist->Node == node && (arealist->Flags & AREALIST_DESC)) {
if ((fh = fopen(arealist->AreaFile, "rt"))) {
while (fgets(buf, 199, fh)) {
for (c = 0; buf[c] > 32; c++);
if (buf[c] != 0) {
buf[c] = 0;
if (stricmp(buf, area) == 0) {
c++;
while (buf[c] <= 32 && buf[c] != 0)
c++;
if (buf[c] != 0) {
d = 0;
while (buf[c] != 0 && buf[c] != 10 && buf[c] != 13 && d < 77)
desc[d++] = buf[c++];
desc[d] = 0;
fclose(fh);
return (TRUE);
}
}
}
}
fclose(fh);
} else {
LogWrite(1, SYSTEMERR, "Failed to open file \"%s\"\n", arealist->AreaFile);
LogWrite(1, SYSTEMERR, "Error: %s", strerror(errno));
}
}
}
return (FALSE);
}
bool AddTossNode(struct Area * area, struct ConfigNode * cnode, ushort flags)
{
struct TossNode *tnode;
/* Check if it already exists */
for (tnode = (struct TossNode *) area->TossNodes.First; tnode; tnode = tnode->Next)
if (tnode->ConfigNode == cnode)
return (TRUE);
if (!(tnode = (struct TossNode *) calloc(1, sizeof(struct TossNode)))) {
nomem = TRUE;
return (FALSE);
}
jbAddNode((struct jbList *) &area->TossNodes, (struct jbNode *) tnode), tnode->ConfigNode = cnode;
tnode->Flags = flags;
return (TRUE);
}
static time_t lastt=0;
void MakeDirectory(uchar * dest, ulong destsize, uchar * defdir, uchar * areaname)
{
ulong c, d;
uchar lowercase[200], shortname[50];
/* Convert to lower case */
mystrncpy(lowercase, areaname, 200);
for (c = 0; lowercase[c] != 0; c++)
lowercase[c] = tolower(lowercase[c]);
/* Make 8 digit serial number */
if (lastt == 0)
lastt = time(NULL);
else
lastt++;
snprintf(shortname, 50, "%08lx", lastt);
d = 0;
for (c = 0; c < strlen(defdir) && d != destsize - 1; c++) {
if (defdir[c] == '%' && (defdir[c + 1] | 32) == 'a') {
strncpy(&dest[d], areaname, (size_t) (destsize - 1 - d));
dest[destsize - 1] = 0;
d = strlen(dest);
c++;
} else if (defdir[c] == '%' && (defdir[c + 1] | 32) == 'l') {
strncpy(&dest[d], lowercase, (size_t) (destsize - 1 - d));
dest[destsize - 1] = 0;
d = strlen(dest);
c++;
} else if (defdir[c] == '%' && (defdir[c + 1] | 32) == '8') {
strncpy(&dest[d], shortname, (size_t) (destsize - 1 - d));
dest[destsize - 1] = 0;
d = strlen(dest);
c++;
} else
dest[d++] = defdir[c];
}
dest[d] = 0;
}
struct Area *AddArea(uchar * name, struct Node4D *node, struct Node4D *mynode, ulong active, ulong forcepassthru)
{
struct Area *temparea, *defarea;
struct Aka *tempaka;
struct ConfigNode *tempcnode;
if (!(temparea = (struct Area *) calloc(1, sizeof(struct Area)))) {
nomem = TRUE;
return (NULL);
}
jbNewList(&temparea->TossNodes);
jbNewList(&temparea->BannedNodes);
jbAddNode(&config.AreaList, (struct jbNode *) temparea);
for (tempaka = (struct Aka *) config.AkaList.First; tempaka; tempaka = tempaka->Next)
if (Compare4D(&tempaka->Node, mynode) == 0)
break;
if (!tempaka)
tempaka = (struct Aka *) config.AkaList.First;
for (tempcnode = (struct ConfigNode *) config.CNodeList.First; tempcnode; tempcnode = tempcnode->Next)
if (Compare4D(&tempcnode->Node, node) == 0)
break;
/* Find default area to use */
defarea = NULL;
/* First we try to find one for specific groups */
if (tempcnode && tempcnode->DefaultGroup) {
uchar groups[100];
for (defarea = (struct Area *) config.AreaList.First; defarea; defarea = defarea->Next)
if (strnicmp(defarea->Tagname, "DEFAULT_", 8) == 0) {
mystrncpy(groups, &defarea->Tagname[8], 50);
if (MatchFlags(tempcnode->DefaultGroup, groups))
break;
}
}
/* If not found, we try to find the general default area */
if (!defarea) {
for (defarea = (struct Area *) config.AreaList.First; defarea; defarea = defarea->Next)
if (stricmp(defarea->Tagname, "DEFAULT") == 0)
break;
}
if (defarea) {
struct TossNode *tnode;
ulong c;
uchar *forbiddenchars = "\"#'`()*,/:;<>|";
uchar buf[100], buf2[200];
mystrncpy(buf, name, 100);
for (c = 0; buf[c] != 0; c++)
if (buf[c] < 33 || buf[c] > 126 || strchr(forbiddenchars, buf[c]))
buf[c] = '_';
/*
* Cannot create directory directly into temparea->Path.
* MakeDirectory checks for duplicate area names in the
* AreaList and would get confused
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
MakeDirectory(buf2, 200, defarea->Path, buf);
mystrncpy(temparea->Path, buf2, 200);
if (!forcepassthru)
temparea->Messagebase = defarea->Messagebase;
strcpy(temparea->Description, defarea->Description);
if (defarea->Flags & AREA_MANDATORY)
temparea->Flags |= AREA_MANDATORY;
if (defarea->Flags & AREA_DEFREADONLY)
temparea->Flags |= AREA_DEFREADONLY;
if (defarea->Flags & AREA_IGNOREDUPES)
temparea->Flags |= AREA_IGNOREDUPES;
if (defarea->Flags & AREA_IGNORESEENBY)
temparea->Flags |= AREA_IGNORESEENBY;
if (defarea->Flags & AREA_IMPORTSEENBY)
temparea->Flags |= AREA_IMPORTSEENBY;
temparea->KeepDays = defarea->KeepDays;
temparea->KeepNum = defarea->KeepNum;
for (tnode = (struct TossNode *) defarea->TossNodes.First; tnode; tnode = tnode->Next)
AddTossNode(temparea, tnode->ConfigNode, tnode->Flags);
}
GetDescription(name, tempcnode, temparea->Description);
if (!active)
temparea->Flags |= AREA_UNCONFIRMED;
mystrncpy(temparea->Tagname, name, 80);
temparea->Aka = tempaka;
temparea->AreaType = AREATYPE_ECHOMAIL;
if (tempcnode) {
temparea->Group = tempcnode->DefaultGroup;
AddTossNode(temparea, tempcnode, TOSSNODE_FEED);
for (tempcnode = (struct ConfigNode *) config.CNodeList.First; tempcnode; tempcnode = tempcnode->Next)
if (MatchFlags(temparea->Group, tempcnode->AddGroups)) {
ushort flags;
flags = 0;
if ((temparea->Flags & AREA_DEFREADONLY) || MatchFlags(temparea->Group, tempcnode->ReadOnlyGroups))
flags = TOSSNODE_READONLY;
AddTossNode(temparea, tempcnode, flags);
}
}
config.changed = TRUE;
temparea->changed = TRUE;
return (temparea);
}
/**************************** Echomail *****************************/
bool FindNodes2D(struct jbList * list, struct Node4D * node)
{
struct Nodes2D *tmp;
ushort c;
for (tmp = (struct Nodes2D *) list->First; tmp; tmp = tmp->Next)
for (c = 0; c < tmp->Nodes; c++)
if (tmp->Net[c] == node->Net && tmp->Node[c] == node->Node)
return (TRUE);
return (FALSE);
}
bool WriteBad(struct MemMessage * mm, uchar * reason)
{
struct Area *temparea;
/* struct TextChunk *chunk;*/
uchar buf[200];
LogWrite(6, DEBUG, "Is in WriteBad(..., \"%s\")", reason);
for (temparea = (struct Area *) config.AreaList.First; temparea; temparea = temparea->Next)
if (temparea->AreaType == AREATYPE_BAD)
break;
if (!temparea) {
LogWrite(2, TOSSINGERR, "No BAD area configured, message lost");
return (TRUE);
}
/* Insert a new textchunk with information first in the message */
/* if (!(chunk = (struct TextChunk *) malloc(sizeof(struct TextChunk)))) {*/
/* nomem = TRUE;*/
/* return (FALSE);*/
/* }*/
/* chunk->Next = (struct TextChunk *) mm->TextChunks.First;*/
/* mm->TextChunks.First = (struct jbNode *) chunk;*/
/* if (!mm->TextChunks.Last)*/
/* mm->TextChunks.Last = (struct jbNode *) chunk;*/
/* Lines must be inserted in reverse order */
snprintf(buf, 200, "\001REASON: %s\r", reason);
mmAddLine(mm, buf, MM_HEAD);
snprintf(buf, 200, "\001FROM: %u:%u/%u.%u\r", mm->PktOrig.Zone, mm->PktOrig.Net, mm->PktOrig.Node, mm->PktOrig.Point);
mmAddLine(mm, buf, MM_HEAD);
snprintf(buf, 200, "\001AREA:%s\r", mm->Area);
mmAddLine(mm, buf, MM_HEAD);
if (temparea->Messagebase) {
if (!((*temparea->Messagebase->importfunc) (mm, temparea)))
return (FALSE);
}
temparea->NewTexts++;
return (TRUE);
}
bool AddNodePath(struct jbList * list, struct Node4D * node)
{
uchar buf[40];
struct Path *path;
struct Node4D n4d;
ushort lastnet, num;
bool lastok;
ulong jbcpos;
lastok = FALSE;
lastnet = 0;
/* Find last entry in Path */
path = (struct Path *) list->Last;
if (path && path->Paths != 0) {
num = path->Paths - 1;
jbcpos = 0;
while (jbstrcpy(buf, path->Path[num], 40, &jbcpos)) {
if (Parse4D(buf, &n4d)) {
if (n4d.Net == 0)
n4d.Net = lastnet;
else
lastnet = n4d.Net;
lastok = TRUE;
} else {
lastok = FALSE;
}
}
}
/* Are we already in the PATH line? */
if (lastok) {
if (n4d.Net == node->Net && n4d.Node == node->Node && n4d.Point == node->Point)
return (TRUE);
}
/* Make address */
if (lastok && n4d.Net == node->Net)
snprintf(buf, 40, "%u", node->Node);
else
snprintf(buf, 40, "%u/%u", node->Net, node->Node);
/* Add new */
path = (struct Path *) list->Last;
if (path) {
if (path->Paths != 0) {
if (strlen(buf) + strlen(path->Path[path->Paths - 1]) <= 70) {
/* Add to old path */
strcat(path->Path[path->Paths - 1], " ");
strcat(path->Path[path->Paths - 1], buf);
return (TRUE);
}
}
}
if (path && path->Paths == PKT_NUMPATH)
path = NULL; /* Chunk is full */
if (!path) {
/* Alloc new path */
if (!(path = (struct Path *) malloc(sizeof(struct Path)))) {
nomem = TRUE;
return (FALSE);
}
jbAddNode(list, (struct jbNode *) path);
path->Next = NULL;
path->Paths = 0;
}
/* Always net/node when a new line */
snprintf(path->Path[path->Paths], 100, "%u/%u", node->Net, node->Node);
path->Paths++;
return (TRUE);
}
uchar *StripRe(uchar * str)
{
for (;;) {
if (strnicmp(str, "Re:", 3) == 0) {
str += 3;
if (*str == ' ')
str++;
} else if (strnicmp(str, "Re^", 3) == 0 && str[4] == ':') {
str += 5;
if (*str == ' ')
str++;
} else if (strnicmp(str, "Re[", 3) == 0 && str[4] == ']' && str[5] == ':') {
str += 6;
if (*str == ' ')
str++;
} else
break;
}
return (str);
}
bool HandleEchomail(struct MemMessage * mm)
{
struct Area *temparea;
struct TossNode *temptnode;
struct AddNode *tmpaddnode;
struct RemNode *tmpremnode;
struct ConfigNode *tempcnode;
struct Carbon *tempcarbon;
uchar buf[200];
LogWrite(6, DEBUG, "Is in HandleEchomail()");
mm->Type = PKTS_ECHOMAIL;
mm->Attr = 0;
/* Find orignode */
for (tempcnode = (struct ConfigNode *) config.CNodeList.First; tempcnode; tempcnode = tempcnode->Next)
if (Compare4D(&mm->PktOrig, &tempcnode->Node) == 0)
break;
if (!stricmp(mm->Area, "NETMAIL")) {
LogWrite(1, TOSSINGERR, "Echomail message to NETMAIL area. CrashEcho confused :-/", mm->Area);
toss_bad++;
if (!WriteBad(mm, "Echomail message to \"NETMAIL\" area."))
return (FALSE);
}
/* Find area */
for (temparea = (struct Area *) config.AreaList.First; temparea; temparea = temparea->Next)
if (stricmp(temparea->Tagname, mm->Area) == 0)
break;
/* Auto-add */
if (!temparea) {
if (tempcnode)
temparea = AddArea(mm->Area, &mm->PktOrig, &mm->PktDest, tempcnode->Flags & NODE_AUTOADD, FALSE);
else
temparea = AddArea(mm->Area, &mm->PktOrig, &mm->PktDest, FALSE, FALSE);
if (!temparea)
return (FALSE);
if (temparea->Flags & AREA_UNCONFIRMED)
LogWrite(3, TOSSINGERR, "Unknown area %s", mm->Area);
else
LogWrite(3, TOSSINGINFO, "Unknown area %s -- auto-adding", mm->Area);
}
/* Don't toss in auto-added areas */
if (temparea->Flags & AREA_UNCONFIRMED) {
toss_bad++;
if (!WriteBad(mm, "Unknown area tag"))
return (FALSE);
return (TRUE);
}
/* Don't toss in removed areas */
if (temparea->AreaType == AREATYPE_DELETED) {
LogWrite(1, TOSSINGERR, "Posting not allowed to removed area %s", mm->Area);
toss_bad++;
if (!WriteBad(mm, "Posting not allowed to removed area"))
return (FALSE);
return (TRUE);
}
/* Check if the node receives this area */
if ((nowdoing == DOING_TOSS || nowdoing == DOING_TOSSBAD) && !mm->no_security) {
for (temptnode = (struct TossNode *) temparea->TossNodes.First; temptnode; temptnode = temptnode->Next)
if (Compare4D(&temptnode->ConfigNode->Node, &mm->PktOrig) == 0)
break;
if (!temptnode) {
LogWrite(1, TOSSINGERR, "%u:%u/%u.%u not active for %s", mm->PktOrig.Zone, mm->PktOrig.Net, mm->PktOrig.Node, mm->PktOrig.Point, mm->Area);
toss_bad++;
if (!WriteBad(mm, "Sender not active for this area"))
return (FALSE);
return (TRUE);
}
if (temptnode->Flags & TOSSNODE_READONLY || (temparea->Expires && !(temptnode->Flags & TOSSNODE_FEED))) {
LogWrite(1, TOSSINGERR, "%u:%u/%u.%u not allowed to post in %s", mm->PktOrig.Zone, mm->PktOrig.Net, mm->PktOrig.Node, mm->PktOrig.Point, mm->Area);
toss_bad++;
if (!WriteBad(mm, "Sender not allowed to post in this area"))
return (FALSE);
return (TRUE);
}
}
/* We got message, so clear the EXPIRES field */
if (temparea->Expires) {
/* FIXME check if message comes from FEED */
temparea->Expires = 0;
config.changed = TRUE;
temparea->changed = TRUE;
}
/* Remove all SEEN-BY:s if the message comes from an other zone */
if (temparea->Aka->Node.Zone != mm->PktOrig.Zone && mm->SeenBy.First)
jbFreeList(&mm->SeenBy);
/* Check if a node already is in seen-by */
if ((config.cfg_Flags & CFG_CHECKSEENBY) && !(temparea->Flags & AREA_IGNORESEENBY)) {
for (temptnode = (struct TossNode *) temparea->TossNodes.First; temptnode; temptnode = temptnode->Next) {
temptnode->ConfigNode->IsInSeenBy = FALSE;
if (temptnode->ConfigNode->Node.Zone == temparea->Aka->Node.Zone)
if (temptnode->ConfigNode->Node.Point == 0)
if (FindNodes2D(&mm->SeenBy, &temptnode->ConfigNode->Node))
temptnode->ConfigNode->IsInSeenBy = TRUE;
}
}
/* Add nodes to seen-by */
for (temptnode = (struct TossNode *) temparea->TossNodes.First; temptnode; temptnode = temptnode->Next)
if (temptnode->ConfigNode->Node.Point == 0 && temparea->Aka->Node.Zone == temptnode->ConfigNode->Node.Zone)
if (!(temptnode->ConfigNode->Flags & NODE_PASSIVE))
if (!(temptnode->Flags & TOSSNODE_WRITEONLY))
if (!mmAddNodes2DList (&mm->SeenBy, temptnode->ConfigNode->Node.Net, temptnode->ConfigNode->Node.Node))
return (FALSE);
/* Remove nodes specified in config from seen-by and path */
for (tmpremnode = (struct RemNode *) temparea->Aka->RemList.First; tmpremnode; tmpremnode = tmpremnode->Next)
mmRemNodes2DListPat(&mm->SeenBy, &tmpremnode->NodePat);
/* Add nodes specified in config to seen-by */
for (tmpaddnode = (struct AddNode *) temparea->Aka->AddList.First; tmpaddnode; tmpaddnode = tmpaddnode->Next)
mmAddNodes2DList(&mm->SeenBy, tmpaddnode->Node.Net, tmpaddnode->Node.Node);
/* Add own node to seen-by */
if (temparea->Aka->Node.Point == 0) {
if (!mmAddNodes2DList (&mm->SeenBy, temparea->Aka->Node.Net, temparea->Aka->Node.Node))
return (FALSE);
}
/* Add own node to path */
if (temparea->Aka->Node.Point == 0) {
if (!AddNodePath(&mm->Path, &temparea->Aka->Node))
return (FALSE);
}
/* Dupecheck */
if (config.cfg_DupeMode != DUPE_IGNORE && (nowdoing == DOING_TOSS || nowdoing == DOING_TOSSBAD) && !(temparea->Flags & AREA_IGNOREDUPES)) {
if (CheckDupe(mm)) {
LogWrite(4, TOSSINGERR, "Duplicate message in %s", mm->Area);
toss_dupes++;
temparea->NewDupes++;
if (nowdoing == DOING_TOSS && tempcnode)
tempcnode->Dupes++;
if (config.cfg_DupeMode == DUPE_BAD) {
if (!WriteBad(mm, "Duplicate message"))
return (FALSE);
}
return (TRUE);
}
}
temparea->NewTexts++;
if (!mmSortNodes2D(&mm->SeenBy))
return (FALSE);
/* Write to all nodes */
if (!mm->Rescanned)
/* not rescanned */
for (temptnode = (struct TossNode *) temparea->TossNodes.First; temptnode; temptnode = temptnode->Next)
/* is not sender of packet */
if (Compare4D(&mm->PktOrig, &temptnode->ConfigNode->Node) != 0)
/* is not passive */
if (!(temptnode->ConfigNode->Flags & NODE_PASSIVE))
/* is not write-only */
if (!(temptnode->Flags & TOSSNODE_WRITEONLY))
/* is not already in seen-by */
if (!(temptnode->ConfigNode->IsInSeenBy == TRUE && (config.cfg_Flags & CFG_CHECKSEENBY)))
if (!WriteEchoMail(mm, temptnode->ConfigNode, temparea->Aka))
return (FALSE);
if (nowdoing == DOING_TOSS || nowdoing == DOING_TOSSBAD) {
if (temparea->Messagebase) {
toss_import++;
if (config.cfg_Flags & CFG_STRIPRE)
strcpy(mm->Subject, StripRe(mm->Subject));
if (!(*temparea->Messagebase->importfunc) (mm, temparea))
return (FALSE);
}
}
if ((nowdoing == DOING_TOSS || nowdoing == DOING_TOSSBAD) || (nowdoing == DOING_SCAN && (config.cfg_Flags & CFG_CCONSCAN))) {
/* Add ^aAREA */
snprintf(buf, 200, "\001AREA:%s\r", mm->Area);
mmAddLine(mm, buf, MM_HEAD);
for (tempcarbon = (struct Carbon *) config.CarbonList.First; tempcarbon; tempcarbon = tempcarbon->Next)
if (MatchPattern(tempcarbon->FromArea, mm->Area) &&
MatchPattern(tempcarbon->Pattern, tempcarbon->CCType == CC_SUBJ ? mm->Subject : tempcarbon->CCType == CC_FROM ? mm->From : mm->To)) {
for (temparea = (struct Area *) config.AreaList.First; temparea; temparea = temparea->Next)
if (stricmp(temparea->Tagname, tempcarbon->ToArea) == 0)
break;
/* Copy message */
if (temparea && temparea->Messagebase) {
toss_cc++;
if (!(*temparea->Messagebase->importfunc) (mm, temparea))
return (FALSE);
}
}
}
return (TRUE);
}
/**************************** Netmail *****************************/
/* Main netmail handling */
bool HandleNetmail(struct MemMessage * mm)
{
struct ConfigNode *pktcnode;
struct TextChunk *tmpchunk, *chunk;
uchar buf[400];
ulong size;
LogWrite(6, DEBUG, "Is in HandleNetmail()");
/* Find orignode */
for (pktcnode = (struct ConfigNode *) config.CNodeList.First; pktcnode; pktcnode = pktcnode->Next)
if (Compare4D(&mm->PktOrig, &pktcnode->Node) == 0)
break;
/* Calculate size */
size = 0;
for (tmpchunk = (struct TextChunk *) mm->TextChunks.First; tmpchunk; tmpchunk = tmpchunk->Next)
if (tmpchunk->Data)
size += strlen(tmpchunk->Data);
/* Statistics */
if (nowdoing == DOING_TOSS && pktcnode) {
pktcnode->GotNetmails++;
pktcnode->GotNetmailBytes += size;
}
/* Set zones if they are zero */
if (mm->DestNode.Zone == 0)
mm->DestNode.Zone = mm->PktDest.Zone;
if (mm->OrigNode.Zone == 0)
mm->OrigNode.Zone = mm->PktOrig.Zone;
/* Add CR if last line doesn't end with CR */
chunk = (struct TextChunk *) mm->TextChunks.First;
if (chunk && chunk->Data) {
if (chunk->Data[strlen(chunk->Data) - 1] != 13 && chunk->Data[strlen(chunk->Data) - 1])
mmAddBuf(&mm->TextChunks, "\015", 1, MM_ADD);
}
if (nowdoing == DOING_TOSS) {
mm->Attr &= FLAG_IMPORT;
mm->Attr |= FLAG_PVT;
} else if (nowdoing == DOING_SCAN) {
mm->Attr &= FLAG_EXPORT;
mm->Attr |= (FLAG_PVT | FLAG_KILLSENT);
}
/* Import netmail */
if (config.cfg_Flags & CFG_STRIPRE)
strcpy(mm->Subject, StripRe(mm->Subject));
if (nowdoing == DOING_TOSS) {
Print4D(&mm->OrigNode, buf, 400);
LogWrite(4, TOSSINGINFO, "Importing message from %s at %s", mm->From, buf);
}
config.Netmail.NewTexts++;
if (config.Netmail.Messagebase) {
toss_import++;
if (config.cfg_Flags & CFG_STRIPRE)
strcpy(mm->Subject, StripRe(mm->Subject));
if (!(config.Netmail.Messagebase->importfunc) (mm, &config.Netmail))
return (FALSE);
}
return (TRUE);
}
/******************************* end netmail **********************************/
/********************************** Rescan *******************************/
bool HandleRescan(struct MemMessage * mm)
{
struct Area *temparea;
rescan_total++;
/* Find area */
for (temparea = (struct Area *) config.AreaList.First; temparea; temparea = temparea->Next)
if (stricmp(temparea->Tagname, mm->Area) == 0)
break;
/* Add own node to seen-by to be on the safe side */
if (temparea->Aka->Node.Point == 0) {
if (!mmAddNodes2DList (&mm->SeenBy, temparea->Aka->Node.Net, temparea->Aka->Node.Node))
return (FALSE);
}
/* Add destination node to seen-by to be on the safe side */
if (RescanNode->Node.Point == 0) {
if (!mmAddNodes2DList (&mm->SeenBy, RescanNode->Node.Net, RescanNode->Node.Node))
return (FALSE);
}
/* Add own node to path */
if (temparea->Aka->Node.Point == 0) {
if (!AddNodePath(&mm->Path, &temparea->Aka->Node))
return (FALSE);
}
if (!mmSortNodes2D(&mm->SeenBy))
return (FALSE);
mm->Rescanned = TRUE;
if (!WriteEchoMail(mm, RescanNode, temparea->Aka))
return (FALSE);
return (TRUE);
}
/********************************** TossBad ******************************/
bool HandleBad(struct MemMessage * mm)
{
if (HandleEchomail(mm)) {
mm->Changed = TRUE;
mm->Deleted = TRUE;
return TRUE;
}
return FALSE;
}
syntax highlighted by Code2HTML, v. 0.9.1