sbbsecho.c 149 KB
Newer Older
1
/* sbbsecho.c */
2

3
/* Synchronet FidoNet EchoMail Scanning/Tossing and NetMail Tossing Utility */
4

5
6
7
8
9
10
/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
11
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 *																			*
 * 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:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/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 mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/
37

38
/* Portions written by Allen Christiansen 1994-1996 						*/
39
40
41
42
43
44
45
46
47

#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
48
#include <sys/stat.h>
49
50
51
52
53

#ifdef __WATCOMC__
	#include <mem.h>
#endif

54
#ifndef __unix__
55
56
57
	#include <malloc.h>
#endif

rswindell's avatar
rswindell committed
58
#include "conwrap.h"		/* getch() */
59
60
61
62
63
64
#include "sbbs.h"			/* load_cfg() */
#include "sbbsdefs.h"
#include "smblib.h"
#include "scfglib.h"
#include "lzh.h"
#include "sbbsecho.h"
deuce's avatar
deuce committed
65
#include "genwrap.h"		/* PLATFORM_DESC */
66
67
68
69

smb_t *smb,*email;
long misc=(IMPORT_PACKETS|IMPORT_NETMAIL|IMPORT_ECHOMAIL|EXPORT_ECHOMAIL
			|DELETE_NETMAIL|DELETE_PACKETS);
70
71
BOOL export_netmail_option=TRUE;
ulong netmail=0;	/* statistic */
72
73
74
char tmp[256],pkt_type=0;
int secure,cur_smb=0;
FILE *fidologfile=NULL;
75
BOOL twit_list;
76

77
faddr_t		sys_faddr = {1,1,1,0};		/* Default system address: 1:1/1.0 */
78
79
config_t	cfg;
scfg_t		scfg;
80
char		revision[16];
81
char		compiler[32];
82

83
BOOL pause_on_exit=FALSE;
84
BOOL pause_on_abend=FALSE;
85

86
#if !defined(_WIN32)
87
88
89
90
91
92
#define delfile(x) remove(x)
#else
int delfile(char *filename)
{
	int i=0;

93
	while(remove(filename) && i++<120)	/* Wait up to 60 seconds to delete file */
94
		Sleep(500); 					/* for Win95 bug fix */
95
	return(i);
96
97
98
}
#endif

99
#if defined(__unix__)	/* borrowed from MSVC */
rswindell's avatar
rswindell committed
100
unsigned _rotr (
101
102
103
104
        unsigned val,
        int shift
        )
{
105
106
107
108
109
110
111
112
113
114
115
    register unsigned lobit;        /* non-zero means lo bit set */
    register unsigned num = val;    /* number to rotate */

    shift &= 0x1f;                  /* modulo 32 -- this will also make
                                       negative shifts work */
    while (shift--) {
	    lobit = num & 1;        /* get high bit */
        num >>= 1;              /* shift right one bit */
        if (lobit)
			num |= 0x80000000;  /* set hi bit if lo bit was set */
	}
116

117
    return num;
118
119
120
}
#endif

121
122
void logprintf(char *str, ...);

rswindell's avatar
rswindell committed
123
/****************************************************************************/
124
/* This is needed by load_cfg.c												*/
rswindell's avatar
rswindell committed
125
/****************************************************************************/
126
int lprintf(int level, char *fmat, ...)
rswindell's avatar
rswindell committed
127
128
129
130
131
132
{
	va_list argptr;
	char sbuf[256];
	int chcount;

	va_start(argptr,fmat);
133
	chcount=vsnprintf(sbuf,sizeof(sbuf),fmat,argptr);
134
	sbuf[sizeof(sbuf)-1]=0;
rswindell's avatar
rswindell committed
135
	va_end(argptr);
136
137
	truncsp(sbuf);
	printf("%s\n",sbuf);
138

139
	if(level<=cfg.log_level)
140
		logprintf("%s",sbuf);
rswindell's avatar
rswindell committed
141
142
143
	return(chcount);
}

144
145
146
147
148
149
150
151
152
153
/**********************/
/* Log print function */
/**********************/
void logprintf(char *str, ...)
{
    va_list argptr;
    char buf[256];
    time_t now;
    struct tm *gm;

154
155
156
157
158
159
	if(!(misc&LOGFILE) || fidologfile==NULL)
		return;
	va_start(argptr,str);
	vsnprintf(buf,sizeof(buf),str,argptr);
	buf[sizeof(buf)-1]=0;
	va_end(argptr);
rswindell's avatar
rswindell committed
160
	strip_ctrl(buf, buf);
161
162
	now=time(NULL);
	gm=localtime(&now);
163
	fprintf(fidologfile,"%02u/%02u/%02u %02u:%02u:%02u %s\n"
164
165
166
		,(scfg.sys_misc&SM_EURODATE) ? gm->tm_mday : gm->tm_mon+1
		,(scfg.sys_misc&SM_EURODATE) ? gm->tm_mon+1 : gm->tm_mday
		,TM_YEAR(gm->tm_year),gm->tm_hour,gm->tm_min,gm->tm_sec
167
		,buf);
168
169
170
171
172
}

/*****************************************************************************/
/* Returns command line generated from instr with %c replacments             */
/*****************************************************************************/
173
char *mycmdstr(scfg_t* cfg, char *instr, char *fpath, char *fspec)
174
{
175
    static char cmd[MAX_PATH+1];
176
177
178
    char str[256],str2[128];
    int i,j,len;

179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
	len=strlen(instr);
	for(i=j=0;i<len && j<128;i++) {
		if(instr[i]=='%') {
			i++;
			cmd[j]=0;
			switch(toupper(instr[i])) {
				case 'F':   /* File path */
					strcat(cmd,fpath);
					break;
				case 'G':   /* Temp directory */
					if(cfg->temp_dir[0]!='\\' 
						&& cfg->temp_dir[0]!='/' 
						&& cfg->temp_dir[1]!=':') {
						strcpy(str,cfg->node_dir);
						strcat(str,cfg->temp_dir);
						if(FULLPATH(str2,str,40))
							strcpy(str,str2);
						backslash(str);
						strcat(cmd,str);}
					else
						strcat(cmd,cfg->temp_dir);
					break;
				case 'J':
					if(cfg->data_dir[0]!='\\' 
						&& cfg->data_dir[0]!='/' 
						&& cfg->data_dir[1]!=':') {
						strcpy(str,cfg->node_dir);
						strcat(str,cfg->data_dir);
						if(FULLPATH(str2,str,40))
							strcpy(str,str2);
						backslash(str);
210
211
						strcat(cmd,str); 
					}
212
213
214
215
216
217
218
219
220
221
222
223
					else
						strcat(cmd,cfg->data_dir);
					break;
				case 'K':
					if(cfg->ctrl_dir[0]!='\\' 
						&& cfg->ctrl_dir[0]!='/' 
						&& cfg->ctrl_dir[1]!=':') {
						strcpy(str,cfg->node_dir);
						strcat(str,cfg->ctrl_dir);
						if(FULLPATH(str2,str,40))
							strcpy(str,str2);
						backslash(str);
224
225
						strcat(cmd,str); 
					}
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
					else
						strcat(cmd,cfg->ctrl_dir);
					break;
				case 'N':   /* Node Directory (same as SBBSNODE environment var) */
					strcat(cmd,cfg->node_dir);
					break;
				case 'O':   /* SysOp */
					strcat(cmd,cfg->sys_op);
					break;
				case 'Q':   /* QWK ID */
					strcat(cmd,cfg->sys_id);
					break;
				case 'S':   /* File Spec */
					strcat(cmd,fspec);
					break;
				case '!':   /* EXEC Directory */
242
					strcat(cmd,cfg->exec_dir);
243
					break;
244
245
246
247
248
                case '@':   /* EXEC Directory for DOS/OS2/Win32, blank for Unix */
#ifndef __unix__
                    strcat(cmd,cfg->exec_dir);
#endif
                    break;
249
250
251
252
253
254
255
256
257
258
259
				case '#':   /* Node number (same as SBBSNNUM environment var) */
					sprintf(str,"%d",cfg->node_num);
					strcat(cmd,str);
					break;
				case '*':
					sprintf(str,"%03d",cfg->node_num);
					strcat(cmd,str);
					break;
				case '%':   /* %% for percent sign */
					strcat(cmd,"%");
					break;
260
261
262
263
264
265
266
267
268
269
270
271
272
273
				case '.':	/* .exe for DOS/OS2/Win32, blank for Unix */
#ifndef __unix__
					strcat(cmd,".exe");
#endif
					break;
				case '?':	/* Platform */
#ifdef __OS2__
					strcpy(str,"OS2");
#else
					strcpy(str,PLATFORM_DESC);
#endif
					strlwr(str);
					strcat(cmd,str);
					break;
274
				default:    /* unknown specification */
275
					lprintf(LOG_ERR,"ERROR Checking Command Line '%s'",instr);
276
					bail(1);
277
278
279
280
					break; 
			}
			j=strlen(cmd); 
		}
281
		else
282
283
			cmd[j++]=instr[i]; 
}
284
	cmd[j]=0;
285

286
	return(cmd);
287
288
289
290
291
292
293
}

/****************************************************************************/
/* Runs an external program directly using spawnvp							*/
/****************************************************************************/
int execute(char *cmdline)
{
rswindell's avatar
rswindell committed
294
#if 1
295
	return system(cmdline);
rswindell's avatar
rswindell committed
296
#else
297
298
299
300
301
302
303
	char c,d,e,cmdlen,*arg[30],str[256];
	int i;

	strcpy(str,cmdline);
	arg[0]=str;	/* point to the beginning of the string */
	cmdlen=strlen(str);
	for(c=0,d=1,e=0;c<cmdlen;c++,e++)	/* Break up command line */
304
		if(str[c]==' ') {
305
306
307
308
309
310
			str[c]=0;			/* insert nulls */
			arg[d++]=str+c+1;	/* point to the beginning of the next arg */
			e=0; }
	arg[d]=0;
	i=spawnvp(P_WAIT,arg[0],arg);
	return(i);
rswindell's avatar
rswindell committed
311
#endif
312
}
313

314
315
316
317
318
319
/******************************************************************************
 Returns the system address with the same zone as the address passed
******************************************************************************/
faddr_t getsysfaddr(short zone)
{
	int i;
320

321
322
323
	for(i=0;i<scfg.total_faddrs;i++)
		if(scfg.faddr[i].zone==zone)
			return(scfg.faddr[i]);
324
	return(sys_faddr);
325
}
326

327
328
329
330
331
332
int get_flo_outbound(faddr_t dest, char* outbound, size_t maxlen)
{
	char* last;
	if(dest.zone==sys_faddr.zone)		/* Default zone, use default outbound */
		strncpy(outbound,cfg.outbound,maxlen);
	else {								/* Inter-zone outbound is OUTBOUND.XXX */
rswindell's avatar
rswindell committed
333
		safe_snprintf(outbound,maxlen,"%.*s.%03x"
334
335
336
337
338
339
340
341
342
343
344
345
			,(int)strlen(cfg.outbound)-1,cfg.outbound,dest.zone);
	}
	if(dest.point) {					/* Point destination is OUTBOUND\*.PNT */
		char point[128];
		SAFEPRINTF2(point,"%04x%04x.pnt"
			,dest.net,dest.node);
		strncat(outbound,point,maxlen); 
	}
	backslash(outbound);
	return mkpath(outbound);
}

346
347
348
349
350
/******************************************************************************
 This function creates or appends on existing Binkley compatible .?LO file
 attach file.
 Returns 0 on success.
******************************************************************************/
351
int write_flofile(char *attachment, faddr_t dest, BOOL bundle)
352
{
353
354
355
356
357
	char fname[MAX_PATH+1];
	char outbound[MAX_PATH+1];
	char str[MAX_PATH+1];
	char ch;
	char searchstr[MAX_PATH+1];
358
	ushort attr=0;
359
	int i;
360
361
362
363
364
365
	FILE *stream;

	i=matchnode(dest,0);
	if(i<(int)cfg.nodecfgs)
		attr=cfg.nodecfg[i].attr;

rswindell's avatar
rswindell committed
366
367
368
369
	if(attr&ATTR_CRASH) ch='c';
	else if(attr&ATTR_HOLD) ch='h';
	else if(attr&ATTR_DIRECT) ch='d';
	else ch='f';
370
371

	get_flo_outbound(dest, outbound, sizeof(outbound)-2);
372
	if(dest.point)
rswindell's avatar
rswindell committed
373
		sprintf(fname,"%s%08x.%clo",outbound,dest.point,ch);
374
	else
rswindell's avatar
rswindell committed
375
		sprintf(fname,"%s%04x%04x.%clo",outbound,dest.net,dest.node,ch);
rswindell's avatar
rswindell committed
376
	if(bundle && (misc&TRUNC_BUNDLES))
377
378
379
		ch='#';
	else
		ch='^';
380
381
382
	if(*attachment == '^')	/* work-around for BRE/FE inter-BBS attachment bug */
		attachment++;
	fexistcase(attachment);	/* just in-case it's the wrong case for a Unix file system */
383
	sprintf(searchstr,"%c%s",ch,attachment);
384
385
	if(findstr(searchstr,fname))	/* file already in FLO file */
		return(0);
386
	if((stream=fopen(fname,"a"))==NULL) {
387
		lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s",errno,strerror(errno),__LINE__,fname);
388
389
		return(-1); 
	}
390
	fprintf(stream,"%s\n",searchstr);
391
392
393
394
	fclose(stream);
	return(0);
}

395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
/* Writes text buffer to file, expanding sole LFs to CRLFs */
size_t fwrite_crlf(char* buf, size_t len, FILE* fp)
{
	char	ch,last_ch=0;
	size_t	i;
	size_t	wr=0;	/* total chars written (may be > len) */

	for(i=0;i<len;i++) {
		ch=*buf++;
		if(ch=='\n' && last_ch!='\r') {
			if(fputc('\r',fp)==EOF)
				return(wr);
			wr++;
		}
		if(fputc(ch,fp)==EOF)
			return(wr);
		wr++;
		last_ch=ch;
	}

	return(wr);
}

418
419
420
421
422
/******************************************************************************
 This function will create a netmail message (.MSG format).
 If file is non-zero, will set file attachment bit (for bundles).
 Returns 0 on success.
******************************************************************************/
423
int create_netmail(char *to, char *from, char *subject, char *body, faddr_t dest, time_t t, BOOL file_attached)
424
{
425
426
	FILE *fp;
	char fname[MAX_PATH+1];
427
428
429
430
431
432
433
434
	ushort attr=0;
	int fmsg;
	uint i;
	static uint startmsg;
	faddr_t	faddr;
	fmsghdr_t hdr;
	struct tm *tm;

435
436
437
438
	if(from==NULL)
		from="SBBSecho";
	if(to==NULL)
		to="Sysop";
439
440
441
442
443
444
445
	if(!startmsg) startmsg=1;
	i=matchnode(dest,0);
	if(i<cfg.nodecfgs) {
		attr=cfg.nodecfg[i].attr;
		if(!attr) {
			i=matchnode(dest,2);
			if(i<cfg.nodecfgs)
446
447
448
				attr=cfg.nodecfg[i].attr; 
		} 
	}
449

450
	MKDIR(scfg.netmail_dir);
451
452
453
454
455
456
457
458
459
460
461
462
463
464
	for(i=startmsg;i;i++) {
		sprintf(fname,"%s%u.msg",scfg.netmail_dir,i);
		if(!fexistcase(fname))
			break; 
	}
	if(!i) {
		lprintf(LOG_WARNING,"Directory full: %s",scfg.netmail_dir);
		return(-1); 
	}
	startmsg=i+1;
	if((fp=fnopen(&fmsg,fname,O_RDWR|O_CREAT))==NULL) {
		lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s",errno,strerror(errno),__LINE__,fname);
		return(-1); 
	}
465

466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
	faddr=getsysfaddr(dest.zone);
	memset(&hdr,0,sizeof(fmsghdr_t));
	hdr.origzone=faddr.zone;
	hdr.orignet=faddr.net;
	hdr.orignode=faddr.node;
	hdr.origpoint=faddr.point;
	hdr.destzone=dest.zone;
	hdr.destnet=dest.net;
	hdr.destnode=dest.node;
	hdr.destpoint=dest.point;

	hdr.attr=(FIDO_PRIVATE|FIDO_KILLSENT|FIDO_LOCAL);
	if(file_attached)
		hdr.attr|=FIDO_FILE;

	if(attr&ATTR_HOLD)
		hdr.attr|=FIDO_HOLD;
	if(attr&ATTR_CRASH)
		hdr.attr|=FIDO_CRASH;

	tm=localtime(&t);
	sprintf(hdr.time,"%02u %3.3s %02u  %02u:%02u:%02u"
		,tm->tm_mday,mon[tm->tm_mon],TM_YEAR(tm->tm_year)
		,tm->tm_hour,tm->tm_min,tm->tm_sec);

	SAFECOPY(hdr.to,to);
	SAFECOPY(hdr.from,from);
	SAFECOPY(hdr.subj,subject);

	fwrite(&hdr,sizeof(fmsghdr_t),1,fp);
	fprintf(fp,"\1INTL %hu:%hu/%hu %hu:%hu/%hu\r"
		,hdr.destzone,hdr.destnet,hdr.destnode
		,hdr.origzone,hdr.orignet,hdr.orignode);

	/* Add FSC-53 FLAGS kludge */
	fprintf(fp,"\1FLAGS");
	if(attr&ATTR_DIRECT)
		fprintf(fp," DIR");
	if(file_attached) {
		if(misc&TRUNC_BUNDLES)
			fprintf(fp," TFS");
507
		else
508
509
510
			fprintf(fp," KFS");
	}
	fprintf(fp,"\r");
511

512
513
514
515
516
517
518
519
520
521
	if(hdr.destpoint)
		fprintf(fp,"\1TOPT %hu\r",hdr.destpoint);
	if(hdr.origpoint)
		fprintf(fp,"\1FMPT %hu\r",hdr.origpoint);
	if(!file_attached || (!(attr&ATTR_DIRECT) && file_attached))
		fwrite_crlf(body,strlen(body)+1,fp);	/* Write additional NULL */
	else
		fwrite("\0",1,1,fp);               /* Write NULL */
	printf("Created %s\n", fname);
	return fclose(fp);
522
523
524
525
526
527
528
529
530
531
532
}

/******************************************************************************
 This function takes the contents of 'infile' and puts it into a netmail
 message bound for addr.
******************************************************************************/
void file_to_netmail(FILE *infile,char *title,faddr_t addr,char *to)
{
	char *buf,*p;
	long l,m,len;

533
534
535
536
	l=len=ftell(infile);
	if(len>8192L)
		len=8192L;
	rewind(infile);
deuce's avatar
deuce committed
537
	if((buf=(char *)malloc(len+1))==NULL) {
538
		lprintf(LOG_ERR,"ERROR line %d allocating %lu for file to netmail buf",__LINE__,len);
539
540
		return; 
	}
541
542
543
	while((m=fread(buf,1,(len>8064L) ? 8064L:len,infile))>0) {
		buf[m]=0;
		if(l>8064L && (p=strrchr(buf,'\n'))!=NULL) {
544
			p++;
545
546
			if(*p) {
				*p=0;
547
				p++;
548
549
550
				fseek(infile,-1L,SEEK_CUR);
				while(*p) { 			/* Seek back to end of last line */
					p++;
551
552
553
554
					fseek(infile,-1L,SEEK_CUR); 
				} 
			} 
		}
555
556
		if(ftell(infile)<l)
			strcat(buf,"\r\nContinued in next message...\r\n");
557
		create_netmail(to,/* from: */NULL, title,buf,addr,time(NULL),FALSE); 
558
	}
deuce's avatar
deuce committed
559
	free(buf);
560
}
561
562
563
564

/* Returns TRUE if area is linked with specified node address */
BOOL area_is_linked(unsigned area_num, faddr_t* addr)
{
565
566
	unsigned i;
	for(i=0;i<cfg.area[area_num].uplinks;i++)
567
568
569
570
571
		if(!memcmp(addr,&cfg.area[area_num].uplink[i],sizeof(faddr_t)))
			return TRUE;
	return FALSE;
}

572
573
574
575
576
577
578
579
580
/******************************************************************************
 This function sends a notify list to applicable nodes, this list includes the
 settings configured for the node, as well as a list of areas the node is
 connected to.
******************************************************************************/
void notify_list(void)
{
	FILE *	tmpf;
	char	str[256];
deuce's avatar
deuce committed
581
	uint	i,k;
582
583
584
585
586
587
588

	for(k=0;k<cfg.nodecfgs;k++) {

		if(!(cfg.nodecfg[k].attr&SEND_NOTIFY))
			continue;

		if((tmpf=tmpfile())==NULL) {
589
			lprintf(LOG_ERR,"ERROR line %d couldn't open tmpfile",__LINE__);
590
591
			return; 
		}
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616

		fprintf(tmpf,"Following are the options set for your system and a list "
			"of areas\r\nyou are connected to.  Please make sure everything "
			"is correct.\r\n\r\n");
		fprintf(tmpf,"Packet Type       %s\r\n"
			,cfg.nodecfg[k].pkt_type==PKT_TWO ? "2"
			:cfg.nodecfg[k].pkt_type==PKT_TWO_TWO ? "2.2":"2+");
		fprintf(tmpf,"Archive Type      %s\r\n"
			,(cfg.nodecfg[k].arctype>cfg.arcdefs) ?
			 "None":cfg.arcdef[cfg.nodecfg[k].arctype].name);
		fprintf(tmpf,"Mail Status       %s\r\n"
			,cfg.nodecfg[k].attr&ATTR_CRASH ? "Crash"
			:cfg.nodecfg[k].attr&ATTR_HOLD ? "Hold" : "None");
		fprintf(tmpf,"Direct            %s\r\n"
			,cfg.nodecfg[k].attr&ATTR_DIRECT ? "Yes":"No");
		fprintf(tmpf,"Passive           %s\r\n"
			,cfg.nodecfg[k].attr&ATTR_PASSIVE ? "Yes":"No");
		fprintf(tmpf,"Remote AreaMgr    %s\r\n\r\n"
			,cfg.nodecfg[k].password[0] ? "Yes" : "No");

		fprintf(tmpf,"Connected Areas\r\n---------------\r\n");
		for(i=0;i<cfg.areas;i++) {
			sprintf(str,"%s\r\n",cfg.area[i].name);
			if(str[0]=='*')
				continue;
617
618
619
			if(area_is_linked(i,&cfg.nodecfg[k].faddr))
				fprintf(tmpf,"%s",str); 
		}
620
621

		if(ftell(tmpf))
622
			file_to_netmail(tmpf,"SBBSecho Notify List",cfg.nodecfg[k].faddr, /* To: */NULL);
623
624
		fclose(tmpf); 
	}
625
}
626

627
628
629
630
/******************************************************************************
 This function creates a netmail to addr showing a list of available areas (0),
 a list of connected areas (1), or a list of removed areas (2).
******************************************************************************/
631
632
633
634
635
636
enum arealist_type {
	 AREALIST_ALL			// %LIST
	,AREALIST_CONNECTED		// %QUERY
	,AREALIST_UNLINKED		// %UNLINKED
};
void netmail_arealist(enum arealist_type type, faddr_t addr, char* to)
637
{
638
639
	char str[256],title[128],match,*p,*tp;
	int i,j,k,x,y;
640
	str_list_t	area_list;
641

642
	if(type == AREALIST_ALL)
643
		strcpy(title,"List of Available Areas");
644
	else if(type == AREALIST_CONNECTED)
645
646
647
648
		strcpy(title,"List of Connected Areas");
	else
		strcpy(title,"List of Unlinked Areas");

649
650
	if((area_list=strListInit()) == NULL) {
		lprintf(LOG_ERR,"ERROR line %d couldn't allocate string list",__LINE__);
651
652
		return; 
	}
653

654
655
656
657
658
659
	/* Include relevant areas from the area file (e.g. areas.bbs): */
	for(i=0;i<cfg.areas;i++) {
		if((type == AREALIST_CONNECTED || (misc&ELIST_ONLY)) && !area_is_linked(i,&addr))
			continue;
		if(type == AREALIST_UNLINKED && area_is_linked(i,&addr))
			continue;
660
		strListPush(&area_list, cfg.area[i].name); 
661
	} 
662

663
	if(type != AREALIST_CONNECTED) {
664
665
666
667
668
669
		i=matchnode(addr,0);
		if(i<cfg.nodecfgs) {
			for(j=0;j<cfg.listcfgs;j++) {
				match=0;
				for(k=0;k<cfg.listcfg[j].numflags;k++) {
					if(match) break;
670
					for(x=0;x<cfg.nodecfg[i].numflags;x++) {
671
672
						if(!stricmp(cfg.listcfg[j].flag[k].flag
							,cfg.nodecfg[i].flag[x].flag)) {
673
674
							FILE* fp;
							if((fp=fopen(cfg.listcfg[j].listpath,"r"))==NULL) {
675
676
								lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s"
									,errno,strerror(errno),__LINE__,cfg.listcfg[j].listpath);
677
								match=1;
678
679
								break; 
							}
680
							while(!feof(fp)) {
681
								memset(str,0,sizeof(str));
682
								if(!fgets(str,sizeof(str),fp))
683
									break;
684
								truncsp(str);
685
								p=str;
686
								SKIP_WHITESPACE(p);
687
								if(*p==0 || *p==';')     /* Ignore Blank and Comment Lines */
688
									continue;
689
690
691
								tp=p;
								FIND_WHITESPACE(tp);
								*tp=0;
692
693
694
								for(y=0;y<cfg.areas;y++)
									if(!stricmp(cfg.area[y].name,p))
										break;
695
696
								if(y>=cfg.areas || !area_is_linked(y,&addr))
									strListPush(&area_list, p); 
697
							}
698
							fclose(fp);
699
							match=1;
700
							break; 
701
702
						}
					}
703
704
705
706
				} 
			} 
		} 
	}
707
708
	strListSortAlpha(area_list);
	if(!strListCount(area_list))
709
		create_netmail(to,/* from: */NULL,title,"None.",addr,time(NULL),FALSE);
710
711
712
713
714
715
716
717
718
719
720
721
	else {
		FILE* fp;
		if((fp=tmpfile())==NULL) {
			lprintf(LOG_ERR,"ERROR line %d couldn't open tmpfile",__LINE__);
		} else {
			strListWriteFile(fp, area_list, "\r\n");
			file_to_netmail(fp,title,addr,to);
			fclose(fp);
		}
	}
	lprintf(LOG_INFO,"Created AreaFix response netmail with %s (%u areas)", title, strListCount(area_list));
	strListFree(&area_list);
722
}
723

rswindell's avatar
rswindell committed
724
int check_elists(char *areatag,faddr_t addr)
725
726
{
	FILE *stream;
727
	char str[1025],quit=0,*p,*tp;
728
	int i,j,k,x,match=0;
729

rswindell's avatar
rswindell committed
730
731
732
733
734
735
736
737
738
	i=matchnode(addr,0);
	if(i<cfg.nodecfgs) {
		for(j=0;j<cfg.listcfgs;j++) {
			quit=0;
			for(k=0;k<cfg.listcfg[j].numflags;k++) {
				if(quit) break;
				for(x=0;x<cfg.nodecfg[i].numflags;x++)
					if(!stricmp(cfg.listcfg[j].flag[k].flag
						,cfg.nodecfg[i].flag[x].flag)) {
739
						if((stream=fopen(cfg.listcfg[j].listpath,"r"))==NULL) {
740
741
							lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s"
								,errno,strerror(errno),__LINE__,cfg.listcfg[j].listpath);
rswindell's avatar
rswindell committed
742
							quit=1;
743
744
							break; 
						}
rswindell's avatar
rswindell committed
745
						while(!feof(stream)) {
746
							if(!fgets(str,sizeof(str),stream))
rswindell's avatar
rswindell committed
747
748
								break;
							p=str;
749
							SKIP_WHITESPACE(p);
rswindell's avatar
rswindell committed
750
751
							if(*p==';')     /* Ignore Comment Lines */
								continue;
752
753
754
755
							tp=p;
							FIND_WHITESPACE(tp);
							*tp=0;
							if(!stricmp(areatag,p)) {
rswindell's avatar
rswindell committed
756
								match=1;
757
758
759
								break; 
							} 
						}
rswindell's avatar
rswindell committed
760
						fclose(stream);
761
						quit=1;
rswindell's avatar
rswindell committed
762
763
						if(match)
							return(match);
764
765
766
767
768
						break; 
					} 
			} 
		} 
	}
rswindell's avatar
rswindell committed
769
	return(match);
770
771
772
773
}
/******************************************************************************
 Used by AREAFIX to add/remove/change areas in the areas file
******************************************************************************/
774
void alter_areas(str_list_t add_area, str_list_t del_area, faddr_t addr, char* to)
775
776
{
	FILE *nmfile,*afilein,*afileout,*fwdfile;
777
778
	char str[1024],fields[1024],field1[256],field2[256],field3[256]
		,outpath[MAX_PATH+1]
779
		,*outname,*p,*tp,nomatch=0,match=0;
780
	int i,j,k,x,y;
781
782
	ulong tagcrc;

783
784
	SAFECOPY(outpath,cfg.areafile);
	*getfname(outpath)=0;
785
	if((outname=tempnam(outpath,"AREAS"))==NULL) {
786
		lprintf(LOG_ERR,"ERROR tempnam(%s,AREAS)",outpath);
787
788
		return; 
	}
789
	if((nmfile=tmpfile())==NULL) {
790
		lprintf(LOG_ERR,"ERROR in tmpfile()");
791
		free(outname);
792
793
		return; 
	}
794
	if((afileout=fopen(outname,"w+"))==NULL) {
795
		lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s",errno,strerror(errno),__LINE__,outname);
796
797
		fclose(nmfile);
		free(outname);
798
799
		return; 
	}
800
	if((afilein=fopen(cfg.areafile,"r"))==NULL) {
801
		lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s",errno,strerror(errno),__LINE__,cfg.areafile);
802
803
804
		fclose(afileout);
		fclose(nmfile);
		free(outname);
805
806
		return; 
	}
807
	while(!feof(afilein)) {
808
		if(!fgets(fields,sizeof(fields),afilein))
809
810
811
			break;
		truncsp(fields);
		p=fields;
812
		SKIP_WHITESPACE(p);
813
		if(*p==';') {    /* Skip Comment Lines */
814
			fprintf(afileout,"%s\n",fields);
815
816
			continue; 
		}
817
		SAFECOPY(field1,p);         /* Internal Code Field */
818
		truncstr(field1," \t\r\n");
819
820
821
		FIND_WHITESPACE(p);
		SKIP_WHITESPACE(p);
		SAFECOPY(field2,p);         /* Areatag Field */
822
		truncstr(field2," \t\r\n");
823
824
		FIND_WHITESPACE(p);
		SKIP_WHITESPACE(p);
825
		if((tp=strchr(p,';'))!=NULL) {
826
827
			SAFECOPY(field3,p);     /* Comment Field (if any) */
			FIND_WHITESPACE(tp);
828
829
			*tp=0; 
		}
830
831
		else
			field3[0]=0;
832
		if(strListCount(del_area)) { 				/* Check for areas to remove */
833
			lprintf(LOG_DEBUG,"Removing areas for %s from %s", smb_faddrtoa(&addr,NULL), cfg.areafile);
834
835
836
837
838
839
			for(i=0;del_area[i]!=NULL;i++) {
				if(!stricmp(del_area[i],field2) ||
					!stricmp(del_area[0],"-ALL"))     /* Match Found */
					break; 
			}
			if(del_area[i]!=NULL) {
840
841
				for(i=0;i<cfg.areas;i++) {
					if(!stricmp(field2,cfg.area[i].name)) {
842
						lprintf(LOG_DEBUG,"Unlinking area (%s) for %s in %s", field2, smb_faddrtoa(&addr,NULL), cfg.areafile);
843
						if(!area_is_linked(i,&addr)) {
844
845
							fprintf(afileout,"%s\n",fields);
							/* bugfix here Mar-25-2004 (wasn't breaking for "-ALL") */
846
							if(stricmp(del_area[0],"-ALL"))
847
848
849
								fprintf(nmfile,"%s not connected.\r\n",field2);
							break; 
						}
850

851
852
853
854
855
856
						/* Added 12/4/95 to remove uplink from connected uplinks */

						for(k=j;k<cfg.area[i].uplinks-1;k++)
							memcpy(&cfg.area[i].uplink[k],&cfg.area[i].uplink[k+1]
								,sizeof(faddr_t));
						--cfg.area[i].uplinks;
857
858
						if(cfg.area[i].uplinks==0) {
							FREE_AND_NULL(cfg.area[i].uplink);
859
						} else {
860
							if((cfg.area[i].uplink=(faddr_t *)
deuce's avatar
deuce committed
861
								realloc(cfg.area[i].uplink,sizeof(faddr_t)
862
								*(cfg.area[i].uplinks)))==NULL) {
863
864
								lprintf(LOG_ERR,"ERROR line %d allocating memory for area "
									"#%u uplinks.",__LINE__,i+1);
865
								bail(1); 
866
								return;
867
							}
868
						}
869
870
871
872
873
874
875

						fprintf(afileout,"%-16s%-23s ",field1,field2);
						for(j=0;j<cfg.area[i].uplinks;j++) {
							if(!memcmp(&cfg.area[i].uplink[j],&addr
								,sizeof(faddr_t)))
								continue;
							fprintf(afileout,"%s "
876
877
								,smb_faddrtoa(&cfg.area[i].uplink[j],NULL)); 
						}
878
879
						if(field3[0])
							fprintf(afileout,"%s",field3);
880
						fprintf(afileout,"\n");
881
						fprintf(nmfile,"%s removed.\r\n",field2);
882
883
884
						break; 
					} 
				}
885
				if(i==cfg.areas)			/* Something screwy going on */
886
					fprintf(afileout,"%s\n",fields);
887
888
889
890
				continue; 
			} 				/* Area match so continue on */
		}
		if(strListCount(add_area)) { 				/* Check for areas to add */
891
			lprintf(LOG_DEBUG,"Adding areas for %s to %s", smb_faddrtoa(&addr,NULL), cfg.areafile);
892
893
894
			for(i=0;add_area[i]!=NULL;i++)
				if(!stricmp(add_area[i],field2) ||
					!stricmp(add_area[0],"+ALL"))      /* Match Found */
895
					break;
896
897
898
			if(add_area[i]!=NULL) {
				if(stricmp(add_area[i],"+ALL"))
					add_area[i][0]=0;  /* So we can check other lists */
899
900
				for(i=0;i<cfg.areas;i++) {
					if(!stricmp(field2,cfg.area[i].name)) {
901
						lprintf(LOG_DEBUG,"Linking area (%s) for %s in %s", field2, smb_faddrtoa(&addr,NULL), cfg.areafile);
902
						if(area_is_linked(i,&addr)) {
903
							fprintf(afileout,"%s\n",fields);
904
							fprintf(nmfile,"%s already connected.\r\n",field2);
905
906
							break; 
						}
rswindell's avatar
rswindell committed
907
						if((misc&ELIST_ONLY) && !check_elists(field2,addr)) {
908
							fprintf(afileout,"%s\n",fields);
909
910
							break; 
						}
911
912
913
914
915

						/* Added 12/4/95 to add uplink to connected uplinks */

						++cfg.area[i].uplinks;
						if((cfg.area[i].uplink=(faddr_t *)
deuce's avatar
deuce committed
916
							realloc(cfg.area[i].uplink,sizeof(faddr_t)
917
							*(cfg.area[i].uplinks)))==NULL) {
918
919
							lprintf(LOG_ERR,"ERROR line %d allocating memory for area "
								"#%u uplinks.",__LINE__,i+1);
920
921
922
							bail(1); 
							return;
						}
923
						memcpy(&cfg.area[i].uplink[cfg.area[i].uplinks-1],&addr,sizeof(faddr_t));
924
925
926
927

						fprintf(afileout,"%-16s%-23s ",field1,field2);
						for(j=0;j<cfg.area[i].uplinks;j++)
							fprintf(afileout,"%s "
928
								,smb_faddrtoa(&cfg.area[i].uplink[j],NULL));
929
930
						if(field3[0])
							fprintf(afileout,"%s",field3);
931
						fprintf(afileout,"\n");
932
						fprintf(nmfile,"%s added.\r\n",field2);
933
934
935
						break; 
					} 
				}
936
				if(i==cfg.areas)			/* Something screwy going on */
937
					fprintf(afileout,"%s\n",fields);
938
939
940
941
942
943
				continue;  					/* Area match so continue on */
			}
			nomatch=1; 						/* This area wasn't in there */
		}
		fprintf(afileout,"%s\n",fields);	/* No match so write back line */
	}
944
	fclose(afilein);
945
	if(nomatch || (strListCount(add_area) && !stricmp(add_area[0],"+ALL"))) {
946
947
948
949
950
951
		i=matchnode(addr,0);
		if(i<cfg.nodecfgs) {
			for(j=0;j<cfg.listcfgs;j++) {
				match=0;
				for(k=0;k<cfg.listcfg[j].numflags;k++) {
					if(match) break;
952
					for(x=0;x<cfg.nodecfg[i].numflags;x++) {
953
954
955
						if(!stricmp(cfg.listcfg[j].flag[k].flag
							,cfg.nodecfg[i].flag[x].flag)) {
							if((fwdfile=tmpfile())==NULL) {
956
								lprintf(LOG_ERR,"ERROR line %d opening forward temp "
957
958
									"file",__LINE__);
								match=1;
959
960
								break; 
							}
961
							if((afilein=fopen(cfg.listcfg[j].listpath,"r"))==NULL) {
962
963
								lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s"
									,errno,strerror(errno),__LINE__,cfg.listcfg[j].listpath);
964
965
								fclose(fwdfile);
								match=1;
966
967
								break; 
							}
968
							while(!feof(afilein)) {
969
								if(!fgets(str,sizeof(str),afilein))
970
									break;
971
								p=str;
972
								SKIP_WHITESPACE(p);
973
974
								if(*p==';')     /* Ignore Comment Lines */
									continue;
975
976
977
								tp=p;
								FIND_WHITESPACE(tp);
								*tp=0;
978
								if(add_area[0]!=NULL && stricmp(add_area[0],"+ALL")==0) {
979
980
									SAFECOPY(tmp,p);
									tagcrc=crc32(strupr(tmp),0);
981
982
983
984
									for(y=0;y<cfg.areas;y++)
										if(tagcrc==cfg.area[y].tag)
											break;
									if(y<cfg.areas)
985
986
987
988
989
990
										continue; 
								}
								for(y=0;add_area[y]!=NULL;y++)
									if((!stricmp(add_area[y],str) &&
										add_area[y][0]) ||
										!stricmp(add_area[0],"+ALL"))
991
										break;
992
								if(add_area[y]!=NULL) {
993
994
995
									fprintf(afileout,"%-16s%-23s","P",str);
									if(cfg.listcfg[j].forward.zone)
										fprintf(afileout," %s"
996
997
											,smb_faddrtoa(&cfg.listcfg[j].forward,NULL));
									fprintf(afileout," %s\n",smb_faddrtoa(&addr,NULL));
998
									fprintf(nmfile,"%s added.\r\n",str);
999
1000
									if(stricmp(add_area[0],"+ALL"))
										add_area[y][0]=0;
1001
1002
									if(!(cfg.listcfg[j].misc&NOFWD)
										&& cfg.listcfg[j].forward.zone)
1003
1004
1005
										fprintf(fwdfile,"%s\r\n",str); 
								} 
							}
1006
1007
1008
							fclose(afilein);
							if(!(cfg.listcfg[j].misc&NOFWD) && ftell(fwdfile)>0)
								file_to_netmail(fwdfile,cfg.listcfg[j].password
1009
									,cfg.listcfg[j].forward,/* To: */"Areafix");
1010
1011
							fclose(fwdfile);
							match=1;
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
							break; 
						}
					}
				} 
			} 
		} 
	}
	if(strListCount(add_area) && stricmp(add_area[0],"+ALL")) {
		for(i=0;add_area[i]!=NULL;i++)
			if(add_area[i][0])
				fprintf(nmfile,"%s not found.\r\n",add_area[i]); 
	}
1024
	if(!ftell(nmfile))
1025
		create_netmail(to,/* from: */NULL,"Area Change Request","No changes made.",addr,time(NULL),FALSE);
1026
	else
1027
		file_to_netmail(nmfile,"Area Change Request",addr,to);
1028
1029
1030
	fclose(nmfile);
	fclose(afileout);
	if(delfile(cfg.areafile))					/* Delete AREAS.BBS */
1031
		lprintf(LOG_ERR,"ERROR line %d removing %s %s",__LINE__,cfg.areafile
1032
			,strerror(errno));
1033
	if(rename(outname,cfg.areafile))		   /* Rename new AREAS.BBS file */
1034
		lprintf(LOG_ERR,"ERROR line %d renaming %s to %s",__LINE__,outname,cfg.areafile);
1035
	free(outname);
1036
1037
1038
1039
1040
1041
1042
1043
1044
}
/******************************************************************************
 Used by AREAFIX to add/remove/change uplink info in the configuration file
 old = the old setting for this option, new = what the setting is changing to
 option = 0 for compression type change
		  1 for areafix password change
		  2 to set this node to passive
		  3 to set this node to active (remove passive)
******************************************************************************/
1045
void alter_config(faddr_t addr, char *old, char *new, int option)
1046
1047
{
	FILE *outfile,*cfgfile;
1048
	char outpath[MAX_PATH+1],cmd[32],arcname[32],*outname,*p,*tp
1049
		,match=0;
1050
1051
1052
1053
	char *afline=NULL;
	size_t afline_size;
	int cfgnum;
	int j,k;
1054
1055
	faddr_t taddr;

1056
	cfgnum=matchnode(addr,0);
1057
1058
	SAFECOPY(outpath,cfg.cfgfile);
	*getfname(outpath)=0;
1059
	if((outname=tempnam(outpath,"CFG"))==NULL) {