|
|
3.15b
/* un_qwk.cpp */
/* Synchronet QWK unpacking routine */
/* $Id: un_qwk.cpp,v 1.1.1.2 2018/04/24 16:43:37 root Exp $ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2010 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* 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. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to [email protected] *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#include "sbbs.h"
#include "qwk.h"
/****************************************************************************/
/* Unpacks .QWK packet, hubnum is the number of the QWK net hub */
/****************************************************************************/
bool sbbs_t::unpack_qwk(char *packet,uint hubnum)
{
char str[MAX_PATH+1],fname[MAX_PATH+1];
char tmp[512];
char inbox[MAX_PATH+1];
uchar block[QWK_BLOCK_LEN];
int k,file;
uint i,j,n,lastsub=INVALID_SUB;
uint usernum;
uint blocks;
long l,size,misc;
ulong t;
ulong msgs=0;
ulong tmsgs=0;
time_t start;
time_t startsub;
DIR* dir;
DIRENT* dirent;
FILE* qwk;
FILE* fp;
smbmsg_t msg;
str_list_t headers=NULL;
str_list_t ip_can=NULL;
str_list_t host_can=NULL;
str_list_t subject_can=NULL;
str_list_t twit_list=NULL;
const char* hostname;
memset(&msg,0,sizeof(msg));
start=time(NULL);
if((l=(long)flength(packet))<1) {
errormsg(WHERE,ERR_LEN,packet,l);
return(false);
}
delfiles(cfg.temp_dir,ALLFILES);
i=external(cmdstr(cfg.qhub[hubnum]->unpack,packet,ALLFILES,NULL),EX_OFFLINE);
if(i) {
errormsg(WHERE,ERR_EXEC,cmdstr(cfg.qhub[hubnum]->unpack,packet,ALLFILES,NULL),i);
return(false);
}
SAFEPRINTF(str,"%sMESSAGES.DAT",cfg.temp_dir);
if(!fexistcase(str)) {
lprintf(LOG_WARNING,"%s doesn't contain MESSAGES.DAT (%s)",packet,str);
return(false);
}
if((qwk=fnopen(&file,str,O_RDONLY))==NULL) {
errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
return(false);
}
size=(long)filelength(file);
SAFEPRINTF(str,"%sHEADERS.DAT",cfg.temp_dir);
if(fexistcase(str)) {
if((fp=fopen(str,"r")) == NULL)
errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
else {
headers=iniReadFile(fp);
fclose(fp);
}
remove(str);
}
/********************/
/* Process messages */
/********************/
eprintf(LOG_INFO,"Importing QWK Network Packet: %s",packet);
ip_can=trashcan_list(&cfg,"ip");
host_can=trashcan_list(&cfg,"host");
subject_can=trashcan_list(&cfg,"subject");
SAFEPRINTF(fname,"%stwitlist.cfg",cfg.ctrl_dir);
if((fp=fopen(fname,"r"))!=NULL) {
twit_list=strListReadFile(fp,NULL,128);
fclose(fp);
}
for(l=QWK_BLOCK_LEN;l<size;l+=blocks*QWK_BLOCK_LEN) {
if(terminated) {
eprintf(LOG_NOTICE,"!Terminated");
break;
}
fseek(qwk,l,SEEK_SET);
fread(block,QWK_BLOCK_LEN,1,qwk);
if(block[0]<' ' || block[0]&0x80) {
eprintf(LOG_NOTICE,"!Invalid QWK message status (%02X) at offset %lu in %s"
,block[0], l, packet);
blocks=1;
continue;
}
sprintf(tmp,"%.6s",block+116);
blocks=atoi(tmp); /* i = number of blocks */
if(blocks<2) {
eprintf(LOG_NOTICE,"!Invalid number of QWK blocks (%d) at offset %lu in %s"
,blocks, l+116, packet);
blocks=1;
continue;
}
/*********************************/
/* public message on a sub-board */
/*********************************/
n=(uint)block[123]|(((uint)block[124])<<8); /* conference number */
qwk_new_msg(&msg,(char*)block,/* offset: */l,headers,/* parse_sender_hfields: */true);
if(cfg.max_qwkmsgage && msg.hdr.when_written.time < (uint32_t)now
&& (now-msg.hdr.when_written.time)/(24*60*60) > cfg.max_qwkmsgage) {
eprintf(LOG_NOTICE,"!Filtering QWK message from %s due to age: %u days"
,msg.from
,(now-msg.hdr.when_written.time)/(24*60*60));
logline(LOG_NOTICE,"P!",str);
continue;
}
if(findstr_in_list(msg.from_ip,ip_can)) {
eprintf(LOG_NOTICE,"!Filtering QWK message from %s due to blocked IP: %s"
,msg.from
,msg.from_ip);
continue;
}
hostname=getHostNameByAddr(msg.from_host);
if(findstr_in_list(hostname,host_can)) {
eprintf(LOG_NOTICE,"!Filtering QWK message from %s due to blocked hostname: %s"
,msg.from
,hostname);
continue;
}
if(findstr_in_list(msg.subj,subject_can)) {
eprintf(LOG_NOTICE,"!Filtering QWK message from %s due to filtered subject: %s"
,msg.from
,msg.subj);
continue;
}
if(!n) { /* NETMAIL */
eprintf(LOG_INFO,"QWK NetMail from %s to %s", cfg.qhub[hubnum]->id, msg.to);
if(!stricmp(msg.to,"NETMAIL")) { /* QWK to FidoNet NetMail */
qwktonetmail(qwk,(char *)block,NULL,hubnum+1);
continue;
}
if(strchr(msg.to,'@')) {
qwktonetmail(qwk,(char *)block,msg.to,hubnum+1);
continue;
}
usernum=atoi(msg.to);
if(usernum && usernum>lastuser(&cfg))
usernum=0;
if(!usernum)
usernum=matchuser(&cfg,msg.to,TRUE /* sysop_alias */);
if(!usernum) {
eprintf(LOG_NOTICE,"!QWK NetMail from %s to UNKNOWN USER: %s", cfg.qhub[hubnum]->id, msg.to);
continue;
}
getuserrec(&cfg,usernum,U_MISC,8,str);
misc=ahtoul(str);
if(misc&NETMAIL && cfg.sys_misc&SM_FWDTONET) {
getuserrec(&cfg,usernum,U_NETMAIL,LEN_NETMAIL,str);
qwktonetmail(qwk,(char*)block,str,hubnum+1);
continue;
}
smb_stack(&smb,SMB_STACK_PUSH);
sprintf(smb.file,"%smail",cfg.data_dir);
smb.retry_time=cfg.smb_retry_time;
smb.subnum=INVALID_SUB;
if((k=smb_open(&smb))!=0) {
errormsg(WHERE,ERR_OPEN,smb.file,k,smb.last_error);
smb_stack(&smb,SMB_STACK_POP);
continue;
}
if(!filelength(fileno(smb.shd_fp))) {
smb.status.max_crcs=cfg.mail_maxcrcs;
smb.status.max_msgs=0;
smb.status.max_age=cfg.mail_maxage;
smb.status.attr=SMB_EMAIL;
if((k=smb_create(&smb))!=0) {
smb_close(&smb);
errormsg(WHERE,ERR_CREATE,smb.file,k,smb.last_error);
smb_stack(&smb,SMB_STACK_POP);
continue;
}
}
if((k=smb_locksmbhdr(&smb))!=0) {
smb_close(&smb);
errormsg(WHERE,ERR_LOCK,smb.file,k,smb.last_error);
smb_stack(&smb,SMB_STACK_POP);
continue;
}
if((k=smb_getstatus(&smb))!=0) {
smb_close(&smb);
errormsg(WHERE,ERR_READ,smb.file,k,smb.last_error);
smb_stack(&smb,SMB_STACK_POP);
continue;
}
smb_unlocksmbhdr(&smb);
if(qwk_import_msg(qwk,(char *)block,blocks,hubnum+1,INVALID_SUB,usernum,&msg)) {
SAFEPRINTF(str,text[UserSentYouMail],msg.from);
putsmsg(&cfg,usernum,str);
tmsgs++;
}
smb_close(&smb);
smb_stack(&smb,SMB_STACK_POP);
continue;
}
for(j=0;j<cfg.qhub[hubnum]->subs;j++)
if(cfg.qhub[hubnum]->conf[j]==n)
break;
if(j>=cfg.qhub[hubnum]->subs) { /* ignore messages for subs not in config */
eprintf(LOG_NOTICE,"!Message from %s on UNKNOWN QWK CONFERENCE NUMBER: %u"
,cfg.qhub[hubnum]->id, n);
continue;
}
j=cfg.qhub[hubnum]->sub[j];
/* TWIT FILTER */
if(findstr_in_list(msg.from,twit_list) || findstr_in_list(msg.to,twit_list)) {
eprintf(LOG_NOTICE,"!Filtering QWK post from %s to %s on %s %s"
,msg.from
,msg.to
,cfg.grp[cfg.sub[j]->grp]->sname,cfg.sub[j]->lname);
continue;
}
if(j!=lastsub) {
if(msgs) {
t=time(NULL)-startsub;
if(t<1)
t=1;
eprintf(LOG_INFO,"Imported %lu QWK msgs in %lu seconds (%lu msgs/sec)", msgs,t,msgs/t);
}
msgs=0;
startsub=time(NULL);
eprintf(LOG_INFO,"Importing QWK messages from %s into %s %s"
,cfg.qhub[hubnum]->id, cfg.grp[cfg.sub[j]->grp]->sname,cfg.sub[j]->lname);
if(lastsub!=INVALID_SUB)
smb_close(&smb);
lastsub=INVALID_SUB;
sprintf(smb.file,"%s%s",cfg.sub[j]->data_dir,cfg.sub[j]->code);
smb.retry_time=cfg.smb_retry_time;
smb.subnum=j;
if((k=smb_open(&smb))!=0) {
errormsg(WHERE,ERR_OPEN,smb.file,k,smb.last_error);
continue;
}
if(!filelength(fileno(smb.shd_fp))) {
smb.status.max_crcs=cfg.sub[j]->maxcrcs;
smb.status.max_msgs=cfg.sub[j]->maxmsgs;
smb.status.max_age=cfg.sub[j]->maxage;
smb.status.attr=cfg.sub[j]->misc&SUB_HYPER ? SMB_HYPERALLOC :0;
if((k=smb_create(&smb))!=0) {
smb_close(&smb);
errormsg(WHERE,ERR_CREATE,smb.file,k,smb.last_error);
continue;
}
}
if((k=smb_locksmbhdr(&smb))!=0) {
smb_close(&smb);
errormsg(WHERE,ERR_LOCK,smb.file,k,smb.last_error);
continue;
}
if((k=smb_getstatus(&smb))!=0) {
smb_close(&smb);
errormsg(WHERE,ERR_READ,smb.file,k,smb.last_error);
continue;
}
smb_unlocksmbhdr(&smb);
lastsub=j;
}
if(qwk_import_msg(qwk,(char *)block,blocks,hubnum+1,/*subnum: */j,/*touser: */0,&msg)) {
signal_sub_sem(&cfg,j);
msgs++;
tmsgs++;
}
}
update_qwkroute(NULL); /* Write ROUTE.DAT */
smb_freemsgmem(&msg);
fclose(qwk);
iniFreeStringList(headers);
strListFree(&ip_can);
strListFree(&host_can);
strListFree(&subject_can);
strListFree(&twit_list);
if(lastsub!=INVALID_SUB)
smb_close(&smb);
delfiles(cfg.temp_dir,"*.NDX");
SAFEPRINTF(str,"%sMESSAGES.DAT",cfg.temp_dir);
remove(str);
SAFEPRINTF(str,"%sDOOR.ID",cfg.temp_dir);
remove(str);
SAFEPRINTF(str,"%sCONTROL.DAT",cfg.temp_dir);
remove(str);
SAFEPRINTF(str,"%sNETFLAGS.DAT",cfg.temp_dir);
remove(str);
dir=opendir(cfg.temp_dir);
while(dir!=NULL && (dirent=readdir(dir))!=NULL) {
sprintf(str,"%s%s",cfg.temp_dir,dirent->d_name);
if(isdir(str)) /* sub-dir */
continue;
// Create directory if necessary
sprintf(inbox,"%sqnet/%s.in",cfg.data_dir,cfg.qhub[hubnum]->id);
MKDIR(inbox);
// Copy files
sprintf(fname,"%s/%s",inbox,dirent->d_name);
mv(str,fname,1 /* overwrite */);
sprintf(str,text[ReceivedFileViaQWK],dirent->d_name,cfg.qhub[hubnum]->id);
putsmsg(&cfg,1,str);
eprintf(LOG_INFO,"Received %s from %s", dirent->d_name, cfg.qhub[hubnum]->id);
}
if(dir!=NULL)
closedir(dir);
t=time(NULL)-start;
if(tmsgs) {
if(t<1)
t=1;
eprintf(LOG_INFO,"Finished Importing QWK Network Packet from %s: "
"(%lu msgs) in %lu seconds (%lu msgs/sec)"
,cfg.qhub[hubnum]->id, tmsgs, t, tmsgs/t);
/* trigger timed event with internal code of 'qnet-qwk' to run */
sprintf(str,"%sqnet-qwk.now",cfg.data_dir);
ftouch(str);
}
delfiles(cfg.temp_dir,ALLFILES);
return(true);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.