|
|
3.15b
/* un_rep.cpp */
/* Synchronet QWK replay (REP) packet unpacking routine */
/* $Id: un_rep.cpp,v 1.1.1.2 2018/04/24 16:42:33 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 2011 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"
/****************************************************************************/
/* Convert a QWK conference number into a sub-board offset */
/* Return INVALID_SUB upon failure to convert */
/****************************************************************************/
uint sbbs_t::resolve_qwkconf(uint n)
{
uint j,k;
for (j=0;j<usrgrps;j++) {
for(k=0;k<usrsubs[j];k++)
if(cfg.sub[usrsub[j][k]]->qwkconf==n)
break;
if(k<usrsubs[j])
break;
}
if(j>=usrgrps) {
if(n<1000) { /* version 1 method, start at 101 */
j=n/100;
k=n-(j*100);
}
else { /* version 2 method, start at 1001 */
j=n/1000;
k=n-(j*1000);
}
j--; /* j is group */
k--; /* k is sub */
if(j>=usrgrps || k>=usrsubs[j] || cfg.sub[usrsub[j][k]]->qwkconf)
return INVALID_SUB;
}
return usrsub[j][k];
}
/****************************************************************************/
/* Unpacks .REP packet, 'repname' is the path and filename of the packet */
/****************************************************************************/
bool sbbs_t::unpack_rep(char* repfile)
{
char str[MAX_PATH+1],fname[MAX_PATH+1];
char rep_fname[MAX_PATH+1];
char msg_fname[MAX_PATH+1];
char tmp[512];
char inbox[MAX_PATH+1];
char block[QWK_BLOCK_LEN];
int file;
uint i,j,k,lastsub=INVALID_SUB;
uint blocks;
uint usernum;
long l,size,misc;
ulong n;
ulong ex;
node_t node;
FILE* rep;
FILE* fp;
DIR* dir;
DIRENT* dirent;
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;
const char* AttemptedToUploadREPpacket="Attempted to upload REP packet";
memset(&msg,0,sizeof(msg));
if(repfile!=NULL) {
delfiles(cfg.temp_dir,ALLFILES);
SAFECOPY(rep_fname,repfile);
} else
SAFEPRINTF2(rep_fname,"%s%s.rep",cfg.temp_dir,cfg.sys_id);
if(!fexistcase(rep_fname)) {
bputs(text[QWKReplyNotReceived]);
logline(LOG_NOTICE,"U!",AttemptedToUploadREPpacket);
logline(LOG_NOTICE,nulstr,"REP file not received");
return(false);
}
for(k=0;k<cfg.total_fextrs;k++)
if(!stricmp(cfg.fextr[k]->ext,useron.tmpext) && chk_ar(cfg.fextr[k]->ar,&useron,&client))
break;
if(k>=cfg.total_fextrs)
k=0;
ex=EX_STDOUT;
if(online!=ON_REMOTE)
ex|=EX_OFFLINE;
i=external(cmdstr(cfg.fextr[k]->cmd,rep_fname,ALLFILES,NULL),ex);
if(i) {
bputs(text[QWKExtractionFailed]);
logline(LOG_NOTICE,"U!",AttemptedToUploadREPpacket);
logline(LOG_NOTICE,nulstr,"Extraction failed");
return(false);
}
SAFEPRINTF2(msg_fname,"%s%s.msg",cfg.temp_dir,cfg.sys_id);
if(!fexistcase(msg_fname)) {
bputs(text[QWKReplyNotReceived]);
logline(LOG_NOTICE,"U!",AttemptedToUploadREPpacket);
logline(LOG_NOTICE,nulstr,"MSG file not received");
return(false);
}
if((rep=fnopen(&file,msg_fname,O_RDONLY))==NULL) {
errormsg(WHERE,ERR_OPEN,msg_fname,O_RDONLY);
return(false);
}
size=(long)filelength(file);
SAFEPRINTF(fname,"%sHEADERS.DAT",cfg.temp_dir);
if(fexistcase(fname)) {
FILE* fp;
set_qwk_flag(QWK_HEADERS);
if((fp=fopen(fname,"r")) == NULL)
errormsg(WHERE,ERR_OPEN,fname,0);
else {
headers=iniReadFile(fp);
fclose(fp);
}
remove(fname);
}
fread(block,QWK_BLOCK_LEN,1,rep);
if(strnicmp((char *)block,cfg.sys_id,strlen(cfg.sys_id))) {
if(headers!=NULL)
iniFreeStringList(headers);
fclose(rep);
bputs(text[QWKReplyNotReceived]);
logline(LOG_NOTICE,"U!",AttemptedToUploadREPpacket);
logline(LOG_NOTICE,nulstr,"Incorrect QWK BBS ID");
return(false);
}
logline("U+","Uploaded REP packet");
/********************/
/* Process messages */
/********************/
bputs(text[QWKUnpacking]);
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);
}
now=time(NULL);
for(l=QWK_BLOCK_LEN;l<size;l+=blocks*QWK_BLOCK_LEN) {
if(terminated) {
bprintf("!Terminated");
break;
}
lncntr=0; /* defeat pause */
if(fseek(rep,l,SEEK_SET)!=0) {
errormsg(WHERE,ERR_SEEK,msg_fname,l);
break;
}
if(fread(block,1,QWK_BLOCK_LEN,rep)!=QWK_BLOCK_LEN) {
errormsg(WHERE,ERR_READ,msg_fname,(long)ftell(rep));
break;
}
sprintf(tmp,"%.6s",block+116);
blocks=atoi(tmp); /* i = number of blocks */
if(blocks<2) {
SAFEPRINTF3(str,"%s blocks (read '%s' at offset %ld)", msg_fname, tmp, l);
errormsg(WHERE,ERR_CHK,str,blocks);
blocks=1;
continue;
}
qwk_new_msg(&msg, block, /* offset: */l, headers, /* parse_sender_hfields: */useron.rest&FLAG('Q') ? true:false);
if(cfg.max_qwkmsgage && msg.hdr.when_written.time < (uint32_t)now
&& (now-msg.hdr.when_written.time)/(24*60*60) > cfg.max_qwkmsgage) {
SAFEPRINTF2(str,"!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)) {
SAFEPRINTF2(str,"!Filtering QWK message from %s due to blocked IP: %s"
,msg.from
,msg.from_ip);
logline(LOG_NOTICE,"P!",str);
continue;
}
hostname = getHostNameByAddr(msg.from_host);
if(findstr_in_list(hostname,host_can)) {
SAFEPRINTF2(str,"!Filtering QWK message from %s due to blocked hostname: %s"
,msg.from
,hostname);
logline(LOG_NOTICE,"P!",str);
continue;
}
if(findstr_in_list(msg.subj,subject_can)) {
SAFEPRINTF2(str,"!Filtering QWK message from %s due to filtered subject: %s"
,msg.from
,msg.subj);
logline(LOG_NOTICE,"P!",str);
continue;
}
if(atoi(block+1)==0) { /**********/
if(useron.rest&FLAG('E')) { /* E-mail */
bputs(text[R_Email]); /**********/
continue;
}
if(msg.to!=NULL) {
if(stricmp(msg.to,"NETMAIL")==0) { /* QWK to FidoNet NetMail */
qwktonetmail(rep,block,NULL,0);
continue;
}
if(strchr(msg.to,'@')) {
qwktonetmail(rep,block,msg.to,0);
continue;
}
if(!stricmp(msg.to,"SBBS")) { /* to SBBS, config stuff */
qwkcfgline(msg.subj,INVALID_SUB);
continue;
}
}
if(useron.etoday>=cfg.level_emailperday[useron.level] && !(useron.exempt&FLAG('M'))
&& !(useron.rest&FLAG('Q'))) {
bputs(text[TooManyEmailsToday]);
continue;
}
usernum=0;
if(msg.to!=NULL) {
usernum=atoi(msg.to);
if(usernum>lastuser(&cfg))
usernum=0;
if(!usernum)
usernum=matchuser(&cfg,msg.to,TRUE /* sysop_alias */);
}
if(!usernum) {
bputs(text[UnknownUser]);
continue;
}
if(usernum==1 && useron.rest&FLAG('S')) {
bprintf(text[R_Feedback],cfg.sys_op);
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(rep,block,str,0);
continue;
}
SAFEPRINTF(smb.file,"%smail",cfg.data_dir);
smb.retry_time=cfg.smb_retry_time;
if(lastsub!=INVALID_SUB) {
smb_close(&smb);
lastsub=INVALID_SUB;
}
smb.subnum=INVALID_SUB;
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.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);
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);
if(qwk_import_msg(rep, block, blocks
,/* fromhub: */0,/* subnum: */INVALID_SUB,/* touser: */usernum,&msg)) {
if(usernum==1) {
useron.fbacks++;
logon_fbacks++;
putuserrec(&cfg,useron.number,U_FBACKS,5
,ultoa(useron.fbacks,tmp,10));
}
else {
useron.emails++;
logon_emails++;
putuserrec(&cfg,useron.number,U_EMAILS,5
,ultoa(useron.emails,tmp,10));
}
useron.etoday++;
putuserrec(&cfg,useron.number,U_ETODAY,5
,ultoa(useron.etoday,tmp,10));
bprintf(text[Emailed],username(&cfg,usernum,tmp),usernum);
SAFEPRINTF3(str,"%s sent QWK e-mail to %s #%d"
,useron.alias,username(&cfg,usernum,tmp),usernum);
logline("E+",str);
if(cfg.node_num) {
for(k=1;k<=cfg.sys_nodes;k++) { /* Tell user, if online */
getnodedat(k,&node,0);
if(node.useron==usernum && !(node.misc&NODE_POFF)
&& (node.status==NODE_INUSE
|| node.status==NODE_QUIET)) {
SAFEPRINTF2(str,text[EmailNodeMsg]
,cfg.node_num,msg.from);
putnmsg(&cfg,k,str);
break;
}
}
}
if(cfg.node_num==0 || k>cfg.sys_nodes) {
SAFEPRINTF(str,text[UserSentYouMail],msg.from);
putsmsg(&cfg,usernum,str);
}
}
smb_close(&smb);
} /* end of email */
/**************************/
else { /* message on a sub-board */
/**************************/
n=resolve_qwkconf(atol((char *)block+1)); /* conference number */
if(n==INVALID_SUB) {
bprintf(text[QWKInvalidConferenceN],n);
SAFEPRINTF2(str,"%s: Invalid QWK conference number %lu",useron.alias,n);
logline(LOG_NOTICE,"P!",str);
continue;
}
/* if posting, add to new-scan config for QWKnet nodes automatically */
if(useron.rest&FLAG('Q'))
subscan[n].cfg|=SUB_CFG_NSCAN;
if(msg.to!=NULL) {
if(stricmp(msg.to,"SBBS")==0) { /* to SBBS, config stuff */
qwkcfgline(msg.subj,n);
continue;
}
}
#if 0 /* This stuff isn't really necessary anymore */
if(!SYSOP && cfg.sub[n]->misc&SUB_QNET) { /* QWK Netted */
sprintf(str,"%-25.25s","DROP"); /* Drop from new-scan? */
if(!strnicmp((char *)block+71,str,25)) /* don't allow post */
continue;
sprintf(str,"%-25.25s","ADD"); /* Add to new-scan? */
if(!strnicmp((char *)block+71,str,25)) /* don't allow post */
continue;
}
#endif
if(useron.rest&FLAG('Q') && !(cfg.sub[n]->misc&SUB_QNET)) {
bputs(text[CantPostOnSub]);
logline(LOG_NOTICE,"P!","Attempted to post QWK message on non-QWKnet sub");
continue;
}
if(useron.rest&FLAG('P')) {
bputs(text[R_Post]);
logline(LOG_NOTICE,"P!","QWK Post attempted");
continue;
}
if(useron.ptoday>=cfg.level_postsperday[useron.level]
&& !(useron.rest&FLAG('Q'))) {
bputs(text[TooManyPostsToday]);
continue;
}
if(useron.rest&FLAG('N')
&& cfg.sub[n]->misc&(SUB_FIDO|SUB_PNET|SUB_QNET|SUB_INET)) {
bputs(text[CantPostOnSub]);
logline(LOG_NOTICE,"P!","QWK Networked post attempted");
continue;
}
if(!chk_ar(cfg.sub[n]->post_ar,&useron,&client)) {
bputs(text[CantPostOnSub]);
logline(LOG_NOTICE,"P!","QWK Post attempted");
continue;
}
if((block[0]=='*' || block[0]=='+')
&& !(cfg.sub[n]->misc&SUB_PRIV)) {
bputs(text[PrivatePostsNotAllowed]);
logline(LOG_NOTICE,"P!","QWK Private post attempt");
continue;
}
if(block[0]=='*' || block[0]=='+' /* Private post */
|| cfg.sub[n]->misc&SUB_PONLY) {
if(msg.to==NULL || !msg.to[0]
|| stricmp(msg.to,"All")==0) { /* to blank */
bputs(text[NoToUser]); /* or all */
continue;
}
}
#if 0 /* This stuff isn't really necessary anymore */
if(!SYSOP && !(useron.rest&FLAG('Q'))) {
sprintf(str,"%-25.25s","SYSOP");
if(!strnicmp((char *)block+21,str,25)) {
sprintf(str,"%-25.25s",username(&cfg,1,tmp));
memcpy((char *)block+21,str,25); /* change from sysop */
} /* to user name */
}
#endif
/* TWIT FILTER */
if(findstr_in_list(msg.from,twit_list) || findstr_in_list(msg.to,twit_list)) {
SAFEPRINTF4(str,"!Filtering QWK post from %s to %s on %s %s"
,msg.from
,msg.to
,cfg.grp[cfg.sub[n]->grp]->sname,cfg.sub[n]->lname);
logline(LOG_NOTICE,"P!",str);
continue;
}
if(n!=lastsub) {
if(lastsub!=INVALID_SUB)
smb_close(&smb);
lastsub=INVALID_SUB;
SAFEPRINTF2(smb.file,"%s%s",cfg.sub[n]->data_dir,cfg.sub[n]->code);
smb.retry_time=cfg.smb_retry_time;
smb.subnum=n;
if((j=smb_open(&smb))!=0) {
errormsg(WHERE,ERR_OPEN,smb.file,j,smb.last_error);
continue;
}
if(!filelength(fileno(smb.shd_fp))) {
smb.status.max_crcs=cfg.sub[n]->maxcrcs;
smb.status.max_msgs=cfg.sub[n]->maxmsgs;
smb.status.max_age=cfg.sub[n]->maxage;
smb.status.attr=cfg.sub[n]->misc&SUB_HYPER ? SMB_HYPERALLOC:0;
if((j=smb_create(&smb))!=0) {
smb_close(&smb);
lastsub=INVALID_SUB;
errormsg(WHERE,ERR_CREATE,smb.file,j,smb.last_error);
continue;
}
}
if((j=smb_locksmbhdr(&smb))!=0) {
smb_close(&smb);
lastsub=INVALID_SUB;
errormsg(WHERE,ERR_LOCK,smb.file,j,smb.last_error);
continue;
}
if((j=smb_getstatus(&smb))!=0) {
smb_close(&smb);
lastsub=INVALID_SUB;
errormsg(WHERE,ERR_READ,smb.file,j,smb.last_error);
continue;
}
smb_unlocksmbhdr(&smb);
lastsub=n;
}
if(qwk_import_msg(rep, block, blocks
,/* fromhub: */0,/* subnum: */n,/* touser: */0,&msg)) {
logon_posts++;
user_posted_msg(&cfg, &useron, 1);
bprintf(text[Posted],cfg.grp[cfg.sub[n]->grp]->sname
,cfg.sub[n]->lname);
SAFEPRINTF3(str,"%s posted QWK message on %s %s"
,useron.alias,cfg.grp[cfg.sub[n]->grp]->sname,cfg.sub[n]->lname);
signal_sub_sem(&cfg,n);
logline("P+",str);
if(!(useron.rest&FLAG('Q')))
user_event(EVENT_POST);
}
} /* end of public message */
}
update_qwkroute(NULL); /* Write ROUTE.DAT */
iniFreeStringList(headers);
strListFree(&ip_can);
strListFree(&host_can);
strListFree(&subject_can);
strListFree(&twit_list);
if(lastsub!=INVALID_SUB)
smb_close(&smb);
fclose(rep);
/* QWKE support */
SAFEPRINTF(fname,"%sTODOOR.EXT",cfg.temp_dir);
if(fexistcase(fname)) {
useron.qwk|=QWK_EXT;
FILE* fp=fopen(fname,"r");
char* p;
if(fp!=NULL) {
while(!feof(fp)) {
if(!fgets(str,sizeof(str)-1,fp))
break;
if(strnicmp(str,"AREA ",5)==0) {
p=str+5;
SKIP_WHITESPACE(p);
if((n=resolve_qwkconf(atoi(p))) != INVALID_SUB) {
FIND_WHITESPACE(p);
SKIP_WHITESPACE(p);
if(strchr(p,'D'))
subscan[n].cfg&=~SUB_CFG_NSCAN;
else if(strchr(p,'a') || strchr(p,'g'))
subscan[n].cfg|=SUB_CFG_NSCAN;
else if(strchr(p,'p'))
subscan[n].cfg|=SUB_CFG_NSCAN|SUB_CFG_YSCAN;
}
continue;
}
if(strnicmp(str,"RESET ",6)==0) {
p=str+6;
SKIP_WHITESPACE(p);
if((n=resolve_qwkconf(atoi(p))) != INVALID_SUB) {
FIND_WHITESPACE(p);
SKIP_WHITESPACE(p);
/* If the [#ofmessages] is blank then the pointer should be set back to the start of the message base */
if(*p==0)
subscan[n].ptr=0;
else {
/* otherwise it should be set back [#ofmessages] back from the end of the message base. */
uint32_t last=0;
getlastmsg(n,&last,/* time_t* */NULL);
l=last-atol(p);
if(l<0)
l=0;
subscan[n].ptr=l;
}
}
}
}
fclose(fp);
}
}
if(useron.rest&FLAG('Q')) { /* QWK Net Node */
if(fexistcase(msg_fname))
remove(msg_fname);
if(fexistcase(rep_fname))
remove(rep_fname);
SAFEPRINTF(fname,"%sATTXREF.DAT",cfg.temp_dir);
if(fexistcase(fname))
remove(fname);
dir=opendir(cfg.temp_dir);
while(dir!=NULL && (dirent=readdir(dir))!=NULL) { /* Extra files */
// Move files
SAFEPRINTF2(str,"%s%s",cfg.temp_dir,dirent->d_name);
if(isdir(str))
continue;
// Create directory if necessary
SAFEPRINTF2(inbox,"%sqnet/%s.in",cfg.data_dir,useron.alias);
MKDIR(inbox);
SAFEPRINTF2(fname,"%s/%s",inbox,dirent->d_name);
mv(str,fname,1);
SAFEPRINTF2(str,text[ReceivedFileViaQWK],dirent->d_name,useron.alias);
putsmsg(&cfg,1,str);
}
if(dir!=NULL)
closedir(dir);
SAFEPRINTF(fname,"%sqnet-rep.now",cfg.data_dir);
ftouch(fname);
}
bputs(text[QWKUnpacked]);
CRLF;
/**********************************************/
/* Hang-up now if that's what the user wanted */
/**********************************************/
autohangup();
return(true);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.