sbbsecho.c 157 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
85
/* statistics */
ulong netmail=0;	/* imported */
ulong echomail=0;	/* imported */
ulong exported_netmail=0;
ulong exported_echomail=0;
ulong packed_netmail=0;

rswindell's avatar
rswindell committed
86
int cur_smb=0;
87
FILE *fidologfile=NULL;
rswindell's avatar
rswindell committed
88
bool twit_list;
rswindell's avatar
rswindell committed
89
str_list_t bad_areas;
90

rswindell's avatar
rswindell committed
91
92
93
94
95
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];
96

rswindell's avatar
rswindell committed
97
98
99
100
bool pause_on_exit=false;
bool pause_on_abend=false;
bool mtxfile_locked=false;
bool terminated=false;
101

102
103
str_list_t	locked_bso_nodes;

rswindell's avatar
rswindell committed
104
105
106
int mv(const char *insrc, const char *indest, bool copy);
void export_echomail(const char *sub_code, const nodecfg_t*, bool rescan);

107
108
109
110
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
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;
}

137
138
139
140
141
142
143
144
145
146
147
/* 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
148
149
/* for *.bsy file contents: */
const char* program_id(void)
150
{
rswindell's avatar
rswindell committed
151
152
153
	static char str[256];
	
	SAFEPRINTF2(str, "%u %s", getpid(), sbbsecho_pid());
154

rswindell's avatar
rswindell committed
155
	return str;
156
157
}

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

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

rswindell's avatar
rswindell committed
174
175
176
177
	if(fidologfile!=NULL && level<=cfg.log_level) {
	    time_t now = time(NULL);
		struct tm *tm;
		struct tm tmbuf = {0};
178
		char timestamp[128];
rswindell's avatar
rswindell committed
179
180
181
		strip_ctrl(sbuf, sbuf);
		if((tm = localtime(&now)) == NULL)
			tm = &tmbuf;
182
183
184
185
186
		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
187
188
		fflush(fidologfile);
	}
rswindell's avatar
rswindell committed
189
190
191
	return(chcount);
}

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

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

212
213
214
215
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
	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);
243
244
						strcat(cmd,str); 
					}
245
246
247
248
249
250
251
252
253
254
255
256
					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);
257
258
						strcat(cmd,str); 
					}
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
					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 */
275
					strcat(cmd,cfg->exec_dir);
276
					break;
277
278
279
280
281
                case '@':   /* EXEC Directory for DOS/OS2/Win32, blank for Unix */
#ifndef __unix__
                    strcat(cmd,cfg->exec_dir);
#endif
                    break;
282
283
284
285
286
287
288
289
290
291
292
				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;
293
294
295
296
297
298
299
300
301
302
				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;
303
				default:    /* unknown specification */
304
					lprintf(LOG_ERR,"ERROR Checking Command Line '%s'",instr);
305
					bail(1);
306
307
308
309
					break; 
			}
			j=strlen(cmd); 
		}
310
		else
311
312
			cmd[j++]=instr[i]; 
}
313
	cmd[j]=0;
314

315
	return(cmd);
316
317
318
}

/****************************************************************************/
rswindell's avatar
rswindell committed
319
/* Runs an external program directly using system()							*/
320
321
322
/****************************************************************************/
int execute(char *cmdline)
{
rswindell's avatar
rswindell committed
323
324
325
326
327
328
	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));
329

rswindell's avatar
rswindell committed
330
	return retval;
331
}
332

333
334
335
/******************************************************************************
 Returns the system address with the same zone as the address passed
******************************************************************************/
rswindell's avatar
rswindell committed
336
fidoaddr_t getsysfaddr(short zone)
337
338
{
	int i;
339

340
341
342
	for(i=0;i<scfg.total_faddrs;i++)
		if(scfg.faddr[i].zone==zone)
			return(scfg.faddr[i]);
343
	return(sys_faddr);
344
}
345

rswindell's avatar
rswindell committed
346
int get_outbound(fidoaddr_t dest, char* outbound, size_t maxlen, bool fileboxes)
347
{
rswindell's avatar
rswindell committed
348
349
	nodecfg_t*	nodecfg;

350
	strncpy(outbound,zone_root_outbound(dest.zone),maxlen);
rswindell's avatar
rswindell committed
351
352
353
354
355
356
	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/" */
357
358
359
			char* p = lastchar(outbound);
			if(IS_PATH_DELIM(*p))
				*p = 0;
rswindell's avatar
rswindell committed
360
361
362
363
364
365
			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);
		}
366
367
	}
	backslash(outbound);
368
369
370
	if(isdir(outbound))
		return 0;
	lprintf(LOG_DEBUG, "Creating outbound directory for %s: %s", smb_faddrtoa(&dest, NULL), outbound);
371
372
373
	return mkpath(outbound);
}

rswindell's avatar
rswindell committed
374
375
376
377
378
379
380
381
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)
382
{
rswindell's avatar
rswindell committed
383
	const char* outbound;
384
385
	char fname[MAX_PATH+1];

rswindell's avatar
rswindell committed
386
387
	if(!cfg.flo_mailer)
		return true;
388

rswindell's avatar
rswindell committed
389
	outbound = get_current_outbound(dest, /* fileboxes: */false);
390
391
392
393
394
395

	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
396
397
398
399
400
	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;
401
		lprintf(LOG_NOTICE, "Node (%s) externally locked via: %s", smb_faddrtoa(&dest, NULL), fname);
rswindell's avatar
rswindell committed
402
403
404
405
406
407
408
		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);
409
410
411
	}
	strListPush(&locked_bso_nodes, fname);
	lprintf(LOG_DEBUG, "Node (%s) successfully locked via: %s", smb_faddrtoa(&dest, NULL), fname);
rswindell's avatar
rswindell committed
412
413
414
415
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
	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));
446
447
}

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

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

	if(!bso_lock_node(dest))
		return 1;

rswindell's avatar
rswindell committed
469
470
471
472
473
	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;
474
	}
rswindell's avatar
rswindell committed
475
476
477
478
479
480
481
482
483
484
485
486
	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;
487
488
}

489
/* Writes text buffer to file, expanding sole LFs to CRLFs */
rswindell's avatar
rswindell committed
490
size_t fwrite_crlf(const char* buf, size_t len, FILE* fp)
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
{
	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
512
bool fidoctrl_line_exists(const smbmsg_t* msg, const char* prefix)
513
{
514
	if(msg==NULL || prefix==NULL)
rswindell's avatar
rswindell committed
515
		return false;
516
517
518
	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
519
			return true;
520
	}
rswindell's avatar
rswindell committed
521
	return false;
522
523
}

rswindell's avatar
rswindell committed
524
fidoaddr_t fmsghdr_srcaddr(const fmsghdr_t* hdr)
525
526
527
528
529
530
531
532
533
534
535
{
	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
536
const char* fmsghdr_srcaddr_str(const fmsghdr_t* hdr)
537
538
539
540
541
542
543
{
	static char buf[64];
	fidoaddr_t addr = fmsghdr_srcaddr(hdr);

	return smb_faddrtoa(&addr, buf);
}

rswindell's avatar
rswindell committed
544
fidoaddr_t fmsghdr_destaddr(const fmsghdr_t* hdr)
545
546
547
548
549
550
551
552
553
554
555
{
	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
556
const char* fmsghdr_destaddr_str(const fmsghdr_t* hdr)
557
558
559
560
561
562
563
{
	static char buf[64];
	fidoaddr_t addr = fmsghdr_destaddr(hdr);

	return smb_faddrtoa(&addr, buf);
}

564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
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
580
	if(origaddr.zone == 0 || faddr_contains_wildcard(&origaddr))
581
582
583
584
585
586
587
588
		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
589
590
591
592
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
593
	enum pkt_type type = PKT_TYPE_2;
rswindell's avatar
rswindell committed
594
595
596
597
598
599
600
601
602
603
604
605
606
607

	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
608
609
610
611
	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
612
		dest.point = hdr->type2plus.destpoint;
rswindell's avatar
rswindell committed
613
614
615
616
617
618
		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
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
		}
	} 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
638
	enum pkt_type pkt_type = PKT_TYPE_2;
rswindell's avatar
rswindell committed
639
640
641
642
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
	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)
668
		strncpy((char*)hdr->type2.password, nodecfg->pktpwd, sizeof(hdr->type2.password));
rswindell's avatar
rswindell committed
669

rswindell's avatar
rswindell committed
670
	if(pkt_type == PKT_TYPE_2)
rswindell's avatar
rswindell committed
671
672
673
674
		return true;

	if(pkt_type == PKT_TYPE_2_2) {
		hdr->type2_2.subversion = 2;	/* 2.2 */
675
676
		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
677
678
679
		return true;
	}
	
rswindell's avatar
rswindell committed
680
681
	/* 2e and 2+ */
	if(pkt_type != PKT_TYPE_2_EXT && pkt_type != PKT_TYPE_2_PLUS) {
rswindell's avatar
rswindell committed
682
683
684
685
		lprintf(LOG_ERR, "UNSUPPORTED PACKET TYPE: %u", pkt_type);
		return false;
	}

rswindell's avatar
rswindell committed
686
687
688
689
	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
690
691
692
693
694
695
696
697
698
699
700
701
702
	}
	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;
}

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

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

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

758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
	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
773
774
775
776
	if(nodecfg != NULL) {
		switch(nodecfg->status) {
			case MAIL_STATUS_HOLD:	hdr.attr|=FIDO_HOLD;	break;
			case MAIL_STATUS_CRASH:	hdr.attr|=FIDO_CRASH;	break;
777
			case MAIL_STATUS_NORMAL:						break;
rswindell's avatar
rswindell committed
778
779
780
		}
		direct = nodecfg->direct;
	}
781

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

797
798
799
800
801
802
803
804
805
	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);
806
	}
807
808
	/* Add FSC-53 FLAGS kludge */
	fprintf(fp,"\1FLAGS");
rswindell's avatar
rswindell committed
809
	if(direct)
810
811
		fprintf(fp," DIR");
	if(file_attached) {
rswindell's avatar
rswindell committed
812
		if(cfg.trunc_bundles)
813
			fprintf(fp," TFS");
814
		else
815
816
817
			fprintf(fp," KFS");
	}
	fprintf(fp,"\r");
818

819
820
821
822
	if(hdr.destpoint)
		fprintf(fp,"\1TOPT %hu\r",hdr.destpoint);
	if(hdr.origpoint)
		fprintf(fp,"\1FMPT %hu\r",hdr.origpoint);
823
824
825
826
827
828
829
	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
830
	if(!file_attached || (!direct && file_attached))
831
832
833
		fwrite_crlf(body,strlen(body)+1,fp);	/* Write additional NULL */
	else
		fwrite("\0",1,1,fp);               /* Write NULL */
rswindell's avatar
rswindell committed
834
835
836
	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);
837
	return fclose(fp);
838
839
840
841
842
843
}

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

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

rswindell's avatar
rswindell committed
878
879
/* Returns true if area is linked with specified node address */
bool area_is_linked(unsigned area_num, const fidoaddr_t* addr)
880
{
881
	unsigned i;
rswindell's avatar
rswindell committed
882
883
884
885
	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;
886
887
}

888
889
/* Returns area index */
uint find_area(const char* echotag)
rswindell's avatar
rswindell committed
890
{
891
892
893
894
895
896
897
898
899
900
901
902
903
904
	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;
}

905
906
/* Returns subnum (INVALID_SUB if pass-through) or SUB_NOT_FOUND */
#define SUB_NOT_FOUND ((uint)-2)
907
908
909
910
911
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))
912
		return cfg.area[area].sub;
rswindell's avatar
rswindell committed
913

914
	return SUB_NOT_FOUND;
rswindell's avatar
rswindell committed
915
916
}

917
918
919
920
921
/******************************************************************************
 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
922
void gen_notify_list(void)
923
924
925
{
	FILE *	tmpf;
	char	str[256];
deuce's avatar
deuce committed
926
	uint	i,k;
927

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

rswindell's avatar
rswindell committed
930
		if(!cfg.nodecfg[k].send_notify)
931
932
933
			continue;

		if((tmpf=tmpfile())==NULL) {
934
			lprintf(LOG_ERR,"ERROR line %d couldn't open tmpfile",__LINE__);
935
936
			return; 
		}
937
938
939
940

		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
941
		fprintf(tmpf,"Packet Type       %s\r\n", pktTypeStringList[cfg.nodecfg[k].pkt_type]);
942
		fprintf(tmpf,"Archive Type      %s\r\n"
rswindell's avatar
rswindell committed
943
944
945
946
			,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");
		fprintf(tmpf,"Passive           %s\r\n", cfg.nodecfg[k].passive ? "Yes":"No");
947
948
949
950
951
952
953
954
		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
955
			if(area_is_linked(i,&cfg.nodecfg[k].addr))
956
957
				fprintf(tmpf,"%s",str); 
		}
958
959

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

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

981
	if(type == AREALIST_ALL)
982
		strcpy(title,"List of Available Areas");
983
	else if(type == AREALIST_CONNECTED)
984
985
986
987
		strcpy(title,"List of Connected Areas");
	else
		strcpy(title,"List of Unlinked Areas");

988
989
	if((area_list=strListInit()) == NULL) {
		lprintf(LOG_ERR,"ERROR line %d couldn't allocate string list",__LINE__);
990
991
		return; 
	}
992

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

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

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

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

rswindell's avatar
rswindell committed
1124
1125
1126
1127
1128
1129
1130
1131
	if((add_count = strListCount(add_area)) !=0 )
		lprintf(LOG_DEBUG,"Adding %u areas for %s to %s"
			,add_count, smb_faddrtoa(&addr,NULL), cfg.areafile);

	if((del_count = strListCount(del_area)) != 0)
		lprintf(LOG_DEBUG,"Removing %u areas for %s from %s"
			,del_count, smb_faddrtoa(&addr,NULL), cfg.areafile);

1132
1133
	SAFECOPY(outpath,cfg.areafile);
	*getfname(outpath)=0;