|
|
1.1 root 1: /* QWKNODES.C */
2:
3: /* Synchronet QWKnet node list or route.dat file generator */
4:
1.1.1.2 ! root 5: /* $Id: qwknodes.c,v 1.12 2003/07/11 07:58:47 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: * *
11: * Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html *
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 "crc32.h"
40:
41: unsigned _stklen=10000;
42: smb_t smb;
43: scfg_t cfg;
44:
45: /****************************************************************************/
46: /* Updates 16-bit "rcrc" with character 'ch' */
47: /****************************************************************************/
48: void ucrc16(uchar ch, ushort *rcrc) {
49: ushort i, cy;
50: uchar nch=ch;
51:
52: for (i=0; i<8; i++) {
53: cy=*rcrc & 0x8000;
54: *rcrc<<=1;
55: if (nch & 0x80) *rcrc |= 1;
56: nch<<=1;
57: if (cy) *rcrc ^= 0x1021; }
58: }
59:
60: /****************************************************************************/
61: /* Returns 16-crc of string (not counting terminating NULL) */
62: /****************************************************************************/
63: ushort crc16(char *str)
64: {
65: int i=0;
66: ushort crc=0;
67:
68: ucrc16(0,&crc);
69: while(str[i])
70: ucrc16(str[i++],&crc);
71: ucrc16(0,&crc);
72: ucrc16(0,&crc);
73: return(crc);
74: }
75:
76: /****************************************************************************/
77: /* Returns 32-crc of string (not counting terminating NULL) */
78: /****************************************************************************/
79: ulong _crc32(char *str)
80: {
81: int i=0;
82: ulong crc=0xffffffffUL;
83:
84: while(str[i])
85: crc=ucrc32(str[i++],crc);
86: crc=~crc;
87: return(crc);
88: }
89:
90: /****************************************************************************/
91: /* Converts unix time format (long - time_t) into a char str MM/DD/YY */
92: /****************************************************************************/
93: char * unixtodstr(time_t unix, char *str)
94: {
95: struct tm* tm;
96:
97: if(!unix)
98: strcpy(str,"00/00/00");
99: else {
1.1.1.2 ! root 100: tm=localtime(&unix);
1.1 root 101: if(tm==NULL) {
102: strcpy(str,"00/00/00");
103: return(str);
104: }
105: if(tm->tm_mon>11) { /* DOS leap year bug */
106: tm->tm_mon=0;
107: tm->tm_year++; }
108: if(tm->tm_mday>31)
109: tm->tm_mday=1;
110: if(cfg.sys_misc&SM_EURODATE)
111: sprintf(str,"%02u/%02u/%02u",tm->tm_mday,tm->tm_mon+1
112: ,TM_YEAR(tm->tm_year));
113: else
114: sprintf(str,"%02u/%02u/%02u",tm->tm_mon+1,tm->tm_mday
115: ,TM_YEAR(tm->tm_year)); }
116: return(str);
117: }
118:
119: /****************************************************************************/
120: /* Puts a backslash on path strings */
121: /****************************************************************************/
122: void backslash(char *str)
123: {
124: int i;
125:
126: i=strlen(str);
127: if(i && str[i-1]!='\\') {
128: str[i]='\\'; str[i+1]=0; }
129: }
130: /****************************************************************************/
131: /* Network open function. Opens all files DENYALL and retries LOOP_NOPEN */
132: /* number of times if the attempted file is already open or denying access */
133: /* for some other reason. All files are opened in BINARY mode. */
134: /****************************************************************************/
135: int nopen(char *str, int access)
136: {
137: int file,share,count=0;
138:
139: if(access==O_RDONLY) share=SH_DENYWR;
140: else share=SH_DENYRW;
141: while(((file=sopen(str,O_BINARY|access,share,S_IWRITE))==-1)
1.1.1.2 ! root 142: && (errno==EACCES errno==EAGAIN) && count++<LOOP_NOPEN);
! 143: if(file==-1 && (errno==EACCES || errno==EAGAIN))
1.1 root 144: lputs("\7\r\nNOPEN: ACCESS DENIED\r\n\7");
145: return(file);
146: }
147: /****************************************************************************/
148: /* This function performs an nopen, but returns a file stream with a buffer */
149: /* allocated. */
150: /****************************************************************************/
151: FILE *fnopen(int *file, char *str, int access)
152: {
153: char mode[128];
154: FILE *stream;
155:
156: if(((*file)=nopen(str,access))==-1)
157: return(NULL);
158:
159: if(access&O_APPEND) {
160: if(access&O_RDONLY)
161: strcpy(mode,"a+");
162: else
163: strcpy(mode,"a"); }
164: else {
165: if(access&O_WRONLY)
166: strcpy(mode,"r+");
167: else
168: strcpy(mode,"r"); }
169: stream=fdopen((*file),mode);
170: if(stream==NULL) {
171: close(*file);
172: return(NULL); }
173: setvbuf(stream,NULL,_IOFBF,16*1024);
174: return(stream);
175: }
176:
177: /****************************************************************************/
178: /* Truncates white-space chars off end of 'str' and terminates at first tab */
179: /****************************************************************************/
180: void truncsp(char *str)
181: {
182: uchar c;
183:
184: c=strlen(str);
185: while(c && (uchar)str[c-1]<=SP) c--;
186: str[c]=0;
187: }
188:
189: void stripctrla(uchar *str)
190: {
191: uchar out[256];
192: int i,j;
193:
194: for(i=j=0;str[i];i++) {
1.1.1.2 ! root 195: if(str[i]==CTRL_A && str[i+1]!=0)
1.1 root 196: i++;
197: else
198: out[j++]=str[i]; }
199: out[j]=0;
200: strcpy(str,out);
201: }
202:
203:
1.1.1.2 ! root 204: int lputs(char* str)
1.1 root 205: {
206: char tmp[256];
207: int i,j,k;
208:
209: j=strlen(str);
210: for(i=k=0;i<j;i++) /* remove CRs */
211: if(str[i]==CR && str[i+1]==LF)
212: continue;
213: else
214: tmp[k++]=str[i];
215: tmp[k]=0;
216: return(fputs(tmp,stderr));
217: }
218: /****************************************************************************/
219: /* Performs printf() through local assembly routines */
220: /* Called from everywhere */
221: /****************************************************************************/
222: int lprintf(char *fmat, ...)
223: {
224: va_list argptr;
225: char sbuf[256];
226: int chcount;
227:
1.1.1.2 ! root 228: va_start(argptr,fmat);
! 229: chcount=vsnprintf(sbuf,sizeof(sbuf),fmat,argptr);
! 230: sbuf[sizeof(sbuf)-1]=0;
! 231: va_end(argptr);
! 232: lputs(sbuf);
! 233: return(chcount);
1.1 root 234: }
235: void bail(int code)
236: {
1.1.1.2 ! root 237: exit(code);
1.1 root 238: }
239:
240:
241: char *loadmsgtail(smbmsg_t msg)
242: {
243: char *buf=NULL;
244: ushort xlat;
245: int i;
246: long l=0,length;
247:
248: for(i=0;i<msg.hdr.total_dfields;i++) {
249: if(msg.dfield[i].type!=TEXT_TAIL)
250: continue;
251: fseek(smb.sdt_fp,msg.hdr.offset+msg.dfield[i].offset
252: ,SEEK_SET);
253: fread(&xlat,2,1,smb.sdt_fp);
254: if(xlat!=XLAT_NONE) /* no translations supported */
255: continue;
256: length=msg.dfield[i].length-2;
257: if((buf=REALLOC(buf,l+msg.dfield[i].length+1))==NULL)
258: return(buf);
259: l+=fread(buf+l,1,length,smb.sdt_fp);
260: buf[l]=0; }
261: return(buf);
262: }
263:
264:
265: void gettag(smbmsg_t msg, char *tag)
266: {
267: char *buf,*p;
268:
269: tag[0]=0;
270: buf=loadmsgtail(msg);
271: if(buf==NULL)
272: return;
273: truncsp(buf);
274: stripctrla(buf);
275: p=strrchr(buf,LF);
276: if(!p) p=buf;
277: else p++;
278: if(!strnicmp(p," � Synchronet � ",16))
279: p+=16;
280: if(!strnicmp(p," * Synchronet * ",16))
281: p+=16;
282: while(*p && *p<=SP) p++;
283: strcpy(tag,p);
284: FREE(buf);
285: }
286:
287:
288: #define FEED (1<<0)
289: #define LOCAL (1<<1)
290: #define APPEND (1<<2)
291: #define TAGS (1<<3)
292:
293: #define ROUTE (1<<1)
294: #define NODES (1<<2)
295: #define USERS (1<<3)
296:
297: char *usage="\nusage: qwknodes [/opts] cmds"
298: "\n"
299: "\n cmds: r = create route.dat"
300: "\n u = create users.dat"
301: "\n n = create nodes.dat
302: "\n"
303: "\n opts: f = format addresses for nodes that feed from this system"
304: "\n a = append existing output files"
305: "\n t = include tag lines in nodes.dat
306: "\n l = include local users in users.dat
307: "\n m# = maximum message age set to # days"
308: "\n";
309:
310: void main(int argc, char **argv)
311: {
312: char str[256],tmp[128],tag[256],addr[256],*p;
313: int i,j,mode=0,cmd=0,o_mode,max_age=0;
314: ushort smm,sbl;
315: ulong *crc=NULL,curcrc,total_crcs=0,l;
316: FILE *route,*users,*nodes;
317: time_t now;
318: read_cfg_text_t txt;
319: smbmsg_t msg;
320:
321: txt.openerr="\7\r\nError opening %s for read.\r\n";
322: txt.reading="\r\nReading %s...";
323: txt.readit="\rRead %s ";
324: txt.allocerr="\7\r\nError allocating %u bytes of memory\r\n";
325: txt.error="\7\r\nERROR: Offset %lu in %s\r\n\r\n";
326:
327: fprintf(stderr,"\nSynchronet QWKnet Node/Route/User List v1.20 "
328: "Copyright 2000 Rob Swindell\n");
329:
330:
331: for(i=1;i<argc;i++)
332: for(j=0;argv[i][j];j++)
333: switch(toupper(argv[i][j])) {
334: case '/':
335: case '-':
336: while(argv[i][++j])
337: switch(toupper(argv[i][j])) {
338: case 'F':
339: mode|=FEED;
340: break;
341: case 'L':
342: mode|=LOCAL;
343: break;
344: case 'A':
345: mode|=APPEND;
346: break;
347: case 'T':
348: mode|=TAGS;
349: break;
350: case 'M':
351: j++;
352: max_age=atoi(argv[i]+j);
353: while(isdigit(argv[i][j+1])) j++;
354: break;
355: default:
356: printf(usage);
357: exit(1); }
358: j--;
359: break;
360: case 'R':
361: cmd|=ROUTE;
362: break;
363: case 'U':
364: cmd|=USERS;
365: break;
366: case 'N':
367: cmd|=NODES;
368: break;
369: default:
370: printf(usage);
371: exit(1); }
372:
373: if(!cmd) {
374: printf(usage);
375: exit(1); }
376:
377: if(mode&APPEND)
378: o_mode=O_WRONLY|O_CREAT|O_APPEND;
379: else
380: o_mode=O_WRONLY|O_CREAT|O_TRUNC;
381:
382: if(cmd&NODES)
383: if((nodes=fnopen(&i,"nodes.dat",o_mode))==NULL) {
384: printf("\7\nError opening nodes.dat\n");
385: exit(1); }
386:
387: if(cmd&USERS)
388: if((users=fnopen(&i,"users.dat",o_mode))==NULL) {
389: printf("\7\nError opening users.dat\n");
390: exit(1); }
391:
392: if(cmd&ROUTE)
393: if((route=fnopen(&i,"route.dat",o_mode))==NULL) {
394: printf("\7\nError opening route.dat\n");
395: exit(1); }
396:
397: if(!node_dir[0]) {
398: p=getenv("SBBSNODE");
399: if(p==NULL) {
400: printf("\7\nSBBSNODE environment variable not set.\n");
401: exit(1); }
402: strcpy(node_dir,p); }
403:
404: if(node_dir[strlen(node_dir)-1]!='\\')
405: strcat(node_dir,"\\");
406:
407: read_node_cfg(&cfg,txt);
408: if(ctrl_dir[0]=='.') { /* Relative path */
409: strcpy(str,ctrl_dir);
410: sprintf(ctrl_dir,"%s%s",node_dir,str);
1.1.1.2 ! root 411: if(FULLPATH(str,ctrl_dir,40))
1.1 root 412: strcpy(ctrl_dir,str); }
413: backslash(ctrl_dir);
414:
415: read_main_cfg(&cfg,txt);
416: if(data_dir[0]=='.') { /* Relative path */
417: strcpy(str,data_dir);
418: sprintf(data_dir,"%s%s",node_dir,str);
1.1.1.2 ! root 419: if(FULLPATH(str,data_dir,40))
1.1 root 420: strcpy(data_dir,str); }
421: backslash(data_dir);
422: read_msgs_cfg(txt);
423:
424: now=time(NULL);
425: smm=crc16("smm");
426: sbl=crc16("sbl");
427: fprintf(stderr,"\n\n");
428: for(i=0;i<total_subs;i++) {
429: if(!(sub[i]->misc&SUB_QNET))
430: continue;
431: fprintf(stderr,"%-*s %s\n"
432: ,LEN_GSNAME,grp[sub[i]->grp]->sname,sub[i]->lname);
433: sprintf(smb.file,"%s%s",sub[i]->data_dir,sub[i]->code);
434: smb.retry_time=30;
1.1.1.2 ! root 435: smb.sunum=i;
1.1 root 436: if((j=smb_open(&smb))!=0) {
437: printf("smb_open returned %d\n",j);
438: continue; }
439: if((j=smb_locksmbhdr(&smb))!=0) {
440: printf("smb_locksmbhdr returned %d\n",j);
441: smb_close(&smb);
442: continue; }
443: if((j=smb_getstatus(&smb))!=0) {
444: printf("smb_getstatus returned %d\n",j);
445: smb_close(&smb);
446: continue; }
447: smb_unlocksmbhdr(&smb);
448: msg.offset=smb.status.total_msgs;
449: if(!msg.offset) {
450: smb_close(&smb);
451: printf("Empty.\n");
452: continue; }
453: while(!kbhit() && !ferror(smb.sid_fp) && msg.offset) {
454: msg.offset--;
455: fseek(smb.sid_fp,msg.offset*sizeof(idxrec_t),SEEK_SET);
456: if(!fread(&msg.idx,1,sizeof(idxrec_t),smb.sid_fp))
457: break;
458: fprintf(stderr,"%-5lu\r",msg.offset+1);
459: if(msg.idx.to==smm || msg.idx.to==sbl)
460: continue;
461: if(max_age && now-msg.idx.time>((ulong)max_age*24UL*60UL*60UL))
462: continue;
463: if((j=smb_lockmsghdr(&smb,&msg))!=0) {
464: printf("smb_lockmsghdr returned %d\n",j);
465: break; }
466: if((j=smb_getmsghdr(&smb,&msg))!=0) {
467: printf("smb_getmsghdr returned %d\n",j);
468: break; }
469: smb_unlockmsghdr(&smb,&msg);
470: if((mode&LOCAL && msg.from_net.type==NET_NONE)
471: || msg.from_net.type==NET_QWK) {
472: if(msg.from_net.type!=NET_QWK)
473: msg.from_net.addr="";
474: if(cmd&USERS) {
475: sprintf(str,"%s%s",msg.from_net.addr,msg.from);
476: curcrc=crc32(str); }
477: else
478: curcrc=crc32(msg.from_net.addr);
479: for(l=0;l<total_crcs;l++)
480: if(curcrc==crc[l])
481: break;
482: if(l==total_crcs) {
483: total_crcs++;
484: if((crc=(ulong *)REALLOC(crc
485: ,sizeof(ulong)*total_crcs))==NULL) {
486: printf("Error allocating %lu bytes\n"
487: ,sizeof(ulong)*total_crcs);
488: break; }
489: crc[l]=curcrc;
490: if(cmd&ROUTE && msg.from_net.type==NET_QWK) {
491: strcpy(addr,msg.from_net.addr);
492: if(mode&FEED) {
493: p=strrchr(addr,'/');
494: if(!p)
495: p=addr;
496: else
497: *(p++)=0;
498: sprintf(str,"%s %s:%s%c%s"
499: ,unixtodstr(msg.hdr.when_written.time,tmp)
500: ,p,sys_id,p==addr ? 0 : '/'
501: ,addr);
502: fprintf(route,"%s\r\n",str); }
503: else {
504: p=strrchr(addr,'/');
505: if(p) {
506: *(p++)=0;
507: fprintf(route,"%s %s:%.*s\r\n"
508: ,unixtodstr(msg.hdr.when_written.time,str)
509: ,p
510: ,(uint)(p-addr)
511: ,addr); } } }
512: if(cmd&USERS) {
513: if(msg.from_net.type!=NET_QWK)
514: strcpy(str,sys_id);
515: else if(mode&FEED)
516: sprintf(str,"%s/%s",sys_id,msg.from_net.addr);
517: else
518: strcpy(str,msg.from_net.addr);
519: p=strrchr(str,'/');
520: if(p)
521: fprintf(users,"%-25.25s %-8.8s %s (%s)\r\n"
522: ,msg.from,p+1
523: ,unixtodstr(msg.hdr.when_written.time,tmp)
524: ,str);
525: else
526: fprintf(users,"%-25.25s %-8.8s %s\r\n"
527: ,msg.from,str
528: ,unixtodstr(msg.hdr.when_written.time,tmp)); }
529: if(cmd&NODES && msg.from_net.type==NET_QWK) {
530: if(mode&TAGS)
531: gettag(msg,tag);
532: if(mode&FEED)
533: sprintf(str,"%s/%s",sys_id,msg.from_net.addr);
534: else
535: strcpy(str,msg.from_net.addr);
536: p=strrchr(str,'/');
537: if(p) {
538: if(mode&TAGS)
539: fprintf(nodes,"%-8.8s %s\r\n"
540: ,p+1
541: ,tag);
542: else
543: fprintf(nodes,"%-8.8s %s (%s)\r\n"
544: ,p+1
545: ,unixtodstr(msg.hdr.when_written.time,tmp)
546: ,str); }
547: else
548: fprintf(nodes,"%-8.8s %s\r\n"
549: ,str
550: ,mode&TAGS
551: ? tag
552: : unixtodstr(msg.hdr.when_written.time,tmp)); }
553: } }
554: smb_freemsgmem(&msg); }
555:
556: smb_close(&smb);
557: if(kbhit()) {
558: getch();
559: fprintf(stderr,"Key pressed.\n");
560: break; } }
561: fprintf(stderr,"Done.\n");
562: }
563:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.