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

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

rswindell's avatar
rswindell committed
382
383
	if(!cfg.flo_mailer)
		return true;
384

rswindell's avatar
rswindell committed
385
	outbound = get_current_outbound(dest, /* fileboxes: */false);
386
387
388
389
390
391

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

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

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

	if(!bso_lock_node(dest))
		return 1;

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

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

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

	return smb_faddrtoa(&addr, buf);
}

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

	return smb_faddrtoa(&addr, buf);
}

rswindell's avatar
rswindell committed
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
632
633
634
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)
635
		strncpy((char*)hdr->type2.password, nodecfg->pktpwd, sizeof(hdr->type2.password));
rswindell's avatar
rswindell committed
636
637
638
639
640
641

	if(pkt_type == PKT_TYPE_2_0)
		return true;

	if(pkt_type == PKT_TYPE_2_2) {
		hdr->type2_2.subversion = 2;	/* 2.2 */
642
643
		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
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
		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;
}

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

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

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

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

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

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

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

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

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

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

rswindell's avatar
rswindell committed
853
854
855
856
857
858
859
860
861
862
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;
}

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

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

rswindell's avatar
rswindell committed
876
		if(!cfg.nodecfg[k].send_notify)
877
878
879
			continue;

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

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

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

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

927
	if(type == AREALIST_ALL)
928
		strcpy(title,"List of Available Areas");
929
	else if(type == AREALIST_CONNECTED)
930
931
932
933
		strcpy(title,"List of Connected Areas");
	else
		strcpy(title,"List of Unlinked Areas");

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

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

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

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

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

rswindell's avatar
rswindell committed
1073
1074
1075
1076
1077
1078
1079
1080
	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);

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

rswindell's avatar
rswindell committed
1148
						/* Added 12/4/95 to remove link from connected link */
1149

1150
1151
						for(k=u;k<cfg.area[u].links-1;k++)
							memcpy(&cfg.area[u].link[k],&cfg.area[u].link[k+1]
rswindell's avatar
rswindell committed
1152
								,sizeof(fidoaddr_t));
1153
1154
1155
						--cfg.area[u].links;
						if(cfg.area[u].links==0) {
							FREE_AND_NULL(cfg.area[u].link);
1156
						} else {
1157
1158
1159
							if((cfg.area[u].link=(fidoaddr_t *)
								realloc(cfg.area[u].link,sizeof(fidoaddr_t)
								*(cfg.area[u].links)))==NULL) {
1160
								lprintf(LOG_ERR,"ERROR line %d allocating memory for area "
1161
									"#%u links.",__LINE__,u+1);
1162
								bail(1); 
1163
								return;
1164
							}
1165
						}
1166

1167
1168
1169
						fprintf(afileout,"%-*s %-*s "
							,LEN_EXTCODE, field1
							,FIDO_AREATAG_LEN, field2);
1170
						for(j=0;j<cfg.area[u].links;j++) {
rswindell's avatar
rswindell committed
1171
							if(!memcmp(&cfg.area[u].link[j],&addr
rswindell's avatar
rswindell committed
1172
								,sizeof(fidoaddr_t)))
1173
1174
								continue;
							fprintf(afileout,"%s "
rswindell's avatar
rswindell committed
1175
								,smb_faddrtoa(&cfg.area[u].link[j],NULL)); 
1176
						}
1177
1178
						if(field3[0])
							fprintf(afileout,"%s",field3);
1179
						fprintf(afileout,"\n");
1180
						fprintf(nmfile,"%s removed.\r\n",field2);
1181
1182
1183
						break; 
					} 
				}
1184
				if(u==cfg.areas)			/* Something screwy going on */
1185
					fprintf(afileout,"%s\n",fields);
1186
1187
1188
				continue; 
			} 				/* Area match so continue on */
		}
rswindell's avatar
rswindell committed
1189
		if(add_count) { 				/* Check for areas to add */
1190
1191
			for(u=0;add_area[u]!=NULL;u++)
				if(!stricmp(add_area[u],field2) ||
1192
					!stricmp(add_area[0],"+ALL"))      /* Match Found */
1193
					break;
1194
1195
1196
1197
1198
			if(add_area[u]!=NULL) {
				if(stricmp(add_area[u],"+ALL"))
					add_area[u][0]=0;  /* So we can check other lists */
				for(u=0;u<cfg.areas;u++) {
					if(!stricmp(field2,cfg.area[u].name)) {
1199
						lprintf(LOG_DEBUG,"Linking area (%s) for %s in %s", field2, smb_faddrtoa(&addr,NULL), cfg.areafile);
1200
						if(area_is_linked(u,&addr)) {
1201
							fprintf(afileout,"%s\n",fields);
1202
							fprintf(nmfile,"%s already connected.\r\n",field2);
1203
1204
							break; 
						}
rswindell's avatar
rswindell committed
1205
						if(cfg.add_from_echolists_only && !check_elists(field2,addr)) {
1206
							fprintf(afileout,"%s\n",fields);
1207
1208
							break; 
						}
1209

rswindell's avatar
rswindell committed
1210
						/* Added 12/4/95 to add link to connected links */
1211

1212
1213
1214
1215
						++cfg.area[u].links;
						if((cfg.area[u].link=(fidoaddr_t *)
							realloc(cfg.area[u].link,sizeof(fidoaddr_t)
							*(cfg.area[u].links)))==NULL) {
1216
							lprintf(LOG_ERR,"ERROR line %d allocating memory for area "
1217
								"#%u links.",__LINE__,u+1);
1218
1219
1220
							bail(1); 
							return;
						}
1221
						memcpy(&cfg.area[u].link[cfg.area[u].links-1],&addr,sizeof(fidoaddr_t));
1222

1223
1224
1225
						fprintf(afileout,"%-*s %-*s "
							,LEN_EXTCODE, field1
							,FIDO_AREATAG_LEN, field2);
1226
						for(j=0;j<cfg.area[u].links;j++)
1227
							fprintf(afileout,"%s "
rswindell's avatar
rswindell committed
1228
								,smb_faddrtoa(&cfg.area[u].link[j],NULL));
1229
1230
						if(field3[0])
							fprintf(afileout,"%s",field3);
1231
						fprintf(afileout,"\n");
1232
						fprintf(nmfile,"%s added.\r\n",field2);
1233
1234
1235
						break; 
					} 
				}
1236
				if(u==cfg.areas)			/* Something screwy going on */
1237
					fprintf(afileout,"%s\n",fields);
1238
1239
1240
1241
1242
1243
				continue;  					/* Area match so continue on */
			}
			nomatch=1; 						/* This area wasn't in there */
		}
		fprintf(afileout,"%s\n",fields);	/* No match so write back line */
	}
1244
	fclose(afilein);
1245
	if(nomatch || (strListCount(add_area) && !stricmp(add_area[0],"+ALL"))) {
rswindell's avatar
rswindell committed
1246
1247
		nodecfg_t* nodecfg=findnodecfg(&cfg, addr,0);
		if(nodecfg != NULL) {
1248
1249
			for(j=0;j<cfg.listcfgs;j++) {
				match=0;
rswindell's avatar
rswindell committed
1250
				for(k=0; cfg.listcfg[j].keys[k] ;k++) {
1251
					if(match) break;
rswindell's avatar
rswindell committed
1252
1253
1254
					for(x=0; nodecfg->keys[x] ;x++) {
						if(!stricmp(cfg.listcfg[j].keys[k]
							,nodecfg->keys[x])) {
1255
							if((fwdfile=tmpfile())==NULL) {
1256
								lprintf(LOG_ERR,"ERROR line %d opening forward temp "
1257
1258
									"file",__LINE__);
								match=1;
1259
1260
								break; 
							}