// --------------------------------------------------------------------
// 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 <io.h>
#include <direct.h>
#else
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#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 <smapi/msgapi.h>
#include <smapi/progprot.h>
#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;
}
syntax highlighted by Code2HTML, v. 0.9.1