sbbsecho.c 147 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
70
71
72
73

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

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

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

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

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

98
#if defined(__unix__)	/* borrowed from MSVC */
rswindell's avatar
rswindell committed
99
unsigned _rotr (
100
101
102
103
        unsigned val,
        int shift
        )
{
104
105
106
107
108
109
110
111
112
113
114
    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 */
	}
115

116
    return num;
117
118
119
}
#endif

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

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

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

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

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

153
154
155
156
157
158
	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
159
	strip_ctrl(buf, buf);
160
161
	now=time(NULL);
	gm=localtime(&now);
162
	fprintf(fidologfile,"%02u/%02u/%02u %02u:%02u:%02u %s\n"
163
164
165
		,(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
166
		,buf);
167
168
169
170
171
}

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

178
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
	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);
209
210
						strcat(cmd,str); 
					}
211
212
213
214
215
216
217
218
219
220
221
222
					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);
223
224
						strcat(cmd,str); 
					}
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
					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 */
241
					strcat(cmd,cfg->exec_dir);
242
					break;
243
244
245
246
247
                case '@':   /* EXEC Directory for DOS/OS2/Win32, blank for Unix */
#ifndef __unix__
                    strcat(cmd,cfg->exec_dir);
#endif
                    break;
248
249
250
251
252
253
254
255
256
257
258
				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;
259
260
261
262
263
264
265
266
267
268
269
270
271
272
				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;
273
				default:    /* unknown specification */
274
					lprintf(LOG_ERR,"ERROR Checking Command Line '%s'",instr);
275
					bail(1);
276
277
278
279
					break; 
			}
			j=strlen(cmd); 
		}
280
		else
281
282
			cmd[j++]=instr[i]; 
}
283
	cmd[j]=0;
284

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

/****************************************************************************/
/* Runs an external program directly using spawnvp							*/
/****************************************************************************/
int execute(char *cmdline)
{
rswindell's avatar
rswindell committed
293
#if 1
294
	return system(cmdline);
rswindell's avatar
rswindell committed
295
#else
296
297
298
299
300
301
302
	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 */
303
		if(str[c]==' ') {
304
305
306
307
308
309
			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
310
#endif
311
}
312

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

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

326
327
328
329
330
/******************************************************************************
 This function creates or appends on existing Binkley compatible .?LO file
 attach file.
 Returns 0 on success.
******************************************************************************/
331
int write_flofile(char *attachment, faddr_t dest, BOOL bundle)
332
{
333
334
335
336
337
	char fname[MAX_PATH+1];
	char outbound[MAX_PATH+1];
	char str[MAX_PATH+1];
	char ch;
	char searchstr[MAX_PATH+1];
338
	ushort attr=0;
339
	int i;
340
341
342
343
344
345
	FILE *stream;

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

rswindell's avatar
rswindell committed
346
347
348
349
	if(attr&ATTR_CRASH) ch='c';
	else if(attr&ATTR_HOLD) ch='h';
	else if(attr&ATTR_DIRECT) ch='d';
	else ch='f';
350
	if(dest.zone==sys_faddr.zone)		/* Default zone, use default outbound */
351
		SAFECOPY(outbound,cfg.outbound);
352
	else {								/* Inter-zone outbound is OUTBOUND.XXX */
353
		SAFEPRINTF3(outbound,"%.*s.%03x"
rswindell's avatar
rswindell committed
354
			,(int)strlen(cfg.outbound)-1,cfg.outbound,dest.zone);
355
356
357
		MKDIR(outbound);
		backslash(outbound);
	}
358
	if(dest.point) {					/* Point destination is OUTBOUND\*.PNT */
rswindell's avatar
rswindell committed
359
		sprintf(str,"%04x%04x.pnt"
360
			,dest.net,dest.node);
361
362
		strcat(outbound,str); 
	}
rswindell's avatar
rswindell committed
363
364
	if(outbound[strlen(outbound)-1]=='\\'
		|| outbound[strlen(outbound)-1]=='/')
365
		outbound[strlen(outbound)-1]=0;
rswindell's avatar
rswindell committed
366
	MKDIR(outbound);
367
	backslash(outbound);
368
	if(dest.point)
rswindell's avatar
rswindell committed
369
		sprintf(fname,"%s%08x.%clo",outbound,dest.point,ch);
370
	else
rswindell's avatar
rswindell committed
371
		sprintf(fname,"%s%04x%04x.%clo",outbound,dest.net,dest.node,ch);
rswindell's avatar
rswindell committed
372
	if(bundle && (misc&TRUNC_BUNDLES))
373
374
375
		ch='#';
	else
		ch='^';
376
377
378
	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 */
379
	sprintf(searchstr,"%c%s",ch,attachment);
380
381
	if(findstr(searchstr,fname))	/* file already in FLO file */
		return(0);
382
	if((stream=fopen(fname,"a"))==NULL) {
383
		lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s",errno,strerror(errno),__LINE__,fname);
384
385
		return(-1); 
	}
386
	fprintf(stream,"%s\n",searchstr);
387
388
389
390
	fclose(stream);
	return(0);
}

391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
/* 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);
}

414
415
416
417
418
/******************************************************************************
 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.
******************************************************************************/
419
int create_netmail(char *to, char *subject, char *body, faddr_t dest, BOOL file_attached)
420
421
{
	FILE *fstream;
422
	char str[256],fname[MAX_PATH+1];
423
424
425
426
427
428
429
430
431
	ushort attr=0;
	int fmsg;
	uint i;
	static uint startmsg;
	time_t t;
	faddr_t	faddr;
	fmsghdr_t hdr;
	struct tm *tm;

432
433
434
435
436
437
438
	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)
439
440
441
				attr=cfg.nodecfg[i].attr; 
		} 
	}
442

443
	MKDIR(scfg.netmail_dir);
444
445
	do {
		for(i=startmsg;i;i++) {
446
			sprintf(fname,"%s%u.msg",scfg.netmail_dir,i);
447
448
449
			if(!fexistcase(fname))
				break; 
		}
450
		if(!i) {
451
			lprintf(LOG_WARNING,"Directory full: %s",scfg.netmail_dir);
452
453
			return(-1); 
		}
454
455
		startmsg=i+1;
		if((fstream=fnopen(&fmsg,fname,O_RDWR|O_CREAT))==NULL) {
456
457
458
			lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s",errno,strerror(errno),__LINE__,fname);
			return(-1); 
		}
459

460
461
462
463
464
465
466
467
468
469
470
471
		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);
472
		if(file_attached)
473
			hdr.attr|=FIDO_FILE;
474

475
476
477
478
		if(attr&ATTR_HOLD)
			hdr.attr|=FIDO_HOLD;
		if(attr&ATTR_CRASH)
			hdr.attr|=FIDO_CRASH;
479

480
481
482
483
484
485
486
487
488
		sprintf(hdr.from,"SBBSecho");

		t=time(NULL);
		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);

		if(to)
489
			SAFECOPY(hdr.to,to);
490
		else
491
			SAFECOPY(hdr.to,"SYSOP");
492

493
		SAFECOPY(hdr.subj,subject);
494
495
496
497
498
499

		fwrite(&hdr,sizeof(fmsghdr_t),1,fstream);
		sprintf(str,"\1INTL %hu:%hu/%hu %hu:%hu/%hu\r"
			,hdr.destzone,hdr.destnet,hdr.destnode
			,hdr.origzone,hdr.orignet,hdr.orignode);
		fwrite(str,strlen(str),1,fstream);
500
501
502
503
504
505
506
507

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

513
514
		if(hdr.destpoint) {
			sprintf(str,"\1TOPT %hu\r",hdr.destpoint);
515
516
			fwrite(str,strlen(str),1,fstream); 
		}
517
518
		if(hdr.origpoint) {
			sprintf(str,"\1FMPT %hu\r",hdr.origpoint);
519
520
			fwrite(str,strlen(str),1,fstream); 
		}
521
		if(!file_attached || (!(attr&ATTR_DIRECT) && file_attached))
522
			fwrite_crlf(body,strlen(body)+1,fstream);	/* Write additional NULL */
523
524
525
		else
			fwrite("\0",1,1,fstream);               /* Write NULL */
		fclose(fstream);
526
	} while(!fexistcase(fname));
527
	return(0);
528
529
530
531
532
533
534
535
536
537
538
}

/******************************************************************************
 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;

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

/* Returns TRUE if area is linked with specified node address */
BOOL area_is_linked(unsigned area_num, faddr_t* addr)
{
571
572
	unsigned i;
	for(i=0;i<cfg.area[area_num].uplinks;i++)
573
574
575
576
577
		if(!memcmp(addr,&cfg.area[area_num].uplink[i],sizeof(faddr_t)))
			return TRUE;
	return FALSE;
}

578
579
580
581
582
583
584
585
586
/******************************************************************************
 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
587
	uint	i,k;
588
589
590
591
592
593
594

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

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

		if((tmpf=tmpfile())==NULL) {
595
			lprintf(LOG_ERR,"ERROR line %d couldn't open tmpfile",__LINE__);
596
597
			return; 
		}
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622

		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;
623
624
625
			if(area_is_linked(i,&cfg.nodecfg[k].faddr))
				fprintf(tmpf,"%s",str); 
		}
626
627

		if(ftell(tmpf))
628
			file_to_netmail(tmpf,"SBBSecho Notify List",cfg.nodecfg[k].faddr, /* To: */NULL);
629
630
		fclose(tmpf); 
	}
631
}
632

633
634
635
636
/******************************************************************************
 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).
******************************************************************************/
637
638
639
640
641
642
enum arealist_type {
	 AREALIST_ALL			// %LIST
	,AREALIST_CONNECTED		// %QUERY
	,AREALIST_UNLINKED		// %UNLINKED
};
void netmail_arealist(enum arealist_type type, faddr_t addr, char* to)
643
{
644
645
	char str[256],title[128],match,*p,*tp;
	int i,j,k,x,y;
646
	str_list_t	area_list;
647

648
	if(type == AREALIST_ALL)
649
		strcpy(title,"List of Available Areas");
650
	else if(type == AREALIST_CONNECTED)
651
652
653
654
		strcpy(title,"List of Connected Areas");
	else
		strcpy(title,"List of Unlinked Areas");

655
656
	if((area_list=strListInit()) == NULL) {
		lprintf(LOG_ERR,"ERROR line %d couldn't allocate string list",__LINE__);
657
658
		return; 
	}
659

660
661
662
663
664
665
	/* 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;
666
		strListPush(&area_list, cfg.area[i].name); 
667
	} 
668

669
	if(type != AREALIST_CONNECTED) {
670
671
672
673
674
675
		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;
676
					for(x=0;x<cfg.nodecfg[i].numflags;x++) {
677
678
						if(!stricmp(cfg.listcfg[j].flag[k].flag
							,cfg.nodecfg[i].flag[x].flag)) {
679
680
							FILE* fp;
							if((fp=fopen(cfg.listcfg[j].listpath,"r"))==NULL) {
681
682
								lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s"
									,errno,strerror(errno),__LINE__,cfg.listcfg[j].listpath);
683
								match=1;
684
685
								break; 
							}
686
							while(!feof(fp)) {
687
								memset(str,0,sizeof(str));
688
								if(!fgets(str,sizeof(str),fp))
689
									break;
690
								truncsp(str);
691
								p=str;
692
								SKIP_WHITESPACE(p);
693
								if(*p==0 || *p==';')     /* Ignore Blank and Comment Lines */
694
									continue;
695
696
697
								tp=p;
								FIND_WHITESPACE(tp);
								*tp=0;
698
699
700
								for(y=0;y<cfg.areas;y++)
									if(!stricmp(cfg.area[y].name,p))
										break;
701
702
								if(y>=cfg.areas || !area_is_linked(y,&addr))
									strListPush(&area_list, p); 
703
							}
704
							fclose(fp);
705
							match=1;
706
							break; 
707
708
						}
					}
709
710
711
712
				} 
			} 
		} 
	}
713
714
	strListSortAlpha(area_list);
	if(!strListCount(area_list))
715
		create_netmail(to,title,"None.",addr,FALSE);
716
717
718
719
720
721
722
723
724
725
726
727
	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);
728
}
729

rswindell's avatar
rswindell committed
730
int check_elists(char *areatag,faddr_t addr)
731
732
{
	FILE *stream;
733
	char str[1025],quit=0,*p,*tp;
734
	int i,j,k,x,match=0;
735

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

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

857
858
859
860
861
862
						/* 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;
863
864
						if(cfg.area[i].uplinks==0) {
							FREE_AND_NULL(cfg.area[i].uplink);
865
						} else {
866
							if((cfg.area[i].uplink=(faddr_t *)
deuce's avatar
deuce committed
867
								realloc(cfg.area[i].uplink,sizeof(faddr_t)
868
								*(cfg.area[i].uplinks)))==NULL) {
869
870
								lprintf(LOG_ERR,"ERROR line %d allocating memory for area "
									"#%u uplinks.",__LINE__,i+1);
871
								bail(1); 
872
								return;
873
							}
874
						}
875
876
877
878
879
880
881

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

						/* 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
922
							realloc(cfg.area[i].uplink,sizeof(faddr_t)
923
							*(cfg.area[i].uplinks)))==NULL) {
924
925
							lprintf(LOG_ERR,"ERROR line %d allocating memory for area "
								"#%u uplinks.",__LINE__,i+1);
926
927
928
							bail(1); 
							return;
						}
929
						memcpy(&cfg.area[i].uplink[cfg.area[i].uplinks-1],&addr,sizeof(faddr_t));
930
931
932
933

						fprintf(afileout,"%-16s%-23s ",field1,field2);
						for(j=0;j<cfg.area[i].uplinks;j++)
							fprintf(afileout,"%s "
934
								,smb_faddrtoa(&cfg.area[i].uplink[j],NULL));
935
936
						if(field3[0])
							fprintf(afileout,"%s",field3);
937
						fprintf(afileout,"\n");
938
						fprintf(nmfile,"%s added.\r\n",field2);
939
940
941
						break; 
					} 
				}
942
				if(i==cfg.areas)			/* Something screwy going on */
943
					fprintf(afileout,"%s\n",fields);
944
945
946
947
948
949
				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 */
	}
950
	fclose(afilein);
951
	if(nomatch || (strListCount(add_area) && !stricmp(add_area[0],"+ALL"))) {
952
953
954
955
956
957
		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;
958
					for(x=0;x<cfg.nodecfg[i].numflags;x++) {
959
960
961
						if(!stricmp(cfg.listcfg[j].flag[k].flag
							,cfg.nodecfg[i].flag[x].flag)) {
							if((fwdfile=tmpfile())==NULL) {
962
								lprintf(LOG_ERR,"ERROR line %d opening forward temp "
963
964
									"file",__LINE__);
								match=1;
965
966
								break; 
							}
967
							if((afilein=fopen(cfg.listcfg[j].listpath,"r"))==NULL) {
968
969
								lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s"
									,errno,strerror(errno),__LINE__,cfg.listcfg[j].listpath);
970
971
								fclose(fwdfile);
								match=1;
972
973
								break; 
							}
974
							while(!feof(afilein)) {
975
								if(!fgets(str,sizeof(str),afilein))
976
									break;
977
								p=str;
978
								SKIP_WHITESPACE(p);
979
980
								if(*p==';')     /* Ignore Comment Lines */
									continue;
981
982
983
								tp=p;
								FIND_WHITESPACE(tp);
								*tp=0;
984
								if(add_area[0]!=NULL && stricmp(add_area[0],"+ALL")==0) {
985
986
									SAFECOPY(tmp,p);
									tagcrc=crc32(strupr(tmp),0);
987
988
989
990
									for(y=0;y<cfg.areas;y++)
										if(tagcrc==cfg.area[y].tag)
											break;
									if(y<cfg.areas)
991
992
993
994
995
996
										continue; 
								}
								for(y=0;add_area[y]!=NULL;y++)
									if((!stricmp(add_area[y],str) &&
										add_area[y][0]) ||
										!stricmp(add_area[0],"+ALL"))
997
										break;
998
								if(add_area[y]!=NULL) {
999
1000
1001
									fprintf(afileout,"%-16s%-23s","P",str);
									if(cfg.listcfg[j].forward.zone)
										fprintf(afileout," %s"
1002
1003
											,smb_faddrtoa(&cfg.listcfg[j].forward,NULL));
									fprintf(afileout," %s\n",smb_faddrtoa(&addr,NULL));
1004
									fprintf(nmfile,"%s added.\r\n",str);
1005
1006
									if(stricmp(add_area[0],"+ALL"))
										add_area[y][0]=0;
1007
1008
									if(!(cfg.listcfg[j].misc&NOFWD)
										&& cfg.listcfg[j].forward.zone)
1009
1010
1011
										fprintf(fwdfile,"%s\r\n",str); 
								} 
							}
1012
1013
1014
							fclose(afilein);
							if(!(cfg.listcfg[j].misc&NOFWD) && ftell(fwdfile)>0)
								file_to_netmail(fwdfile,cfg.listcfg[j].password
1015
									,cfg.listcfg[j].forward,/* To: */"Areafix");
1016
1017
							fclose(fwdfile);
							match=1;