/******************************************************** * File: pkt.c * Created at Sun Jan 28 22:10:32 MSK 2001 by raorn // raorn@binec.ru * pkt processing * $Id: pkt.c,v 1.16 2002/03/03 21:05:57 raorn Exp $ *******************************************************/ #include "crashecho.h" /* * * Read Pkt * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define PKT_MINREADLEN 200 bool messageend; bool shortread, longread; ushort getuword(uchar * buf, ulong offset) { return (ushort) (buf[offset] + 256 * buf[offset + 1]); } void putuword(uchar * buf, ulong offset, ushort num) { buf[offset] = num % 256; buf[offset + 1] = num / 256; } ulong ReadNull(uchar * buf, ulong maxlen, FILE *fh) { /* Reads from fh until buffer full or NULL */ int ch, c = 0; if (shortread) return (0); ch = fgetc(fh); while (ch != EOF && ch != 0 && c != maxlen - 1) { buf[c++] = ch; ch = fgetc(fh); } buf[c] = 0; if (ch == EOF) shortread = TRUE; if (ch != 0 && c == maxlen - 1) longread = TRUE; return (c); } ulong ReadCR(uchar * buf, ulong maxlen, FILE *fh) { /* Reads from fh until buffer full or CR */ int 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) buf[c++] = ch; buf[c] = 0; if (ch == 0) messageend = TRUE; if (ch == EOF) shortread = TRUE; return (c); } bool ReadPkt(uchar * pkt, struct FileEntry * fe, bool(*handlefunc) (struct MemMessage * mm, bool no_echomail), bool no_security, bool no_echomail) { FILE *fh, *pktofsh; struct Aka *tmpaka; struct ConfigNode *tmpcnode; uchar pktofs[200]; ulong rlen, msgnum, msgoffset, c; uchar buf[200]; uchar PktHeader[SIZE_PKTHEADER]; uchar PktMsgHeader[SIZE_PKTMSGHEADER]; struct Node4D PktOrig, PktDest; uchar *monthnames[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???" }; struct MemMessage *mm; struct TextChunk *chunk; bool pkt_pw, pkt_4d, pkt_5d; shortread = FALSE; longread = FALSE; pkt_pw = FALSE; pkt_4d = FALSE; pkt_5d = FALSE; PktOrig.Zone = 0; PktOrig.Net = 0; PktOrig.Node = 0; PktOrig.Point = 0; PktDest.Zone = 0; PktDest.Net = 0; PktDest.Node = 0; PktDest.Point = 0; if (!(mm = mmAlloc())) return (FALSE); if (!(fh = fopen(pkt, "rb"))) { LogWrite(1, SYSTEMERR, "Unable to open %s", pkt); LogWrite(1, SYSTEMERR, "Error: %s", strerror(errno)); mmFree(mm); return (TRUE); } if (fread(PktHeader, 1, SIZE_PKTHEADER, fh) != SIZE_PKTHEADER) { LogWrite(1, TOSSINGERR, "Packet header in %s is too short", pkt); fclose(fh); mmFree(mm); BadFile(pkt); return (TRUE); } if (getuword(PktHeader, PKTHEADER_PKTTYPE) != 0x0002) { LogWrite(1, TOSSINGERR, "%s is not a Type-2 packet", pkt); fclose(fh); mmFree(mm); BadFile(pkt); return (TRUE); } if (getuword(PktHeader, PKTHEADER_BAUD) == 2) { /* PktOrig och PktDest */ PktOrig.Zone = getuword(PktHeader, PKTHEADER_ORIGZONE); PktOrig.Net = getuword(PktHeader, PKTHEADER_ORIGNET); PktOrig.Node = getuword(PktHeader, PKTHEADER_ORIGNODE); PktOrig.Point = getuword(PktHeader, PKTHEADER_ORIGPOINT); PktDest.Zone = getuword(PktHeader, PKTHEADER_DESTZONE); PktDest.Net = getuword(PktHeader, PKTHEADER_DESTNET); PktDest.Node = getuword(PktHeader, PKTHEADER_DESTNODE); PktDest.Point = getuword(PktHeader, PKTHEADER_DESTPOINT); pkt_5d = TRUE; } else { /* PktOrig och PktDest */ if (getuword(PktHeader, PKTHEADER_ORIGZONE)) { PktOrig.Zone = getuword(PktHeader, PKTHEADER_ORIGZONE); PktDest.Zone = getuword(PktHeader, PKTHEADER_DESTZONE); } else if (getuword(PktHeader, PKTHEADER_QORIGZONE)) { PktOrig.Zone = getuword(PktHeader, PKTHEADER_QORIGZONE); PktDest.Zone = getuword(PktHeader, PKTHEADER_QDESTZONE); } else { PktOrig.Zone = 0; PktDest.Zone = 0; } PktOrig.Net = getuword(PktHeader, PKTHEADER_ORIGNET); PktOrig.Node = getuword(PktHeader, PKTHEADER_ORIGNODE); PktDest.Net = getuword(PktHeader, PKTHEADER_DESTNET); PktDest.Node = getuword(PktHeader, PKTHEADER_DESTNODE); if (PktHeader[PKTHEADER_CWVALIDCOPY] == PktHeader[PKTHEADER_CAPABILWORD + 1] && PktHeader[PKTHEADER_CWVALIDCOPY + 1] == PktHeader[PKTHEADER_CAPABILWORD]) { pkt_4d = TRUE; if (getuword(PktHeader, PKTHEADER_ORIGPOINT) != 0 && getuword(PktHeader, PKTHEADER_ORIGNET) == 0xffff) PktOrig.Net = getuword(PktHeader, PKTHEADER_AUXNET); PktOrig.Point = getuword(PktHeader, PKTHEADER_ORIGPOINT); PktDest.Point = getuword(PktHeader, PKTHEADER_DESTPOINT); } } /* Check packet destination */ if ((config.cfg_Flags & CFG_CHECKPKTDEST) && !no_security) { for (tmpaka = (struct Aka *) config.AkaList.First; tmpaka; tmpaka = tmpaka->Next) if (Compare4D(&tmpaka->Node, &PktDest) == 0) break; if (!tmpaka) { LogWrite(1, TOSSINGERR, "Addressed to %u:%u/%u.%u, not to me", PktDest.Zone, PktDest.Net, PktDest.Node, PktDest.Point); fclose(fh); mmFree(mm); BadFile(pkt); return (TRUE); } } /* Fixa zone */ /* XXX I think this code does nothing, since Compare4D will always fail... */ if (PktOrig.Zone == 0) for (tmpcnode = (struct ConfigNode *) config.CNodeList.First; tmpcnode; tmpcnode = tmpcnode->Next) { if (Compare4D(&PktOrig, &tmpcnode->Node) == 0) { PktOrig.Zone = tmpcnode->Node.Zone; break; } } if (PktDest.Zone == 0) for (tmpaka = (struct Aka *) config.AkaList.First; tmpaka; tmpaka = tmpaka->Next) { if (Compare4D(&PktDest, &tmpaka->Node) == 0) { PktDest.Zone = tmpaka->Node.Zone; break; } } if (PktOrig.Zone == 0) PktOrig.Zone = config.cfg_DefaultZone; if (PktDest.Zone == 0) PktDest.Zone = config.cfg_DefaultZone; for (tmpcnode = (struct ConfigNode *) config.CNodeList.First; tmpcnode; tmpcnode = tmpcnode->Next) if (Compare4D(&PktOrig, &tmpcnode->Node) == 0) break; if (tmpcnode) { if (tmpcnode->PacketPW[0] != 0 && PktHeader[PKTHEADER_PASSWORD] != 0) pkt_pw = TRUE; } buf[0] = 0; if (pkt_pw) strcat(buf, ", pw"); if (pkt_4d) strcat(buf, ", 4d"); if (pkt_5d) strcat(buf, ", 5d"); if (buf[0] != 0) buf[0] = '/'; if (pkt_5d) { uchar domain[10]; mystrncpy(domain, &PktHeader[PKTHEADER45_ORIGDOMAIN], 9); LogWrite(1, ACTIONINFO, "Tossing %s (%luK) from %d:%d/%d.%d@%s %s", fe->Name, (fe->Size + 512) / 1024, PktOrig.Zone, PktOrig.Net, PktOrig.Node, PktOrig.Point, domain, buf); } else { int month; month = getuword(PktHeader, PKTHEADER_MONTH); if (month > 11) month = 12; LogWrite(1, ACTIONINFO, "Tossing %s (%luK) from %d:%d/%d.%d (%02ld-%s-%02ld %02ld:%02ld:%02ld) %s", fe->Name, (fe->Size + 512) / 1024, PktOrig.Zone, PktOrig.Net, PktOrig.Node, PktOrig.Point, getuword(PktHeader, PKTHEADER_DAY), monthnames[month], getuword(PktHeader, PKTHEADER_YEAR) % 100, getuword(PktHeader, PKTHEADER_HOUR), getuword(PktHeader, PKTHEADER_MINUTE), getuword(PktHeader, PKTHEADER_SECOND), buf); } if (tmpcnode) { strncpy(buf, &PktHeader[PKTHEADER_PASSWORD], 8); buf[8] = 0; if (!no_security && (tmpcnode->PacketPW[0] != 0 && stricmp(buf, tmpcnode->PacketPW)) && (buf[0] != 0 || !(config.cfg_Flags & CFG_ALLOWNULLPASSWORDS))) { LogWrite(1, TOSSINGERR, "Wrong password"); fclose(fh); mmFree(mm); BadFile(pkt); return (TRUE); } } snprintf(pktofs, 200, "%s.offset", pkt); if ((pktofsh=fopen(pktofs, "rb")) != NULL) { fread(&msgoffset, sizeof(msgoffset), 1, pktofsh); fread(&msgnum, sizeof(msgnum), 1, pktofsh); fseek(fh, msgoffset, SEEK_SET); fclose(pktofsh); LogWrite(1, ACTIONINFO, "Old packet with %ld processed messages found, continuing from offset %ld", msgnum, msgoffset); } else { msgoffset = ftell(fh); msgnum = 0; } while (1) { if ((pktofsh=fopen(pktofs, "wb")) != NULL) { fwrite(&msgoffset, sizeof(msgoffset), 1, pktofsh); fwrite(&msgnum, sizeof(msgnum), 1, pktofsh); fclose(pktofsh); } msgnum++; msgoffset = ftell(fh); if (fread(PktMsgHeader, 1, SIZE_PKTMSGHEADER, fh) < 2) { LogWrite(1, TOSSINGERR, "Packet header too short for msg #%lu (offset %ld)", msgnum + 1, msgoffset); fclose(fh); mmFree(mm); BadFile(pkt); /* FIXME should we delete pktofs file here? */ return (TRUE); } if (getuword(PktMsgHeader, PKTMSGHEADER_PKTTYPE) != 2) break; printf("Message %lu \015", msgnum); fflush(stdout); /* Init variables */ mmClear(mm); mm->OrigNode.Net = getuword(PktMsgHeader, PKTMSGHEADER_ORIGNET); mm->OrigNode.Node = getuword(PktMsgHeader, PKTMSGHEADER_ORIGNODE); mm->DestNode.Net = getuword(PktMsgHeader, PKTMSGHEADER_DESTNET); mm->DestNode.Node = getuword(PktMsgHeader, PKTMSGHEADER_DESTNODE); mm->DestNode.Zone = PktDest.Zone; mm->DestNode.Zone = PktOrig.Zone; mm->Attr = getuword(PktMsgHeader, PKTMSGHEADER_ATTR); mm->Cost = getuword(PktMsgHeader, PKTMSGHEADER_COST); Copy4D(&mm->PktOrig, &PktOrig); Copy4D(&mm->PktDest, &PktDest); if (no_security) mm->no_security = TRUE; /* Get header strings */ ReadNull(mm->DateTime, 20, fh); ReadNull(mm->To, 36, fh); ReadNull(mm->From, 36, fh); ReadNull(mm->Subject, 72, fh); /* Corrupt packet? */ if (shortread) { LogWrite(1, TOSSINGERR, "Message header for msg #%lu (offset %ld) is short", msgnum, msgoffset); fclose(fh); mmFree(mm); BadFile(pkt); return (TRUE); } if (longread) { LogWrite(1, TOSSINGERR, "Header strings too long in msg #%lu (offset %ld)", msgnum, msgoffset); fclose(fh); mmFree(mm); BadFile(pkt); return (TRUE); } /* Start reading message text */ messageend = FALSE; rlen = ReadCR(buf, 200, fh); /* Echomail or netmail? */ if (strncmp(buf, "AREA:", 5) == 0) { mystrncpy(mm->Area, &buf[5], 80); /* Strip spaces from area name */ stripleadtrail(mm->Area); /* Uppercase areatag */ for (c = 0; mm->Area[c]; c++) if (islower(mm->Area[c])) mm->Area[c] = toupper(mm->Area[c]); } else { if (!mmAddLine(mm, buf, MM_ADD)) { fclose(fh); mmFree(mm); return (FALSE); } } /* Get rest of text */ while (!messageend) { rlen = ReadCR(buf, 200, fh); if (shortread) { fclose(fh); mmFree(mm); LogWrite(1, TOSSINGERR, "Got unexpected EOF when reading msg #%lu (offset %ld)", msgnum, msgoffset); BadFile(pkt); return (TRUE); } if (buf[0]) { if (!mmAddLine(mm, buf, MM_ADD)) { fclose(fh); mmFree(mm); return (FALSE); } } } /* Stats */ for (tmpcnode = (struct ConfigNode *) config.CNodeList.First; tmpcnode; tmpcnode = tmpcnode->Next) if (Compare4D(&tmpcnode->Node, &mm->PktOrig) == 0) break; if (tmpcnode) { ulong size; size = 0; for (chunk = (struct TextChunk *) mm->TextChunks.First; chunk; chunk = chunk->Next) if (chunk->Data) size += strlen(chunk->Data); if (mm->Area[0]) { tmpcnode->GotEchomails++; tmpcnode->GotEchomailBytes += size; } else { tmpcnode->GotNetmails++; tmpcnode->GotNetmailBytes += size; } } if (ctrlc) { fclose(fh); mmFree(mm); return (FALSE); } if (!(*handlefunc) (mm, no_echomail)) { fclose(fh); mmFree(mm); return (FALSE); } } if (getuword(PktMsgHeader, PKTMSGHEADER_PKTTYPE) != 0) { fclose(fh); mmFree(mm); LogWrite(1, TOSSINGERR, "Unknown message type %lu for message #%lu (offset %ld)", getuword(PktMsgHeader, PKTMSGHEADER_PKTTYPE), msgnum + 1, msgoffset); BadFile(pkt); return (TRUE); } printf(" \015"); fflush(stdout); unlink(pktofs); fclose(fh); mmFree(mm); return (TRUE); } /* * * Write Pkt * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void pktWrite(struct Pkt *pkt, uchar * buf, ulong len) { if (fwrite(buf, 1, len, pkt->fh) != len) { ioerror = TRUE; ioerrornum = errno; } pkt->Len += len; } void WriteNull(struct Pkt *pkt, uchar * str) { pktWrite(pkt, str, (ulong) (strlen(str) + 1)); } struct Pkt *FindPkt(struct Node4D *node, struct Node4D *mynode, ushort type) { struct Pkt *pkt; for (pkt = (struct Pkt *) PktList.First; pkt; pkt = pkt->Next) if (Compare4D(node, &pkt->Dest) == 0 && Compare4D(mynode, &pkt->Orig) == 0 && type == pkt->Type) return (pkt); return (NULL); } static time_t lastt = 0; static ulong serial = 0; struct Pkt *CreatePkt(struct Node4D *dest, struct ConfigNode *node, struct Aka *aka, ushort type) { uchar buf[100], buf2[100]; struct Pkt *pkt; ulong num, c; time_t t; struct tm *tp; uchar PktHeader[SIZE_PKTHEADER]; do { t = time(NULL); if (t == lastt) serial++; else serial = 0; if (serial == 256) serial = 0; lastt = t; num = (t << 8) + serial; snprintf(buf2, 100, "%08lx.newpkt", num); MakeFullPath(config.cfg_PacketCreate, buf2, buf, 100); } while (Exists(buf)); if (!(pkt = (struct Pkt *) calloc(1, sizeof(struct Pkt)))) { nomem = TRUE; return (NULL); } if (!(pkt->fh = fopen(buf, "wb"))) { LogWrite(1, SYSTEMERR, "Unable to create packet %s", buf); LogWrite(1, SYSTEMERR, "Error: %s", strerror(errno)); free(pkt); return (NULL); } pkt->hexnum = num; pkt->Type = type; Copy4D(&pkt->Dest, dest); Copy4D(&pkt->Orig, &aka->Node); putuword(PktHeader, PKTHEADER_ORIGNODE, aka->Node.Node); putuword(PktHeader, PKTHEADER_DESTNODE, dest->Node); time(&t); tp = localtime(&t); putuword(PktHeader, PKTHEADER_DAY, tp->tm_mday); putuword(PktHeader, PKTHEADER_MONTH, tp->tm_mon); putuword(PktHeader, PKTHEADER_YEAR, tp->tm_year + 1900); putuword(PktHeader, PKTHEADER_HOUR, tp->tm_hour); putuword(PktHeader, PKTHEADER_MINUTE, tp->tm_min); putuword(PktHeader, PKTHEADER_SECOND, tp->tm_sec); putuword(PktHeader, PKTHEADER_BAUD, 0); putuword(PktHeader, PKTHEADER_PKTTYPE, 2); putuword(PktHeader, PKTHEADER_ORIGNET, aka->Node.Net); putuword(PktHeader, PKTHEADER_DESTNET, dest->Net); PktHeader[PKTHEADER_PRODCODELOW] = 0xfe; PktHeader[PKTHEADER_REVMAJOR] = VERSION_MAJOR; putuword(PktHeader, PKTHEADER_QORIGZONE, aka->Node.Zone); putuword(PktHeader, PKTHEADER_QDESTZONE, dest->Zone); putuword(PktHeader, PKTHEADER_AUXNET, 0); putuword(PktHeader, PKTHEADER_CWVALIDCOPY, 0x0100); PktHeader[PKTHEADER_PRODCODEHIGH] = 0; PktHeader[PKTHEADER_REVMINOR] = VERSION_MINOR; putuword(PktHeader, PKTHEADER_CAPABILWORD, 0x0001); putuword(PktHeader, PKTHEADER_ORIGZONE, aka->Node.Zone); putuword(PktHeader, PKTHEADER_DESTZONE, dest->Zone); putuword(PktHeader, PKTHEADER_ORIGPOINT, aka->Node.Point); putuword(PktHeader, PKTHEADER_DESTPOINT, dest->Point); PktHeader[PKTHEADER_PRODDATA] = 0; PktHeader[PKTHEADER_PRODDATA + 1] = 0; PktHeader[PKTHEADER_PRODDATA + 2] = 0; PktHeader[PKTHEADER_PRODDATA + 3] = 0; for (c = 0; c < 8; c++) PktHeader[PKTHEADER_PASSWORD + c] = 0; if (node) strncpy(&PktHeader[PKTHEADER_PASSWORD], node->PacketPW, 8); pktWrite(pkt, PktHeader, SIZE_PKTHEADER); if (ioerror) { fclose(pkt->fh); free(pkt); return (NULL); } return (pkt); } void FinishPacket(struct Pkt *pkt) { pktWrite(pkt, "", 1); pktWrite(pkt, "", 1); fclose(pkt->fh); if (pkt->hexnum) { uchar oldname[200], newname[200], buf1[100], buf2[100]; /* Create packet name */ snprintf(buf1, 100, "%08lx.newpkt", pkt->hexnum); /* FIXME packet name may be too long */ snprintf(buf2, 100, "%08lx_%d_%d_%d_%d_%d_%d_%d_%d.newpkt", pkt->hexnum, pkt->Orig.Zone, pkt->Orig.Net, pkt->Orig.Node, pkt->Orig.Point, pkt->Dest.Zone, pkt->Dest.Net, pkt->Dest.Node, pkt->Dest.Point); MakeFullPath(config.cfg_PacketCreate, buf1, oldname, 200); MakeFullPath(config.cfg_PacketCreate, buf2, newname, 200); if (rename(oldname, newname)) { LogWrite(1, SYSTEMERR, "Failed to rename %s to %s", oldname, newname); LogWrite(1, SYSTEMERR, "Error: %s", strerror(errno)); } } jbFreeNode(&PktList, (struct jbNode *) pkt); } void ClosePackets(void) { struct Pkt *pkt, *pkt2; pkt = (struct Pkt *) PktList.First; while (pkt) { pkt2 = pkt->Next; FinishPacket(pkt); pkt = pkt2; } } bool WriteMsgHeader(struct Pkt *pkt, struct MemMessage *mm) { uchar PktMsgHeader[SIZE_PKTMSGHEADER]; putuword(PktMsgHeader, PKTMSGHEADER_PKTTYPE, 0x0002); putuword(PktMsgHeader, PKTMSGHEADER_ORIGNODE, mm->OrigNode.Node); putuword(PktMsgHeader, PKTMSGHEADER_DESTNODE, mm->DestNode.Node); putuword(PktMsgHeader, PKTMSGHEADER_ORIGNET, mm->OrigNode.Net); putuword(PktMsgHeader, PKTMSGHEADER_DESTNET, mm->DestNode.Net); putuword(PktMsgHeader, PKTMSGHEADER_ATTR, mm->Attr); putuword(PktMsgHeader, PKTMSGHEADER_COST, mm->Cost); pktWrite(pkt, PktMsgHeader, SIZE_PKTMSGHEADER); WriteNull(pkt, mm->DateTime); WriteNull(pkt, mm->To); WriteNull(pkt, mm->From); WriteNull(pkt, mm->Subject); if (ioerror) return (FALSE); return (TRUE); } bool WritePath(struct Pkt * pkt, struct jbList * list) { ushort c; struct Path *path; for (path = (struct Path *) list->First; path; path = path->Next) for (c = 0; c < path->Paths; c++) if (path->Path[c][0] != 0) { pktWrite(pkt, "\001PATH: ", 7); pktWrite(pkt, path->Path[c], (ulong) strlen(path->Path[c])); pktWrite(pkt, "\015", 1); } if (ioerror) return (FALSE); return (TRUE); } bool WriteSeenBy(struct Pkt * pkt, struct jbList * list) { uchar *buf; if (!(buf = mmMakeSeenByBuf(list))) return (FALSE); pktWrite(pkt, buf, (ulong) strlen(buf)); free(buf); return (TRUE); } bool WriteEchoMail(struct MemMessage * mm, struct ConfigNode * node, struct Aka * aka) { uchar buf[200]; struct Pkt *pkt; struct TextChunk *chunk; ulong size; toss_written++; mm->Type = PKTS_ECHOMAIL; size = 0; for (chunk = (struct TextChunk *) mm->TextChunks.First; chunk; chunk = chunk->Next) if (chunk->Data) size += strlen(chunk->Data); node->SentEchomails++; node->SentEchomailBytes += size; pkt = FindPkt(&node->Node, &aka->Node, mm->Type); if (!pkt || (pkt && config.cfg_MaxPktSize != 0 && pkt->Len > config.cfg_MaxPktSize)) { if (pkt) FinishPacket(pkt); if (!(pkt = CreatePkt(&node->Node, node, aka, mm->Type))) { return FALSE; } jbAddNode(&PktList, (struct jbNode *) pkt); } Copy4D(&mm->DestNode, &node->Node); Copy4D(&mm->OrigNode, &aka->Node); if (!WriteMsgHeader(pkt, mm)) return FALSE; snprintf(buf, 200, "AREA:%s\015", mm->Area); pktWrite(pkt, buf, (ulong) strlen(buf)); if (ioerror) return (FALSE); if (mm->Rescanned) { snprintf(buf, 200, "\001RESCANNED %u:%u/%u.%u\015", aka->Node.Zone, aka->Node.Net, aka->Node.Node, aka->Node.Point); pktWrite(pkt, buf, (ulong) strlen(buf)); } if (ioerror) return (FALSE); for (chunk = (struct TextChunk *) mm->TextChunks.First; chunk; chunk = chunk->Next) { if (chunk->Data) pktWrite(pkt, chunk->Data, strlen(chunk->Data)); if (ioerror) return (FALSE); } if (node->Node.Zone != aka->Node.Zone || (node->Flags & NODE_TINYSEENBY)) { struct jbList seenbylist; struct Nodes2D *seenby; if (!(seenby = (struct Nodes2D *) malloc(sizeof(struct Nodes2D)))) { nomem = TRUE; return (FALSE); } seenby->Nodes = 0; seenby->Next = NULL; jbNewList(&seenbylist); jbAddNode(&seenbylist, (struct jbNode *) seenby); if (node->Node.Point == 0) if (!mmAddNodes2DList(&seenbylist, node->Node.Net, node->Node.Node)) { jbFreeList(&seenbylist); return (FALSE); } if (aka->Node.Point == 0) if (!mmAddNodes2DList(&seenbylist, aka->Node.Net, aka->Node.Node)) { jbFreeList(&seenbylist); return (FALSE); } if (!mmSortNodes2D(&seenbylist)) { jbFreeList(&seenbylist); return (FALSE); } if (!WriteSeenBy(pkt, &seenbylist)) { jbFreeList(&seenbylist); return (FALSE); } jbFreeList(&seenbylist); } else if (!(node->Flags & NODE_NOSEENBY)) { if (!mmSortNodes2D(&mm->SeenBy)) return (FALSE); if (!WriteSeenBy(pkt, &mm->SeenBy)) return (FALSE); } if (!WritePath(pkt, &mm->Path)) return (FALSE); pktWrite(pkt, "", 1); return (TRUE); }