sbbsecho.c 150 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

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

#define MAX_OPEN_SMBS	10
61
62

smb_t *smb,*email;
rswindell's avatar
rswindell committed
63
64
65
66
67
68
69
70
71
72
73
74
bool opt_import_packets		= true;
bool opt_import_netmail		= true;
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;

rswindell's avatar
rswindell committed
75
76
77
78
79
80
81
/* 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
82
83
char tmp[256];
int cur_smb=0;
84
FILE *fidologfile=NULL;
rswindell's avatar
rswindell committed
85
bool twit_list;
86

rswindell's avatar
rswindell committed
87
88
89
90
91
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];
92

rswindell's avatar
rswindell committed
93
94
95
96
bool pause_on_exit=false;
bool pause_on_abend=false;
bool mtxfile_locked=false;
bool terminated=false;
97

98
99
str_list_t	locked_bso_nodes;

rswindell's avatar
rswindell committed
100
101
102
int mv(const char *insrc, const char *indest, bool copy);
void export_echomail(const char *sub_code, const nodecfg_t*, bool rescan);

103
104
105
106
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
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;
}

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

rswindell's avatar
rswindell committed
151
	return str;
152
153
}

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

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

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

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

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

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

311
	return(cmd);
312
313
314
}

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

rswindell's avatar
rswindell committed
326
	return retval;
327
}
328

329
330
331
/******************************************************************************
 Returns the system address with the same zone as the address passed
******************************************************************************/
rswindell's avatar
rswindell committed
332
fidoaddr_t getsysfaddr(short zone)
333
334
{
	int i;
335

336
337
338
	for(i=0;i<scfg.total_faddrs;i++)
		if(scfg.faddr[i].zone==zone)
			return(scfg.faddr[i]);
339
	return(sys_faddr);
340
}
341

rswindell's avatar
rswindell committed
342
int get_outbound(fidoaddr_t dest, char* outbound, size_t maxlen, bool fileboxes)
343
{
rswindell's avatar
rswindell committed
344
345
	nodecfg_t*	nodecfg;

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

rswindell's avatar
rswindell committed
367
368
369
370
371
372
373
374
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)
375
{
rswindell's avatar
rswindell committed
376
	const char* outbound;
377
378
	char fname[MAX_PATH+1];

rswindell's avatar
rswindell committed
379
380
	if(!cfg.flo_mailer)
		return true;
381

rswindell's avatar
rswindell committed
382
	outbound = get_current_outbound(dest, /* fileboxes: */false);
383
384
385
386
387
388

	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
389
390
391
392
393
	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;
394
		lprintf(LOG_NOTICE, "Node (%s) externally locked via: %s", smb_faddrtoa(&dest, NULL), fname);
rswindell's avatar
rswindell committed
395
396
397
398
399
400
401
		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);
402
403
404
	}
	strListPush(&locked_bso_nodes, fname);
	lprintf(LOG_DEBUG, "Node (%s) successfully locked via: %s", smb_faddrtoa(&dest, NULL), fname);
rswindell's avatar
rswindell committed
405
406
407
408
409
410
411
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
	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));
439
440
}

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

rswindell's avatar
rswindell committed
454
455
456
457
	if(use_outbox && (nodecfg=findnodecfg(&cfg, dest, /* exact: */false)) != NULL) {
		if(nodecfg->outbox[0])
			return 0;
	}
458
459
460
461

	if(!bso_lock_node(dest))
		return 1;

rswindell's avatar
rswindell committed
462
463
464
465
466
	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;
467
	}
rswindell's avatar
rswindell committed
468
469
470
471
472
473
474
475
476
477
478
479
	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;
480
481
}

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

rswindell's avatar
rswindell committed
517
fidoaddr_t fmsghdr_srcaddr(const fmsghdr_t* hdr)
518
519
520
521
522
523
524
525
526
527
528
{
	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
529
const char* fmsghdr_srcaddr_str(const fmsghdr_t* hdr)
530
531
532
533
534
535
536
{
	static char buf[64];
	fidoaddr_t addr = fmsghdr_srcaddr(hdr);

	return smb_faddrtoa(&addr, buf);
}

rswindell's avatar
rswindell committed
537
fidoaddr_t fmsghdr_destaddr(const fmsghdr_t* hdr)
538
539
540
541
542
543
544
545
546
547
548
{
	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
549
const char* fmsghdr_destaddr_str(const fmsghdr_t* hdr)
550
551
552
553
554
555
556
{
	static char buf[64];
	fidoaddr_t addr = fmsghdr_destaddr(hdr);

	return smb_faddrtoa(&addr, buf);
}

rswindell's avatar
rswindell committed
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
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;
	enum pkt_type type = PKT_TYPE_2_0;

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

	if(hdr->type2plus.cword == BYTE_SWAP_16(hdr->type2plus.cwcopy)  /* 2+ Packet Header (FSC-39) */
		&& (hdr->type2plus.cword&1)) {
		type = PKT_TYPE_2_PLUS;
		dest.point = hdr->type2plus.destpoint;
		if(hdr->type2plus.origpoint!=0 && orig.net == 0xffff) {	/* see FSC-0048 for details */
			orig.net = hdr->type2plus.auxnet;
			orig.point = hdr->type2plus.origpoint;
		}
	} 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)
{
	enum pkt_type pkt_type = PKT_TYPE_2_0;
	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)
632
		strncpy((char*)hdr->type2.password, nodecfg->pktpwd, sizeof(hdr->type2.password));
rswindell's avatar
rswindell committed
633
634
635
636
637
638

	if(pkt_type == PKT_TYPE_2_0)
		return true;

	if(pkt_type == PKT_TYPE_2_2) {
		hdr->type2_2.subversion = 2;	/* 2.2 */
639
640
		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
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
		return true;
	}
	
	/* 2+ */
	if(pkt_type != PKT_TYPE_2_PLUS) {
		lprintf(LOG_ERR, "UNSUPPORTED PACKET TYPE: %u", pkt_type);
		return false;
	}

	if(orig.point != 0) {
		hdr->type2plus.orignet	= 0xffff;
		hdr->type2plus.auxnet	= orig.net; 
	}
	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;
}

666
667
668
669
670
/******************************************************************************
 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
671
672
int create_netmail(const char *to, const smbmsg_t* msg, const char *subject, const char *body, fidoaddr_t dest
					,bool file_attached)
673
{
674
675
	FILE *fp;
	char fname[MAX_PATH+1];
676
	char* from=NULL;
677
678
	uint i;
	static uint startmsg;
rswindell's avatar
rswindell committed
679
	fidoaddr_t	faddr;
680
	fmsghdr_t hdr;
681
	time_t t;
682
	struct tm *tm;
683
	when_t when_written;
rswindell's avatar
rswindell committed
684
685
	nodecfg_t* nodecfg;
	bool	direct=false;
686

687
	if(msg==NULL) {
rswindell's avatar
rswindell committed
688
		when_written.time = time32(NULL);
689
690
691
692
693
		when_written.zone = sys_timezone(&scfg);
	} else {
		from = msg->from;
		when_written = msg->hdr.when_written;
	}
694
695
696
697
	if(from==NULL)
		from="SBBSecho";
	if(to==NULL)
		to="Sysop";
698
	if(!startmsg) startmsg=1;
rswindell's avatar
rswindell committed
699
700
701
	if((nodecfg=findnodecfg(&cfg, dest, 0)) != NULL) {
		if(nodecfg->status == MAIL_STATUS_NORMAL && !nodecfg->direct)
			nodecfg=findnodecfg(&cfg, dest, /* skip exact match: */2);
702
	}
703

704
	MKDIR(scfg.netmail_dir);
705
706
707
708
709
710
711
712
713
714
	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;
715
	if((fp=fnopen(NULL,fname,O_RDWR|O_CREAT))==NULL) {
716
717
718
		lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s",errno,strerror(errno),__LINE__,fname);
		return(-1); 
	}
719

720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
	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
735
736
737
738
	if(nodecfg != NULL) {
		switch(nodecfg->status) {
			case MAIL_STATUS_HOLD:	hdr.attr|=FIDO_HOLD;	break;
			case MAIL_STATUS_CRASH:	hdr.attr|=FIDO_CRASH;	break;
739
			case MAIL_STATUS_NORMAL:						break;
rswindell's avatar
rswindell committed
740
741
742
		}
		direct = nodecfg->direct;
	}
743

744
	t = when_written.time;
rswindell's avatar
rswindell committed
745
	tm = localtime(&t);
746
747
748
749
750
751
752
753
754
755
756
757
758
	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);

759
760
761
762
763
764
765
766
767
	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);
768
	}
769
770
	/* Add FSC-53 FLAGS kludge */
	fprintf(fp,"\1FLAGS");
rswindell's avatar
rswindell committed
771
	if(direct)
772
773
		fprintf(fp," DIR");
	if(file_attached) {
rswindell's avatar
rswindell committed
774
		if(cfg.trunc_bundles)
775
			fprintf(fp," TFS");
776
		else
777
778
779
			fprintf(fp," KFS");
	}
	fprintf(fp,"\r");
780

781
782
783
784
	if(hdr.destpoint)
		fprintf(fp,"\1TOPT %hu\r",hdr.destpoint);
	if(hdr.origpoint)
		fprintf(fp,"\1FMPT %hu\r",hdr.origpoint);
785
786
787
788
789
790
791
	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
792
	if(!file_attached || (!direct && file_attached))
793
794
795
		fwrite_crlf(body,strlen(body)+1,fp);	/* Write additional NULL */
	else
		fwrite("\0",1,1,fp);               /* Write NULL */
rswindell's avatar
rswindell committed
796
797
798
	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);
799
	return fclose(fp);
800
801
802
803
804
805
}

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

811
812
813
814
	l=len=ftell(infile);
	if(len>8192L)
		len=8192L;
	rewind(infile);
deuce's avatar
deuce committed
815
	if((buf=(char *)malloc(len+1))==NULL) {
816
		lprintf(LOG_ERR,"ERROR line %d allocating %lu for file to netmail buf",__LINE__,len);
817
818
		return; 
	}
819
820
821
	while((m=fread(buf,1,(len>8064L) ? 8064L:len,infile))>0) {
		buf[m]=0;
		if(l>8064L && (p=strrchr(buf,'\n'))!=NULL) {
822
			p++;
823
824
			if(*p) {
				*p=0;
825
				p++;
826
827
828
				fseek(infile,-1L,SEEK_CUR);
				while(*p) { 			/* Seek back to end of last line */
					p++;
829
830
831
832
					fseek(infile,-1L,SEEK_CUR); 
				} 
			} 
		}
833
834
		if(ftell(infile)<l)
			strcat(buf,"\r\nContinued in next message...\r\n");
rswindell's avatar
rswindell committed
835
		create_netmail(to, /* msg: */NULL, title, buf, dest, /* attachment: */false); 
836
	}
deuce's avatar
deuce committed
837
	free(buf);
838
}
839

rswindell's avatar
rswindell committed
840
841
/* Returns true if area is linked with specified node address */
bool area_is_linked(unsigned area_num, const fidoaddr_t* addr)
842
{
843
	unsigned i;
rswindell's avatar
rswindell committed
844
845
846
847
	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;
848
849
}

rswindell's avatar
rswindell committed
850
851
852
853
854
855
856
857
858
859
uint find_linked_echo(const char* echotag, fidoaddr_t addr)
{
	unsigned i;
	for(i=0; i<cfg.areas; i++)
		if(stricmp(cfg.area[i].name, echotag) == 0 && area_is_linked(i, &addr))
			return cfg.area[i].sub;

	return INVALID_SUB;
}

860
861
862
863
864
/******************************************************************************
 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
865
void gen_notify_list(void)
866
867
868
{
	FILE *	tmpf;
	char	str[256];
deuce's avatar
deuce committed
869
	uint	i,k;
870

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

rswindell's avatar
rswindell committed
873
		if(!cfg.nodecfg[k].send_notify)
874
875
876
			continue;

		if((tmpf=tmpfile())==NULL) {
877
			lprintf(LOG_ERR,"ERROR line %d couldn't open tmpfile",__LINE__);
878
879
			return; 
		}
880
881
882
883

		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
884
		fprintf(tmpf,"Packet Type       %s\r\n", pktTypeStringList[cfg.nodecfg[k].pkt_type]);
885
		fprintf(tmpf,"Archive Type      %s\r\n"
rswindell's avatar
rswindell committed
886
887
888
889
			,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");
890
891
892
893
894
895
896
897
		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
898
			if(area_is_linked(i,&cfg.nodecfg[k].addr))
899
900
				fprintf(tmpf,"%s",str); 
		}
901
902

		if(ftell(tmpf))
rswindell's avatar
rswindell committed
903
			file_to_netmail(tmpf,"SBBSecho Notify List",cfg.nodecfg[k].addr, /* To: */NULL);
904
905
		fclose(tmpf); 
	}
906
}
907

908
909
910
911
/******************************************************************************
 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).
******************************************************************************/
912
913
914
915
916
enum arealist_type {
	 AREALIST_ALL			// %LIST
	,AREALIST_CONNECTED		// %QUERY
	,AREALIST_UNLINKED		// %UNLINKED
};
rswindell's avatar
rswindell committed
917
void netmail_arealist(enum arealist_type type, fidoaddr_t addr, const char* to)
918
{
919
	char str[256],title[128],match,*p,*tp;
920
921
	unsigned k,x,y;
	unsigned u;
922
	str_list_t	area_list;
923

924
	if(type == AREALIST_ALL)
925
		strcpy(title,"List of Available Areas");
926
	else if(type == AREALIST_CONNECTED)
927
928
929
930
		strcpy(title,"List of Connected Areas");
	else
		strcpy(title,"List of Unlinked Areas");

931
932
	if((area_list=strListInit()) == NULL) {
		lprintf(LOG_ERR,"ERROR line %d couldn't allocate string list",__LINE__);
933
934
		return; 
	}
935

936
	/* Include relevant areas from the area file (e.g. areas.bbs): */
937
938
	for(u=0;u<cfg.areas;u++) {
		if((type == AREALIST_CONNECTED || cfg.add_from_echolists_only) && !area_is_linked(u,&addr))
939
			continue;
940
		if(type == AREALIST_UNLINKED && area_is_linked(u,&addr))
941
			continue;
942
		strListPush(&area_list, cfg.area[u].name); 
943
	} 
944

945
	if(type != AREALIST_CONNECTED) {
rswindell's avatar
rswindell committed
946
947
		nodecfg_t* nodecfg=findnodecfg(&cfg, addr,0);
		if(nodecfg != NULL) {
948
			for(u=0;u<cfg.listcfgs;u++) {
949
				match=0;
950
				for(k=0; cfg.listcfg[u].keys[k]; k++) {
951
					if(match) break;
rswindell's avatar
rswindell committed
952
					for(x=0; nodecfg->keys[x]; x++) {
953
						if(!stricmp(cfg.listcfg[u].keys[k]
rswindell's avatar
rswindell committed
954
							,nodecfg->keys[x])) {
955
							FILE* fp;
956
							if((fp=fopen(cfg.listcfg[u].listpath,"r"))==NULL) {
957
								lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s"
958
									,errno,strerror(errno),__LINE__,cfg.listcfg[u].listpath);
959
								match=1;
960
961
								break; 
							}
962
							while(!feof(fp)) {
963
								memset(str,0,sizeof(str));
964
								if(!fgets(str,sizeof(str),fp))
965
									break;
966
								truncsp(str);
967
								p=str;
968
								SKIP_WHITESPACE(p);
969
								if(*p==0 || *p==';')     /* Ignore Blank and Comment Lines */
970
									continue;
971
972
973
								tp=p;
								FIND_WHITESPACE(tp);
								*tp=0;
974
975
976
								for(y=0;y<cfg.areas;y++)
									if(!stricmp(cfg.area[y].name,p))
										break;
977
978
979
980
								if(y>=cfg.areas || !area_is_linked(y,&addr)) {
									if(strListFind(area_list, p, /* case_sensitive */false) < 0)
										strListPush(&area_list, p);
								}
981
							}
982
							fclose(fp);
983
							match=1;
984
							break; 
985
986
						}
					}
987
988
989
990
				} 
			} 
		} 
	}
991
992
	strListSortAlpha(area_list);
	if(!strListCount(area_list))
rswindell's avatar
rswindell committed
993
		create_netmail(to,/* msg: */NULL,title,"None.",addr,/* attachment: */false);
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
	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);
1006
}
1007

rswindell's avatar
rswindell committed
1008
int check_elists(const char *areatag, fidoaddr_t addr)
1009
1010
{
	FILE *stream;
1011
	char str[1025],quit=0,*p,*tp;
1012
1013
	unsigned k,x,match=0;
	unsigned u;
1014

rswindell's avatar
rswindell committed
1015
1016
	nodecfg_t* nodecfg=findnodecfg(&cfg, addr,0);
	if(nodecfg!=NULL) {
1017
		for(u=0;u<cfg.listcfgs;u++) {
rswindell's avatar
rswindell committed
1018
			quit=0;
1019
			for(k=0; cfg.listcfg[u].keys[k]; k++) {
rswindell's avatar
rswindell committed
1020
				if(quit) break;
rswindell's avatar
rswindell committed
1021
				for(x=0; nodecfg->keys[x] ;x++)
1022
					if(!stricmp(cfg.listcfg[u].keys[k]
rswindell's avatar
rswindell committed
1023
						,nodecfg->keys[x])) {
1024
						if((stream=fopen(cfg.listcfg[u].listpath,"r"))==NULL) {
1025
							lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s"
1026
								,errno,strerror(errno),__LINE__,cfg.listcfg[u].listpath);
rswindell's avatar
rswindell committed
1027
							quit=1;
1028
1029
							break; 
						}
rswindell's avatar
rswindell committed
1030
						while(!feof(stream)) {
1031
							if(!fgets(str,sizeof(str),stream))
rswindell's avatar
rswindell committed
1032
1033
								break;
							p=str;
1034
							SKIP_WHITESPACE(p);
rswindell's avatar
rswindell committed
1035
1036
							if(*p==';')     /* Ignore Comment Lines */
								continue;
1037
1038
1039
1040
							tp=p;
							FIND_WHITESPACE(tp);
							*tp=0;
							if(!stricmp(areatag,p)) {
rswindell's avatar
rswindell committed
1041
								match=1;
1042
1043
1044
								break; 
							} 
						}
rswindell's avatar
rswindell committed
1045
						fclose(stream);
1046
						quit=1;
rswindell's avatar
rswindell committed
1047
1048
						if(match)
							return(match);
1049
1050
1051
1052
1053
						break; 
					} 
			} 
		} 
	}
rswindell's avatar
rswindell committed
1054
	return(match);
1055
1056
1057
1058
}
/******************************************************************************
 Used by AREAFIX to add/remove/change areas in the areas file
******************************************************************************/
rswindell's avatar
rswindell committed
1059
void alter_areas(str_list_t add_area, str_list_t del_area, fidoaddr_t addr, const char* to)
1060
1061
{
	FILE *nmfile,*afilein,*afileout,*fwdfile;
1062
1063
	char str[1024],fields[1024],field1[256],field2[256],field3[256]
		,outpath[MAX_PATH+1]
1064
		,*outname,*p,*tp,nomatch=0,match=0;
1065
1066
	unsigned j,k,x,y;
	unsigned u;
rswindell's avatar
rswindell committed
1067
1068
	size_t add_count;
	size_t del_count;
1069

rswindell's avatar
rswindell committed
1070
1071
1072
1073
1074
1075
1076
1077
	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);

1078
1079
	SAFECOPY(outpath,cfg.areafile);
	*getfname(outpath)=0;
1080
	if((outname=tempnam(outpath,"AREAS"))==NULL) {
1081
		lprintf(LOG_ERR,"ERROR tempnam(%s,AREAS)",outpath);
1082
1083
		return; 
	}
1084
	if((nmfile=tmpfile())==NULL) {
1085
		lprintf(LOG_ERR,"ERROR in tmpfile()");
1086
		free(outname);
1087
1088
		return; 
	}
1089
	if((afileout=fopen(outname,"w+"))==NULL) {
1090
		lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s",errno,strerror(errno),__LINE__,outname);
1091
1092
		fclose(nmfile);
		free(outname);
1093
1094
		return; 
	}
1095
	if((afilein=fopen(cfg.areafile,"r"))==NULL) {
1096
		lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s",errno,strerror(errno),__LINE__,cfg.areafile);
1097
1098
1099
		fclose(afileout);
		fclose(nmfile);
		free(outname);
1100
1101
		return; 
	}
1102
	while(!feof(afilein)) {
1103
		if(!fgets(fields,sizeof(fields),afilein))
1104
1105
1106
			break;
		truncsp(fields);
		p=fields;
1107
		SKIP_WHITESPACE(p);
1108
		if(*p==';') {    /* Skip Comment Lines */
1109
			fprintf(afileout,"%s\n",fields);
1110
1111
			continue; 
		}
1112
		SAFECOPY(field1,p);         /* Internal Code Field */
1113
		truncstr(field1," \t\r\n");
1114
1115
1116
		FIND_WHITESPACE(p);
		SKIP_WHITESPACE(p);
		SAFECOPY(field2,p);         /* Areatag Field */
1117
		truncstr(field2," \t\r\n");
1118
1119
		FIND_WHITESPACE(p);
		SKIP_WHITESPACE(p);
1120
		if((tp=strchr(p,';'))!=NULL) {
1121
1122
			SAFECOPY(field3,p);     /* Comment Field (if any) */
			FIND_WHITESPACE(tp);
1123
1124
			*tp=0; 
		}
1125
1126
		else
			field3[0]=0;
rswindell's avatar
rswindell committed
1127
		if(del_count) { 				/* Check for areas to remove */
1128
1129
			for(u=0;del_area[u]!=NULL;u++) {
				if(!stricmp(del_area[u],field2) ||
1130
1131
1132
					!stricmp(del_area[0],"-ALL"))     /* Match Found */
					break; 
			}