/********************************************************
* File: mb_msg.c
* Created at Sun Jan 28 22:10:30 MSK 2001 by raorn // raorn@binec.ru
* *.MSG support
* $Id: mb_msg.c,v 1.21 2002/03/03 21:05:57 raorn Exp $
*******************************************************/
#include "crashecho.h"
struct msg_Area {
struct msg_Area *Next;
struct Area *area;
ulong LowMsg;
ulong HighMsg;
ulong OldHighWater;
ulong HighWater;
};
bool msg_GetHighLowMsg(struct msg_Area *area);
bool msg_WriteHighWater(struct msg_Area *area);
bool msg_WriteMSG(struct MemMessage *mm, uchar * file, bool impseenby);
ulong msg_ReadCR(uchar * buf, ulong maxlen, FILE *fh);
bool msg_ExportMSGNum(struct Area *area, ulong num, bool (*acceptfunc) (struct MemMessage *mm), bool (*handlefunc) (struct MemMessage *mm));
struct jbList msg_AreaList;
bool msg_messageend;
bool msg_shortread;
struct msg_Area *msg_getarea(struct Area *area)
{
struct msg_Area *ma;
/* Check if area already exists */
for (ma = (struct msg_Area *) msg_AreaList.First; ma; ma = ma->Next)
if (ma->area == area)
return (ma);
/* This is the first time we use this area */
if (!(ma = calloc(1, sizeof(struct msg_Area)))) {
nomem = TRUE;
return (FALSE);
}
jbAddNode(&msg_AreaList, (struct jbNode *) ma);
ma->area = area;
if (!msg_GetHighLowMsg(ma))
return (FALSE);
return (ma);
}
bool msg_beforefunc(void)
{
jbNewList(&msg_AreaList);
return (TRUE);
}
bool msg_afterfunc(bool success)
{
struct msg_Area *ma;
if (success && (config.cfg_msg_Flags & CFG_MSG_HIGHWATER))
for (ma = (struct msg_Area *) msg_AreaList.First; ma; ma = ma->Next)
if (ma->HighWater != ma->OldHighWater)
msg_WriteHighWater(ma);
return (TRUE);
}
bool msg_importfunc(struct MemMessage * mm, struct Area * area)
{
uchar buf[200], buf2[20];
struct msg_Area *ma;
if (!(ma = msg_getarea(area)))
return (FALSE);
do {
ma->HighMsg++;
snprintf(buf2, 200, "%lu.msg", ma->HighMsg);
MakeFullPath(ma->area->Path, buf2, buf, 200);
} while (Exists(buf));
return msg_WriteMSG(mm, buf, area->Flags & AREA_IMPORTSEENBY);
}
bool msg_scanfunc(struct Area * area, bool usehw, bool ignorehw, ulong max, struct jbList *msglist, bool(*acceptfunc) (struct MemMessage * mm), bool(*handlefunc) (struct MemMessage * mm))
{
ulong start, stop;
uchar buf[200];
struct StoredMsg Msg;
FILE *fh;
struct msg_Area *ma;
if (!(ma = msg_getarea(area)))
return (FALSE);
if (usehw && config.cfg_msg_Flags & CFG_MSG_HIGHWATER) {
if (ma->HighWater == 0) {
MakeFullPath(area->Path, "1.msg", buf, 200);
if ((fh = fopen(buf, "rb"))) {
if ((fread(&Msg, 1, sizeof(struct StoredMsg), fh) == sizeof(struct StoredMsg))) {
ma->HighWater = Msg.ReplyTo;
ma->OldHighWater = Msg.ReplyTo;
}
fclose(fh);
}
}
}
if (ignorehw)
start = 1;
else {
if (ma->HighWater)
start = ma->HighWater + 1;
else
start = ma->LowMsg;
if (start < ma->LowMsg)
start = ma->LowMsg;
}
stop = ma->HighMsg;
if (max != 0 && stop - start + 1 > max)
start = stop - max + 1;
while (start <= stop) {
if (!msg_ExportMSGNum(area, start, acceptfunc, handlefunc))
return (FALSE);
if (ctrlc)
return (FALSE);
start++;
}
if (usehw)
ma->HighWater = stop- 1;
return (TRUE);
}
bool msg_ExportMSGNum(struct Area * area, ulong num, bool(*acceptfunc) (struct MemMessage *mm), bool(*handlefunc) (struct MemMessage *mm))
{
ulong rlen;
uchar buf[200], buf2[50];
bool kludgeadd;
FILE *fh;
struct StoredMsg Msg;
struct MemMessage *mm;
bool gotarea = FALSE, gotfrom = FALSE;
LogWrite(6, SYSTEMINFO, "In msg_ExportMSGNum(\"%s\", %d, ...)", area->Tagname, num);
if (!(mm = mmAlloc()))
return (FALSE);
snprintf(buf2, 50, "%lu.msg", num);
MakeFullPath(area->Path, buf2, buf, 200);
if (!(fh = fopen(buf, "rb"))) {
/* Message doesn't exist */
mmFree(mm);
return (TRUE);
}
if (fread(&Msg, 1, sizeof(struct StoredMsg), fh) != sizeof(struct StoredMsg)) {
LogWrite(1, TOSSINGERR, "Unexpected EOF while reading %s, message ignored", buf);
fclose(fh);
mmFree(mm);
return (TRUE);
}
mm->OrigNode.Net = Msg.OrigNet;
mm->OrigNode.Node = Msg.OrigNode;
mm->DestNode.Net = Msg.DestNet;
mm->DestNode.Node = Msg.DestNode;
if (area->AreaType == AREATYPE_NETMAIL)
mm->Area[0]=0;
else
strcpy(mm->Area, area->Tagname);
mystrncpy(mm->To, Msg.To, 36);
mystrncpy(mm->From, Msg.From, 36);
mystrncpy(mm->Subject, Msg.Subject, 72);
mystrncpy(mm->DateTime, Msg.DateTime, 20);
mm->Attr = Msg.Attr;
mm->Cost = Msg.Cost;
kludgeadd = FALSE;
msg_messageend = FALSE;
msg_shortread = FALSE;
do {
rlen = msg_ReadCR(buf, 200, fh);
if (buf[0] == 1 && area->AreaType == AREATYPE_BAD) {
if (!gotfrom && rlen > 6 && !strncmp(buf, "\001FROM:", 6)) {
struct Node4D node;
uchar buf2[100];
mystrncpy(buf2, &buf[6], (rlen - 6 > 99 ? 99 : rlen - 6) + 1);
stripleadtrail(buf2);
if (Parse4D(buf2, &node))
Copy4D(&mm->PktOrig, &node);
/* Just skip this kludge */
gotfrom = TRUE;
continue;
} else if (!gotarea && rlen > 6 && !strncmp(buf, "\001AREA:", 6)) {
mystrncpy(mm->Area, &buf[6], (rlen - 6 > 79 ? 79 : rlen - 6) + 1);
stripleadtrail(mm->Area); /* Strip spaces from area name */
gotarea = TRUE;
/* Just skip this kludge */
continue;
} else if (rlen >= 8 && !strncmp(buf, "\001REASON:", 8))
/* Just skip this kludge */
continue;
}
if (buf[0] != 1 && buf[0] != 10 && !kludgeadd) {
kludgeadd = TRUE;
if (mm->Area[0] == 0) {
if (mm->DestNode.Zone == 0 || mm->OrigNode.Zone == 0) {
/* No INTL line and no zone in header */
mm->DestNode.Zone = area->Aka->Node.Zone;
mm->OrigNode.Zone = area->Aka->Node.Zone;
Msg.DestZone = area->Aka->Node.Zone;
Msg.OrigZone = area->Aka->Node.Zone;
if(config.cfg_Flags & CFG_FORCEINTL) {
snprintf(buf2, 50, "\001INTL %u:%u/%u %u:%u/%u\015",
Msg.DestZone, Msg.DestNet, Msg.DestNode,
Msg.OrigZone, Msg.OrigNet, Msg.OrigNode);
mmAddLine(mm,buf2, MM_HEAD);
/* FIXME What with FMPT/TOPT? */
}
}
}
}
if (buf[0]) {
if (!mmAddLine(mm, buf, MM_ADD)) {
fclose(fh);
mmFree(mm);
return (FALSE);
}
}
} while (!msg_messageend && !msg_shortread);
fclose(fh);
mm->msgnum = num;
/* FIXME Check if /^\001FLAGS.*LOK.*$/ */
if ((*acceptfunc) (mm)) {
if (!(*handlefunc) (mm)) {
mmFree(mm);
return (FALSE);
}
snprintf(buf2, 50, "%lu.msg", num);
MakeFullPath(area->Path, buf2, buf, 200);
if (mm->Changed) {
Msg.Attr = mm->Attr;
if (mm->Deleted) {
unlink(buf);
} else {
if ((fh = fopen(buf, "r+b"))) {
fwrite(&Msg, sizeof(struct StoredMsg), 1, fh);
fclose(fh);
}
}
}
}
mmFree(mm);
return (TRUE);
}
ulong msg_templowmsg;
ulong msg_temphighmsg;
void msg_scandirfunc(uchar * file)
{
if (strlen(file) > 4) {
if (stricmp(&file[strlen(file) - 4], ".msg") == 0) {
if (atol(file) > msg_temphighmsg)
msg_temphighmsg = atol(file);
if (atol(file) < msg_templowmsg || msg_templowmsg == 0 ||
msg_templowmsg == 1)
if (atol(file) >= 2)
msg_templowmsg = atol(file);
}
}
}
bool msg_GetHighLowMsg(struct msg_Area *area)
{
mode_t oldumask;
if (!Exists(area->area->Path)) {
LogWrite(2, SYSTEMINFO, "Creating directory \"%s\"", area->area->Path);
oldumask = umask(config.cfg_MsgbaseUmask);
if (mkdir(area->area->Path, 0777)) {
umask(oldumask);
LogWrite(1, SYSTEMERR, "Unable to create directory");
LogWrite(1, SYSTEMERR, "Error: %s", strerror(errno));
return (FALSE);
}
umask(oldumask);
}
msg_templowmsg = 0;
msg_temphighmsg = 0;
if (!ScanDir(area->area->Path, msg_scandirfunc)) {
LogWrite(1, SYSTEMERR, "Failed to scan directory %s", area->area->Path);
LogWrite(1, SYSTEMERR, "Error: %s", strerror(errno));
return (FALSE);
}
area->HighMsg = msg_temphighmsg;
area->LowMsg = msg_templowmsg;
if (area->HighMsg == 0)
area->HighMsg = 1;
if (area->LowMsg == 0 || area->LowMsg == 1)
area->LowMsg = 2;
return (TRUE);
}
bool msg_WriteHighWater(struct msg_Area * area)
{
FILE *fh;
uchar buf[200];
struct StoredMsg Msg;
mode_t oldumask;
if (area->HighWater > 65535) {
LogWrite(1, TOSSINGERR, "Warning: Highwater mark in %s exceeds 65535, cannot store in 1.msg",
area->area->Tagname);
return (TRUE);
}
strcpy(Msg.From, "CrashEcho");
strcpy(Msg.To, "All");
strcpy(Msg.Subject, "HighWater mark");
MakeFidoDate(time(NULL), Msg.DateTime);
Msg.TimesRead = 0;
Msg.DestNode = 0;
Msg.OrigNode = 0;
Msg.Cost = 0;
Msg.OrigNet = 0;
Msg.DestNet = 0;
Msg.DestZone = 0;
Msg.OrigZone = 0;
Msg.OrigPoint = 0;
Msg.DestPoint = 0;
Msg.ReplyTo = area->HighWater;
Msg.Attr = FLAG_SENT | FLAG_PVT;
Msg.NextReply = 0;
MakeFullPath(area->area->Path, "1.msg", buf, 200);
oldumask = umask(config.cfg_MsgbaseUmask);
if (!(fh = fopen(buf, "wb"))) {
umask(oldumask);
LogWrite(1, SYSTEMERR, "Failed to write Highwater mark to %s", buf);
LogWrite(1, SYSTEMERR, "Error: %s", strerror(errno));
return (FALSE);
}
umask(oldumask);
if (fwrite(&Msg, 1, sizeof(struct StoredMsg), fh) != sizeof(struct StoredMsg)) {
ioerror = TRUE;
ioerrornum = errno;
}
if (fwrite("", 1, 1, fh) != 1) {
ioerror = TRUE;
ioerrornum = errno;
}
fclose(fh);
if (ioerror)
return (FALSE);
return (TRUE);
}
bool msg_WriteMSG(struct MemMessage * mm, uchar * file, bool impseenby)
{
struct StoredMsg Msg;
struct TextChunk *chunk;
struct Path *path;
FILE *fh;
int c;
mode_t oldumask;
strcpy(Msg.From, mm->From);
strcpy(Msg.To, mm->To);
strcpy(Msg.Subject, mm->Subject);
strcpy(Msg.DateTime, mm->DateTime);
Msg.TimesRead = 0;
Msg.ReplyTo = 0;
Msg.NextReply = 0;
Msg.Cost = mm->Cost;
Msg.Attr = mm->Attr;
if (mm->Area[0] == 0) {
Msg.DestZone = mm->DestNode.Zone;
Msg.DestNet = mm->DestNode.Net;
Msg.DestNode = mm->DestNode.Node;
Msg.DestPoint = mm->DestNode.Point;
Msg.OrigZone = mm->OrigNode.Zone;
Msg.OrigNet = mm->OrigNode.Net;
Msg.OrigNode = mm->OrigNode.Node;
Msg.OrigPoint = mm->OrigNode.Point;
} else {
Msg.DestZone = 0;
Msg.DestNet = 0;
Msg.DestNode = 0;
Msg.DestPoint = 0;
Msg.OrigZone = 0;
Msg.OrigNet = 0;
Msg.OrigNode = 0;
Msg.OrigPoint = 0;
}
oldumask = umask(config.cfg_MsgbaseUmask);
if (!(fh = fopen(file, "wb"))) {
umask(oldumask);
LogWrite(1, SYSTEMERR, "Failed to write to %s\n", file);
LogWrite(1, SYSTEMERR, "Error: %s", strerror(errno));
return (FALSE);
}
umask(oldumask);
/* Write header */
if (fwrite(&Msg, 1, sizeof(struct StoredMsg), fh) != sizeof(struct StoredMsg)) {
ioerror = TRUE;
ioerrornum = errno;
}
/* Write text */
for (chunk = (struct TextChunk *) mm->TextChunks.First; chunk; chunk = chunk->Next) {
if (chunk->Data)
if (fwrite(chunk->Data, 1, strlen(chunk->Data), fh) != strlen(chunk->Data)) {
ioerror = TRUE;
ioerrornum = errno;
}
}
/* Write seen-by */
if (impseenby && mm->Area[0] != 0) {
uchar *sbbuf;
if (!(sbbuf = mmMakeSeenByBuf(&mm->SeenBy))) {
fclose(fh);
return (FALSE);
}
if (sbbuf[0]) {
if (fwrite(sbbuf, 1, strlen(sbbuf), fh) != strlen(sbbuf)) {
ioerror = TRUE;
ioerrornum = errno;
}
}
free(sbbuf);
}
/* Write path */
for (path = (struct Path *) mm->Path.First; path; path = path->Next)
for (c = 0; c < path->Paths; c++)
if (path->Path[c][0] != 0) {
if (fwrite("\001PATH: ", 1, 7, fh) != 7) {
ioerror = TRUE;
ioerrornum = errno;
}
if (fwrite(path->Path[c], 1, strlen(path->Path[c]), fh) != strlen(path->Path[c])) {
ioerror = TRUE;
ioerrornum = errno;
}
if (fwrite("\015", 1, 1, fh) != 1) {
ioerror = TRUE;
ioerrornum = errno;
}
}
if (fputc(0, fh) == EOF) {
ioerror = TRUE;
ioerrornum = errno;
}
fclose(fh);
if (ioerror)
return (FALSE);
return (TRUE);
}
ulong msg_ReadCR(uchar * buf, ulong maxlen, FILE *fh)
{
/* Reads from fh until buffer full or CR */
short ch, c = 0;
ch = fgetc(fh);
while (ch != EOF && ch != 0 && ch != 13 && c != maxlen - 2) {
if(ch != 10)
buf[c++] = ch;
if (c != maxlen - 2)
ch = fgetc(fh);
}
if (ch == 13 || ch == 10)
buf[c++] = ch;
buf[c] = 0;
if (ch == 0)
msg_messageend = TRUE;
if (ch == EOF)
msg_shortread = TRUE;
return (c);
}
syntax highlighted by Code2HTML, v. 0.9.1