This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
deb-goldedplus/golded3/geqwks.cpp
2006-05-14 17:17:32 +00:00

961 lines
22 KiB
C++

// ------------------------------------------------------------------
// GoldED+
// Copyright (C) 1990-1999 Odinn Sorensen
// Copyright (C) 1999-2000 Alexander S. Aganichev
// ------------------------------------------------------------------
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston,
// MA 02111-1307 USA
// ------------------------------------------------------------------
// $Id$
// ------------------------------------------------------------------
// QWK packet handling.
// ------------------------------------------------------------------
#include <golded.h>
#include <gs_qwk.h>
// ------------------------------------------------------------------
static void ReadGldFile() {
if (QWK->FoundBBS())
{
Path gldfile;
QWK->ResetConfNo();
gsprintf(PRINTF_DECLARE_BUFFER(gldfile), "%s%s.GLD", CFG->goldpath, QWK->BbsID());
gfile fp(gldfile, "rt");
if (fp.isopen())
{
char* key;
char* val;
char buf[256];
while (fp.Fgets(buf, sizeof(buf)))
{
val = strtrim(buf);
getkeyval(&key, &val);
strtrim(StripQuotes(val));
if(QWK->FindEcho(val))
QWK->ConfNo(atoi(key));
}
}
}
}
// ------------------------------------------------------------------
int ImportQWK() {
if(not *QWK->ImportPath())
return 0;
gfile fpb; // For BBSID.GLD
Path file;
Path gldfile;
char bbsid[9] = {""};
// Parse the control file
strcpy(file, AddPath(QWK->ImportPath(), "CONTROL.DAT"));
gfile fp(file, "rt");
if (fp.isopen())
{
char buf[256];
int line = 0;
int confno = 0;
int confcnt = 0;
int confnos = 0;
while (fp.Fgets(buf, sizeof(buf)))
{
line++;
strtrim(buf);
if((line >= 12) and (confcnt < confnos)) {
if(line % 2)
{
if (fpb.isopen())
fpb.Printf("%u \"%s\"\n", confno, buf);
confcnt++;
}
else
confno = atoi(buf);
}
else if(line == 5) {
char* ptr = strchr(buf, ',');
if (ptr)
{
strxcpy(bbsid, strskip_wht(ptr+1), 9);
gsprintf(PRINTF_DECLARE_BUFFER(gldfile), "%s%s.GLD", CFG->goldpath, bbsid);
fpb.Fopen(gldfile, "wt");
}
}
else if(line == 11)
confnos = atoi(buf) + 1;
}
fpb.Fclose();
fp.Fclose();
remove(file);
}
if(strblank(bbsid))
return 0;
QWK->FindBBS(bbsid);
ReadGldFile();
int imported = 0;
OrigArea = CurrArea = -1;
strcpy(file, AddPath(QWK->ImportPath(), "MESSAGES.DAT"));
fp.Fopen(file, "rb");
if (fp.isopen())
{
// Skip past product info header
fp.FseekSet(sizeof(QWKHdr));
QWKHdr hdr;
GMsg* msg = (GMsg*)throw_calloc(1, sizeof(GMsg));
// Read each message, header first
int tosstobadmsgs = false;
int lastconfno = -1;
int more;
do {
ResetMsg(msg);
memset(&hdr, 0, sizeof(QWKHdr));
more = 1 == fp.Fread(&hdr, sizeof(QWKHdr));
if(more) {
char blocks[7];
strxcpy(blocks, hdr.blocks, 7);
uint msglen = atoi(blocks);
if(msglen == 0) {
break;
}
msglen = (msglen-1)*128;
if(hdr.confno != lastconfno) {
lastconfno = hdr.confno;
if(QWK->FindEcho(hdr.confno)) {
int areano = AL.AreaEchoToNo(QWK->EchoID());
if(areano != -1) {
CurrArea = AL.AreaNoToId(areano);
tosstobadmsgs = false;
}
}
else {
int areano = AL.AreaEchoToNo(QWK->BadMsgs());
if(areano != -1) {
CurrArea = AL.AreaNoToId(areano);
tosstobadmsgs = true;
}
else
{
tosstobadmsgs = -1;
fp.Fseek(msglen, SEEK_CUR);
}
}
}
if(tosstobadmsgs != -1) {
if(OrigArea != CurrArea) {
if(AA->isopen()) {
AA->Unlock();
AA->Close();
}
AL.SetActiveAreaId(CurrArea);
OrigArea = CurrArea;
AA->Open();
AA->Lock();
AA->RandomizeData();
}
// Convert header
msg->orig = msg->oorig = AA->aka();
msg->dest = msg->odest = AA->aka();
msg->attr.pvt(hdr.status == '*' or hdr.status == '+');
msg->attr.rcv(hdr.status == '+' or hdr.status == '-' or hdr.status == '`' or hdr.status == '^' or hdr.status == '#');
msg->attr.del(hdr.activestatus == 226);
strtrim(strxcpy(msg->by, hdr.from, 26));
strtrim(strxcpy(msg->to, hdr.to, 26));
strtrim(strxcpy(msg->re, hdr.subject, 26));
int _year, _month, _day, _hour, _minute;
sscanf(hdr.date, "%d%*c%d%*c%2d", &_month, &_day, &_year);
sscanf(hdr.time, "%d%*c%2d", &_hour, &_minute);
struct tm _tm;
_tm.tm_year = (_year < 80) ? (_year+100) : _year;
_tm.tm_mon = _month - 1;
_tm.tm_mday = _day;
_tm.tm_hour = _hour;
_tm.tm_min = _minute;
_tm.tm_sec = 0;
_tm.tm_isdst = -1;
time32_t a = gmktime(&_tm);
struct tm tp; ggmtime(&tp, &a);
tp.tm_isdst = -1;
time32_t b = gmktime(&tp);
msg->written = a + a - b;
a = gtime(NULL);
ggmtime(&tp, &a);
tp.tm_isdst = -1;
b = gmktime(&tp);
msg->arrived = a + a - b;
// Read message text
char* txtptr = msg->txt = (char*)throw_calloc(1, msglen+128);
if(tosstobadmsgs) {
sprintf(msg->txt, "AREA:%s_%u\r", bbsid, hdr.confno);
txtptr += strlen(msg->txt);
}
fp.Fread(txtptr, msglen);
strtrim(txtptr);
strchg(txtptr, 0xE3, 0x0D);
imported++;
AA->istossed = true;
update_statuslinef("%s: %u", "", AA->echoid(), imported);
msg->TextToLines(CFG->dispmargin-1);
if(msg->messageid or msg->references or msg->inreplyto or *msg->ifrom) {
char kbuf[256];
uint txtlen = strlen(msg->txt);
if(*msg->ifrom) {
INam _fromname;
IAdr _fromaddr;
ParseInternetAddr(msg->ifrom, _fromname, _fromaddr);
if (AA->Internetgate().addr.valid())
{
char abuf[40];
gsprintf(PRINTF_DECLARE_BUFFER(kbuf),
"\x1""REPLYTO %s %s\r""\x1""REPLYADDR %s\r",
AA->Internetgate().addr.make_string(abuf),
*AA->Internetgate().name ? AA->Internetgate().name : "UUCP",
_fromaddr
);
uint addlen = strlen(kbuf);
msg->txt = (char*)throw_realloc(msg->txt, txtlen+addlen+1);
memmove(msg->txt+addlen, msg->txt, txtlen+1);
memcpy(msg->txt, kbuf, addlen);
txtlen += addlen;
}
}
if(msg->references) {
char* mptr = msg->references;
char* sptr = mptr;
while(*mptr) {
if(not strnieql(mptr, "<NOMSGID_", 9)) {
sptr = strpbrk(mptr, " ,");
if(sptr == NULL)
sptr = mptr + strlen(mptr);
while(((*sptr == ' ') or (*sptr == ',')) and *sptr)
*sptr++ = NUL;
CvtMessageIDtoMSGID(mptr, kbuf, AA->echoid(), "REPLY");
strcat(kbuf, "\r");
uint addlen = strlen(kbuf);
msg->txt = (char*)throw_realloc(msg->txt, txtlen+addlen+1);
memmove(msg->txt+addlen, msg->txt, txtlen+1);
memcpy(msg->txt, kbuf, addlen);
txtlen += addlen;
}
mptr = sptr;
}
}
if(msg->inreplyto) {
if(not strnieql(msg->inreplyto, "<NOMSGID_", 9)) {
CvtMessageIDtoMSGID(msg->inreplyto, kbuf, AA->echoid(), "REPLY");
strcat(kbuf, "\r");
uint addlen = strlen(kbuf);
msg->txt = (char*)throw_realloc(msg->txt, txtlen+addlen+1);
memmove(msg->txt+addlen, msg->txt, txtlen+1);
memcpy(msg->txt, kbuf, addlen);
txtlen += addlen;
}
}
if(msg->messageid) {
if(not strnieql(msg->messageid, "<NOMSGID_", 9)) {
CvtMessageIDtoMSGID(msg->messageid, kbuf, AA->echoid(), "MSGID");
strcat(kbuf, "\r");
uint addlen = strlen(kbuf);
msg->txt = (char*)throw_realloc(msg->txt, txtlen+addlen+1);
memmove(msg->txt+addlen, msg->txt, txtlen+1);
memcpy(msg->txt, kbuf, addlen);
}
}
}
if(*msg->realto and (strieql(msg->to, AA->Whoto()) or not *msg->to))
strcpy(msg->to, msg->realto);
AA->SaveMsg(GMSG_NEW, msg);
}
}
} while(more);
if(AA->isopen()) {
AA->Unlock();
AA->Close();
}
ResetMsg(msg);
throw_free(msg);
fp.Fclose();
remove(file);
if (*QWK->TossLog())
{
fp.Fopen(QWK->TossLog(), "at");
if (fp.isopen())
{
uint na = 0;
while(na < AL.size()) {
if(AL[na]->istossed) {
AL[na]->istossed = false;
AL[na]->isunreadchg = true;
fp.Printf("%s\n", AL[na]->echoid());
}
na++;
}
}
}
if (imported and *QWK->ReplyLinker())
{
char buf[256];
gsprintf(PRINTF_DECLARE_BUFFER(buf), LNG->Replylinker, QWK->ReplyLinker());
ShellToDos(QWK->ReplyLinker(), buf, LGREY_|_BLACK, YES);
}
}
if(imported)
startupscan_success = true;
return imported;
}
// ------------------------------------------------------------------
int ExportQwkMsg(GMsg* msg, gfile& fp, int confno, int& pktmsgno) {
// Prepare for Return Receipt Request
char msg__re[26];
if (QWK->ReceiptAllowed() and msg->attr.rrq())
gsprintf(PRINTF_DECLARE_BUFFER(msg__re), "RRR%-22.22s", msg->re);
else
strxcpy(msg__re, msg->re, 26);
// Build QWK header
QWKHdr hdr;
char buf[26];
int tolen = strlen(msg->to); tolen = MinV(25,tolen);
int bylen = strlen(msg->by); bylen = MinV(25,bylen);
int relen = strlen(msg__re); relen = MinV(25,relen);
memset(&hdr, ' ', sizeof(QWKHdr));
hdr.status = msg->attr.pvt() ? '*' : ' ';
gsprintf(PRINTF_DECLARE_BUFFER(buf), "%u", confno);
memcpy(hdr.msgno, buf, strlen(buf));
struct tm _tm; ggmtime(&_tm, &msg->written);
int _year = _tm.tm_year % 100;
gsprintf(PRINTF_DECLARE_BUFFER(buf), "%02d-%02d-%02d", _tm.tm_mon+1, _tm.tm_mday, _year);
memcpy(hdr.date, buf, 8);
gsprintf(PRINTF_DECLARE_BUFFER(buf), "%02d:%02d", _tm.tm_hour, _tm.tm_min);
memcpy(hdr.time, buf, 5);
strxcpy(buf, msg->to, tolen+1);
if(not QWK->MixCaseAllowed())
strupr(buf);
memcpy(hdr.to, buf, tolen);
strxcpy(buf, msg->by, bylen+1);
if(not QWK->MixCaseAllowed())
strupr(buf);
memcpy(hdr.from, buf, bylen);
memcpy(hdr.subject, msg__re, relen);
hdr.activestatus = '\xE1';
hdr.confno = (word)confno;
hdr.pktmsgno = (word)++pktmsgno;
// Write preliminary header
fp.Fwrite(&hdr, sizeof(QWKHdr));
// Write body
int level = 0;
if(CharTable)
level = CharTable->level ? CharTable->level : 2;
char mbuf[512];
uint msglen = 0;
if(msg->charsetencoding & GCHENC_MNE) {
if(not striinc("MNEMONIC", CharTable->exp))
LoadCharset(CFG->xlatlocalset, "MNEMONIC");
}
// ASA: Do we need it at all?
else if(IsQuotedPrintable(msg->charset)) {
LoadCharset(CFG->xlatlocalset, ExtractPlainCharset(msg->charset));
}
else {
LoadCharset(CFG->xlatlocalset, msg->charset);
}
char qwkterm = '\xE3';
// Process kludges and write header lines
Line* line = msg->lin;
while(line) {
if(line->type & GLINE_KLUDGE) {
if(AA->isinternet()) {
if ((line->kludge == GKLUD_RFC) or (line->kludge == 0))
{
XlatStr(mbuf, line->txt.c_str(), level, CharTable);
msglen += fp.Printf("%s%c", mbuf, qwkterm);
}
else if(line->type & GLINE_WRAP) {
while(line->next and (line->type & GLINE_WRAP))
line = line->next;
}
}
else {
if ((line->type & GLINE_KLUDGE) and QWK->KludgesAllowed())
{
XlatStr(mbuf, line->txt.c_str(), level, CharTable);
msglen += fp.Printf("%s%c", mbuf, qwkterm);
}
}
}
line = line->next;
}
// Write blank line after header lines
if (AA->Internetrfcbody())
msglen += fp.Printf("%c", qwkterm);
// Write all message lines
line = msg->lin;
while(line) {
if (not (line->type & GLINE_KLUDGE))
{
XlatStr(mbuf, line->txt.c_str(), level, CharTable);
msglen += fp.Printf("%s%c", mbuf, qwkterm);
}
line = line->next;
}
// Calculate blocks
uint endlen = msglen % 128;
uint blocks = 1+(msglen/128)+(endlen?1:0);
gsprintf(PRINTF_DECLARE_BUFFER(buf), "%u", blocks);
memcpy(hdr.blocks, buf, strlen(buf));
// Write padding spaces at the end if necessary
if (endlen)
{
char padding[128];
memset(padding, ' ', 128);
fp.Fwrite(padding, 128-endlen);
}
// Re-write the header
fp.Fseek(-(blocks*128), SEEK_CUR);
fp.Fwrite(&hdr, sizeof(QWKHdr));
fp.Fseek((blocks-1)*128, SEEK_CUR);
// Mark msg as sent
msg->attr.snt1();
msg->attr.scn1();
msg->attr.uns0();
AA->SaveHdr(GMSG_UPDATE, msg);
return 1;
}
// ------------------------------------------------------------------
int ExportQwkArea(int areano, gfile& fp, int confno, int& pktmsgno) {
int exported = 0;
AL.SetActiveAreaNo(areano);
AA->Open();
AA->Lock();
AA->RandomizeData();
GMsg* msg = (GMsg*)throw_calloc(1, sizeof(GMsg));
for(uint n=0; n<AA->Expo.Count(); n++) {
if(AA->LoadMsg(msg, AA->Expo[n], 80)) {
if(msg->attr.uns()) {
exported += ExportQwkMsg(msg, fp, confno, pktmsgno);
update_statuslinef("%s: %u", "", AA->echoid(), exported);
}
}
}
ResetMsg(msg);
throw_free(msg);
AA->Unlock();
AA->Close();
AA->Expo.ResetAll();
return exported;
}
// ------------------------------------------------------------------
int ExportQWK() {
if(not *QWK->ExportPath())
return 0;
int exported = 0;
gfile fp;
Path scanfile;
// Get the scan list
strcpy(scanfile, AddPath(CFG->goldpath, "GOLDQWK.LST"));
fp.Fopen(scanfile, "rt");
if (fp.isopen())
{
char buf[256];
while (fp.Fgets(buf, sizeof(buf)))
{
char* ptr = strchr(buf, ' ');
if(ptr) {
*ptr++ = NUL;
int a = AL.AreaEchoToNo(buf);
if(a != -1 and AL[a]->isqwk())
AL[a]->Expo.Add(atol(ptr));
}
}
fp.Fclose();
}
// Export from the QWK areas
if(QWK->FirstBBS()) {
do {
ReadGldFile();
Path replyfile;
int pktmsgno = 0;
if (QWK->FirstConf())
{
gsprintf(PRINTF_DECLARE_BUFFER(replyfile), "%s%s.MSG", QWK->ExportPath(), QWK->BbsID());
fp.Fopen(replyfile, "wb");
if (fp.isopen())
{
char firstrec[128];
memset(firstrec, ' ', 128);
memcpy(firstrec, QWK->BbsID(), strlen(QWK->BbsID()));
fp.Fwrite(firstrec, 128);
pktmsgno = 0;
}
do {
int a = AL.AreaEchoToNo(QWK->EchoID());
if(a != -1 and AL[a]->Expo.Count()) {
if(QWK->ConfNo() != -1)
exported += ExportQwkArea(a, fp, QWK->ConfNo(), pktmsgno);
}
} while(QWK->NextConf());
}
if (fp.isopen())
{
fp.Fclose();
if(pktmsgno == 0)
remove(replyfile);
}
} while(QWK->NextBBS());
}
// Delete the scanfile
remove(scanfile);
return exported;
}
// ------------------------------------------------------------------
Qwk::Qwk() {
bbs = bbsp = NULL;
mapp = NULL;
bbss = 0;
}
// ------------------------------------------------------------------
Qwk::~Qwk() {
Reset();
}
// ------------------------------------------------------------------
void Qwk::Reset() {
for(int n=0; n<bbss; n++)
throw_release(bbs[n].map);
throw_xrelease(bbs);
bbsp = NULL;
mapp = NULL;
bbss = 0;
}
// ------------------------------------------------------------------
void Qwk::AddBBS(char* bbsid) {
bbs = (QwkBbs*)throw_realloc(bbs, (bbss+1)*sizeof(QwkBbs));
bbsp = bbs + bbss++;
strxcpy(bbsp->bbsid, bbsid, sizeof(bbsp->bbsid));
bbsp->kludges = false;
bbsp->mixcase = false;
bbsp->receipt = false;
bbsp->maxlines = -1;
bbsp->map = NULL;
bbsp->maps = 0;
mapp = NULL;
}
// ------------------------------------------------------------------
void Qwk::AddMap(char* bbsid, char* echoid, char* confname, int confno) {
FindAddBBS(bbsid);
bbsp->map = (QwkMap*)throw_realloc(bbsp->map, (bbsp->maps+1)*sizeof(QwkMap));
mapp = bbsp->map + bbsp->maps++;
strxcpy(mapp->confname, confname, sizeof(mapp->confname));
strxcpy(mapp->echoid, echoid, sizeof(mapp->echoid));
mapp->confno = confno;
}
// ------------------------------------------------------------------
int Qwk::FindBBS(char* bbsid) {
bbsp = bbs;
for(int n=0; n<bbss; n++,bbsp++) {
if(strieql(bbsid, bbsp->bbsid)) {
mapp = bbsp->map;
return true;
}
}
mapp = NULL;
return false;
}
// ------------------------------------------------------------------
void Qwk::FindAddBBS(char* bbsid) {
if(not FindBBS(bbsid))
AddBBS(bbsid);
}
// ------------------------------------------------------------------
int Qwk::FirstBBS() {
if(bbs) {
bbsp = bbs;
bbsn = 1;
return true;
}
bbsp = NULL;
bbsn = 0;
return false;
}
// ------------------------------------------------------------------
int Qwk::NextBBS() {
if(bbsp and (bbsn < bbss)) {
bbsp++;
bbsn++;
return true;
}
bbsp = NULL;
bbsn = 0;
return false;
}
// ------------------------------------------------------------------
int Qwk::FindConf(char* echoid) {
if(bbsp) {
mapp = bbsp->map;
for(int n=0; n<bbsp->maps; n++,mapp++)
if(strieql(echoid, mapp->echoid))
return true;
}
mapp = NULL;
return false;
}
// ------------------------------------------------------------------
int Qwk::FindEcho(char* confname) {
if(bbsp) {
mapp = bbsp->map;
for(int n=0; n<bbsp->maps; n++,mapp++)
if(strieql(confname, mapp->confname))
return true;
}
mapp = NULL;
return false;
}
// ------------------------------------------------------------------
int Qwk::FindEcho(int confno) {
if(bbsp) {
mapp = bbsp->map;
for(int n=0; n<bbsp->maps; n++,mapp++)
if(confno == mapp->confno)
return true;
}
mapp = NULL;
return false;
}
// ------------------------------------------------------------------
int Qwk::FirstConf() {
if(bbsp and bbsp->map) {
mapp = bbsp->map;
mapn = 1;
return true;
}
mapp = NULL;
mapn = 0;
return false;
}
// ------------------------------------------------------------------
int Qwk::NextConf() {
if(mapp and (mapn < bbsp->maps)) {
mapp++;
mapn++;
return true;
}
mapp = NULL;
mapn = 0;
return false;
}
// ------------------------------------------------------------------
const char* Qwk::BbsID() {
return bbsp ? bbsp->bbsid : "";
}
// ------------------------------------------------------------------
const char* Qwk::ConfName() {
return mapp ? mapp->confname : "";
}
// ------------------------------------------------------------------
int Qwk::ConfNo(int set) {
if(mapp) {
if(set != -2)
mapp->confno = set;
return mapp->confno;
}
return -1;
}
// ------------------------------------------------------------------
const char* Qwk::EchoID() {
return mapp ? mapp->echoid : "";
}
// ------------------------------------------------------------------
int Qwk::KludgesAllowed(int set) {
if(bbsp) {
if(set != -1)
bbsp->kludges = set;
return bbsp->kludges;
}
return false;
}
// ------------------------------------------------------------------
int Qwk::MixCaseAllowed(int set) {
if(bbsp) {
if(set != -1)
bbsp->mixcase = set;
return bbsp->mixcase;
}
return false;
}
// ------------------------------------------------------------------
int Qwk::ReceiptAllowed(int set) {
if(bbsp) {
if(set != -1)
bbsp->receipt = set;
return bbsp->receipt;
}
return false;
}
// ------------------------------------------------------------------
int Qwk::MaxLines(int set) {
if(bbsp) {
if(set != -1)
bbsp->maxlines = set;
return bbsp->maxlines;
}
return 0;
}
// ------------------------------------------------------------------
void Qwk::ResetConfNo(int set) {
if(bbsp) {
mapp = bbsp->map;
for(int n=0; n<bbsp->maps; n++,mapp++)
mapp->confno = set;
}
}
// ------------------------------------------------------------------
char* Qwk::BadMsgs(char* set) {
if(set)
strxcpy(cfg.badmsgs, set, sizeof(Echo));
return cfg.badmsgs;
}
// ------------------------------------------------------------------
char* Qwk::ExportPath(char* set) {
if(set)
PathCopy(cfg.exportpath, set);
return cfg.exportpath;
}
// ------------------------------------------------------------------
char* Qwk::ImportPath(char* set) {
if(set)
PathCopy(cfg.importpath, set);
return cfg.importpath;
}
// ------------------------------------------------------------------
char* Qwk::ReplyLinker(char* set) {
if(set)
strxcpy(cfg.replylinker, set, sizeof(Path));
return cfg.replylinker;
}
// ------------------------------------------------------------------
char* Qwk::TossLog(char* set) {
if(set)
strxcpy(cfg.tosslog, set, sizeof(Path));
return cfg.tosslog;
}
// ------------------------------------------------------------------