/******************************************************** * 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); }