// --------------------------------------------------------------------
// M s g b a s e . c p p
//
// Fido messages tracker
// Message bases. root class and MSG base format.
// --------------------------------------------------------------------
// Copyright (c) 1998,99 by Fyodor Ustinov
// FIDONet 2:5020/79
//
// All rights reserved.
// --------------------------------------------------------------------
#ifndef __GNUC__
#include <io.h>
#include <direct.h>
#else
#include <sys/types.h>
#include <dirent.h>
#include <unistd.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 "configure.hpp"
#include "nodelist.hpp"
#include "utils.hpp"
#include "msg.hpp"
#include "msgbase.hpp"
#include "sqbase.hpp"
#include "pktbase.hpp"
#include "aka.hpp"
#include <smapi/msgapi.h>
#include <smapi/progprot.h>
#ifdef _AIX
#include "aix_conv.hpp"
#endif
// ---------------------------
typedef struct {
char FromName[36];
char ToName[36];
char Subject[72];
char DateTime[20];
unsigned short int TimesRead;
unsigned short int DestNode;
unsigned short int OrigNode;
unsigned short int Cost;
unsigned short int OrigNet;
unsigned short int DestNet;
char Reserved[8];
unsigned short int ReplyTo;
unsigned short int Attr;
unsigned short int NextReply;
} MsgHeader;
#define H_Private 0x0001
#define H_Crash 0x0002
#define H_Received 0x0004
#define H_Send 0x0008
#define H_FileAttach 0x0010
#define H_Transit 0x0020
#define H_Orphan 0x0040
#define H_KillSend 0x0080
#define H_Local 0x0100
#define H_Hold 0x0200
#define H_NU1 0x0400
#define H_FileRequest 0x0800
#define H_RRQ 0x1000
#define H_IRR 0x2000
#define H_ARQ 0x4000
#define H_FURQ 0x8000
// ---------------------------
void SetMsgAttr(cMSG &m,unsigned short int &Attr) {
Attr = 0;
if (m.fPrivate == 1) Attr = Attr | H_Private;
if (m.fCrash == 1) Attr = Attr | H_Crash;
if (m.fReceived == 1) Attr = Attr | H_Received;
if (m.fSend == 1) Attr = Attr | H_Send;
if (m.fFileAttach == 1) Attr = Attr | H_FileAttach;
if (m.fTransit == 1) Attr = Attr | H_Transit;
if (m.fOrphan == 1) Attr = Attr | H_Orphan;
if (m.fKillSend == 1) Attr = Attr | H_KillSend;
if (m.fLocal == 1) Attr = Attr | H_Local;
if (m.fHold == 1) Attr = Attr | H_Hold;
if (m.fFileRequest == 1) Attr = Attr | H_FileRequest;
if (m.fRRQ == 1) Attr = Attr | H_RRQ;
if (m.fIRR == 1) Attr = Attr | H_IRR;
if (m.fARQ == 1) Attr = Attr | H_ARQ;
if (m.fFURQ == 1) Attr = Attr | H_FURQ;
}
void SetMsgAttr(unsigned short int &Attr,cMSG &m) {
if (Attr & H_Private) m.fPrivate = 1;
if (Attr & H_Crash) m.fCrash = 1;
if (Attr & H_Received) m.fReceived = 1;
if (Attr & H_Send) m.fSend = 1;
if (Attr & H_FileAttach) m.fFileAttach = 1;
if (Attr & H_Transit) m.fTransit = 1;
if (Attr & H_Orphan) m.fOrphan = 1;
if (Attr & H_KillSend) m.fKillSend = 1;
if (Attr & H_Local) m.fLocal = 1;
if (Attr & H_Hold) m.fHold = 1;
if (Attr & H_FileRequest) m.fFileRequest = 1;
if (Attr & H_RRQ) m.fRRQ = 1;
if (Attr & H_IRR) m.fIRR = 1;
if (Attr & H_ARQ) m.fARQ = 1;
if (Attr & H_FURQ) m.fFURQ = 1;
}
// ---------------------------
void AddKluToChain(char *&cl, char *Kn, char *Kb) {
char *buff;
int olen;
buff = (char *)malloc(60000);
CheckMem(buff);
if (Kb == NULL) {
sprintf(buff,"%s\r",Kn);
} else if (Kn == NULL) {
sprintf(buff,"%s\r",Kb);
} else {
sprintf(buff,"%s %s\r",Kn, Kb);
}
olen = 0;
if (cl != NULL) {
olen = strlen(cl);
cl = (char *)realloc(cl,olen+strlen(buff)+1);
CheckMem(cl);
strcat(cl,buff);
} else {
cl = (char *)realloc(cl,strlen(buff)+1);
CheckMem(cl);
strcpy(cl,buff);
}
free(buff);
}
void PrepKluChain(char *&Ctrl, cMSG &m, int IsKludge) {
IndBiList<Kludge>::ElemPtr Klu;
CHP = 201;
Klu = m._Klu.GetFirst();
CHP = 205;
while (Klu != NULL) {
if (Klu->Name() != NULL && strlen(Klu->Name()) != 0) {
if ((stricmp(Klu->Name(),"SEEN-BY:") == 0)
|| (strcmp(Klu->Name(),"---") == 0)
|| (stricmp(Klu->Name(),"\1VIA") == 0)
|| (stricmp(Klu->Name(),"\1Recd") == 0)
|| (stricmp(Klu->Name(),"\1Forwarded") == 0)
|| (stricmp(Klu->Name()," * Origin:") == 0)
|| (stricmp(Klu->Name(),"\1PATH:") == 0)) {
if (IsKludge != TRUE) {
AddKluToChain(Ctrl,Klu->Name(), Klu->Body());
}
} else {
if (IsKludge == TRUE) {
AddKluToChain(Ctrl,Klu->Name(), Klu->Body());
}
}
} else if (Klu->Body() != NULL) {
if (IsKludge == TRUE) {
AddKluToChain(Ctrl,Klu->Name(), Klu->Body());
}
}
Klu++;
}
CHP = 206;
}
int WriteMsgBody(cMSG &m,FILE *fh) {
char *Buff;
unsigned int FSize;
char *Ctrl;
CHP = 203;
Buff = (char *) malloc(40960);
CheckMem(Buff);
CHP = 204;
#ifdef __OS2__
// Very strange situation...
// Without this code in OS/2 programm _strongly_ freeze.
// fprintf(stderr," \b");fflush(stderr);
#endif
Ctrl = NULL;
CHP = 205;
m.Normalise();
CHP = 206;
PrepKluChain(Ctrl,m,TRUE);
CHP = 207;
if (Ctrl != NULL) {
if (fwrite(Ctrl,strlen(Ctrl),1,fh) != 1) {
free(Ctrl);
free(Buff);
fclose (fh);
return FALSE;
}
free(Ctrl);
Ctrl = NULL;
}
if (!m.fEmpty) {
FSize = strlen(m.Body());
if (fwrite(m.Body(),FSize,1,fh) != 1) {
free(Buff);
fclose (fh);
return FALSE;
}
if (*(m.Body() + FSize - 1) != '\r') {
if (fwrite("\r",1,1,fh) != 1) {
free(Buff);
fclose (fh);
return FALSE;
}
}
}
CHP = 208;
PrepKluChain(Ctrl,m,FALSE);
if (Ctrl != NULL) {
CHP = 20801;
if (fwrite(Ctrl,strlen(Ctrl),1,fh) != 1) {
free(Ctrl);
free(Buff);
fclose (fh);
return FALSE;
}
free(Ctrl);
Ctrl = NULL;
}
CHP = 209;
free(Buff);
CHP = 210;
if (fwrite("\0",1,1,fh) != 1) {
fclose (fh);
return FALSE;
}
CHP = 211;
return TRUE;
}
// ---------------------------
// ---------------------------
MSGBASE::~MSGBASE() {
}
MSGASMSG::MSGASMSG() {
CHP = 215;
DirName = NULL;
MsgNum = 0;
MaxNum = 0;
MsgMask = NULL;
}
MSGASMSG::~MSGASMSG() {
CHP = 216;
Clear();
}
// ---------------------------
void MSGASMSG::AddToMask(unsigned int Num) {
if (Num > MaxNum) {
MsgMask = (char *) realloc(MsgMask,Num+1);
CheckMem(MsgMask);
MaxNum++;
while (MaxNum != Num) {
MsgMask[MaxNum++] = 0;
}
}
MsgMask[Num] = 1;
}
// ---------------------------
void MSGASMSG::Clear(void) {
CHP = 217;
if (DirName != NULL) {
free(DirName);
DirName = NULL;
}
if (MsgMask != NULL) {
free(MsgMask);
MsgMask = NULL;
}
MsgNum = 0;
MaxNum = 0;
}
// ---------------------------
int MSGASMSG::Set(char *Dir, int BaseType) {
char Buff[1024];
BaseType++;
CHP = 218;
Clear();
if (!DirExists(Dir) && !CreateMissingBase) {
return FALSE;
}
DirName = (char *) malloc(strlen(Dir) + 2);
CheckMem(DirName);
strcpy(DirName,Dir);
if (DirName[strlen(DirName)-1] != PATHDELIMC) {
strcat(DirName,PATHDELIMS);
}
strcpy(Buff,DirName);
strcat(Buff,"0.ftr");
fcopen(Buff,"rb");
if (!DirExists(Dir)) {
return FALSE;
}
return TRUE;
}
// ---------------------------
int MSGASMSG::Next(void) {
CHP = 219;
if (DirName == NULL) {
return FALSE;
}
if (MsgNum == 0) {
return FALSE;
}
if (MaxNum == 0) {
return FALSE;
}
CHP = 220;
MsgNum++;
while (MsgNum <= MaxNum) {
if (MsgMask[MsgNum] != 0) {
return TRUE;
}
MsgNum++;
}
CHP = 221;
MsgNum = 0;
return FALSE;
}
// ---------------------------
int MSGASMSG::Rewind(void) {
char bb[512];
DIR *ff;
struct dirent *pp;
if (DirName == NULL) {
return FALSE;
}
if (MsgMask != NULL) {
free(MsgMask);
MsgMask = NULL;
}
MsgNum = 0;
MaxNum = 0;
Log.Level(LOGD) << "Do Rewind for dir '" << DirName << "'" << EOL;
ff = opendir(dirslashbug(DirName));
if (ff == NULL) {
Log.Level(LOGD) << "Error in opendir. ERRNO == " << errno << EOL;
return FALSE;
}
while ((pp = readdir(ff)) != NULL) {
// WARNING!!!!!!!!!!! i'm not sure about d_type in all operation systems
// if ((pp->d_type & 0x1a) == 0) {
if (fsCompareName(pp->d_name,"*"MsgExtension) != 0) {
strcpy(bb,pp->d_name);
Log.Level(LOGD) << "File '" << bb << "' matched with mask." << EOL;
*strchr(bb,'.') = '\0';
if (StrIsNum(bb)) {
Log.Level(LOGD) << bb << " is a number. Add to list." << EOL;
AddToMask(atoi(bb));
}
}
}
closedir(ff);
Log.Level(LOGD) << "------------------" << EOL;
Log.Level(LOGD) << "Max message number is: " << MaxNum << EOL;
MsgNum = 1;
if (MaxNum == 0) {
return FALSE;
}
while (MsgNum <= MaxNum) {
if (MsgMask[MsgNum] == 1) {
Log.Level(LOGD) << "First message number is: " << MsgNum << EOL;
Log.Level(LOGD) << "------------------" << EOL;
return TRUE;
}
MsgNum++;
}
MsgNum = 1;
Log.Level(LOGD) << "Messages not found. Set first number to 1" << EOL;
Log.Level(LOGD) << "------------------" << EOL;
return FALSE;
}
// ---------------------------
int MSGASMSG::Renumber(void) {
unsigned int Num, NewNum;
char Buff[1024];
char Buff2[1024];
Log.Level(LOGD) << EOL;
Log.Level(LOGD) << "Do Renumber for base '" << DirName << "'" << EOL;
Log.Level(LOGD) << "----------------------------------------" << EOL;
if (Rewind() == FALSE) {
Log.Level(LOGD) << "Base is Empty?" << EOL;
return TRUE;
}
Num = 1;
while (Num <= MaxNum) {
if (MsgMask[Num] == 0) {
Num++;
} else {
NewNum = 1;
while(NewNum <= MaxNum) {
if (MsgMask[NewNum] == 1) {
NewNum++;
} else {
if (NewNum < Num) {
sprintf(Buff,"%s%u"MsgExtension,DirName,Num);
sprintf(Buff2,"%s%u"MsgExtension,DirName,NewNum);
Log.Level(LOGD) << "Rename '" << Buff << "' to '" << Buff2 << "'" << EOL;
if (rename(Buff,Buff2) != 0) {
Log.Level(LOGE) << "Unable to rename '" << Buff << "' to '" << Buff2 << "'" << EOL;
return FALSE;
}
MsgMask[NewNum] = 1;
MsgMask[Num] = 0;
break;
} else {
break;
}
}
}
Num++;
}
}
return TRUE;
}
// ---------------------------
int MSGASMSG::DeleteMsg(void) {
char Buff[1024];
if (MsgMask[MsgNum] == 0) {
return TRUE;
}
sprintf(Buff,"%s%u"MsgExtension,DirName,MsgNum);
MsgMask[MsgNum] = 0;
return (unlink(Buff) == 0);
}
// ---------------------------
char *MSGASMSG::ReadToMem(void) {
FILE *fh;
char *Buff;
unsigned long FSize;
Buff = (char *) malloc(4096);
CheckMem(Buff);
sprintf(Buff,"%s%u"MsgExtension,DirName,MsgNum);
fh = fopen(Buff,"rb");
free(Buff);
if (fh == NULL) {
return NULL;
}
if (fseek(fh,0,SEEK_END) != 0) {
fclose (fh);
return NULL;
}
FSize = ftell(fh);
if (fseek(fh,0,SEEK_SET) != 0) {
fclose (fh);
return NULL;
}
Buff = (char *) malloc(FSize + sizeof(FSize));
CheckMem(Buff);
*(unsigned long *)Buff = FSize;
if (FSize != 0) {
if (fread(Buff + sizeof(FSize),FSize,1,fh) != 1) {
free(Buff);
fclose (fh);
return NULL;
}
}
fclose(fh);
return Buff;
}
// ---------------------------
char *MSGASMSG::MessageName(void) {
static char Buff[2048];
sprintf(Buff,"%s%u"MsgExtension,DirName,MsgNum);
return Buff;
}
// ---------------------------
int MSGASMSG::WriteFromMem(char *Buff) {
FILE *fh;
unsigned long FSize;
unsigned int Num;
char *b;
char tmt[1024];
Num = MaxNum;
do {
Num++;
sprintf(tmt,"%s%u"MsgExtension,DirName,Num);
} while(access(tmt,F_OK) == 0);
AddToMask(Num);
b = (char *) malloc(4096);
CheckMem(b);
sprintf(b,"%s%u"MsgExtension,DirName,Num);
fh = fopen(b,"wb");
free(b);
if (fh == NULL) {
return FALSE;
}
FSize = *(unsigned long *)Buff;
if (FSize != 0) {
if (fwrite(Buff + sizeof(FSize),FSize,1,fh) != 1) {
fclose (fh);
return FALSE;
}
}
fclose(fh);
return TRUE;
}
// ---------------------------
int MSGASMSG::ReadMsg(cMSG &m) {
MsgHeader Hdr;
FILE *fh;
char *Buff;
unsigned long FSize;
int i;
CHP = 222;
Buff = (char *) malloc(4096);
CheckMem(Buff);
sprintf(Buff,"%s%u"MsgExtension,DirName,MsgNum);
fh = fopen(Buff,"rb");
i = errno;
if (fh == NULL) {
if (i != EACCES) {
Log.Level(LOGE) << "Unable to open message '" << Buff << "', Errno: " << i << EOL;
}
free(Buff);
return FALSE;
}
free(Buff);
CHP = 223;
if (fread(&Hdr,sizeof(Hdr),1,fh) != 1) {
i = errno;
Log.Level(LOGE) << "Unable to read message header, Errno: " << i << EOL;
fclose (fh);
return FALSE;
}
m.Clear();
CHP = 224;
#ifdef _AIX
Hdr.TimesRead=RotateShort(Hdr.TimesRead);
Hdr.DestNode=RotateShort(Hdr.DestNode);
Hdr.OrigNode=RotateShort(Hdr.OrigNode);
Hdr.Cost=RotateShort(Hdr.Cost);
Hdr.OrigNet=RotateShort(Hdr.OrigNet);
Hdr.DestNet=RotateShort(Hdr.DestNet);
Hdr.ReplyTo=RotateShort(Hdr.ReplyTo);
Hdr.Attr=RotateShort(Hdr.Attr);
#endif
m._FromAddr.Node(Hdr.OrigNode);
m._FromAddr.Net(Hdr.OrigNet);
m._ToAddr.Node(Hdr.DestNode);
m._ToAddr.Net(Hdr.DestNet);
strncpy(m._Subject,Hdr.Subject,72);
strncpy(m._FromName,Hdr.FromName,36);
strncpy(m._ToName,Hdr.ToName,36);
m._Time = ToTime(Hdr.DateTime);
m._Cost = Hdr.Cost;
m._ReplyTo = Hdr.ReplyTo;
m._TimesRead = Hdr.TimesRead;
m._NextReply = Hdr.NextReply;
memcpy(m._Reserved,Hdr.Reserved,8);
SetMsgAttr(Hdr.Attr,m);
// if (LogLevel >= 5) {
// Log.Level(LOGD) << "MSGASMSG::ReadMsg. Message after parsing header: " << EOL;
// m.Print();
// }
CHP = 225;
// Now, read body...
if (fseek(fh,0L,SEEK_END) != 0) {
i = errno;
Log.Level(LOGE) << "Unable to seek to end of message, Errno: " << i << EOL;
fclose (fh);
return FALSE;
}
FSize = ftell(fh) - sizeof(Hdr);
if (FSize == 0) {
if (UseOwnZone) {
m._FromAddr.Zone(FA_ANYMASK);
m._FromAddr.Zone(GetMyAka(m._FromAddr).Zone());
m._ToAddr.Zone(FA_ANYMASK);
m._ToAddr.Zone(GetMyAka(m._ToAddr).Zone());
}
fclose (fh);
return TRUE;
}
CHP = 226;
if (fseek(fh,sizeof(Hdr),SEEK_SET) != 0) {
i = errno;
Log.Level(LOGE) << "Unable to seek to begin of message, Errno: " << i << EOL;
fclose (fh);
return FALSE;
}
CHP = 227;
Buff = (char *) malloc(FSize+1);
CheckMem(Buff);
memset(Buff,0,FSize+1);
CHP = 228;
if (fread(Buff,FSize,1,fh) != 1) {
i = errno;
Log.Level(LOGE) << "Unable to read message body, Errno: " << i << EOL;
free(Buff);
fclose (fh);
return FALSE;
}
m.ParseMem(Buff);
CHP = 236;
free(Buff);
fclose(fh);
CHP = 237;
return TRUE;
}
// ---------------------------
int MSGASMSG::WriteOneMsg(unsigned int Num, cMSG &m) {
MsgHeader Hdr;
FILE *fh;
char *Buff;
CHP = 23701;
Buff = (char *) malloc(40960);
CHP = 23702;
CheckMem(Buff);
CHP = 23703;
sprintf(Buff,"%s%u"MsgExtension,DirName,Num);
CHP = 23704;
fh = fopen(Buff,"wb");
CHP = 23705;
if (fh == NULL) {
free(Buff);
return FALSE;
}
CHP = 23706;
free(Buff);
CHP = 23707;
Hdr.OrigNode = m._FromAddr.Node();
Hdr.OrigNet = m._FromAddr.Net();
Hdr.DestNode = m._ToAddr.Node();
Hdr.DestNet = m._ToAddr.Net();
strncpy(Hdr.Subject,m._Subject,72);
strncpy(Hdr.FromName,m._FromName,36);
strncpy(Hdr.ToName,m._ToName,36);
strncpy(Hdr.DateTime,FromTime(m._Time),20);
Hdr.Cost = m._Cost;
Hdr.ReplyTo = m._ReplyTo;
Hdr.TimesRead = m._TimesRead;
Hdr.NextReply = m._NextReply;
memcpy(Hdr.Reserved,m._Reserved,8);
CHP = 23708;
SetMsgAttr(m,Hdr.Attr);
CHP = 23709;
#ifdef _AIX
Hdr.TimesRead=RotateShort(Hdr.TimesRead);
Hdr.DestNode=RotateShort(Hdr.DestNode);
Hdr.OrigNode=RotateShort(Hdr.OrigNode);
Hdr.Cost=RotateShort(Hdr.Cost);
Hdr.OrigNet=RotateShort(Hdr.OrigNet);
Hdr.DestNet=RotateShort(Hdr.DestNet);
Hdr.ReplyTo=RotateShort(Hdr.ReplyTo);
Hdr.Attr=RotateShort(Hdr.Attr);
#endif
if (fwrite(&Hdr,sizeof(Hdr),1,fh) != 1) {
fclose (fh);
return FALSE;
}
CHP = 23710;
if (!WriteMsgBody(m,fh)) {
fclose (fh);
return FALSE;
}
CHP = 23711;
fclose(fh);
CHP = 23712;
return TRUE;
}
// ---------------------------
int MSGASMSG::WriteMsg(cMSG &m) {
return WriteOneMsg(MsgNum,m);
}
// ---------------------------
int MSGASMSG::WriteNewMsg(cMSG &m) {
unsigned int Num;
char Buff[1024];
Num = MaxNum;
do {
Num++;
sprintf(Buff,"%s%u"MsgExtension,DirName,Num);
} while(access(Buff,F_OK) == 0);
AddToMask(Num);
return WriteOneMsg(Num,m);
}
// ---------------------------
void MSGASMSG::Print(void) {
#if 0
if (LogLevel >= 5) {
Log.Level(LOGD) << "---------------- MSGASMSG -------------------" << EOL;
if (DirName != NULL) Log.Level(LOGD) << "Directory == '" << DirName << "'" << EOL;
Log.Level(LOGD) << "Current Msg number == '" << MsgNum << "'" << EOL;
}
#endif
}
// ---------------------------
MSGBASE *MakeBase(char *BName) {
MSGBASE *tmt;
// Make message base from name.
// First character of base name can be:
// $ -- Squish style area
// @ -- JAM style area
// # -- PKT style area
// Without this characters style of area is a MSG
if (*BName == '$') {
tmt = new SQUISH('$');
} else if (*BName == '#') {
tmt = new PKTBASE();
} else if (*BName == '@') {
tmt = new SQUISH('@');
} else {
tmt = new MSGASMSG();
}
if (tmt == NULL) {
yyerror("Internal Error. Out of memory.");
return NULL;
}
return tmt;
}
syntax highlighted by Code2HTML, v. 0.9.1