// -------------------------------------------------------------------- // P K T b a s e . c p p // // Fido messages tracker // Message bases. *.PKT base format. // -------------------------------------------------------------------- // Copyright (c) 1998-2001 by Fyodor Ustinov // FIDONet 2:5020/79 // // All rights reserved. // -------------------------------------------------------------------- #ifndef __GNUC__ #include #include #else #include #include #include #include #include #endif #include #include #include #include #include #include "constant.hpp" #include "vars.hpp" #include "log.hpp" #include "nodelist.hpp" #include "utils.hpp" #include "msg.hpp" #include "msgbase.hpp" #include "pktbase.hpp" #include "passwd.hpp" #include "aka.hpp" #include "configure.hpp" #include #include #include "tpkt.hpp" #ifdef _AIX #include "aix_conv.hpp" #endif // --------------------------- typedef struct { word FromNode; word ToNode; word FromNet; word ToNet; word Attr; word Cost; char DateTime[20]; } tPMSG; PKTBASE::PKTBASE() { DirName = NULL; PktName = NULL; fNoCheckPwd = FALSE; fh = NULL; MsgMask = NULL; MsgNum = 0; MaxMsgNum = 0; dp = NULL; fForWrite = FALSE; fCreated = FALSE; } PKTBASE::~PKTBASE() { Clear(); } // --------------------------- void PKTBASE::AddToMask(unsigned int Num) { if (Num > MaxMsgNum) { MsgMask = (char *) realloc(MsgMask,Num+1); CheckMem(MsgMask); MaxMsgNum++; while (MaxMsgNum != Num) { MsgMask[MaxMsgNum++] = 1; } } MsgMask[Num] = 1; } // --------------------------- int PKTBASE::CopyHeader(FILE *tf) { tPKTH PKTH; if (fread(&PKTH,sizeof(tPKTH),1,fh) != 1) { Log.Level(LOGE) << " Error reading PKT header '" << PktName << "'." << EOL; return FALSE; } // Removed by UFM. In this point transformation of pkt header not need. //#ifdef _AIX // AIXConvPKTH(PKTH); //#endif if (fwrite(&PKTH,sizeof(tPKTH),1,tf) != 1) { Log.Level(LOGE) << " Error writing PKT header." << EOL; return FALSE; } return TRUE; } // --------------------------- int PKTBASE::CopyTail(FILE *tf) { char Buffer[10240]; int rc; while(!feof(fh)) { if ((rc = fread(Buffer,1,10240,fh)) != 10240) { if (!feof(fh)) { Log.Level(LOGE) << " Error reading tail of PKT." << EOL; return FALSE; } } if (fwrite(Buffer,1,rc,tf) != (unsigned) rc) { Log.Level(LOGE) << " Error writing tail of PKT." << EOL; return FALSE; } } return TRUE; } // --------------------------- #define READBLOCKLEN 4096 int PKTBASE::CopyOneMessage(FILE *tf) { char *Buff; int I,i; Buff = (char *)malloc(sizeof(tPMSG)+256); CheckMem(Buff); if (LogLevel >= 5) { Log.Level(LOGD) << "...Current file position " << (int) ftell(fh) << EOL; } I = 0; if (fread(&I,2,1,fh) != 1) { free(Buff); Log.Level(LOGE) << " Error: Unable to read packed message header." << EOL; return FALSE; } Log.Level(LOGD) << "...Message signature: " << I << EOL; if (I != 2) { Log.Level(LOGE) << " Error: Missing 0200 in begin of message." << EOL; free(Buff); return FALSE; } if (!ReadHeader(fh,Buff)) { free(Buff); Log.Level(LOGE) << " Error: Unable to read packed message header." << EOL; return FALSE; } I = sizeof(tPMSG); for (i = 0; i < 3; i++) { do { if (fread(Buff+I,1,1,fh) != 1) { return FALSE; } I++; } while(Buff[I-1] != '\0'); } do { Buff = (char *)realloc(Buff,I + READBLOCKLEN + 2); CheckMem(Buff); memset(Buff+I,0,READBLOCKLEN + 1); for (i = 0; i < READBLOCKLEN; i++) { if (fread(Buff+I,1,1,fh) != 1) { Log.Level(LOGE) << " Error reading body of message." << EOL; free(Buff); return FALSE; } I++; if (Buff[I-1] == '\0') break; } } while(Buff[I-1] != '\0'); if (tf != NULL) { i = 2; if (fwrite(&i,2,1,tf) != 1) { Log.Level(LOGE) << " Error writing copy of signature." << EOL; free(Buff); return FALSE; } if (fwrite(Buff,I,1,tf) != 1) { Log.Level(LOGE) << " Error writing copy of message." << EOL; free(Buff); return FALSE; } } free(Buff); return TRUE; } // --------------------------- int PKTBASE::CopyMessages(FILE *tf) { uint Num; for(Num = 1; Num <= MaxMsgNum; Num++) { if (MsgMask[Num] == 0) { if (!CopyOneMessage(NULL)) return FALSE; } else { if (!CopyOneMessage(tf)) return FALSE; } } return TRUE; } // --------------------------- int PKTBASE::_Close(void) { uint Num; char TempName[1024]; char *tmt; FILE *tf; Log.Level(LOGD) << "_Close PKT '" << PktName << "'" << EOL; Log.Level(LOGD) << "MaxMsgNum: " << MaxMsgNum << EOL; if (fh == NULL) { MsgNum = 0; MaxMsgNum = 0; Log.Level(LOGD) << "...Handle is NULL. Do nothing." << EOL; return TRUE; } Log.Level(LOGD) << "...Handle is not NULL" << EOL; if (MaxMsgNum == 0) { if (!fCreated) { fclose(fh); fh = NULL; MsgNum = 0; return TRUE; } else { fclose(fh); fh = NULL; unlink(PktName); MsgNum = 0; MaxMsgNum = 0; return TRUE; } } if (LogLevel >= 5) { Log.Level(LOGD) << "...MaxMsgNum <> 0" << EOL; for(Num = 1; Num <= MaxMsgNum; Num++) { Log.Level(LOGD) << " " << (int) MsgMask[Num]; } Log.Level(LOGD) << EOL; } for(Num = 1; Num <= MaxMsgNum; Num++) { if (MsgMask[Num] != 0) break; } if (Num > MaxMsgNum) { fclose(fh); fh = NULL; unlink(PktName); MsgNum = 0; MaxMsgNum = 0; return TRUE; } Log.Level(LOGD) << "...In PKT Exists not deleted messages" << EOL; for(Num = 1; Num <= MaxMsgNum; Num++) { if (MsgMask[Num] == 0) break; } if (Num > MaxMsgNum ) { fclose(fh); MsgNum = 0; MaxMsgNum = 0; fh = NULL; return TRUE; } Log.Level(LOGD) << "...In PKT Exists _deleted_ messages" << EOL; if (fseek(fh,0L,SEEK_SET) != 0) { fclose(fh); fh = NULL; MsgNum = 0; MaxMsgNum = 0; Log.Level(LOGE) << " Unable to set to begin of PKT file." << EOL; return FALSE; } Log.Level(LOGD) << "...Seek to begin - completed" << EOL; strcpy(TempName,PktName); tmt = strrchr(TempName,PATHDELIMC); if (tmt == NULL) { #ifndef UNIX tmt = strchr(TempName,':'); if (tmt != NULL) { tmt++; } else { #endif tmt = TempName; #ifndef UNIX } #endif } else { tmt++; } *tmt = '\0'; strcat(TempName,"TPKT.FTR"); Log.Level(LOGD) << "...Temporary file: '" << TempName << "'" << EOL; tf = fopen(TempName,"w+b"); if (tf == NULL) { Log.Level(LOGE) << " Unable to create temporary file." << EOL; fclose(fh); fh = NULL; MsgNum = 0; MaxMsgNum = 0; return FALSE; } Log.Level(LOGD) << "...Temporary file created." << EOL; if (!CopyHeader(tf)) { fclose(fh); fclose(tf); fh = NULL; unlink(TempName); MsgNum = 0; MaxMsgNum = 0; return FALSE; } Log.Level(LOGD) << "...Copying header of PKT completed." << EOL; if (!CopyMessages(tf)) { fclose(fh); fclose(tf); fh = NULL; unlink(TempName); MsgNum = 0; MaxMsgNum = 0; return FALSE; } Log.Level(LOGD) << "...Copying Messages completed." << EOL; if (!CopyTail(tf)) { fclose(fh); fclose(tf); fh = NULL; unlink(TempName); MsgNum = 0; MaxMsgNum = 0; return FALSE; } Log.Level(LOGD) << "...Copying Tail completed." << EOL; MsgNum = 0; MaxMsgNum = 0; fclose(fh); fclose(tf); fh = NULL; Log.Level(LOGD) << "...Handles closed." << EOL; unlink(PktName); if (rename(TempName,PktName) != 0) { Log.Level(LOGE) << " Unable to rename temporary file to PKT." << EOL; return FALSE; } return TRUE; } // --------------------------- void PKTBASE::Clear(void) { _Close(); fNoCheckPwd = FALSE; fForWrite = FALSE; fCreated = FALSE; if (dp != NULL) { closedir(dp); dp = NULL; } if (DirName != NULL) { free(DirName); DirName = NULL; } if (PktName != NULL) { free(PktName); PktName = NULL; } if (MsgMask != NULL) { free(MsgMask); MsgMask = NULL; } } // --------------------------- int PKTBASE::Set(char *Dir, int BaseType) { char *tmt; char *Buff; struct stat dd; Clear(); if (*Dir != '#') return FALSE; if (BaseType == BASE_OUT) { // CfgError("You can't save to or rewrite in *.PKT base."); return FALSE; } if (*(Dir+1) == '#') { fNoCheckPwd = TRUE; Dir++; } Buff = strdup(Dir+1); CheckMem(Buff); tmt = strrchr(Buff,'!'); if (tmt == NULL) { tmt = "*"; } else { *tmt = '\0'; tmt++; } Log.Level(LOGD) << "PKTBASE FTN Mask: '" << tmt << "'" << EOL; FMask.Parse(tmt); if (!FMask.PKTValid()) { free(Buff); return FALSE; } if (stat(dirslashbug(Buff),&dd) != 0 && BaseType != BASE_OUT) { free(Buff); return FALSE; } if (S_ISDIR(dd.st_mode) && BaseType != BASE_OUT) { DirName = strdup(Buff); CheckMem(DirName); if (DirName[strlen(DirName)] == PATHDELIMC) { DirName[strlen(DirName)] = '\0'; } Log.Level(LOGD) << "PKTBASE DirName: '" << DirName << "'" << EOL; } else if (S_ISREG(dd.st_mode) && BaseType != BASE_OUT) { PktName = strdup(Buff); CheckMem(PktName); Log.Level(LOGD) << "PKTBASE PktName: '" << PktName << "'" << EOL; } else if (BaseType == BASE_OUT) { PktName = strdup(Buff); CheckMem(PktName); Log.Level(LOGD) << "PKTBASE_OUT PktName: '" << PktName << "'" << EOL; } else { Log.Level(LOGD) << "No one type" << EOL; free(Buff); return FALSE; } if (BaseType == BASE_OUT) { fForWrite = TRUE; } free(Buff); return TRUE; } // --------------------------- int PKTBASE::Next(void) { int SIGN; char Buff[1024]; struct dirent *de; Log.Level(LOGD) << "----- PKTBASE::Next() -----" << EOL; SIGN = 0; MsgNum++; if (fh != NULL) { Log.Level(LOGD) << "PKTBASE::Next(). fh != NULL" << EOL; if (fread(&SIGN,2,1,fh) != 1) { Log.Level(LOGE) << " Error: Unable to read signature from PKT '" << PktName << "'" << EOL; fclose (fh); fh = NULL; return FALSE; } } #ifdef _AIX SIGN=RotateInt(SIGN); #endif Log.Level(LOGD) << "PKTBASE::Next(). SIGN == " << SIGN << EOL; if (SIGN == 0) { if (!_Close()) { return FALSE; } if (dp == NULL) return FALSE; Log.Level(LOGD) << "PKTBASE::Next(). dp != NULL" << EOL; Buff[0] = '\0'; while ((de = readdir(dp)) != NULL) { Log.Level(LOGD) << "PKTBASE::Next(). de->d_name == '" << de->d_name << "'" << EOL; if (fsCompareName(de->d_name,"*.[Pp][Kk][Tt]") != 0) { sprintf(Buff,"%s"PATHDELIMS"%s",DirName,de->d_name); break; } } if (Buff[0] == '\0') { Log.Level(LOGD) << "No more files from ReadDir in Next." << EOL; closedir(dp); dp = NULL; return FALSE; } Log.Level(LOGD) << "New PKT == '" << Buff << "'" << EOL; if (PktName != NULL) { free(PktName); } PktName = strdup(Buff); if (!_Open()) return FALSE; MsgNum = 0; return (Next()); } else if (SIGN != 2) { Log.Level(LOGE) << " Error: Wrong signature in PKT '" << PktName << "'" << EOL; fclose (fh); fh = NULL; return FALSE; } return TRUE; } // --------------------------- int PKTBASE::_Open(void) { tPKTH PKTH; FA f; char Buff[4096]; char *tmt; if (PktName == NULL) { return TRUE; } Log.Level(LOGD) << "_Open PKT '" << PktName << "'" << EOL; if (!_Close()) return FALSE; fh = fopen(PktName,"r+b"); #ifdef UNIX if (errno == EACCES) { Log.Level(LOGE) << " Error _open PKT '" << PktName << "' - permission denied." << EOL; return FALSE; } #endif if (fh == NULL && !fForWrite) { Log.Level(LOGE) << " Error _open PKT '" << PktName << "'." << EOL; return FALSE; } if (fh == NULL && fForWrite) { Log.Level(LOGE) << " Error _open PKT '" << PktName << "'." << EOL; return FALSE; } if (fread(&PKTH,sizeof(tPKTH),1,fh) != 1) { Log.Level(LOGE) << " Error reading PKT header." << EOL; fclose(fh); fh = NULL; return FALSE; } #ifdef _AIX AIXConvPKTH(PKTH); #endif if (PKTH.c0002 != 2 || ((PKTH.c0001 != 0 && PKTH.c0100 != 0) && (PKTH.c0001 != 1 && PKTH.c0100 != 256))) { Log.Level(LOGD) << " " << (uint) PKTH.c0002 << " " << (uint) PKTH.c0001 << " " << (uint) PKTH.c0100 << EOL; Log.Level(LOGE) << " Error: destroyed header or unknown PKT format in PKT '" << PktName << "'" << EOL; Log.Level(LOGE) << " PKT '" << PktName << "' skipped." << EOL; fclose(fh); fh = NULL; return TRUE; } f.Zone(PKTH.FromZone); if (PKTH.FromNet == 0xffff) { f.Net(PKTH.AuxNet); f.Point(PKTH.FromPoint); } else { f.Net(PKTH.FromNet); f.Point(PKTH.FromPoint); } f.Node(PKTH.FromNode); Log.Level(LOGD) << "PKT from: " << f << EOL; if (f != FMask) { fclose(fh); fh = NULL; Log.Level(LOGW) << "Sender of PKT '" << PktName << "' not match with " << FMask << EOL; return TRUE; } if (!fNoCheckPwd) { tmt = GetPasswd(f); if (tmt == NULL) tmt = "\0"; memset(Buff,0,9); strncpy(Buff,PKTH.Passwd,8); if (stricmp(Buff,tmt) != 0) { Log.Level(LOGW) << "Wrong password in PKT '" << PktName << "'" << EOL; Log.Level(LOGW) << "Should be '" << tmt << "'. In PKT '" << Buff << "'" << EOL; fclose(fh); fh = NULL; return TRUE; } } MsgNum = 0; return TRUE; } // --------------------------- int PKTBASE::Rewind(void) { Log.Level(LOGD) << "------ Rewind for *.PKT --------" << EOL; if (!_Close()) return FALSE; Log.Level(LOGD) << "------ _Close OK. --------" << EOL; if (dp != NULL) { closedir(dp); dp = NULL; } Log.Level(LOGD) << "PKTBASE::Rewind(). DirName == '" << (DirName == NULL ? "(NULL)" : DirName) << "'" << EOL; if (DirName != NULL) { dp = opendir(dirslashbug(DirName)); if (dp == NULL) { Log.Level(LOGD) << "Null from OpenDir." << EOL; return FALSE; } } if (!_Open()) return FALSE; if (!Next()) return FALSE; return TRUE; } // --------------------------- int PKTBASE::Renumber(void) { return TRUE; } // --------------------------- int PKTBASE::DeleteMsg(void) { MsgMask[MsgNum] = 0; return TRUE; } // --------------------------- char *PKTBASE::ReadToMem(void) { return NULL; } // --------------------------- char *PKTBASE::MessageName(void) { static char Buff[2048]; strcpy(Buff,"#"); strcat(Buff,PktName); sprintf(Buff+strlen(Buff),":%u",MsgNum); return Buff; } // --------------------------- int PKTBASE::WriteFromMem(char *Buff) { CHP = 537; CHP = 538; if (Buff != NULL) *Buff = *Buff; return FALSE; } // --------------------------- // MHM fix: HTML2FIDO v 1.1.33 is known to produce non-FTSC0001 compliant // messages (where the date occupies less than 20 characters). We fix it here. int PKTBASE::ReadHeader(FILE *tf, char *Buff) { int i, c; if (fread(Buff,sizeof(tPMSG)-20,1,tf) != 1) { return FALSE; } Buff+=sizeof(tPMSG)-20; strcpy(Buff, "14 Dec 90 12:00:00"); // Innocent date for (i=0; i < 20; i++) { c = fgetc(tf); if (c==EOF) return FALSE; if (c=='\0') break; *Buff++ = c; } return TRUE; } // --------------------------- int PKTBASE::ReadMsg(cMSG &m) { tPMSG p; char *Buff; int i, I; CHP = 639; m.Clear(); if (fh == NULL) { return FALSE; } CHP = 640; if (!ReadHeader(fh,(char *)&p)) { if (feof(fh) != 0) { Log.Level(LOGE) << " Warning: New message, but EOF found of PKT '" << PktName << "'." << EOL; return FALSE; } Log.Level(LOGE) << " Error: Unable to read message header from PKT '" << PktName << "'." << EOL; return FALSE; } p.DateTime[19] = '\0'; CHP = 641; #ifdef _AIX p.FromNode=RotateShort(p.FromNode); p.ToNode=RotateShort(p.ToNode); p.FromNet=RotateShort(p.FromNet); p.ToNet=RotateShort(p.ToNet); p.Cost=RotateShort(p.Cost); p.Attr=RotateShort(p.Attr); #endif m._FromAddr.Node(p.FromNode); m._ToAddr.Node(p.ToNode); m._FromAddr.Net(p.FromNet); m._ToAddr.Net(p.ToNet); m._Cost = p.Cost; m._Time = ToTime(p.DateTime); SetMsgAttr(p.Attr,m); CHP = 642; for(i = 0; i < 36; i++) { if (fread(m._ToName+i,1,1,fh) != 1) { Log.Level(LOGE) << " Error: Unable to read message header (ToName) from PKT '" << PktName << "'" << EOL; return FALSE; } if (m._ToName[i] == '\0') break; } CHP = 643; for(i = 0; i < 36; i++) { if (fread(m._FromName+i,1,1,fh) != 1) { Log.Level(LOGE) << " Error: Unable to read message header (FromName) from PKT '" << PktName << "'" << EOL; return FALSE; } if (m._FromName[i] == '\0') break; } CHP = 644; for(i = 0; i < 72; i++) { if (fread(m._Subject+i,1,1,fh) != 1) { Log.Level(LOGE) << " Error: Unable to read message header (Subject) from PKT '" << PktName << "'" << EOL; return FALSE; } if (m._Subject[i] == '\0') break; } CHP = 645; I = 0; Buff = NULL; do { CHP = 6451; Buff = (char *)realloc(Buff,I + READBLOCKLEN + 2); CHP = 6452; CheckMem(Buff); CHP = 6453; memset(Buff+I,0,READBLOCKLEN + 1); CHP = 6454; for (i = 0; i < READBLOCKLEN; i++) { CHP = 6455; if (fread(Buff+I,1,1,fh) != 1) { Log.Level(LOGE) << " Error reading body of message." << EOL; free(Buff); return FALSE; } CHP = 6456; I++; if (Buff[I-1] == '\0') break; CHP = 6457; } } while(Buff[I-1] != '\0'); CHP = 646; m.ParseMem(Buff); CHP = 647; free(Buff); CHP = 648; AddToMask(MsgNum); CHP = 649; return TRUE; } // --------------------------- int PKTBASE::WriteOneMsg(unsigned int Num, cMSG &m) { if (&m != NULL)Num++; return FALSE; } // --------------------------- int PKTBASE::WriteMsg(cMSG &m) { return WriteOneMsg(MsgNum,m); } // --------------------------- int PKTBASE::WriteNewMsg(cMSG &m) { return WriteOneMsg(MsgNum,m); } // --------------------------- void PKTBASE::Print(void) { } // --------------------------- int PKTBASE::CheckOut(void) { struct stat dd; yyerror("You can't save to or rewrite in *.PKT base."); return FALSE; fForWrite = TRUE; if (PktName == NULL) { yyerror("Base can't be a directory."); return FALSE; } if (stat(dirslashbug(PktName),&dd) == 0) { if (S_ISDIR(dd.st_mode)) { yyerror("Base can't be a directory."); return FALSE; } } if (!FMask.Valid() || FMask.Masked()) { yyerror("Address should be full and without any masks."); return FALSE; } return FALSE; } // --------------------------- char *PKTBASE::BaseName(void) { static char Buff[1024]; strcpy(Buff,"#"); if (fNoCheckPwd) strcat(Buff,"#"); if (DirName != NULL) { strcat(Buff,DirName); } else { strcat(Buff,PktName); } strcat(Buff,"!"); strcat(Buff,(char *)(Str)FMask); return Buff; }