|
|
1.1 root 1: /* un_qwk.cpp */
2:
3: /* Synchronet QWK unpacking routine */
4:
1.1.1.2 ! root 5: /* $Id: un_qwk.cpp,v 1.42 2011/09/21 03:10:53 rswindell Exp $ */
1.1 root 6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
1.1.1.2 ! root 11: * Copyright 2010 Rob Swindell - http://www.synchro.net/copyright.html *
1.1 root 12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: #include "sbbs.h"
39: #include "qwk.h"
40:
41: /****************************************************************************/
42: /* Unpacks .QWK packet, hubnum is the number of the QWK net hub */
43: /****************************************************************************/
44: bool sbbs_t::unpack_qwk(char *packet,uint hubnum)
45: {
46: char str[MAX_PATH+1],fname[MAX_PATH+1];
47: char tmp[512];
48: char inbox[MAX_PATH+1];
49: uchar block[QWK_BLOCK_LEN];
50: int k,file;
51: uint i,j,n,lastsub=INVALID_SUB;
1.1.1.2 ! root 52: uint usernum;
1.1 root 53: uint blocks;
54: long l,size,misc;
55: ulong t;
56: ulong msgs=0;
57: ulong tmsgs=0;
58: time_t start;
59: time_t startsub;
60: DIR* dir;
61: DIRENT* dirent;
62: FILE* qwk;
1.1.1.2 ! root 63: FILE* fp;
! 64: smbmsg_t msg;
! 65: str_list_t headers=NULL;
! 66: str_list_t ip_can=NULL;
! 67: str_list_t host_can=NULL;
! 68: str_list_t subject_can=NULL;
! 69: str_list_t twit_list=NULL;
! 70: const char* hostname;
1.1 root 71:
1.1.1.2 ! root 72: memset(&msg,0,sizeof(msg));
1.1 root 73:
74: start=time(NULL);
1.1.1.2 ! root 75: if((l=(long)flength(packet))<1) {
1.1 root 76: errormsg(WHERE,ERR_LEN,packet,l);
77: return(false);
78: }
1.1.1.2 ! root 79: delfiles(cfg.temp_dir,ALLFILES);
1.1 root 80: i=external(cmdstr(cfg.qhub[hubnum]->unpack,packet,ALLFILES,NULL),EX_OFFLINE);
81: if(i) {
82: errormsg(WHERE,ERR_EXEC,cmdstr(cfg.qhub[hubnum]->unpack,packet,ALLFILES,NULL),i);
83: return(false);
84: }
1.1.1.2 ! root 85: SAFEPRINTF(str,"%sMESSAGES.DAT",cfg.temp_dir);
1.1 root 86: if(!fexistcase(str)) {
1.1.1.2 ! root 87: lprintf(LOG_WARNING,"%s doesn't contain MESSAGES.DAT (%s)",packet,str);
1.1 root 88: return(false);
89: }
90: if((qwk=fnopen(&file,str,O_RDONLY))==NULL) {
91: errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
92: return(false);
93: }
1.1.1.2 ! root 94: size=(long)filelength(file);
! 95:
! 96: SAFEPRINTF(str,"%sHEADERS.DAT",cfg.temp_dir);
! 97: if(fexistcase(str)) {
! 98: if((fp=fopen(str,"r")) == NULL)
! 99: errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
! 100: else {
! 101: headers=iniReadFile(fp);
! 102: fclose(fp);
! 103: }
! 104: remove(str);
! 105: }
! 106:
1.1 root 107: /********************/
108: /* Process messages */
109: /********************/
110: eprintf(LOG_INFO,"Importing QWK Network Packet: %s",packet);
111:
1.1.1.2 ! root 112: ip_can=trashcan_list(&cfg,"ip");
! 113: host_can=trashcan_list(&cfg,"host");
! 114: subject_can=trashcan_list(&cfg,"subject");
! 115:
! 116: SAFEPRINTF(fname,"%stwitlist.cfg",cfg.ctrl_dir);
! 117: if((fp=fopen(fname,"r"))!=NULL) {
! 118: twit_list=strListReadFile(fp,NULL,128);
! 119: fclose(fp);
! 120: }
! 121:
1.1 root 122: for(l=QWK_BLOCK_LEN;l<size;l+=blocks*QWK_BLOCK_LEN) {
123: if(terminated) {
124: eprintf(LOG_NOTICE,"!Terminated");
125: break;
126: }
127: fseek(qwk,l,SEEK_SET);
128: fread(block,QWK_BLOCK_LEN,1,qwk);
129: if(block[0]<' ' || block[0]&0x80) {
1.1.1.2 ! root 130: eprintf(LOG_NOTICE,"!Invalid QWK message status (%02X) at offset %lu in %s"
1.1 root 131: ,block[0], l, packet);
132: blocks=1;
133: continue;
134: }
135: sprintf(tmp,"%.6s",block+116);
136: blocks=atoi(tmp); /* i = number of blocks */
137: if(blocks<2) {
1.1.1.2 ! root 138: eprintf(LOG_NOTICE,"!Invalid number of QWK blocks (%d) at offset %lu in %s"
1.1 root 139: ,blocks, l+116, packet);
140: blocks=1;
141: continue;
142: }
143: /*********************************/
144: /* public message on a sub-board */
145: /*********************************/
146: n=(uint)block[123]|(((uint)block[124])<<8); /* conference number */
147:
1.1.1.2 ! root 148: qwk_new_msg(&msg,(char*)block,/* offset: */l,headers,/* parse_sender_hfields: */true);
! 149:
! 150: if(cfg.max_qwkmsgage && msg.hdr.when_written.time < (uint32_t)now
! 151: && (now-msg.hdr.when_written.time)/(24*60*60) > cfg.max_qwkmsgage) {
! 152: eprintf(LOG_NOTICE,"!Filtering QWK message from %s due to age: %u days"
! 153: ,msg.from
! 154: ,(now-msg.hdr.when_written.time)/(24*60*60));
! 155: logline(LOG_NOTICE,"P!",str);
! 156: continue;
! 157: }
! 158:
! 159: if(findstr_in_list(msg.from_ip,ip_can)) {
! 160: eprintf(LOG_NOTICE,"!Filtering QWK message from %s due to blocked IP: %s"
! 161: ,msg.from
! 162: ,msg.from_ip);
! 163: continue;
! 164: }
! 165:
! 166: hostname=getHostNameByAddr(msg.from_host);
! 167: if(findstr_in_list(hostname,host_can)) {
! 168: eprintf(LOG_NOTICE,"!Filtering QWK message from %s due to blocked hostname: %s"
! 169: ,msg.from
! 170: ,hostname);
! 171: continue;
! 172: }
! 173:
! 174: if(findstr_in_list(msg.subj,subject_can)) {
! 175: eprintf(LOG_NOTICE,"!Filtering QWK message from %s due to filtered subject: %s"
! 176: ,msg.from
! 177: ,msg.subj);
! 178: continue;
! 179: }
! 180:
1.1 root 181: if(!n) { /* NETMAIL */
1.1.1.2 ! root 182: eprintf(LOG_INFO,"QWK NetMail from %s to %s", cfg.qhub[hubnum]->id, msg.to);
! 183: if(!stricmp(msg.to,"NETMAIL")) { /* QWK to FidoNet NetMail */
1.1 root 184: qwktonetmail(qwk,(char *)block,NULL,hubnum+1);
185: continue;
186: }
1.1.1.2 ! root 187: if(strchr(msg.to,'@')) {
! 188: qwktonetmail(qwk,(char *)block,msg.to,hubnum+1);
1.1 root 189: continue;
190: }
1.1.1.2 ! root 191: usernum=atoi(msg.to);
! 192: if(usernum && usernum>lastuser(&cfg))
! 193: usernum=0;
! 194: if(!usernum)
! 195: usernum=matchuser(&cfg,msg.to,TRUE /* sysop_alias */);
! 196: if(!usernum) {
! 197: eprintf(LOG_NOTICE,"!QWK NetMail from %s to UNKNOWN USER: %s", cfg.qhub[hubnum]->id, msg.to);
1.1 root 198: continue;
199: }
200:
1.1.1.2 ! root 201: getuserrec(&cfg,usernum,U_MISC,8,str);
1.1 root 202: misc=ahtoul(str);
203: if(misc&NETMAIL && cfg.sys_misc&SM_FWDTONET) {
1.1.1.2 ! root 204: getuserrec(&cfg,usernum,U_NETMAIL,LEN_NETMAIL,str);
1.1 root 205: qwktonetmail(qwk,(char*)block,str,hubnum+1);
206: continue;
207: }
208:
209: smb_stack(&smb,SMB_STACK_PUSH);
210: sprintf(smb.file,"%smail",cfg.data_dir);
211: smb.retry_time=cfg.smb_retry_time;
212: smb.subnum=INVALID_SUB;
213: if((k=smb_open(&smb))!=0) {
214: errormsg(WHERE,ERR_OPEN,smb.file,k,smb.last_error);
215: smb_stack(&smb,SMB_STACK_POP);
216: continue;
217: }
218: if(!filelength(fileno(smb.shd_fp))) {
219: smb.status.max_crcs=cfg.mail_maxcrcs;
220: smb.status.max_msgs=0;
221: smb.status.max_age=cfg.mail_maxage;
222: smb.status.attr=SMB_EMAIL;
223: if((k=smb_create(&smb))!=0) {
224: smb_close(&smb);
1.1.1.2 ! root 225: errormsg(WHERE,ERR_CREATE,smb.file,k,smb.last_error);
1.1 root 226: smb_stack(&smb,SMB_STACK_POP);
227: continue;
228: }
229: }
230: if((k=smb_locksmbhdr(&smb))!=0) {
231: smb_close(&smb);
1.1.1.2 ! root 232: errormsg(WHERE,ERR_LOCK,smb.file,k,smb.last_error);
1.1 root 233: smb_stack(&smb,SMB_STACK_POP);
234: continue;
235: }
236: if((k=smb_getstatus(&smb))!=0) {
237: smb_close(&smb);
1.1.1.2 ! root 238: errormsg(WHERE,ERR_READ,smb.file,k,smb.last_error);
1.1 root 239: smb_stack(&smb,SMB_STACK_POP);
240: continue;
241: }
242: smb_unlocksmbhdr(&smb);
1.1.1.2 ! root 243: if(qwk_import_msg(qwk,(char *)block,blocks,hubnum+1,INVALID_SUB,usernum,&msg)) {
! 244: SAFEPRINTF(str,text[UserSentYouMail],msg.from);
! 245: putsmsg(&cfg,usernum,str);
1.1 root 246: tmsgs++;
247: }
248: smb_close(&smb);
249: smb_stack(&smb,SMB_STACK_POP);
250: continue;
251: }
252:
253: for(j=0;j<cfg.qhub[hubnum]->subs;j++)
254: if(cfg.qhub[hubnum]->conf[j]==n)
255: break;
256: if(j>=cfg.qhub[hubnum]->subs) { /* ignore messages for subs not in config */
1.1.1.2 ! root 257: eprintf(LOG_NOTICE,"!Message from %s on UNKNOWN QWK CONFERENCE NUMBER: %u"
1.1 root 258: ,cfg.qhub[hubnum]->id, n);
259: continue;
260: }
261:
262: j=cfg.qhub[hubnum]->sub[j];
263:
264: /* TWIT FILTER */
1.1.1.2 ! root 265: if(findstr_in_list(msg.from,twit_list) || findstr_in_list(msg.to,twit_list)) {
! 266: eprintf(LOG_NOTICE,"!Filtering QWK post from %s to %s on %s %s"
! 267: ,msg.from
! 268: ,msg.to
! 269: ,cfg.grp[cfg.sub[j]->grp]->sname,cfg.sub[j]->lname);
! 270: continue;
1.1 root 271: }
272:
273: if(j!=lastsub) {
274:
275: if(msgs) {
276: t=time(NULL)-startsub;
277: if(t<1)
278: t=1;
1.1.1.2 ! root 279: eprintf(LOG_INFO,"Imported %lu QWK msgs in %lu seconds (%lu msgs/sec)", msgs,t,msgs/t);
1.1 root 280: }
281: msgs=0;
282: startsub=time(NULL);
283:
1.1.1.2 ! root 284: eprintf(LOG_INFO,"Importing QWK messages from %s into %s %s"
1.1 root 285: ,cfg.qhub[hubnum]->id, cfg.grp[cfg.sub[j]->grp]->sname,cfg.sub[j]->lname);
286:
287: if(lastsub!=INVALID_SUB)
288: smb_close(&smb);
289: lastsub=INVALID_SUB;
290: sprintf(smb.file,"%s%s",cfg.sub[j]->data_dir,cfg.sub[j]->code);
291: smb.retry_time=cfg.smb_retry_time;
292: smb.subnum=j;
293: if((k=smb_open(&smb))!=0) {
294: errormsg(WHERE,ERR_OPEN,smb.file,k,smb.last_error);
295: continue;
296: }
297: if(!filelength(fileno(smb.shd_fp))) {
298: smb.status.max_crcs=cfg.sub[j]->maxcrcs;
299: smb.status.max_msgs=cfg.sub[j]->maxmsgs;
300: smb.status.max_age=cfg.sub[j]->maxage;
301: smb.status.attr=cfg.sub[j]->misc&SUB_HYPER ? SMB_HYPERALLOC :0;
302: if((k=smb_create(&smb))!=0) {
303: smb_close(&smb);
1.1.1.2 ! root 304: errormsg(WHERE,ERR_CREATE,smb.file,k,smb.last_error);
1.1 root 305: continue;
306: }
307: }
308: if((k=smb_locksmbhdr(&smb))!=0) {
309: smb_close(&smb);
1.1.1.2 ! root 310: errormsg(WHERE,ERR_LOCK,smb.file,k,smb.last_error);
1.1 root 311: continue;
312: }
313: if((k=smb_getstatus(&smb))!=0) {
314: smb_close(&smb);
1.1.1.2 ! root 315: errormsg(WHERE,ERR_READ,smb.file,k,smb.last_error);
1.1 root 316: continue;
317: }
318: smb_unlocksmbhdr(&smb);
319: lastsub=j;
320: }
321:
1.1.1.2 ! root 322: if(qwk_import_msg(qwk,(char *)block,blocks,hubnum+1,/*subnum: */j,/*touser: */0,&msg)) {
! 323: signal_sub_sem(&cfg,j);
! 324: msgs++;
! 325: tmsgs++;
1.1 root 326: }
327: }
328:
329: update_qwkroute(NULL); /* Write ROUTE.DAT */
330:
1.1.1.2 ! root 331: smb_freemsgmem(&msg);
1.1 root 332: fclose(qwk);
1.1.1.2 ! root 333:
! 334: iniFreeStringList(headers);
! 335:
! 336: strListFree(&ip_can);
! 337: strListFree(&host_can);
! 338: strListFree(&subject_can);
! 339: strListFree(&twit_list);
! 340:
1.1 root 341: if(lastsub!=INVALID_SUB)
342: smb_close(&smb);
343:
344: delfiles(cfg.temp_dir,"*.NDX");
1.1.1.2 ! root 345: SAFEPRINTF(str,"%sMESSAGES.DAT",cfg.temp_dir);
1.1 root 346: remove(str);
1.1.1.2 ! root 347: SAFEPRINTF(str,"%sDOOR.ID",cfg.temp_dir);
1.1 root 348: remove(str);
1.1.1.2 ! root 349: SAFEPRINTF(str,"%sCONTROL.DAT",cfg.temp_dir);
1.1 root 350: remove(str);
1.1.1.2 ! root 351: SAFEPRINTF(str,"%sNETFLAGS.DAT",cfg.temp_dir);
1.1 root 352: remove(str);
353:
354: dir=opendir(cfg.temp_dir);
355: while(dir!=NULL && (dirent=readdir(dir))!=NULL) {
356: sprintf(str,"%s%s",cfg.temp_dir,dirent->d_name);
357: if(isdir(str)) /* sub-dir */
358: continue;
359:
360: // Create directory if necessary
361: sprintf(inbox,"%sqnet/%s.in",cfg.data_dir,cfg.qhub[hubnum]->id);
362: MKDIR(inbox);
363:
364: // Copy files
365: sprintf(fname,"%s/%s",inbox,dirent->d_name);
366: mv(str,fname,1 /* overwrite */);
367: sprintf(str,text[ReceivedFileViaQWK],dirent->d_name,cfg.qhub[hubnum]->id);
368: putsmsg(&cfg,1,str);
369: eprintf(LOG_INFO,"Received %s from %s", dirent->d_name, cfg.qhub[hubnum]->id);
370: }
371: if(dir!=NULL)
372: closedir(dir);
373:
374: t=time(NULL)-start;
375: if(tmsgs) {
376: if(t<1)
377: t=1;
378: eprintf(LOG_INFO,"Finished Importing QWK Network Packet from %s: "
379: "(%lu msgs) in %lu seconds (%lu msgs/sec)"
380: ,cfg.qhub[hubnum]->id, tmsgs, t, tmsgs/t);
1.1.1.2 ! root 381: /* trigger timed event with internal code of 'qnet-qwk' to run */
! 382: sprintf(str,"%sqnet-qwk.now",cfg.data_dir);
! 383: ftouch(str);
1.1 root 384: }
385: delfiles(cfg.temp_dir,ALLFILES);
386: return(true);
387: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.