proboard/SQUISH.CPP

803 lines
17 KiB
C++
Raw Blame History

#define Use_MsgBase
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <dos.h>
extern "C" {
#include <msgapi.h>
}
#include "proboard.hpp"
/*
#include "cache.hpp"
const byte cachemode_lowmsg = 0;
const byte cachemode_highmsg = 1;
const byte cachemode_nummsgs = 2;
const byte cachemode_lastread = 3;
struct CacheIndexKey
{
int area;
byte mode;
CacheIndexKey(int a,byte m) { area = a ; mode = m; }
int operator==(const CacheIndexKey& k) { return !memcmp(&k,this,sizeof(k)); }
};
static ObjectCache<long,CacheIndexKey> squishCache(300);
*/
static void _near
xmsg2message(XMSG *xmsg,Message *msg)
{
strcpy(msg->from , xmsg->from);
strcpy(msg->to , xmsg->to);
strcpy(msg->subj , xmsg->subj);
msg->origZone = xmsg->orig.zone;
msg->origNet = xmsg->orig.net;
msg->origNode = xmsg->orig.node;
msg->origPoint = xmsg->orig.point;
msg->destZone = xmsg->dest.zone;
msg->destNet = xmsg->dest.net;
msg->destNode = xmsg->dest.node;
msg->destPoint = xmsg->dest.point;
msg->postDate[0] = xmsg->date_written.date.da;
msg->postDate[1] = xmsg->date_written.date.mo;
msg->postDate[2] = xmsg->date_written.date.yr+80;
msg->postTime[0] = xmsg->date_written.time.hh;
msg->postTime[1] = xmsg->date_written.time.mm;
msg->postTime[2] = xmsg->date_written.time.ss;
msg->recvDate[0] = xmsg->date_arrived.date.da;
msg->recvDate[1] = xmsg->date_arrived.date.mo;
msg->recvDate[2] = xmsg->date_arrived.date.yr+80;
msg->recvTime[0] = xmsg->date_arrived.time.hh;
msg->recvTime[1] = xmsg->date_arrived.time.mm;
msg->recvTime[2] = xmsg->date_arrived.time.ss;
msg->attr = 0;
if(xmsg->attr & MSGLOCAL)
{
msg->attr |= MSGATTR_LOCAL;
if(xmsg->attr & MSGSCANNED)
msg->attr |= MSGATTR_SENT;
}
if(xmsg->attr & MSGPRIVATE) msg->attr |= MSGATTR_PRIVATE;
if(xmsg->attr & MSGREAD ) msg->attr |= MSGATTR_RECEIVED;
if(xmsg->attr & MSGCRASH ) msg->attr |= MSGATTR_CRASH;
if(xmsg->attr & MSGFILE ) msg->attr |= MSGATTR_FILE;
if(xmsg->attr & MSGKILL ) msg->attr |= MSGATTR_KILL;
if(xmsg->attr & MSGSENT ) msg->attr |= MSGATTR_SENT;
if(xmsg->attr & MSGORPHAN ) msg->attr |= MSGATTR_ORPHAN;
if(xmsg->attr & MSGFRQ ) msg->attr |= MSGATTR_FILEREQ;
if(xmsg->attr & MSGRRQ ) msg->attr |= MSGATTR_RECEIPTREQ;
if(xmsg->attr & MSGHOLD ) msg->attr |= MSGATTR_HOLD;
if(msg->msgArea->msgKind == MSG_ECHO) msg->attr |= MSGATTR_ECHOMAIL;
if(msg->msgArea->msgKind == MSG_PVTECHO) msg->attr |= MSGATTR_ECHOMAIL;
if(msg->msgArea->msgKind == MSG_NET) msg->attr |= MSGATTR_NETMAIL;
}
static void _near
message2xmsg(XMSG *xmsg,Message *msg)
{
strcpy(xmsg->from , msg->from);
strcpy(xmsg->to , msg->to);
strcpy(xmsg->subj , msg->subj);
xmsg->orig.zone = msg->origZone;
xmsg->orig.net = msg->origNet;
xmsg->orig.node = msg->origNode;
xmsg->orig.point = msg->origPoint;
xmsg->dest.zone = msg->destZone;
xmsg->dest.net = msg->destNet;
xmsg->dest.node = msg->destNode;
xmsg->dest.point = msg->destPoint;
xmsg->date_written.date.da = msg->postDate[0];
xmsg->date_written.date.mo = msg->postDate[1];
xmsg->date_written.date.yr = msg->postDate[2]-80;
xmsg->date_written.time.hh = msg->postTime[0];
xmsg->date_written.time.mm = msg->postTime[1];
xmsg->date_written.time.ss = msg->postTime[2];
xmsg->date_arrived.date.da = msg->recvDate[0];
xmsg->date_arrived.date.mo = msg->recvDate[1];
xmsg->date_arrived.date.yr = msg->recvDate[2]-80;
xmsg->date_arrived.time.hh = msg->recvTime[0];
xmsg->date_arrived.time.mm = msg->recvTime[1];
xmsg->date_arrived.time.ss = msg->recvTime[2];
xmsg->attr &= ~dword( MSGPRIVATE | MSGREAD | MSGLOCAL
| MSGSCANNED | MSGSENT | MSGCRASH
| MSGFILE | MSGKILL | MSGSENT
| MSGORPHAN | MSGFRQ | MSGRRQ
| MSGHOLD
);
if(msg->attr & MSGATTR_LOCAL)
{
xmsg->attr |= MSGLOCAL;
if( ((msg->attr & MSGATTR_ECHOMAIL) || (msg->attr & MSGATTR_NETMAIL))
&& (msg->attr & MSGATTR_SENT))
{
xmsg->attr |= MSGSCANNED | MSGSENT;
}
}
if(msg->attr & MSGATTR_PRIVATE) xmsg->attr |= MSGPRIVATE ;
if(msg->attr & MSGATTR_RECEIVED) xmsg->attr |= MSGREAD ;
if(msg->attr & MSGATTR_CRASH) xmsg->attr |= MSGCRASH ;
if(msg->attr & MSGATTR_FILE) xmsg->attr |= MSGFILE ;
if(msg->attr & MSGATTR_KILL) xmsg->attr |= MSGKILL ;
if(msg->attr & MSGATTR_SENT) xmsg->attr |= MSGSENT ;
if(msg->attr & MSGATTR_ORPHAN) xmsg->attr |= MSGORPHAN ;
if(msg->attr & MSGATTR_FILEREQ) xmsg->attr |= MSGFRQ ;
if(msg->attr & MSGATTR_RECEIPTREQ) xmsg->attr |= MSGRRQ ;
if(msg->attr & MSGATTR_HOLD) xmsg->attr |= MSGHOLD ;
}
struct __sqidx
{
dword ofs;
UMSGID umsgid;
dword hash;
};
bool
SquishMsgBase::open()
{
_minf mi = { 0x200 , 0 };
aka a;
if(a.read(0) >= 0) mi.def_zone = a.zone;
if(MsgOpenApi(&mi) < 0)
{
fatalerror("Unable to initialize Squish API");
}
lastarea = NULL;
lastareanum = -1;
//squishCache.purge();
return TRUE;
}
void
SquishMsgBase::close()
{
if(lastarea != NULL)
{
MsgCloseArea(lastarea);
lastarea = NULL;
lastareanum = -1;
}
MsgCloseApi();
//squishCache.purge();
}
MSG *
SquishMsgBase::readArea(MsgArea& ma)
{
if(ma.areaNum != lastareanum || lastarea == NULL)
{
if(lastarea != NULL) MsgCloseArea(lastarea);
lastarea = MsgOpenArea(ma.path,MSGAREA_CRIFNEC,(ma.msgBaseType == MSGBASE_SQUISH) ?
MSGTYPE_SQUISH :
MSGTYPE_SDM);
if(lastarea == NULL) return NULL;
if(ma.msgBaseType == MSGBASE_SQUISH)
{
SquishSetMaxMsg(lastarea, ma.maxMsgs, 0, ma.msgKillDays);
}
lastareanum = ma.areaNum;
}
return lastarea;
}
long
SquishMsgBase::readMsg(Message &msg,long id)
{
int areanum = msg.areaNum();
MSG *sqarea = readArea(*msg.msgArea);
if(sqarea == NULL) return -1;
MSGH *mh;
XMSG xmsg;
if(msg.msgArea->msgBaseType == MSGBASE_SDM)
{
bool found = FALSE;
if(id > 0)
{
for(; id <= MsgGetHighMsg(sqarea) ; id++)
{
if((mh = MsgOpenMsg(sqarea , MOPEN_READ , id)) != NULL)
{
found = TRUE;
break;
}
}
if(!found) return -1;
}
else
{
for( id = -id ; id >= 1 ; id--)
{
if((mh = MsgOpenMsg(sqarea , MOPEN_READ , id)) != NULL)
{
found = TRUE;
break;
}
}
if(!found) return -1;
}
}
else
{
long msgnum;
if(id < 0) msgnum = MsgUidToMsgn(sqarea,-id,UID_PREV);
else msgnum = MsgUidToMsgn(sqarea, id,UID_NEXT);
if((mh = MsgOpenMsg(sqarea , MOPEN_READ , msgnum)) == NULL) return -1;
id = msgnum;
}
id = labs(id);
MsgReadMsg(mh,&xmsg,0,0,0,0,0);
MsgCloseMsg(mh);
msg.clear();
xmsg2message(&xmsg,&msg);
msg.prev = xmsg.replyto;
msg.next = xmsg.replies[0];
msg.id = MsgMsgnToUid(sqarea,id);
msg.num = id;
msg.setArea(areanum);
return msg.id;
}
long
SquishMsgBase::lowMsg(MsgArea &ma)
{
long x;
//CacheIndexKey idx(ma.areaNum,cachemode_lowmsg);
//if(squishCache.find(x,idx)) return x;
MSG *sqarea = readArea(ma);
if(sqarea == NULL) return -1;
x = MsgMsgnToUid(sqarea,1);
//squishCache.add(x,idx);
return x;
}
long
SquishMsgBase::numMsgs(MsgArea &ma)
{
long x;
//CacheIndexKey idx(ma.areaNum,cachemode_nummsgs);
//if(squishCache.find(x,idx)) return x;
MSG *sqarea = readArea(ma);
if(sqarea == NULL) return -1;
x = MsgGetNumMsg(sqarea);
//squishCache.add(x,idx);
return x;
}
long
SquishMsgBase::highMsg(MsgArea &ma)
{
MSG *sqarea = readArea(ma);
if(sqarea == NULL) return -1;
return MsgMsgnToUid(sqarea,MsgGetHighMsg(sqarea));
}
word
SquishMsgBase::readMsgText(Message& msg,char *ptr,long offset,word size)
{
MSGH *mh;
MSG *sqarea;
if((sqarea = readArea(*msg.msgArea)) == NULL) return 0;
msg.num = MsgUidToMsgn(sqarea,msg.id,UID_EXACT);
if(msg.num < 1) return 0;
if((mh = MsgOpenMsg(sqarea , MOPEN_READ , msg.num)) == NULL) return 0;
if(msg.msgArea->msgBaseType == MSGBASE_SDM)
MsgReadMsg(mh,NULL,0,0,0,0,0); // Workaround for a bug in Squish API
int l = (int) MsgReadMsg(mh,NULL,offset,size,ptr,0,0);
MsgCloseMsg(mh);
if(l < 0) l = 0;
return l;
}
long
SquishMsgBase::appendMsg(Message& msg)
{
MSG *sqarea;
MSGH *mh;
XMSG xmsg;
File f;
String control_text;
String text;
String kludge_text;
if((sqarea = readArea(*msg.msgArea)) == NULL) return -1;
if( !f.open("MSGTMP",fmode_read,512) )
{
return -1;
}
long bytecount = 0;
for(bool inkludge = FALSE;;)
{
int c = f.readByte();
if(c < 0) break;
switch( byte(c) )
{
case '\n' :
case '<EFBFBD>' : continue;
case 1 : inkludge = TRUE;
kludge_text = "";
break;
case '\r' : if(inkludge)
{
inkludge = FALSE;
bytecount--;
control_text << char(1) << kludge_text;
if(!strncmp(kludge_text,"FMPT",4)) msg.origPoint = atoi(&kludge_text[5]);
if(!strncmp(kludge_text,"TOPT",4)) msg.destPoint = atoi(&kludge_text[5]);
}
else
{
text << char(c);
}
break;
default : if(inkludge)
{
kludge_text << char(c);
}
else
{
text << char(c);
}
break;
}
if(!inkludge) bytecount++;
}
f.close();
if(!bytecount) return -1;
control_text << "\x01PID: " PID_STRING_SQUISH;
//----------------------------
// JDR: REGISTRATION REFERENCE
//----------------------------
control_text << (registered ? 'r':'u');
if((mh = MsgOpenMsg(sqarea , MOPEN_CREATE , 0)) == NULL) return -1;
CLEAR_OBJECT(xmsg);
message2xmsg(&xmsg,&msg);
MsgWriteMsg(mh,0,&xmsg,(char *)text,text.len()+1,bytecount,control_text.len() + 1,(char *)control_text);
msg.num = mh->sq->high_msg;
MsgCloseMsg(mh);
msg.id = MsgMsgnToUid(sqarea,msg.num);
//squishCache.purge();
return msg.id;
}
bool
SquishMsgBase::updateMsg(Message& msg)
{
MSG *sqarea = readArea(*msg.msgArea);
if(sqarea == NULL) return FALSE;
msg.num = MsgUidToMsgn(sqarea,msg.id,UID_EXACT);
if(msg.num < 1) return FALSE;
MSGH *mh;
XMSG xmsg;
if((mh = MsgOpenMsg(sqarea , MOPEN_RW , msg.num)) == NULL) return -1;
MsgReadMsg(mh,&xmsg,0,0,0,0,0);
message2xmsg(&xmsg,&msg);
xmsg.replyto = msg.prev;
xmsg.replies[0] = msg.next;
for(int i=1; i < MAX_REPLY; i++) xmsg.replies[i] = 0;
MsgWriteMsg(mh,0,&xmsg,0,0,0,0,0);
MsgCloseMsg(mh);
//squishCache.purge();
if(msg.msgArea->msgBaseType != MSGBASE_SQUISH) return TRUE;
File f;
if(!f.open(FileName(msg.msgArea->path,".SQI"),fmode_rw,1024)) return FALSE;
for(;;)
{
struct __sqidx sidx;
if(f.read(&sidx,sizeof(sidx)) != sizeof(sidx)) break;
if(sidx.umsgid == msg.id)
{
if(msg.attr & MSGATTR_RECEIVED) sidx.hash |= 0x80000000L;
else sidx.hash &= 0x7FFFFFFFL;
f.seek(f.pos() - sizeof(sidx));
f.flush();
f.write(&sidx,sizeof(sidx));
break;
}
}
return TRUE;
}
long
SquishMsgBase::msgNum(MsgArea& ma,long id)
{
MSG *sqarea = readArea(ma);
return MsgUidToMsgn(sqarea,id,UID_EXACT);
}
long
SquishMsgBase::msgId(MsgArea& ma,long num)
{
MSG *sqarea = readArea(ma);
return MsgMsgnToUid(sqarea,num);
}
bool
SquishMsgBase::deleteMsg(Message &msg)
{
MSG *sqarea = readArea(*msg.msgArea);
if(sqarea == NULL) return FALSE;
long num = MsgUidToMsgn(sqarea,msg.id,UID_EXACT);
msg.num = 0;
//squishCache.purge();
return (MsgKillMsg(sqarea,num) ? FALSE:TRUE);
}
static void
showbusy()
{
static int x = 0;
char *ss[] = {
"|",
"/",
"-",
"\\",
NULL
};
/*
char *ss1[] = {
"*....",
"**...",
"***..",
".***.",
"..***",
"...**",
"....*",
"...**",
"..***",
".***.",
"***..",
"**...",
NULL
};
*/
//char **ss = (!io.baud || io.baud > 4800) ? ss1:ss2;
io << '\b' << ss[x] << char(0xFF);
x = ++x % 4;
}
word
SquishMsgBase::scanMail(MessageIndex *mi,word maxmsgs)
{
MsgArea ma;
FileName sqname;
int index = 0;
io << "\3 ";
for(int i = 1; i <= MsgArea::highAreaNum() ; i++)
{
if(!ma.read(i)) continue;
if(ma.msgBaseType != MSGBASE_SQUISH && ma.msgBaseType != MSGBASE_SDM) continue;
if(!user.mailCheckBoards.connected(i)) continue;
if(!check_access(ma.readLevel,ma.readFlags,ma.readFlagsNot)) continue;
XMSG xmsg;
MSGH *msgh;
if(ma.msgBaseType != MSGBASE_SQUISH || ma.msgType == MSG_TOALL)
{
MSG *sqarea = readArea(ma);
if(sqarea == NULL) continue;
long startnum = ma.lowMsg();
if(ma.msgType == MSG_TOALL)
{
startnum = ma.lastRead(user_recnr);
if(startnum < 1)
{
startnum = 1;
}
else
{
startnum = MsgUidToMsgn(sqarea,startnum,UID_EXACT);
}
if(startnum < 1) startnum = MsgUidToMsgn(sqarea,ma.lastRead(user_recnr),UID_NEXT);
else startnum++;
if(ma.lastRead(user_recnr) < 1) startnum = 1;
if(startnum < 1) continue;
}
if(startnum < 1) startnum = 1;
for(long num = startnum ; num <= ma.highMsg() && index < maxmsgs;num++)
{
if((msgh = MsgOpenMsg(sqarea , MOPEN_READ , num)) == NULL) continue;
showbusy();
MsgReadMsg(msgh,&xmsg,0,0,0,0,0);
MsgCloseMsg(msgh);
if(xmsg.attr & MSGREAD) continue;
if(( !stricmp(xmsg.to,user.name)
|| (!stricmp(xmsg.to,user.alias) && ma.flags && strcmp(user.name,user.alias))
|| ma.msgType == MSG_TOALL )
&& (check_access(ma.readLevel,ma.readFlags,ma.readFlagsNot) || ma.sysopAccess())
)
{
mi[index].num = ma.msgId(num);
mi[index].area = ma.areaNum;
index++;
}
}
continue;
}
dword name_hashvalue = SquishHash(user.name);
dword alias_hashvalue = SquishHash(user.alias);
sqname = ma.path;
sqname.changeExt("SQI");
File f(sqname,fmode_read | fmode_copen,2048);
if(!f.opened())
{
LOG("Can't open Squish index file '%s'",(char *)sqname);
continue;
}
showbusy();
while( index < maxmsgs )
{
struct __sqidx si;
if(f.read(&si,sizeof(si)) != sizeof(si)) break;
if(si.hash == name_hashvalue || si.hash == alias_hashvalue)
{
for(int i=index-1 ; i >= 0 ; i--)
{
if(si.umsgid == mi[i].num && ma.areaNum == mi[i].area) break;
}
if(i>=0) continue;
MSG *sqarea = readArea(ma);
if(sqarea == NULL) continue;
long id = si.umsgid;
long num = MsgUidToMsgn(sqarea,id,UID_EXACT);
if(num < 1) continue;
if((msgh = MsgOpenMsg(sqarea , MOPEN_READ , num)) == NULL) continue;
MsgReadMsg(msgh,&xmsg,0,0,0,0,0);
MsgCloseMsg(msgh);
if(xmsg.attr & MSGREAD) continue;
if(( !stricmp(xmsg.to,user.name)
|| (!stricmp(xmsg.to,user.alias) && ma.flags && strcmp(user.name,user.alias))
)
&& (check_access(ma.readLevel,ma.readFlags,ma.readFlagsNot) || ma.sysopAccess())
)
{
mi[index].num = id;
mi[index].area = ma.areaNum;
index++;
}
}
}
}
io << '\b';
return index;
}
long
SquishMsgBase::lastRead(MsgArea& ma,long rec)
{
long n = 0;
File f;
FileName sqname;
if(ma.msgBaseType == MSGBASE_SQUISH) sqname(ma.path,".SQL");
else sqname(ma.path,"LASTREAD");
int lr_size = (ma.msgBaseType == MSGBASE_SQUISH) ? 4 : 2;
if(!f.open(sqname)) return 0;
f.seek(rec * lr_size);
if(f.read(&n,lr_size) != lr_size) return 0;
MSG *sqarea = readArea(ma);
if(sqarea == NULL) return 0;
n = MsgUidToMsgn(sqarea,n,UID_PREV);
n = MsgMsgnToUid(sqarea,n);
return n;
}
void
SquishMsgBase::setLastRead(MsgArea& ma,long rec,long num)
{
File f;
FileName sqname;
//squishCache.purge();
if(ma.msgBaseType == MSGBASE_SQUISH) sqname(ma.path,".SQL");
else sqname(ma.path,"LASTREAD");
if(!f.open(sqname,fmode_rw | fmode_copen)) return;
int lr_size = (ma.msgBaseType == MSGBASE_SQUISH) ? 4 : 2;
if(f.len() < (rec+1)*lr_size)
{
byte x = 0;
f.seek(f.len());
for(long i = f.len() ; i < (rec+1)*lr_size ; i++) f.write(&x,1);
}
f.seek(rec * lr_size);
f.write(&num,lr_size);
}