umonitor.c 38.8 KB
Newer Older
1
2
/* Synchronet for *nix node activity monitor */

Rob Swindell's avatar
Rob Swindell committed
3
/* $Id: umonitor.c,v 1.99 2020/08/17 00:48:52 rswindell Exp $ */
rswindell's avatar
rswindell committed
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)		*
 *																			*
rswindell's avatar
rswindell committed
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
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
#include <signal.h>
deuce's avatar
deuce committed
38
#include <sys/types.h>
39
#include <time.h>
deuce's avatar
deuce committed
40
41
42
#ifdef __QNX__
#include <string.h>
#endif
43
#include <stdio.h>
44
45
46
47

#include "ciolib.h"
#define __COLORS		/* Disable the colour macros in sbbsdefs.h ToDo */
#include "sbbs.h"
48
#include "genwrap.h"
49
50
51
#include "uifc.h"
#include "sbbsdefs.h"
#include "genwrap.h"	/* stricmp */
52
#include "dirwrap.h"	/* lock/unlock/sopen */
53
#include "filewrap.h"	/* lock/unlock/sopen */
54
55
56
#include "sbbs_ini.h"	/* INI parsing */
#include "scfglib.h"	/* SCFG files */
#include "ars_defs.h"	/* needed for SCFG files */
57
#include "userdat.h"	/* getnodedat() */
58
#include "spyon.h"
59
#include "chat.h"
60

61
#define CTRL(x) (x&037)
62
63
64
65
66

/********************/
/* Global Variables */
/********************/
uifcapi_t uifc; /* User Interface (UIFC) Library API */
67
68
const char *YesStr="Yes";
const char *NoStr="No";
69
char app_title[128];
70
int	ciolib_mode=CIOLIB_MODE_AUTO;
71
72
73
74
75
76
77
78
79
80
81
82
83
84

int lprintf(char *fmt, ...)
{
	va_list argptr;
	char sbuf[1024];
	int	len;

	va_start(argptr,fmt);
	len=vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
	sbuf[sizeof(sbuf)-1]=0;
	va_end(argptr);
	uifc.msg(sbuf);
	return(len);
}
85

86
87
void bail(int code)
{
deuce's avatar
deuce committed
88
89
90
	if(code) {
		puts("\nHit a key...");
		getch();
91
	}
deuce's avatar
deuce committed
92
	uifc.bail();
93

deuce's avatar
deuce committed
94
	exit(code);
95
96
97
98
}

void allocfail(uint size)
{
deuce's avatar
deuce committed
99
100
	printf("\7Error allocating %u bytes of memory.\n",size);
	bail(1);
101
102
}

103
void node_toggles(scfg_t *cfg,int nodenum)  {
104
	int nodefile = -1;
105
106
107
108
109
	char**	opt;
	int		i,j;
	node_t	node;
	int		save=0;

deuce's avatar
deuce committed
110
111
112
	if((opt=(char **)alloca(sizeof(char *)*(4+1)))==NULL)
		allocfail(sizeof(char *)*(4+1));
	for(i=0;i<(4+1);i++)
113
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
114
115
116
			allocfail(MAX_OPLN);

	i=0;
117
118
	uifc.helpbuf=	"`Node Toggles\n"
	                "`------------`\n\n"
deuce's avatar
deuce committed
119
120
121
122
123
124
125
126
127
128
129
	                "`The following are `Yes/No `options.  Hitting Enter toggles between.\n\n"
	                "`Locked for SysOps only : `Locks the node so that only SysOps may \n"
	                "                         logon to them.\n"
	                "`Interrupt (Hangup)     : `The current user will be kicked as soon as it \n"
	                "                         is safe to do so.  A brief message is given\n"
	                "                         to user.\n"
	                "`Re-run on logoff       : `Toggles the system to reload the configuration\n"
	                "                         files when the current user logs off.\n"
	                "`Down node after logoff : `Takes the node offline after current user logs\n"
	                "                         off.\n\n"
	                "`[Note] `These toggles take effect immediately.";
130
	while(save==0) {
131
		if(getnodedat(cfg,nodenum,&node,FALSE,&nodefile)) {
132
133
134
			uifc.msg("Error reading node data!");
			break;
		}
135
136
137
		j=0;
		sprintf(opt[j++],"%-30s%3s","Locked for SysOps only",node.misc&NODE_LOCK ? YesStr : NoStr);
		sprintf(opt[j++],"%-30s%3s","Interrupt (Hangup)",node.misc&NODE_INTR ? YesStr : NoStr);
rswindell's avatar
rswindell committed
138
139
140
		sprintf(opt[j++],"%-30s%3s","Re-run on logoff",node.misc&NODE_RRUN ? YesStr : NoStr);
		sprintf(opt[j++],"%-30s%3s","Down node after logoff"
			,(node.misc&NODE_DOWN || (node.status==NODE_OFFLINE)) ? YesStr : NoStr);
141
142
		opt[j][0]=0;

143
		switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0,"Node Toggles",opt)) {
144
145
146
147
148
149
150
151
			case 0:	/* Locked */
				node.misc ^= NODE_LOCK;
				break;

			case 1:	/* Interrupt */
				node.misc ^= NODE_INTR;
				break;

rswindell's avatar
rswindell committed
152
			case 2:	/* Re-run */
153
154
155
				node.misc ^= NODE_RRUN;
				break;

rswindell's avatar
rswindell committed
156
			case 3:	/* Down */
157
				if(node.status != NODE_WFC && node.status != NODE_OFFLINE)
158
					node.misc ^= NODE_DOWN;
159
				else {
160
161
162
163
164
					if(node.status!=NODE_OFFLINE)
						node.status=NODE_OFFLINE;
					else
						node.status=NODE_WFC;
				}
165
166
167
168
169
				break;

			case -1:
				save=1;
				break;
170

171
172
173
174
			default:
				uifc.msg("Option not implemented");
				continue;
		}
175
		putnodedat(cfg,nodenum,&node,FALSE,nodefile);
deuce's avatar
deuce committed
176
	}
deuce's avatar
deuce committed
177
178
179
180
181
182
183
}

int dospy(int nodenum, bbs_startup_t *bbs_startup)  {
	char str[80],str2[80];
	int i;

	if(bbs_startup->temp_dir[0])
deuce's avatar
deuce committed
184
		snprintf(str,sizeof(str),"%slocalspy%d.sock", bbs_startup->temp_dir, nodenum);
deuce's avatar
deuce committed
185
186
187
188
189
190
191
	else
		snprintf(str,sizeof(str),"%slocalspy%d.sock", bbs_startup->ctrl_dir, nodenum);
	i=spyon(str);
	switch(i) {
		case SPY_NOSOCKET:
			uifc.msg("Could not create socket");
			return(-1);
192

deuce's avatar
deuce committed
193
		case SPY_NOCONNECT:
194
			SAFEPRINTF(str2,"Failed to connect to %s",str);
deuce's avatar
deuce committed
195
196
197
198
199
200
201
202
203
204
			uifc.msg(str2);
			return(-1);

		case SPY_SELECTFAILED:
			uifc.msg("select() failed, connection terminated.");
			return(-1);

		case SPY_SOCKETLOST:
			uifc.msg("Spy socket lost");
			return(-1);
205

deuce's avatar
deuce committed
206
207
208
		case SPY_STDINLOST:
			uifc.msg("STDIN has gone away... you probably can't close this window.  :-)");
			return(-1);
209

deuce's avatar
deuce committed
210
211
		case SPY_CLOSED:
			break;
212

deuce's avatar
deuce committed
213
214
215
216
217
218
219
220
		default:
			sprintf(str,"Unknown return code %d",i);
			uifc.msg(str);
			return(-1);
	}
	return(0);
}

221
int sendmessage(scfg_t *cfg, int nodenum,node_t *node)  {
222
223
	char str[80],str2[80];

224
	uifc.input(WIN_MID|WIN_SAV,0,0,"Telegram",str2,58,K_WRAP|K_MSG);
225
	SAFEPRINTF(str,"\1n\1y\1hMessage From Sysop:\1w %s\r\n",str2);
226
	if(getnodedat(cfg,nodenum,node,FALSE,NULL))
227
228
229
		return(-1);
	if(node->useron==0)
		return(-1);
230
	putsmsg(cfg, node->useron, str);
231
232
233
	return(0);
}

234
int clearerrors(scfg_t *cfg, int nodenum, node_t *node) {
235
236
	int nodefile = -1;
	if(getnodedat(cfg,nodenum,node,TRUE,&nodefile)) {
237
238
239
240
		uifc.msg("getnodedat() failed! (Nothing done)");
		return(-1);
	}
	node->errors=0;
241
	putnodedat(cfg,nodenum,node,TRUE,nodefile);
242
	uifc.msg("Error count cleared for this node.");
243
244
245
	return(0);
}

246
247
248
249
250
/* Assumes a 12 char outstr */
char *getsizestr(char *outstr, long size, BOOL bytes) {
	if(bytes) {
		if(size < 1000) {	/* Bytes */
			snprintf(outstr,12,"%ld bytes",size);
251
			return(outstr);
252
253
254
		}
		if(size<10000) {	/* Bytes with comma */
			snprintf(outstr,12,"%ld,%03ld bytes",(size/1000),(size%1000));
255
			return(outstr);
256
257
258
259
260
		}
		size = size/1024;
	}
	if(size<1000) {	/* KB */
		snprintf(outstr,12,"%ld KB",size);
261
		return(outstr);
262
263
264
	}
	if(size<999999) { /* KB With comma */
		snprintf(outstr,12,"%ld,%03ld KB",(size/1000),(size%1000));
265
		return(outstr);
266
267
268
269
	}
	size = size/1024;
	if(size<1000) {	/* MB */
		snprintf(outstr,12,"%ld MB",size);
270
		return(outstr);
271
272
273
	}
	if(size<999999) { /* MB With comma */
		snprintf(outstr,12,"%ld,%03ld MB",(size/1000),(size%1000));
274
		return(outstr);
275
276
277
278
	}
	size = size/1024;
	if(size<1000) {	/* GB */
		snprintf(outstr,12,"%ld GB",size);
279
		return(outstr);
280
281
282
	}
	if(size<999999) { /* GB With comma */
		snprintf(outstr,12,"%ld,%03ld GB",(size/1000),(size%1000));
283
		return(outstr);
284
285
286
287
	}
	size = size/1024;
	if(size<1000) {	/* TB (Yeah, right) */
		snprintf(outstr,12,"%ld TB",size);
288
		return(outstr);
289
290
	}
	sprintf(outstr,"Plenty");
291
	return(outstr);
292
293
294
295
296
297
}

/* Assumes a 12 char outstr */
char *getnumstr(char *outstr, ulong size) {
	if(size < 1000) {
		snprintf(outstr,12,"%ld",size);
298
		return(outstr);
299
300
301
	}
	if(size<1000000) {
		snprintf(outstr,12,"%ld,%03ld",(size/1000),(size%1000));
302
		return(outstr);
303
304
305
	}
	if(size<1000000000) {
		snprintf(outstr,12,"%ld,%03ld,%03ld",(size/1000000),((size/1000)%1000),(size%1000));
306
		return(outstr);
307
308
309
310
	}
	size=size/1000000;
	if(size<1000000) {
		snprintf(outstr,12,"%ld,%03ld M",(size/1000),(size%1000));
311
		return(outstr);
312
313
314
	}
	if(size<10000000) {
		snprintf(outstr,12,"%ld,%03ld,%03ld M",(size/1000000),((size/1000)%1000),(size%1000));
315
		return(outstr);
316
317
	}
	sprintf(outstr,"Plenty");
318
	return(outstr);
319
320
}

321
int drawstats(scfg_t *cfg, int nodenum, node_t *node, int *curp, int *barp) {
322
323
324
325
	stats_t	sstats;
	stats_t	nstats;
	char	statbuf[6*78];		/* Buffer to hold the stats for passing to uifc.showbuf() */
	char	str[4][4][12];
326
	char	heading[128];
327
	char	usrname[128];
328
	char	tmp[128];
329
330
	ulong	free;
	uint	i,l,m;
331
	time_t	t, now;
332
	int		shownode=1;
333

334
	if(getnodedat(cfg,nodenum,node,FALSE,NULL)) {
335
336
337
338
		shownode=0;
	}
	else {
		getstats(cfg, nodenum, &nstats);
339
340
341
342
	}
	username(cfg,node->useron,usrname);

	getstats(cfg, 0, &sstats);
343
	now = time(NULL);
344
	if(shownode) {
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
		static client_t client;
		time_t hangup = now;
		getnodeclient(cfg, nodenum, &client, &hangup);
		t = client.time ? client.time : now;
		if(node->status != NODE_WFC && node->status != NODE_OFFLINE)
			safe_snprintf(heading, sizeof(heading), "`Node #`%-3d %s `%s`: %s"
				,nodenum
				,sectostr(now - t, tmp)
				,client.protocol
				,client.addr);
		else
			safe_snprintf(heading, sizeof(heading), "`Node #`%-3d %s `%s`: %s `on` %.12s"
				,nodenum
				,sectostr(hangup - t, tmp)
				,client.protocol
				,client.addr
				,ctime(&hangup) + 4);
362
363
364
365
		snprintf(str[1][0],12,"%s/%s",getnumstr(str[3][2],nstats.ltoday),getnumstr(str[3][3],sstats.ltoday));
		getnumstr(str[1][1],sstats.logons);
		snprintf(str[1][2],12,"%s/%s",getnumstr(str[3][2],nstats.ttoday),getnumstr(str[3][3],sstats.ttoday));
		getnumstr(str[1][3],sstats.timeon);
rswindell's avatar
rswindell committed
366
		snprintf(str[2][0],12,"%s/%s",getnumstr(str[3][2],sstats.etoday),getnumstr(str[3][3],getmail(cfg,0,0,0)));
367
368
369
370
371
372
		l=m=0;
		for(i=0;i<cfg->total_subs;i++)
			l+=getposts(cfg,i); 			/* l=total posts */
		for(i=0;i<cfg->total_dirs;i++)
			m+=getfiles(cfg,i); 			/* m=total files */
		snprintf(str[2][1],12,"%s/%s",getnumstr(str[3][2],sstats.ptoday),getnumstr(str[3][3],l));
rswindell's avatar
rswindell committed
373
		snprintf(str[2][2],12,"%s/%s",getnumstr(str[3][2],sstats.ftoday),getnumstr(str[3][3],getmail(cfg,1,0,0)));
374
375
376
377
378
379
380
		snprintf(str[2][3],12,"%s/%s",getnumstr(str[3][2],sstats.nusers),getnumstr(str[3][3],total_users(cfg)));
		getsizestr(str[3][0],sstats.ulb,TRUE);
		snprintf(str[3][1],12,"%s/%s",getnumstr(str[3][2],sstats.uls),getnumstr(str[3][3],m));
		getsizestr(str[3][2],sstats.dlb,TRUE);
		getnumstr(str[3][3],sstats.dls);
	}
	else {
381
382
383
384
385
386
387
388
		free=getfreediskspace(cfg->data_dir,1024);
		if(free<1000) {
			free=getfreediskspace(cfg->data_dir,0);
			getsizestr(str[0][0],free,TRUE);
		}
		else
			getsizestr(str[0][0],free,FALSE);
		sprintf(heading, "`Space`: %s `in` %s", str[0][0], cfg->data_dir);
389
390
391
392
		snprintf(str[1][0],12,"%s",getnumstr(str[3][3],sstats.ltoday));
		getnumstr(str[1][1],sstats.logons);
		snprintf(str[1][2],12,"%s",getnumstr(str[3][3],sstats.ttoday));
		getnumstr(str[1][3],sstats.timeon);
rswindell's avatar
rswindell committed
393
		snprintf(str[2][0],12,"%s/%s",getnumstr(str[3][2],sstats.etoday),getnumstr(str[3][3],getmail(cfg,0,0,0)));
394
395
396
397
398
399
		l=m=0;
		for(i=0;i<cfg->total_subs;i++)
			l+=getposts(cfg,i); 			/* l=total posts */
		for(i=0;i<cfg->total_dirs;i++)
			m+=getfiles(cfg,i); 			/* m=total files */
		snprintf(str[2][1],12,"%s/%s",getnumstr(str[3][2],sstats.ptoday),getnumstr(str[3][3],l));
rswindell's avatar
rswindell committed
400
		snprintf(str[2][2],12,"%s/%s",getnumstr(str[3][2],sstats.ftoday),getnumstr(str[3][3],getmail(cfg,1,0,0)));
401
402
403
404
405
406
		snprintf(str[2][3],12,"%s/%s",getnumstr(str[3][2],sstats.nusers),getnumstr(str[3][3],total_users(cfg)));
		getsizestr(str[3][0],sstats.ulb,TRUE);
		snprintf(str[3][1],12,"%s/%s",getnumstr(str[3][2],sstats.uls),getnumstr(str[3][3],m));
		getsizestr(str[3][2],sstats.dlb,TRUE);
		getnumstr(str[3][3],sstats.dls);
	}
407
	snprintf(statbuf,sizeof(statbuf),"%s"
deuce's avatar
deuce committed
408
409
410
			"\n`Logons`: %-11s `Total`: %-11s `Timeon`: %-11s `Total`: %-11s"
			"\n`Emails`: %-11s `Posts`: %-11s `Fbacks`: %-11s `Users`: %-11s"
			"\n`Uloads`: %-11s `Files`: %-11s `Dloads`: %-11s `Files`: %-11s",
411
			heading,
412
413
414
415
			str[1][0],str[1][1],str[1][2],str[1][3],
			str[2][0],str[2][1],str[2][2],str[2][3],
			str[3][0],str[3][1],str[3][2],str[3][3]);

deuce's avatar
deuce committed
416
	uifc.showbuf(WIN_HLP|WIN_L2R|WIN_DYN|WIN_PACK,1,1,80,6,"Statistics",statbuf,curp,barp);
417
/* Node 5 :	Mar 11  Space: 162,024k
418
   Logons: 23/103      Total: 62,610      Timeon: 322/2430    Total: 5,321,900
419
420
421
422
423
   Emails: 4/265       Posts: 4/12811     Fbacks: 2/17	       Users: 1/592
   Uloads: 324k        Files: 1/2195      Dloads: 9,308k      Files: 52 */
	return(0);
}

424
425
426
427
428
429
430
431
432
433
int view_log(char *filename, char *title)
{
	char str[1024];
	int buffile;
	int j;
	char *buf;

	if(fexist(filename)) {
		if((buffile=sopen(filename,O_RDONLY,SH_DENYWR))>=0) {
			j=filelength(buffile);
434
			if(j >= 0 && (buf=(char *)malloc(j+1))!=NULL) {
435
436
437
438
				read(buffile,buf,j);
				close(buffile);
				*(buf+j)=0;
				uifc.showbuf(WIN_MID,0,0,76,uifc.scrn_len-2,title,buf,NULL,NULL);
439
				free(buf);
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
				return(0);
			}
			close(buffile);
			uifc.msg("Error allocating memory for the error log");
			return(3);
		}
		sprintf(str,"Error opening %s",title);
		uifc.msg(str);
		return(1);
	}
	sprintf(str,"%s does not exists",title);
	uifc.msg(str);
	return(2);
}

int view_logs(scfg_t *cfg)
{
	char**	opt;
	int		i;
	char	str[1024];
	struct tm tm;
	struct tm tm_yest;
	time_t	now;

	now=time(NULL);
	localtime_r(&now,&tm);
	now -= 60*60*24;
	localtime_r(&now,&tm_yest);
468
	const int num_opts = 12;
469
470
471
	if((opt=(char **)alloca(sizeof(char *)*(num_opts+1)))==NULL)
		allocfail(sizeof(char *)*(num_opts+1));
	for(i=0;i<(num_opts+1);i++)
472
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
473
474
475
			allocfail(MAX_OPLN);

	i=0;
476
477
	strcpy(opt[i++],"Today's callers");
	strcpy(opt[i++],"Yesterday's callers");
478
	strcpy(opt[i++],"Error log");
479
480
	strcpy(opt[i++],"Today's log");
	strcpy(opt[i++],"Yesterday's log");
481
	strcpy(opt[i++],"Spam log");
482
	strcpy(opt[i++],"SBBSecho log");
483
	strcpy(opt[i++],"EchoMail stats");
484
	strcpy(opt[i++],"BinkP stats");
485
	strcpy(opt[i++],"Bad Areas list");
486
487
488
489
	strcpy(opt[i++],"Guru log");
	strcpy(opt[i++],"Hack log");
	opt[i][0]=0;
	i=0;
490
	uifc.helpbuf=	"`View Logs\n"
deuce's avatar
deuce committed
491
492
493
494
495
496
497
	                "`---------\n\n"
	                "`Today's callers     : `View a list of Today's callers.\n"
	                "`Yesterday's callers : `View a list of Yesterday's callers.\n"
	                "`Error log           : `View the Error log.\n"
	                "`Today's log         : `View Today's system activity.\n"
	                "`Yesterday's log     : `View Yesterday's system activity.\n"
	                "`Spam log            : `View the log of Spam E-Mail sent to the system.\n"
498
	                "`SBBSecho log        : `View the FidoNet EchoMail program log.\n"
499
500
	                "`EchoMail stats      : `view the FidoNet EchoMail statistics.\n"
					"`Binkp stats         : `view the BinkP FidoNet mailer statistics.\n"
501
	                "`Bad Areas list      : `view the list of unknown EchoMail areas.\n"
deuce's avatar
deuce committed
502
503
	                "`Guru log            : `View the transcriptions of chats with the Guru.\n"
	                "`Hack log            : `View the Hack attempt log.";
504

505
	while(1) {
506
		switch(uifc.list(WIN_MID,0,0,0,&i,0,"View Logs",opt))  {
507
508
509
			case -1:
				return(0);
			case 0:
deuce's avatar
deuce committed
510
				sprintf(str,"%slogs/%2.2d%2.2d%2.2d.lol",cfg->logs_dir,tm.tm_mon+1,tm.tm_mday
511
512
513
514
					,TM_YEAR(tm.tm_year));
				view_log(str,"Todays Callers");
				break;
			case 1:
deuce's avatar
deuce committed
515
				sprintf(str,"%slogs/%2.2d%2.2d%2.2d.lol",cfg->logs_dir,tm_yest.tm_mon+1
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
					,tm_yest.tm_mday,TM_YEAR(tm_yest.tm_year));
				view_log(str,"Yesterdays Callers");
				break;
			case 2:
				sprintf(str,"%s/error.log",cfg->logs_dir);
				view_log(str,"Error Log");
				break;
			case 3:
				sprintf(str,"%slogs/%2.2d%2.2d%2.2d.log",cfg->logs_dir,tm.tm_mon+1,tm.tm_mday
					,TM_YEAR(tm.tm_year));
				view_log(str,"Todays Log");
				break;
			case 4:
				sprintf(str,"%slogs/%2.2d%2.2d%2.2d.log",cfg->logs_dir,tm_yest.tm_mon+1
					,tm_yest.tm_mday,TM_YEAR(tm_yest.tm_year));
				view_log(str,"Yesterdays Log");
				break;
			case 5:
				sprintf(str,"%sspam.log",cfg->logs_dir);
				view_log(str,"SPAM Log");
				break;
			case 6:
				sprintf(str,"%ssbbsecho.log",cfg->logs_dir);
539
				view_log(str,"SBBSecho Log");
540
541
				break;
			case 7:
542
543
544
545
				sprintf(str,"%sechostats.ini",cfg->data_dir);
				view_log(str,"EchoMail Stats");
				break;
			case 8:
546
547
548
549
				sprintf(str,"%sbinkstats.ini",cfg->data_dir);
				view_log(str,"BinkP Stats");
				break;
			case 9:
550
551
552
				sprintf(str,"%sbadareas.lst",cfg->data_dir);
				view_log(str,"Bad Area List");
				break;
553
			case 10:
554
555
556
				sprintf(str,"%sguru.log",cfg->logs_dir);
				view_log(str,"Guru Log");
				break;
557
			case 11:
558
559
560
561
562
563
564
565
566
567
				sprintf(str,"%shack.log",cfg->logs_dir);
				view_log(str,"Hack Log");
				break;
		}
	}
}

int do_cmd(char *cmd)
{
	int i;
568
569
570
571
	struct text_info ti;
	char *p;

	gettextinfo(&ti);
572
	p=alloca(ti.screenheight*ti.screenwidth*2);
573
	gettext(1,1,ti.screenwidth,ti.screenheight,p);
574
	suspendciolib();
575
	i=system(cmd);
576
577
	initciolib(ciolib_mode);
	clrscr();
578
	puttext(1,1,ti.screenwidth,ti.screenheight,p);
579
	uifc.scrn(app_title);
580
581
582
	return(i);
}

583
int qwk_callouts(scfg_t *cfg)
584
{
585
586
587
588
589
590
591
592
593
	char**	opt;
	int		i,j;
	char	str[1024];

	if(cfg->total_qhubs<1) {
		uifc.msg("No QWK hubs configured!");
		return(1);
	}

deuce's avatar
deuce committed
594
595
596
	if((opt=(char **)alloca(sizeof(char *)*(cfg->total_qhubs+1)))==NULL)
		allocfail(sizeof(char *)*(cfg->total_qhubs+1));
	for(i=0;i<(cfg->total_qhubs+1);i++)
597
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
598
599
600
			allocfail(MAX_OPLN);


601
602
603
604
	uifc.helpbuf=	"`QWK Callouts\n"
					"`------------\n\n"
					"Select the Hub and press enter to initiate a call out to\n"
					"the highlighted system.";
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623

	j=0;
	while(1) {
		for(i=0;i<cfg->total_qhubs;i++) {
			strcpy(opt[i],cfg->qhub[i]->id);
			sprintf(str,"%sqnet/%s.now",cfg->data_dir,cfg->qhub[i]->id);
			if(fexist(str))
				strcat(opt[i]," (pending)");
		}
		opt[i][0]=0;
		switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&j,0,"QWK Callouts",opt))  {
			case -1:
				return(0);
				break;
			default:
				sprintf(str,"%sqnet/%s.now",cfg->data_dir,cfg->qhub[j]->id);
				ftouch(str);
		}
	}
624
625
626
	return(0);
}

627
int run_events(scfg_t *cfg)
628
{
629
630
631
632
	char**	opt;
	int		i,j;
	char	str[1024];

deuce's avatar
deuce committed
633
634
635
	if((opt=(char **)alloca(sizeof(char *)*(cfg->total_events+1)))==NULL)
		allocfail(sizeof(char *)*(cfg->total_events+1));
	for(i=0;i<(cfg->total_events+1);i++)
636
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
637
638
639
640
641
642
643
644
			allocfail(MAX_OPLN);

	if(cfg->total_events<1) {
		uifc.msg("No events configured!");
		return(1);
	}
	j=0;

645
646
647
	uifc.helpbuf=	"`Run Events\n"
					"`----------\n\n"
					"To run and event, highlight it and press Enter";
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665

	while(1) {
		for(i=0;i<cfg->total_events;i++) {
			strcpy(opt[i],cfg->event[i]->code);
			sprintf(str,"%s%s.now",cfg->data_dir,cfg->event[i]->code);
			if(fexist(str))
				strcat(opt[i]," (pending)");
		}
		opt[i][0]=0;
		switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&j,0,"Run Events",opt))  {
			case -1:
				return(0);
				break;
			default:
				sprintf(str,"%s%s.now",cfg->data_dir,cfg->event[j]->code);
				ftouch(str);
		}
	}
666
667
668
	return(0);
}

669
int recycle_servers(scfg_t *cfg)
670
{
Rob Swindell's avatar
Rob Swindell committed
671
	char str[MAX_PATH + 1];
672
673
	char **opt;
	int i=0;
Rob Swindell's avatar
Rob Swindell committed
674
	const int opt_count = 6;
675

Rob Swindell's avatar
Rob Swindell committed
676
677
	if((opt=(char **)alloca(sizeof(char *)*(opt_count+1)))==NULL)
		allocfail(sizeof(char *)*(opt_count+1));
678

Rob Swindell's avatar
Rob Swindell committed
679
680
681
682
683
684
685
	opt[i++] = "All Servers";
	opt[i++] = "Terminal Server";
	opt[i++] = "Mail Server";
	opt[i++] = "FTP Server";
	opt[i++] = "Web Server";
	opt[i++] = "Services";
	opt[i] = NULL;
686

687
688
	uifc.helpbuf=	"`Recycle Servers\n"
					"`---------------\n\n"
Rob Swindell's avatar
Rob Swindell committed
689
					"To recycle a server, highlight it and press Enter.\n"
690
691
					"This will reload the configuration files for selected\n"
					"server.";
692
693
694

	i=0;
	while(1) {
Rob Swindell's avatar
Rob Swindell committed
695
		const char* ext = "";
696
697
698
699
700
		switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0,"Recycle Servers",opt))  {
			case -1:
				return(0);
				break;
			case 1:
Rob Swindell's avatar
Rob Swindell committed
701
				ext = ".term";
702
703
				break;
			case 2:
Rob Swindell's avatar
Rob Swindell committed
704
				ext = ".mail";
705
706
				break;
			case 3:
Rob Swindell's avatar
Rob Swindell committed
707
				ext = ".ftp";
708
709
				break;
			case 4:
Rob Swindell's avatar
Rob Swindell committed
710
711
712
713
				ext = ".web";
				break;
			case 5:
				ext = ".services";
714
715
				break;
		}
Rob Swindell's avatar
Rob Swindell committed
716
717
		SAFEPRINTF2(str, "%srecycle%s", cfg->ctrl_dir, ext);
		ftouch(str);
718
	}
719
720
721
	return(0);
}

722
723
724
725
726
727
728
729
730
731
732
733
734
735
char *geteditor(char *edit)
{
	if(getenv("EDITOR")==NULL && (getenv("VISUAL")==NULL || getenv("DISPLAY")==NULL))
		strcpy(edit,"vi");
	else {
		if(getenv("DISPLAY")!=NULL && getenv("VISUAL")!=NULL)
			strcpy(edit,getenv("VISUAL"));
		else
			strcpy(edit,getenv("EDITOR"));
	}
	return(edit);
}


736
737
738
739
740
int edit_cfg(scfg_t *cfg)
{
	char**	opt;
	int		i;
	char	cmd[1024];
741
	char	editcmd[1024];
742

743
744
745
746
	const int num_opts = 16;
	if((opt=(char **)alloca(sizeof(char *)*(num_opts+1)))==NULL)
		allocfail(sizeof(char *)*(num_opts+1));
	for(i=0;i<(num_opts+1);i++)
747
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
748
749
750
			allocfail(MAX_OPLN);

	i=0;
751
	strcpy(opt[i++],"sbbs.ini");
752
	strcpy(opt[i++],"modopts.ini");
753
754
755
756
757
	strcpy(opt[i++],"alias.cfg");
	strcpy(opt[i++],"attr.cfg");
	strcpy(opt[i++],"dns_blacklist.cfg");
	strcpy(opt[i++],"dnsbl_exempt.cfg");
	strcpy(opt[i++],"domains.cfg");
758
759
	strcpy(opt[i++],"mailproc.ini");
	strcpy(opt[i++],"mime_types.ini");
760
	strcpy(opt[i++],"relay.cfg");
761
	strcpy(opt[i++],"sbbsecho.ini");
762
	strcpy(opt[i++],"../data/areas.bbs");
763
	strcpy(opt[i++],"services.ini");
764
	strcpy(opt[i++],"ftpalias.cfg");
765
	strcpy(opt[i++],"sockopts.ini");
766
767
	strcpy(opt[i++],"spambait.cfg");
	opt[i][0]=0;
768
	uifc.helpbuf= "Highlight desired file and hit Enter to edit it.";
769
770
	i=0;
	while(1) {
771
		switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0,"Edit Config File",opt))  {
772
773
			case -1:
				return(0);
774
				break;
775
			default:
776
				sprintf(cmd,"%s %s%s",geteditor(editcmd),cfg->ctrl_dir,opt[i]);
777
778
779
780
781
782
				do_cmd(cmd);
				break;
		}
	}
	return(0);
}
783

784
785
786
787
788
int edit_can(scfg_t *cfg)
{
	char**	opt;
	int		i;
	char	cmd[1024];
789
	char	editcmd[1024];
790

791
792
793
794
	const int num_opts = 11;
	if((opt=(char **)alloca(sizeof(char *)*(num_opts+1)))==NULL)
		allocfail(sizeof(char *)*(num_opts+1));
	for(i=0;i<(num_opts+1);i++)
795
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
796
797
798
799
800
801
802
803
804
805
806
807
			allocfail(MAX_OPLN);

	i=0;
	strcpy(opt[i++],"email.can");
	strcpy(opt[i++],"file.can");
	strcpy(opt[i++],"host.can");
	strcpy(opt[i++],"ip.can");
	strcpy(opt[i++],"ip-silent.can");
	strcpy(opt[i++],"name.can");
	strcpy(opt[i++],"phone.can");
	strcpy(opt[i++],"rlogin.can");
	strcpy(opt[i++],"subject.can");
808
809
	strcpy(opt[i++],"../ctrl/twitlist.cfg");
	strcpy(opt[i++],"../ctrl/spamblock.cfg");
810
	opt[i][0]=0;
811
	uifc.helpbuf="Highlight desired file and hit Enter to edit it.";
812
813
	i=0;
	while(1) {
814
		switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0,"Edit Filter File",opt))  {
815
816
			case -1:
				return(0);
817
				break;
818
			default:
819
				sprintf(cmd,"%s %s%s",geteditor(editcmd),cfg->text_dir,opt[i]);
820
821
822
823
824
825
				do_cmd(cmd);
				break;
		}
	}
	return(0);
}
826

827
int main(int argc, char** argv)  {
828

829
830
831
832
	char**	opt;
	char**	mopt;
	int		main_dflt=0;
	int		main_bar=0;
833
	int		sys_cur=0;
deuce's avatar
deuce committed
834
	char	revision[16];
835
	char	str[256],ctrl_dir[MAX_PATH + 1];
deuce's avatar
deuce committed
836
837
	int		i,j;
	node_t	node;
838
	int		nodefile = -1;
839
840
	box_t	boxch;
	scfg_t	cfg;
841
	int		done;
842
	time_t	last_semfile_check = time(NULL);
843
	int		idle_sleep=100;
844

845
846
	SAFEPRINTF2(app_title, "Synchronet UNIX Monitor v%s%c", VERSION, REVISION);

deuce's avatar
deuce committed
847
848
849
	/******************/
	/* Ini file stuff */
	/******************/
850
	char	ini_file[MAX_PATH+1];
851
	FILE*				fp=NULL;
852
	bbs_startup_t		bbs_startup;
853

Rob Swindell's avatar
Rob Swindell committed
854
	sscanf("$Revision: 1.99 $", "%*s %s", revision);
855

deuce's avatar
deuce committed
856
	printf("\nSynchronet UNIX Monitor %s-%s  Copyright %s "
deuce's avatar
deuce committed
857
		"Rob Swindell\n",revision,PLATFORM_DESC,&__DATE__[7]);
858

859
	SAFECOPY(ctrl_dir, get_ctrl_dir(/* warn: */TRUE));
860
	backslash(ctrl_dir);
861

deuce's avatar
deuce committed
862
	gethostname(str,sizeof(str)-1);
863
864

	sbbs_get_ini_fname(ini_file, ctrl_dir, str);
865
866

	/* Initialize BBS startup structure */
deuce's avatar
deuce committed
867
868
	memset(&bbs_startup,0,sizeof(bbs_startup));
	bbs_startup.size=sizeof(bbs_startup);
869
	SAFECOPY(bbs_startup.ctrl_dir,ctrl_dir);
870
871
872
873
874
875

	/* Read .ini file here */
	if(ini_file[0]!=0 && (fp=fopen(ini_file,"r"))!=NULL) {
		printf("Reading %s\n",ini_file);
	}
	/* We call this function to set defaults, even if there's no .ini file */
rswindell's avatar
rswindell committed
876
	sbbs_read_ini(fp, ini_file,
877
		NULL,		/* global_startup */
878
		NULL, &bbs_startup,
879
		NULL, NULL, /* ftp_startup */
880
		NULL, NULL, /* web_startup */
881
882
883
		NULL, NULL, /* mail_startup */
		NULL, NULL  /* services_startup */
		);
884
885
886
887
888
889

	/* close .ini file here */
	if(fp!=NULL)
		fclose(fp);

	chdir(bbs_startup.ctrl_dir);
890

891
	/* Read .cfg files here */
deuce's avatar
deuce committed
892
	memset(&cfg,0,sizeof(cfg));
893
	cfg.size=sizeof(cfg);
894
	SAFECOPY(cfg.ctrl_dir,bbs_startup.ctrl_dir);
895
	if(!load_cfg(&cfg, NULL, TRUE, str, sizeof(str))) {
896
897
898
		printf("ERROR! %s\n",str);
		exit(1);
	}
899
	prep_dir(cfg.ctrl_dir, cfg.temp_dir, sizeof(cfg.temp_dir));
900

deuce's avatar
deuce committed
901
	memset(&uifc,0,sizeof(uifc));
902
	uifc.mode|=UIFC_NOCTRL;
903
904
905

	uifc.esc_delay=500;

deuce's avatar
deuce committed
906
907
908
909
910
911
912
913
	boxch.ls=(char)186;
	boxch.rs=(char)186;
	boxch.ts=(char)205;
	boxch.bs=(char)205;
	boxch.tl=(char)201;
	boxch.tr=(char)187;
	boxch.bl=(char)200;
	boxch.br=(char)188;
914
	for(i=1;i<argc;i++) {
deuce's avatar
deuce committed
915
916
917
918
919
920
921
922
923
924
925
		if(argv[i][0]=='-')
			switch(toupper(argv[i][1])) {
				case 'C':
					uifc.mode|=UIFC_COLOR;
					break;
					case 'L':
					uifc.scrn_len=atoi(argv[i]+2);
					break;
				case 'E':
					uifc.esc_delay=atoi(argv[i]+2);
					break;
926
927
928
				case 'S':
					idle_sleep=atoi(argv[i]+2);
					break;
929
				case 'I':
deuce's avatar
deuce committed
930
931
932
933
934
935
936
937
					switch(toupper(argv[i][2])) {
						case 'A':
							ciolib_mode=CIOLIB_MODE_ANSI;
							break;
						case 'C':
							ciolib_mode=CIOLIB_MODE_CURSES;
							break;
						case 0:
938
							printf("NOTICE: The -i option is deprecated, use -if instead\n");
deuce's avatar
deuce committed
939
940
941
942
							SLEEP(2000);
						case 'F':
							ciolib_mode=CIOLIB_MODE_CURSES_IBM;
							break;
943
944
945
						case 'I':
							ciolib_mode=CIOLIB_MODE_CURSES_ASCII;
							break;
deuce's avatar
deuce committed
946
947
948
949
950
951
952
953
954
						case 'X':
							ciolib_mode=CIOLIB_MODE_X;
							break;
						case 'W':
							ciolib_mode=CIOLIB_MODE_CONIO;
							break;
						default:
							goto USAGE;
					}
955
					break;
deuce's avatar
deuce committed
956
957
				default:
USAGE:
958
					printf("\nusage: %s [ctrl_dir] [options]\n"
deuce's avatar
deuce committed
959
960
961
					         "options:\n\n"
					         "-c  =  force color mode\n"
					         "-e# =  set escape delay to #msec\n"
962
					         "-iX =  set interface mode to X (default=auto) where X is one of:\n"
deuce's avatar
deuce committed
963
#ifdef __unix__
964
965
966
967
					         "       X = X11 mode\n"
					         "       C = Curses mode\n"
					         "       F = Curses mode with forced IBM charset\n"
							 "       I = Curses mode with forced ASCII charset\n"
deuce's avatar
deuce committed
968
#else
969
					         "       W = Win32 native mode\n"
deuce's avatar
deuce committed
970
#endif
971
					         "       A = ANSI mode\n"
deuce's avatar
deuce committed
972
					         "-l# =  set screen lines to #\n"
973
					         "-s# =  set idle sleep to # milliseconds (default: %d)\n"
deuce's avatar
deuce committed
974
975
976
977
978
979
					    ,argv[0]
					    ,idle_sleep
					);
					exit(0);
			}
	}
980

deuce's avatar
deuce committed
981
#ifdef SIGPIPE
982
	signal(SIGPIPE, SIG_IGN);
deuce's avatar
deuce committed
983
#endif
984

985
	uifc.size=sizeof(uifc);
deuce's avatar
deuce committed
986
987
	i=initciolib(ciolib_mode);
	if(i!=0) {
deuce's avatar
deuce committed
988
989
		printf("ciolib library init returned error %d\n",i);
		exit(1);
deuce's avatar
deuce committed
990
	}
deuce's avatar
deuce committed
991
	i=uifcini32(&uifc);  /* curses */
992
993
994
995
996
	if(i!=0) {
		printf("uifc library init returned error %d\n",i);
		exit(1);
	}

997
998
999
1000
	const int main_menu_opts = 11;
	if((opt=(char **)alloca(sizeof(char *)*(main_menu_opts+1)))==NULL)
		allocfail(sizeof(char *)*(main_menu_opts+1));
	for(i=0;i<(main_menu_opts+1);i++)
1001
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
1002
1003
			allocfail(MAX_OPLN);

deuce's avatar
deuce committed
1004
1005
1006
	if((mopt=(char **)alloca(sizeof(char *)*cfg.sys_nodes+2))==NULL)
		allocfail(sizeof(char *)*cfg.sys_nodes+2);
	for(i=0;i<cfg.sys_nodes+2;i++)
1007
		if((mopt[i]=(char *)alloca(MAX_OPLN))==NULL)
1008
1009
			allocfail(MAX_OPLN);

1010
	if(uifc.scrn(app_title)) {
1011
1012
1013
1014
		printf(" USCRN (len=%d) failed!\n",uifc.scrn_len+1);
		bail(1);
	}

1015
	int paging_node = 0;
1016
	while(1) {
1017
		strcpy(mopt[0],"System Options");
1018
		for(i=1;i<=cfg.sys_nodes;i++) {
1019
			if((j=getnodedat(&cfg,i,&node,FALSE,NULL)))
1020
				sprintf(mopt[i],"Error reading node data (%d)!",j);
1021
			else {
1022
				nodestatus(&cfg, &node, str, 71, i);
1023
1024
1025
1026
1027
1028
				if(i == paging_node) {
					strupr(str);
					strcat(str,  " <PAGING>");
				}
				sprintf(mopt[i],"%3d: %s", i, str);
			}
1029
		}
1030
		mopt[i][0]=0;
1031

deuce's avatar
deuce committed
1032
1033
		uifc.helpbuf=  "`Synchronet UNIX Monitor\n"
		               "`------------------\n"