sbbsecho.c 161 KB
Newer Older
1
/* Synchronet FidoNet EchoMail Scanning/Tossing and NetMail Tossing Utility */
2

3
/* $Id$ */
4
// vi: tabstop=4
5
6
7
8
9

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
10
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 *																			*
 * 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.	*
 ****************************************************************************/
36

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

#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
47
#include <sys/stat.h>
48
49
50
#if defined(__unix__)
	#include <signal.h>
#endif
51

rswindell's avatar
rswindell committed
52
#include "conwrap.h"		/* getch() */
53
54
55
56
57
58
#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
59
#include "genwrap.h"		/* PLATFORM_DESC */
rswindell's avatar
rswindell committed
60
61
62
#include "xpendian.h"

#define MAX_OPEN_SMBS	10
63
64

smb_t *smb,*email;
rswindell's avatar
rswindell committed
65
66
bool opt_import_packets		= true;
bool opt_import_netmail		= true;
rswindell's avatar
rswindell committed
67
bool opt_delete_netmail		= true;		/* delete after importing (no effect on exported netmail) */
rswindell's avatar
rswindell committed
68
69
70
71
72
73
74
75
76
bool opt_import_echomail	= true;
bool opt_export_echomail	= true;
bool opt_export_netmail		= true;
bool opt_pack_netmail		= true;
bool opt_gen_notify_list	= false;
bool opt_export_ftn_echomail= false;	/* Export msgs previously imported from FidoNet */
bool opt_update_msgptrs		= false;
bool opt_ignore_msgptrs		= false;
bool opt_leave_msgptrs		= false;
77
bool opt_dump_area_file		= false;
rswindell's avatar
rswindell committed
78

rswindell's avatar
rswindell committed
79
80
81
82
83
84
/* statistics */
ulong netmail=0;	/* imported */
ulong echomail=0;	/* imported */
ulong exported_netmail=0;
ulong exported_echomail=0;
ulong packed_netmail=0;
85
86
87
88
ulong packets_sent=0;
ulong packets_imported=0;
ulong bundles_sent=0;
ulong bundles_unpacked=0;
rswindell's avatar
rswindell committed
89

rswindell's avatar
rswindell committed
90
int cur_smb=0;
91
FILE *fidologfile=NULL;
rswindell's avatar
rswindell committed
92
bool twit_list;
rswindell's avatar
rswindell committed
93
str_list_t bad_areas;
94

rswindell's avatar
rswindell committed
95
96
97
98
99
fidoaddr_t		sys_faddr = {1,1,1,0};		/* Default system address: 1:1/1.0 */
sbbsecho_cfg_t	cfg;
scfg_t			scfg;
char			revision[16];
char			compiler[32];
100

rswindell's avatar
rswindell committed
101
102
103
104
bool pause_on_exit=false;
bool pause_on_abend=false;
bool mtxfile_locked=false;
bool terminated=false;
105

106
107
str_list_t	locked_bso_nodes;

rswindell's avatar
rswindell committed
108
109
110
int mv(const char *insrc, const char *indest, bool copy);
void export_echomail(const char *sub_code, const nodecfg_t*, bool rescan);

111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
const char default_domain[] = "fidonet";

const char* zone_domain(uint16_t zone)
{
	struct zone_mapping *i;

	if (!cfg.use_ftn_domains)
		return default_domain;

	for (i=cfg.zone_map; i; i=i->next)
		if (i->zone == zone)
			return i->domain;

	return default_domain;
}

const char* zone_root_outbound(uint16_t zone)
{
	struct zone_mapping *i;

	if (!cfg.use_ftn_domains)
		return cfg.outbound;

	for (i=cfg.zone_map; i; i=i->next)
		if (i->zone == zone)
			return i->root;

	return cfg.outbound;
}

141
142
143
144
145
146
147
148
149
150
151
/* FTN-compliant "Program Identifier"/PID (also used as a "Tosser Identifier"/TID) */
const char* sbbsecho_pid(void)
{
	static char str[256];
	
	sprintf(str, "SBBSecho %u.%02u-%s r%s %s %s"
		,SBBSECHO_VERSION_MAJOR,SBBSECHO_VERSION_MINOR,PLATFORM_DESC,revision,__DATE__,compiler);

	return str;
}

rswindell's avatar
rswindell committed
152
153
/* for *.bsy file contents: */
const char* program_id(void)
154
{
rswindell's avatar
rswindell committed
155
156
157
	static char str[256];
	
	SAFEPRINTF2(str, "%u %s", getpid(), sbbsecho_pid());
158

rswindell's avatar
rswindell committed
159
	return str;
160
161
}

rswindell's avatar
rswindell committed
162
163
164
165
/**********************/
/* Log print function */
/**********************/
int lprintf(int level, char *fmt, ...)
rswindell's avatar
rswindell committed
166
167
{
	va_list argptr;
rswindell's avatar
rswindell committed
168
	char sbuf[1024];
rswindell's avatar
rswindell committed
169
170
	int chcount;

rswindell's avatar
rswindell committed
171
172
	va_start(argptr,fmt);
	chcount=vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
173
	sbuf[sizeof(sbuf)-1]=0;
rswindell's avatar
rswindell committed
174
	va_end(argptr);
175
176
	truncsp(sbuf);
	printf("%s\n",sbuf);
177

rswindell's avatar
rswindell committed
178
179
180
181
	if(fidologfile!=NULL && level<=cfg.log_level) {
	    time_t now = time(NULL);
		struct tm *tm;
		struct tm tmbuf = {0};
182
		char timestamp[128];
rswindell's avatar
rswindell committed
183
184
185
		strip_ctrl(sbuf, sbuf);
		if((tm = localtime(&now)) == NULL)
			tm = &tmbuf;
186
187
188
189
190
		if(strftime(timestamp, sizeof(timestamp), cfg.logtime, tm) <= 0)
			snprintf(timestamp, sizeof(timestamp)-1, "%u-%02u-%02u %02u:%02u:%02u"
				,1900+tm->tm_year, tm->tm_mon+1, tm->tm_mday
				,tm->tm_hour, tm->tm_min, tm->tm_sec);
		fprintf(fidologfile, "%s %s\n", timestamp, sbuf);
rswindell's avatar
rswindell committed
191
192
		fflush(fidologfile);
	}
rswindell's avatar
rswindell committed
193
194
195
	return(chcount);
}

rswindell's avatar
rswindell committed
196
bool delfile(const char *filename, int line)
197
{
rswindell's avatar
rswindell committed
198
	lprintf(LOG_DEBUG, "Deleting %s (from line %u)", filename, line);
199
	if(remove(filename) != 0) {
200
201
		lprintf(LOG_ERR, "ERROR %u (%s) line %u removing file %s"
			,errno, strerror(errno), line, filename);
rswindell's avatar
rswindell committed
202
		return false;
203
	}
rswindell's avatar
rswindell committed
204
	return true;
205
206
}

207
208
209
/*****************************************************************************/
/* Returns command line generated from instr with %c replacments             */
/*****************************************************************************/
rswindell's avatar
rswindell committed
210
char *mycmdstr(scfg_t* cfg, const char *instr, const char *fpath, const char *fspec)
211
{
212
    static char cmd[MAX_PATH+1];
213
214
215
    char str[256],str2[128];
    int i,j,len;

216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
	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);
247
248
						strcat(cmd,str); 
					}
249
250
251
252
253
254
255
256
257
258
259
260
					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);
261
262
						strcat(cmd,str); 
					}
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
					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 */
279
					strcat(cmd,cfg->exec_dir);
280
					break;
281
282
283
284
285
                case '@':   /* EXEC Directory for DOS/OS2/Win32, blank for Unix */
#ifndef __unix__
                    strcat(cmd,cfg->exec_dir);
#endif
                    break;
286
287
288
289
290
291
292
293
294
295
296
				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;
297
298
299
300
301
302
303
304
305
306
				case '.':	/* .exe for DOS/OS2/Win32, blank for Unix */
#ifndef __unix__
					strcat(cmd,".exe");
#endif
					break;
				case '?':	/* Platform */
					strcpy(str,PLATFORM_DESC);
					strlwr(str);
					strcat(cmd,str);
					break;
307
				default:    /* unknown specification */
308
					lprintf(LOG_ERR,"ERROR Checking Command Line '%s'",instr);
309
					bail(1);
310
311
312
313
					break; 
			}
			j=strlen(cmd); 
		}
314
		else
315
316
			cmd[j++]=instr[i]; 
}
317
	cmd[j]=0;
318

319
	return(cmd);
320
321
322
}

/****************************************************************************/
rswindell's avatar
rswindell committed
323
/* Runs an external program directly using system()							*/
324
325
326
/****************************************************************************/
int execute(char *cmdline)
{
rswindell's avatar
rswindell committed
327
328
329
330
331
332
	int retval;
	
	lprintf(LOG_DEBUG, "Executing: %s", cmdline);
	if((retval = system(cmdline)) != 0)
		lprintf(LOG_ERR,"ERROR executing '%s' system returned: %d, errno: %d (%s)"
			,cmdline, retval, errno, strerror(errno));
333

rswindell's avatar
rswindell committed
334
	return retval;
335
}
336

337
338
339
/******************************************************************************
 Returns the system address with the same zone as the address passed
******************************************************************************/
rswindell's avatar
rswindell committed
340
fidoaddr_t getsysfaddr(short zone)
341
342
{
	int i;
343

344
345
346
	for(i=0;i<scfg.total_faddrs;i++)
		if(scfg.faddr[i].zone==zone)
			return(scfg.faddr[i]);
347
	return(sys_faddr);
348
}
349

rswindell's avatar
rswindell committed
350
int get_outbound(fidoaddr_t dest, char* outbound, size_t maxlen, bool fileboxes)
351
{
rswindell's avatar
rswindell committed
352
353
	nodecfg_t*	nodecfg;

354
	strncpy(outbound,zone_root_outbound(dest.zone),maxlen);
rswindell's avatar
rswindell committed
355
356
357
358
359
360
	if(fileboxes &&
		(nodecfg = findnodecfg(&cfg, dest, /* exact */true)) != NULL
		&& nodecfg->outbox[0])
		strncpy(outbound, nodecfg->outbox, maxlen);
	else if(cfg.flo_mailer) {
		if(dest.zone != sys_faddr.zone)	{ /* Inter-zone outbound is "OUTBOUND.ZZZ/" */
361
362
363
			char* p = lastchar(outbound);
			if(IS_PATH_DELIM(*p))
				*p = 0;
rswindell's avatar
rswindell committed
364
365
366
367
368
369
			safe_snprintf(outbound+strlen(outbound), maxlen,".%03x", dest.zone);
		}
		if(dest.point != 0) {			/* Point destination is "OUTBOUND[.ZZZ]/NNNNnnnn.pnt/" */
			backslash(outbound);
			safe_snprintf(outbound+strlen(outbound), maxlen, "%04x%04x.pnt", dest.net, dest.node);
		}
370
371
	}
	backslash(outbound);
372
373
374
	if(isdir(outbound))
		return 0;
	lprintf(LOG_DEBUG, "Creating outbound directory for %s: %s", smb_faddrtoa(&dest, NULL), outbound);
375
376
377
	return mkpath(outbound);
}

rswindell's avatar
rswindell committed
378
379
380
381
382
383
384
385
const char* get_current_outbound(fidoaddr_t dest, bool fileboxes)
{
	static char outbound[MAX_PATH+1];
	get_outbound(dest, outbound, sizeof(outbound)-1, fileboxes);
	return outbound;
}

bool bso_lock_node(fidoaddr_t dest)
386
{
rswindell's avatar
rswindell committed
387
	const char* outbound;
388
389
	char fname[MAX_PATH+1];

rswindell's avatar
rswindell committed
390
391
	if(!cfg.flo_mailer)
		return true;
392

rswindell's avatar
rswindell committed
393
	outbound = get_current_outbound(dest, /* fileboxes: */false);
394
395
396
397
398
399

	if(dest.point)
		SAFEPRINTF2(fname,"%s%08x.bsy",outbound,dest.point);
	else
		SAFEPRINTF3(fname,"%s%04x%04x.bsy",outbound,dest.net,dest.node);

rswindell's avatar
rswindell committed
400
401
402
403
404
	if(strListFind(locked_bso_nodes, fname, /* case_sensitive: */true) >= 0)
		return true;
	for(unsigned attempt=0;;) {
		if(fmutex(fname, program_id(), cfg.bsy_timeout))
			break;
405
		lprintf(LOG_NOTICE, "Node (%s) externally locked via: %s", smb_faddrtoa(&dest, NULL), fname);
rswindell's avatar
rswindell committed
406
407
408
409
410
411
412
		if(++attempt >= cfg.bso_lock_attempts) {
			lprintf(LOG_WARNING, "Giving up after %u attempts to lock node %s", attempt, smb_faddrtoa(&dest, NULL));
			return false;
		}
		if(terminated)
			return false;
		SLEEP(cfg.bso_lock_delay*1000);
413
414
415
	}
	strListPush(&locked_bso_nodes, fname);
	lprintf(LOG_DEBUG, "Node (%s) successfully locked via: %s", smb_faddrtoa(&dest, NULL), fname);
rswindell's avatar
rswindell committed
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
	return true;
}

const char* bso_flo_filename(fidoaddr_t dest)
{
	nodecfg_t* nodecfg;
	char ch='f';
	const char* outbound;
	static char filename[MAX_PATH+1];

	if((nodecfg=findnodecfg(&cfg, dest, /* exact: */false)) != NULL) {
		switch(nodecfg->status) {
			case MAIL_STATUS_CRASH:	ch='c';	break;
			case MAIL_STATUS_HOLD:	ch='h';	break;
			default:
				if(nodecfg->direct)
					ch='d';
				break;
		}
	}
	outbound = get_current_outbound(dest, /* fileboxes: */false);

	if(dest.point)
		SAFEPRINTF3(filename,"%s%08x.%clo",outbound,dest.point,ch);
	else
		SAFEPRINTF4(filename,"%s%04x%04x.%clo",outbound,dest.net,dest.node,ch);
	return filename;
}

bool bso_file_attached_to_flo(const char* attachment, fidoaddr_t dest, bool bundle)
{
	char searchstr[MAX_PATH+1];
	SAFEPRINTF2(searchstr,"%c%s",(bundle && cfg.trunc_bundles) ? '#':'^', attachment);
	return findstr(searchstr, bso_flo_filename(dest));
450
451
}

452
453
454
455
456
/******************************************************************************
 This function creates or appends on existing Binkley compatible .?LO file
 attach file.
 Returns 0 on success.
******************************************************************************/
rswindell's avatar
rswindell committed
457
int write_flofile(const char *infile, fidoaddr_t dest, bool bundle, bool use_outbox)
458
{
rswindell's avatar
rswindell committed
459
460
	const char* flo_filename;
	char attachment[MAX_PATH+1];
461
	char searchstr[MAX_PATH+1];
rswindell's avatar
rswindell committed
462
463
	FILE *fp;
	nodecfg_t* nodecfg;
464

rswindell's avatar
rswindell committed
465
466
467
468
	if(use_outbox && (nodecfg=findnodecfg(&cfg, dest, /* exact: */false)) != NULL) {
		if(nodecfg->outbox[0])
			return 0;
	}
469
470
471
472

	if(!bso_lock_node(dest))
		return 1;

rswindell's avatar
rswindell committed
473
474
475
476
477
	flo_filename = bso_flo_filename(dest);
	SAFECOPY(attachment, infile);
	if(!fexistcase(attachment))	{ /* just in-case it's the wrong case for a Unix file system */
		lprintf(LOG_ERR, "ERROR line %u, attachment file not found: %s", __LINE__, attachment);
		return -1;
478
	}
rswindell's avatar
rswindell committed
479
480
481
482
483
484
485
486
487
488
489
490
	SAFEPRINTF2(searchstr,"%c%s",bundle && (cfg.trunc_bundles) ? '#':'^', attachment);
	if(findstr(searchstr,flo_filename))	/* file already in FLO file */
		return 0;
	if((fp=fopen(flo_filename,"a"))==NULL) {
		lprintf(LOG_ERR,"ERROR %u (%s) opening %s",errno, strerror(errno), flo_filename);
		return -1; 
	}
	fprintf(fp,"%s\n",searchstr);
	fclose(fp);
	lprintf(LOG_INFO, "File (%s, %1.1fKB) for %s added to BSO/FLO file: %s"
		,attachment, flength(attachment)/1024.0, smb_faddrtoa(&dest,NULL), flo_filename);
	return 0;
491
492
}

493
/* Writes text buffer to file, expanding sole LFs to CRLFs */
rswindell's avatar
rswindell committed
494
size_t fwrite_crlf(const char* buf, size_t len, FILE* fp)
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
{
	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);
}

rswindell's avatar
rswindell committed
516
bool fidoctrl_line_exists(const smbmsg_t* msg, const char* prefix)
517
{
518
	if(msg==NULL || prefix==NULL)
rswindell's avatar
rswindell committed
519
		return false;
520
521
522
	for(int i=0; i<msg->total_hfields; i++) {
		if(msg->hfield[i].type == FIDOCTRL
			&& strncmp((char*)msg->hfield_dat[i], prefix, strlen(prefix)) == 0)
rswindell's avatar
rswindell committed
523
			return true;
524
	}
rswindell's avatar
rswindell committed
525
	return false;
526
527
}

rswindell's avatar
rswindell committed
528
fidoaddr_t fmsghdr_srcaddr(const fmsghdr_t* hdr)
529
530
531
532
533
534
535
536
537
538
539
{
	fidoaddr_t addr;

	addr.zone	= hdr->origzone;
	addr.net	= hdr->orignet;
	addr.node	= hdr->orignode;
	addr.point	= hdr->origpoint;

	return addr;
}

rswindell's avatar
rswindell committed
540
const char* fmsghdr_srcaddr_str(const fmsghdr_t* hdr)
541
542
543
544
545
546
547
{
	static char buf[64];
	fidoaddr_t addr = fmsghdr_srcaddr(hdr);

	return smb_faddrtoa(&addr, buf);
}

rswindell's avatar
rswindell committed
548
fidoaddr_t fmsghdr_destaddr(const fmsghdr_t* hdr)
549
550
551
552
553
554
555
556
557
558
559
{
	fidoaddr_t addr;

	addr.zone	= hdr->destzone;
	addr.net	= hdr->destnet;
	addr.node	= hdr->destnode;
	addr.point	= hdr->destpoint;

	return addr;
}

rswindell's avatar
rswindell committed
560
const char* fmsghdr_destaddr_str(const fmsghdr_t* hdr)
561
562
563
564
565
566
567
{
	static char buf[64];
	fidoaddr_t addr = fmsghdr_destaddr(hdr);

	return smb_faddrtoa(&addr, buf);
}

568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
bool parse_origin(const char* fmsgbuf, fmsghdr_t* hdr)
{
	char* p;
	fidoaddr_t origaddr;
	
	if((p = strstr(fmsgbuf, FIDO_ORIGIN_PREFIX_FORM_1)) == NULL)
		p = strstr(fmsgbuf, FIDO_ORIGIN_PREFIX_FORM_2);
	if(p == NULL)
		return false;

	p += FIDO_ORIGIN_PREFIX_LEN;
	p = strrchr(p, '(');
	if(p == NULL)
		return false;
	p++;
	origaddr = atofaddr(p);
rswindell's avatar
rswindell committed
584
	if(origaddr.zone == 0 || faddr_contains_wildcard(&origaddr))
585
586
587
588
589
590
591
592
		return false;
	hdr->origzone	= origaddr.zone;
	hdr->orignet	= origaddr.net;
	hdr->orignode	= origaddr.node;
	hdr->origpoint	= origaddr.point;
	return true;
}

rswindell's avatar
rswindell committed
593
594
595
596
bool parse_pkthdr(const fpkthdr_t* hdr, fidoaddr_t* orig_addr, fidoaddr_t* dest_addr, enum pkt_type* pkt_type)
{
	fidoaddr_t	orig;
	fidoaddr_t	dest;
rswindell's avatar
rswindell committed
597
	enum pkt_type type = PKT_TYPE_2;
rswindell's avatar
rswindell committed
598
599
600
601
602
603
604
605
606
607
608
609
610
611

	if(hdr->type2.pkttype != 2)
		return false;

	orig.zone	= hdr->type2.origzone;
	orig.net	= hdr->type2.orignet;
	orig.node	= hdr->type2.orignode;
	orig.point	= 0;

	dest.zone	= hdr->type2.destzone;
	dest.net	= hdr->type2.destnet;
	dest.node	= hdr->type2.destnode;
	dest.point	= 0;				/* No point info in the 2.0 hdr! */

rswindell's avatar
rswindell committed
612
613
614
615
	if(hdr->type2plus.cword == BYTE_SWAP_16(hdr->type2plus.cwcopy)  /* 2e Packet Header (FSC-39) */
		&& (hdr->type2plus.cword&1)) {	/* Some call this a Type-2+ packet, but it's not (yet) FSC-48 conforming */
		type = PKT_TYPE_2_EXT;
		orig.point = hdr->type2plus.origpoint;
rswindell's avatar
rswindell committed
616
		dest.point = hdr->type2plus.destpoint;
rswindell's avatar
rswindell committed
617
618
619
620
621
622
		if(orig.zone == 0) orig.zone = hdr->type2plus.origzone;
		if(dest.zone == 0) dest.zone = hdr->type2plus.destzone;
		if(hdr->type2plus.auxnet != 0) {	/* strictly speaking, auxnet may be 0 and a valid 2+ packet */
			type = PKT_TYPE_2_PLUS;
			if(orig.point != 0 && orig.net == 0xffff) 	/* see FSC-0048 for details */
				orig.net = hdr->type2plus.auxnet;
rswindell's avatar
rswindell committed
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
		}
	} else if(hdr->type2_2.subversion==2) {					/* Type 2.2 Packet Header (FSC-45) */
		type = PKT_TYPE_2_2;
		orig.point = hdr->type2_2.origpoint;
		dest.point = hdr->type2_2.destpoint; 
	}

	if(pkt_type != NULL)
		*pkt_type = type;
	if(dest_addr != NULL)
		*dest_addr = dest;
	if(orig_addr != NULL)
		*orig_addr = orig;
	
	return true;
}

bool new_pkthdr(fpkthdr_t* hdr, fidoaddr_t orig, fidoaddr_t dest, const nodecfg_t* nodecfg)
{
rswindell's avatar
rswindell committed
642
	enum pkt_type pkt_type = PKT_TYPE_2;
rswindell's avatar
rswindell committed
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
	struct tm* tm;
	time_t now = time(NULL);

	if(nodecfg != NULL)
		pkt_type = nodecfg->pkt_type;

	memset(hdr, 0, sizeof(fpkthdr_t));

	if((tm = localtime(&now)) != NULL) {
		hdr->type2.year	= tm->tm_year+1900;
		hdr->type2.month= tm->tm_mon;
		hdr->type2.day	= tm->tm_mday;
		hdr->type2.hour	= tm->tm_hour;
		hdr->type2.min	= tm->tm_min;
		hdr->type2.sec	= tm->tm_sec;
	}

	hdr->type2.origzone = orig.zone;
	hdr->type2.orignet	= orig.net;
	hdr->type2.orignode	= orig.node;
	hdr->type2.destzone	= dest.zone;
	hdr->type2.destnet	= dest.net;
	hdr->type2.destnode	= dest.node;
	
	hdr->type2.pkttype	= 2;
	hdr->type2.prodcode	= SBBSECHO_PRODUCT_CODE&0xff;
	hdr->type2.sernum	= SBBSECHO_VERSION_MAJOR;

	if(nodecfg != NULL && nodecfg->pktpwd[0] != 0)
672
		strncpy((char*)hdr->type2.password, nodecfg->pktpwd, sizeof(hdr->type2.password));
rswindell's avatar
rswindell committed
673

rswindell's avatar
rswindell committed
674
	if(pkt_type == PKT_TYPE_2)
rswindell's avatar
rswindell committed
675
676
677
678
		return true;

	if(pkt_type == PKT_TYPE_2_2) {
		hdr->type2_2.subversion = 2;	/* 2.2 */
679
680
		strncpy((char*)hdr->type2_2.origdomn,zone_domain(orig.zone),sizeof(hdr->type2_2.origdomn));
		strncpy((char*)hdr->type2_2.destdomn,zone_domain(dest.zone),sizeof(hdr->type2_2.destdomn));
rswindell's avatar
rswindell committed
681
682
683
		return true;
	}
	
rswindell's avatar
rswindell committed
684
685
	/* 2e and 2+ */
	if(pkt_type != PKT_TYPE_2_EXT && pkt_type != PKT_TYPE_2_PLUS) {
rswindell's avatar
rswindell committed
686
687
688
689
		lprintf(LOG_ERR, "UNSUPPORTED PACKET TYPE: %u", pkt_type);
		return false;
	}

rswindell's avatar
rswindell committed
690
691
692
693
	if(pkt_type == PKT_TYPE_2_PLUS) {
		if(orig.point != 0)
			hdr->type2plus.orignet	= 0xffff;
		hdr->type2plus.auxnet	= orig.net; /* Squish always copies the orignet here */
rswindell's avatar
rswindell committed
694
695
696
697
698
699
700
701
702
703
704
705
706
	}
	hdr->type2plus.cword		= 0x0001;
	hdr->type2plus.cwcopy		= 0x0100;
	hdr->type2plus.prodcodeHi	= SBBSECHO_PRODUCT_CODE>>8;
	hdr->type2plus.prodrevMinor	= SBBSECHO_VERSION_MINOR;
	hdr->type2plus.origzone		= orig.zone;
	hdr->type2plus.destzone		= dest.zone;
	hdr->type2plus.origpoint	= orig.point;
	hdr->type2plus.destpoint	= dest.point;

	return true;
}

707
708
709
710
711
/******************************************************************************
 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.
******************************************************************************/
rswindell's avatar
rswindell committed
712
713
int create_netmail(const char *to, const smbmsg_t* msg, const char *subject, const char *body, fidoaddr_t dest
					,bool file_attached)
714
{
715
	FILE *fp;
716
	char tmp[256];
717
	char fname[MAX_PATH+1];
718
	char* from=NULL;
719
720
	uint i;
	static uint startmsg;
rswindell's avatar
rswindell committed
721
	fidoaddr_t	faddr;
722
	fmsghdr_t hdr;
723
	time_t t;
724
	struct tm *tm;
725
	when_t when_written;
rswindell's avatar
rswindell committed
726
727
	nodecfg_t* nodecfg;
	bool	direct=false;
728

729
	if(msg==NULL) {
rswindell's avatar
rswindell committed
730
		when_written.time = time32(NULL);
731
732
733
734
735
		when_written.zone = sys_timezone(&scfg);
	} else {
		from = msg->from;
		when_written = msg->hdr.when_written;
	}
736
737
738
739
	if(from==NULL)
		from="SBBSecho";
	if(to==NULL)
		to="Sysop";
740
	if(!startmsg) startmsg=1;
rswindell's avatar
rswindell committed
741
742
743
	if((nodecfg=findnodecfg(&cfg, dest, 0)) != NULL) {
		if(nodecfg->status == MAIL_STATUS_NORMAL && !nodecfg->direct)
			nodecfg=findnodecfg(&cfg, dest, /* skip exact match: */2);
744
	}
745

746
	MKDIR(scfg.netmail_dir);
747
748
749
750
751
752
753
754
755
756
	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;
757
	if((fp=fnopen(NULL,fname,O_RDWR|O_CREAT))==NULL) {
758
759
760
		lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s",errno,strerror(errno),__LINE__,fname);
		return(-1); 
	}
761

762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
	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;

rswindell's avatar
rswindell committed
777
778
779
780
	if(nodecfg != NULL) {
		switch(nodecfg->status) {
			case MAIL_STATUS_HOLD:	hdr.attr|=FIDO_HOLD;	break;
			case MAIL_STATUS_CRASH:	hdr.attr|=FIDO_CRASH;	break;
781
			case MAIL_STATUS_NORMAL:						break;
rswindell's avatar
rswindell committed
782
783
784
		}
		direct = nodecfg->direct;
	}
785

786
	t = when_written.time;
rswindell's avatar
rswindell committed
787
	tm = localtime(&t);
788
789
790
791
792
793
794
795
796
797
798
799
800
	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);

801
802
803
804
805
806
807
808
809
	if(!fidoctrl_line_exists(msg, "TZUTC:")) {
		/* TZUTC (FSP-1001) */
		int tzone=smb_tzutc(when_written.zone);
		char* minus="";
		if(tzone<0) {
			minus="-";
			tzone=-tzone;
		}
		fprintf(fp,"\1TZUTC: %s%02d%02u\r", minus, tzone/60, tzone%60);
810
	}
811
812
	/* Add FSC-53 FLAGS kludge */
	fprintf(fp,"\1FLAGS");
rswindell's avatar
rswindell committed
813
	if(direct)
814
815
		fprintf(fp," DIR");
	if(file_attached) {
rswindell's avatar
rswindell committed
816
		if(cfg.trunc_bundles)
817
			fprintf(fp," TFS");
818
		else
819
820
821
			fprintf(fp," KFS");
	}
	fprintf(fp,"\r");
822

823
824
825
826
	if(hdr.destpoint)
		fprintf(fp,"\1TOPT %hu\r",hdr.destpoint);
	if(hdr.origpoint)
		fprintf(fp,"\1FMPT %hu\r",hdr.origpoint);
827
828
829
830
831
832
833
	fprintf(fp,"\1PID: %s\r", (msg==NULL || msg->ftn_pid==NULL) ? sbbsecho_pid() : msg->ftn_pid);
	if(msg != NULL) {
		/* Unknown kludge lines are added here */
		for(int i=0; i<msg->total_hfields; i++)
			if(msg->hfield[i].type == FIDOCTRL)
				fprintf(fp,"\1%.512s\r",(char*)msg->hfield_dat[i]);
	}
rswindell's avatar
rswindell committed
834
	if(!file_attached || (!direct && file_attached))
835
836
837
		fwrite_crlf(body,strlen(body)+1,fp);	/* Write additional NULL */
	else
		fwrite("\0",1,1,fp);               /* Write NULL */
rswindell's avatar
rswindell committed
838
839
840
	lprintf(LOG_INFO, "Created NetMail (%s)%s from %s (%s) to %s (%s), attr: %04hX, subject: %s"
		,getfname(fname), file_attached ? " with attachment" : ""
		,from, smb_faddrtoa(&faddr, tmp), to, smb_faddrtoa(&dest, NULL), hdr.attr, subject);
841
	return fclose(fp);
842
843
844
845
846
847
}

/******************************************************************************
 This function takes the contents of 'infile' and puts it into a netmail
 message bound for addr.
******************************************************************************/
rswindell's avatar
rswindell committed
848
void file_to_netmail(FILE* infile, const char* title, fidoaddr_t dest, const char* to)
849
850
851
852
{
	char *buf,*p;
	long l,m,len;

853
854
855
856
	l=len=ftell(infile);
	if(len>8192L)
		len=8192L;
	rewind(infile);
deuce's avatar
deuce committed
857
	if((buf=(char *)malloc(len+1))==NULL) {
858
		lprintf(LOG_ERR,"ERROR line %d allocating %lu for file to netmail buf",__LINE__,len);
859
860
		return; 
	}
861
862
863
	while((m=fread(buf,1,(len>8064L) ? 8064L:len,infile))>0) {
		buf[m]=0;
		if(l>8064L && (p=strrchr(buf,'\n'))!=NULL) {
864
			p++;
865
866
			if(*p) {
				*p=0;
867
				p++;
868
869
870
				fseek(infile,-1L,SEEK_CUR);
				while(*p) { 			/* Seek back to end of last line */
					p++;
871
872
873
874
					fseek(infile,-1L,SEEK_CUR); 
				} 
			} 
		}
875
876
		if(ftell(infile)<l)
			strcat(buf,"\r\nContinued in next message...\r\n");
rswindell's avatar
rswindell committed
877
		create_netmail(to, /* msg: */NULL, title, buf, dest, /* attachment: */false); 
878
	}
deuce's avatar
deuce committed
879
	free(buf);
880
}
881

rswindell's avatar
rswindell committed
882
883
/* Returns true if area is linked with specified node address */
bool area_is_linked(unsigned area_num, const fidoaddr_t* addr)
884
{
885
	unsigned i;
rswindell's avatar
rswindell committed
886
887
888
889
	for(i=0;i<cfg.area[area_num].links;i++)
		if(!memcmp(addr,&cfg.area[area_num].link[i],sizeof(fidoaddr_t)))
			return true;
	return false;
890
891
}

892
893
/* Returns area index */
uint find_area(const char* echotag)
rswindell's avatar
rswindell committed
894
{
895
896
897
898
899
900
901
902
903
904
905
906
907
908
	unsigned u;

	for(u=0; u < cfg.areas; u++)
		if(stricmp(cfg.area[u].name, echotag) == 0)
			break;

	return u;
}

bool area_is_valid(uint areanum)
{
	return areanum < cfg.areas;
}

909
910
/* Returns subnum (INVALID_SUB if pass-through) or SUB_NOT_FOUND */
#define SUB_NOT_FOUND ((uint)-2)
911
912
913
914
915
uint find_linked_area(const char* echotag, fidoaddr_t addr)
{
	unsigned area;

	if(area_is_valid(area = find_area(echotag)) && area_is_linked(area, &addr))
916
		return cfg.area[area].sub;
rswindell's avatar
rswindell committed
917

918
	return SUB_NOT_FOUND;
rswindell's avatar
rswindell committed
919
920
}

921
922
923
924
925
/******************************************************************************
 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.
******************************************************************************/
rswindell's avatar
rswindell committed
926
void gen_notify_list(void)
927
928
929
{
	FILE *	tmpf;
	char	str[256];
deuce's avatar
deuce committed
930
	uint	i,k;
931

rswindell's avatar
rswindell committed
932
	for(k=0;k<cfg.nodecfgs && !terminated;k++) {
933

rswindell's avatar
rswindell committed
934
		if(!cfg.nodecfg[k].send_notify)
935
936
937
			continue;

		if((tmpf=tmpfile())==NULL) {
938
			lprintf(LOG_ERR,"ERROR line %d couldn't open tmpfile",__LINE__);
939
940
			return; 
		}
941
942
943
944

		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");
rswindell's avatar
rswindell committed
945
		fprintf(tmpf,"Packet Type       %s\r\n", pktTypeStringList[cfg.nodecfg[k].pkt_type]);
946
		fprintf(tmpf,"Archive Type      %s\r\n"
rswindell's avatar
rswindell committed
947
948
949
			,cfg.nodecfg[k].archive == SBBSECHO_ARCHIVE_NONE ? "None" : cfg.nodecfg[k].archive->name);
		fprintf(tmpf,"Mail Status       %s\r\n", mailStatusStringList[cfg.nodecfg[k].status]);
		fprintf(tmpf,"Direct            %s\r\n", cfg.nodecfg[k].direct ? "Yes":"No");
950
		fprintf(tmpf,"Passive (paused)  %s\r\n", cfg.nodecfg[k].passive ? "Yes":"No");
951
952
953
954
955
956
957
958
		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;
rswindell's avatar
rswindell committed
959
			if(area_is_linked(i,&cfg.nodecfg[k].addr))
960
961
				fprintf(tmpf,"%s",str); 
		}
962
963

		if(ftell(tmpf))
rswindell's avatar
rswindell committed
964
			file_to_netmail(tmpf,"SBBSecho Notify List",cfg.nodecfg[k].addr, /* To: */NULL);
965
966
		fclose(tmpf); 
	}
967
}
968

969
970
971
972
/******************************************************************************
 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).
******************************************************************************/
973
974
975
976
977
enum arealist_type {
	 AREALIST_ALL			// %LIST
	,AREALIST_CONNECTED		// %QUERY
	,AREALIST_UNLINKED		// %UNLINKED
};
rswindell's avatar
rswindell committed
978
void netmail_arealist(enum arealist_type type, fidoaddr_t addr, const char* to)
979
{
980
	char str[256],title[128],match,*p,*tp;
981
	unsigned k,x;
982
	unsigned u;
983
	str_list_t	area_list;
984

985
	if(type == AREALIST_ALL)
986
		strcpy(title,"List of Available Areas");
987
	else if(type == AREALIST_CONNECTED)
988
989
990
991
		strcpy(title,"List of Connected Areas");
	else
		strcpy(title,"List of Unlinked Areas");

992
993
	if((area_list=strListInit()) == NULL) {
		lprintf(LOG_ERR,"ERROR line %d couldn't allocate string list",__LINE__);
994
995
		return; 
	}
996

997
	/* Include relevant areas from the area file (e.g. areas.bbs): */
998
999
	for(u=0;u<cfg.areas;u++) {
		if((type == AREALIST_CONNECTED || cfg.add_from_echolists_only) && !area_is_linked(u,&addr))
1000
			continue;
1001
		if(type == AREALIST_UNLINKED && area_is_linked(u,&addr))
1002
			continue;
1003
		strListPush(&area_list, cfg.area[u].name); 
1004
	} 
1005

1006
	if(type != AREALIST_CONNECTED) {
rswindell's avatar
rswindell committed
1007
1008
		nodecfg_t* nodecfg=findnodecfg(&cfg, addr,0);
		if(nodecfg != NULL) {
1009
			for(u=0;u<cfg.listcfgs;u++) {
1010
				match=0;
1011
				for(k=0; cfg.listcfg[u].keys[k]; k++) {
1012
					if(match) break;
rswindell's avatar
rswindell committed
1013
					for(x=0; nodecfg->keys[x]; x++) {
1014
						if(!stricmp(cfg.listcfg[u].keys[k]
rswindell's avatar
rswindell committed
1015
							,nodecfg->keys[x])) {
1016
							FILE* fp;
1017
							if((fp=fopen(cfg.listcfg[u].listpath,"r"))==NULL) {
1018
								lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s"
1019
									,errno,strerror(errno),__LINE__,cfg.listcfg[u].listpath);
1020
								match=1;
1021
1022
								break; 
							}
1023
							while(!feof(fp)) {
1024
								memset(str,0,sizeof(str));
1025
								if(!fgets(str,sizeof(str),fp))
1026
									break;
1027
								truncsp(str);
1028
								p=str;
1029
								SKIP_WHITESPACE(p);
1030
								if(*p==0 || *p==';')     /* Ignore Blank and Comment Lines */
1031
									continue;
1032
1033
1034
								tp=p;
								FIND_WHITESPACE(tp);
								*tp=0;
1035
								if(find_linked_area(p, addr) == SUB_NOT_FOUND) {
1036
1037
1038
									if(strListFind(area_list, p, /* case_sensitive */false) < 0)
										strListPush(&area_list, p);
								}
1039
							}
1040
							fclose(fp);
1041
							match=1;
1042
							break; 
1043
1044
						}
					}
1045
1046
1047
1048
				} 
			} 
		} 
	}
1049
1050
	strListSortAlpha(area_list);
	if(!strListCount(area_list))
rswindell's avatar
rswindell committed
1051
		create_netmail(to,/* msg: */NULL,title,"None.",addr,/* attachment: */false);
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
	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);
1064
}
1065

rswindell's avatar
rswindell committed
1066
int check_elists(const char *areatag, fidoaddr_t addr)
1067
1068
{
	FILE *stream;
1069
	char str[1025],quit=0,*p,*tp;
1070
1071
	unsigned k,x,match=0;
	unsigned u;
1072

rswindell's avatar
rswindell committed
1073
1074
	nodecfg_t* nodecfg=findnodecfg(&cfg, addr,0);
	if(nodecfg!=NULL) {
1075
		for(u=0;u<cfg.listcfgs;u++) {
rswindell's avatar
rswindell committed
1076
			quit=0;
1077
			for(k=0; cfg.listcfg[u].keys[k]; k++) {
rswindell's avatar
rswindell committed
1078
				if(quit) break;
rswindell's avatar
rswindell committed
1079
				for(x=0; nodecfg->keys[x] ;x++)
1080
					if(!stricmp(cfg.listcfg[u].keys[k]
rswindell's avatar
rswindell committed
1081
						,nodecfg->keys[x])) {
1082
						if((stream=fopen(cfg.listcfg[u].listpath,"r"))==NULL) {
1083
							lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s"
1084
								,errno,strerror(errno),__LINE__,cfg.listcfg[u].listpath);
rswindell's avatar
rswindell committed
1085
							quit=1;
1086
1087
							break; 
						}
rswindell's avatar
rswindell committed
1088
						while(!feof(stream)) {
1089
							if(!fgets(str,sizeof(str),stream))
rswindell's avatar
rswindell committed
1090
1091
								break;
							p=str;
1092
							SKIP_WHITESPACE(p);
rswindell's avatar
rswindell committed
1093
1094
							if(*p==';')     /* Ignore Comment Lines */
								continue;
1095
1096
1097
1098
							tp=p;
							FIND_WHITESPACE(tp);
							*tp=0;
							if(!stricmp(areatag,p)) {
rswindell's avatar
rswindell committed
1099
								match=1;
1100
1101
1102
								break; 
							} 
						}
rswindell's avatar
rswindell committed
1103
						fclose(stream);
1104
						quit=1;
rswindell's avatar
rswindell committed
1105
1106
						if(match)
							return(match);
1107
1108
1109
1110
1111
						break; 
					} 
			} 
		} 
	}
rswindell's avatar
rswindell committed
1112
	return(match);
1113
1114
1115
1116
}
/******************************************************************************
 Used by AREAFIX to add/remove/change areas in the areas file
******************************************************************************/
rswindell's avatar
rswindell committed
1117
void alter_areas(str_list_t add_area, str_list_t del_area, fidoaddr_t addr, const char* to)
1118
1119
{
	FILE *nmfile,*afilein,*afileout,*fwdfile;
1120
1121
	char str[1024],fields[1024],field1[256],field2[256],field3[256]
		,outpath[MAX_PATH+1]
1122
		,*outname,*p,*tp,nomatch=0,match=0;
1123
1124
	unsigned j,k,x,y;
	unsigned u;
rswindell's avatar
rswindell committed
1125
1126
	size_t add_count;
	size_t del_count;
1127

rswindell's avatar
rswindell committed
1128
1129
1130
1131
1132