umonitor.c 38.1 KB
Newer Older
1 2 3 4 5 6
/* Synchronet for *nix node activity monitor */

/****************************************************************************
 * @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
7
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *																			*
 * 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										*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

22
#include <signal.h>
deuce's avatar
deuce committed
23
#include <sys/types.h>
24
#include <time.h>
deuce's avatar
deuce committed
25 26 27
#ifdef __QNX__
#include <string.h>
#endif
28
#include <stdio.h>
29 30 31 32

#include "ciolib.h"
#define __COLORS		/* Disable the colour macros in sbbsdefs.h ToDo */
#include "sbbs.h"
33
#include "genwrap.h"
34 35 36
#include "uifc.h"
#include "sbbsdefs.h"
#include "genwrap.h"	/* stricmp */
37
#include "dirwrap.h"	/* lock/unlock/sopen */
38
#include "filewrap.h"	/* lock/unlock/sopen */
39 40 41
#include "sbbs_ini.h"	/* INI parsing */
#include "scfglib.h"	/* SCFG files */
#include "ars_defs.h"	/* needed for SCFG files */
42
#include "userdat.h"	/* getnodedat() */
43
#include "spyon.h"
44
#include "chat.h"
45

46
#define CTRL(x) (x&037)
47 48 49 50 51

/********************/
/* Global Variables */
/********************/
uifcapi_t uifc; /* User Interface (UIFC) Library API */
52 53
const char *YesStr="Yes";
const char *NoStr="No";
54
char app_title[128];
55
int	ciolib_mode=CIOLIB_MODE_AUTO;
56 57 58 59 60 61 62 63 64 65 66 67 68 69

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);
}
70

71 72
void bail(int code)
{
deuce's avatar
deuce committed
73 74 75
	if(code) {
		puts("\nHit a key...");
		getch();
76
	}
deuce's avatar
deuce committed
77
	uifc.bail();
78

deuce's avatar
deuce committed
79
	exit(code);
80 81 82 83
}

void allocfail(uint size)
{
deuce's avatar
deuce committed
84 85
	printf("\7Error allocating %u bytes of memory.\n",size);
	bail(1);
86 87
}

88
void node_toggles(scfg_t *cfg,int nodenum)  {
89
	int nodefile = -1;
90 91 92 93 94
	char**	opt;
	int		i,j;
	node_t	node;
	int		save=0;

deuce's avatar
deuce committed
95 96 97
	if((opt=(char **)alloca(sizeof(char *)*(4+1)))==NULL)
		allocfail(sizeof(char *)*(4+1));
	for(i=0;i<(4+1);i++)
98
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
99 100 101
			allocfail(MAX_OPLN);

	i=0;
102 103
	uifc.helpbuf=	"`Node Toggles\n"
	                "`------------`\n\n"
deuce's avatar
deuce committed
104 105 106 107 108 109 110 111 112 113 114
	                "`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.";
115
	while(save==0) {
116
		if(getnodedat(cfg,nodenum,&node,FALSE,&nodefile)) {
117 118 119
			uifc.msg("Error reading node data!");
			break;
		}
120 121 122
		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
123 124 125
		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);
126 127
		opt[j][0]=0;

128
		switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0,"Node Toggles",opt)) {
129 130 131 132 133 134 135 136
			case 0:	/* Locked */
				node.misc ^= NODE_LOCK;
				break;

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

rswindell's avatar
rswindell committed
137
			case 2:	/* Re-run */
138 139 140
				node.misc ^= NODE_RRUN;
				break;

rswindell's avatar
rswindell committed
141
			case 3:	/* Down */
142
				if(node.status != NODE_WFC && node.status != NODE_OFFLINE)
143
					node.misc ^= NODE_DOWN;
144
				else {
145 146 147 148 149
					if(node.status!=NODE_OFFLINE)
						node.status=NODE_OFFLINE;
					else
						node.status=NODE_WFC;
				}
150 151 152 153 154
				break;

			case -1:
				save=1;
				break;
155

156 157 158 159
			default:
				uifc.msg("Option not implemented");
				continue;
		}
160
		putnodedat(cfg,nodenum,&node,FALSE,nodefile);
deuce's avatar
deuce committed
161
	}
deuce's avatar
deuce committed
162 163 164 165 166 167 168
}

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
169
		snprintf(str,sizeof(str),"%slocalspy%d.sock", bbs_startup->temp_dir, nodenum);
deuce's avatar
deuce committed
170 171 172 173 174 175 176
	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);
177

deuce's avatar
deuce committed
178
		case SPY_NOCONNECT:
179
			SAFEPRINTF(str2,"Failed to connect to %s",str);
deuce's avatar
deuce committed
180 181 182 183 184 185 186 187 188 189
			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);
190

deuce's avatar
deuce committed
191 192 193
		case SPY_STDINLOST:
			uifc.msg("STDIN has gone away... you probably can't close this window.  :-)");
			return(-1);
194

deuce's avatar
deuce committed
195 196
		case SPY_CLOSED:
			break;
197

deuce's avatar
deuce committed
198 199 200 201 202 203 204 205
		default:
			sprintf(str,"Unknown return code %d",i);
			uifc.msg(str);
			return(-1);
	}
	return(0);
}

206
int sendmessage(scfg_t *cfg, int nodenum,node_t *node)  {
207 208
	char str[80],str2[80];

209
	uifc.input(WIN_MID|WIN_SAV,0,0,"Telegram",str2,58,K_WRAP|K_MSG);
210
	SAFEPRINTF(str,"\1n\1y\1hMessage From Sysop:\1w %s\r\n",str2);
211
	if(getnodedat(cfg,nodenum,node,FALSE,NULL))
212 213 214
		return(-1);
	if(node->useron==0)
		return(-1);
215
	putsmsg(cfg, node->useron, str);
216 217 218
	return(0);
}

219
int clearerrors(scfg_t *cfg, int nodenum, node_t *node) {
220 221
	int nodefile = -1;
	if(getnodedat(cfg,nodenum,node,TRUE,&nodefile)) {
222 223 224 225
		uifc.msg("getnodedat() failed! (Nothing done)");
		return(-1);
	}
	node->errors=0;
226
	putnodedat(cfg,nodenum,node,TRUE,nodefile);
227
	uifc.msg("Error count cleared for this node.");
228 229 230
	return(0);
}

231 232 233 234 235
/* 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);
236
			return(outstr);
237 238 239
		}
		if(size<10000) {	/* Bytes with comma */
			snprintf(outstr,12,"%ld,%03ld bytes",(size/1000),(size%1000));
240
			return(outstr);
241 242 243 244 245
		}
		size = size/1024;
	}
	if(size<1000) {	/* KB */
		snprintf(outstr,12,"%ld KB",size);
246
		return(outstr);
247 248 249
	}
	if(size<999999) { /* KB With comma */
		snprintf(outstr,12,"%ld,%03ld KB",(size/1000),(size%1000));
250
		return(outstr);
251 252 253 254
	}
	size = size/1024;
	if(size<1000) {	/* MB */
		snprintf(outstr,12,"%ld MB",size);
255
		return(outstr);
256 257 258
	}
	if(size<999999) { /* MB With comma */
		snprintf(outstr,12,"%ld,%03ld MB",(size/1000),(size%1000));
259
		return(outstr);
260 261 262 263
	}
	size = size/1024;
	if(size<1000) {	/* GB */
		snprintf(outstr,12,"%ld GB",size);
264
		return(outstr);
265 266 267
	}
	if(size<999999) { /* GB With comma */
		snprintf(outstr,12,"%ld,%03ld GB",(size/1000),(size%1000));
268
		return(outstr);
269 270 271 272
	}
	size = size/1024;
	if(size<1000) {	/* TB (Yeah, right) */
		snprintf(outstr,12,"%ld TB",size);
273
		return(outstr);
274 275
	}
	sprintf(outstr,"Plenty");
276
	return(outstr);
277 278 279 280 281 282
}

/* Assumes a 12 char outstr */
char *getnumstr(char *outstr, ulong size) {
	if(size < 1000) {
		snprintf(outstr,12,"%ld",size);
283
		return(outstr);
284 285 286
	}
	if(size<1000000) {
		snprintf(outstr,12,"%ld,%03ld",(size/1000),(size%1000));
287
		return(outstr);
288 289 290
	}
	if(size<1000000000) {
		snprintf(outstr,12,"%ld,%03ld,%03ld",(size/1000000),((size/1000)%1000),(size%1000));
291
		return(outstr);
292 293 294 295
	}
	size=size/1000000;
	if(size<1000000) {
		snprintf(outstr,12,"%ld,%03ld M",(size/1000),(size%1000));
296
		return(outstr);
297 298 299
	}
	if(size<10000000) {
		snprintf(outstr,12,"%ld,%03ld,%03ld M",(size/1000000),((size/1000)%1000),(size%1000));
300
		return(outstr);
301 302
	}
	sprintf(outstr,"Plenty");
303
	return(outstr);
304 305
}

306
int drawstats(scfg_t *cfg, int nodenum, node_t *node, int *curp, int *barp) {
307 308 309 310
	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];
311
	char	heading[128];
312
	char	usrname[128];
313
	char	tmp[128];
314 315
	ulong	free;
	uint	i,l,m;
316
	time_t	t, now;
317
	int		shownode=1;
318

319
	if(getnodedat(cfg,nodenum,node,FALSE,NULL)) {
320 321 322 323
		shownode=0;
	}
	else {
		getstats(cfg, nodenum, &nstats);
324 325 326 327
	}
	username(cfg,node->useron,usrname);

	getstats(cfg, 0, &sstats);
328
	now = time(NULL);
329
	if(shownode) {
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
		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);
347 348 349 350
		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
351
		snprintf(str[2][0],12,"%s/%s",getnumstr(str[3][2],sstats.etoday),getnumstr(str[3][3],getmail(cfg,0,0,0)));
352 353 354 355 356 357
		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
358
		snprintf(str[2][2],12,"%s/%s",getnumstr(str[3][2],sstats.ftoday),getnumstr(str[3][3],getmail(cfg,1,0,0)));
359 360 361 362 363 364 365
		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 {
366 367 368 369 370 371 372 373
		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);
374 375 376 377
		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
378
		snprintf(str[2][0],12,"%s/%s",getnumstr(str[3][2],sstats.etoday),getnumstr(str[3][3],getmail(cfg,0,0,0)));
379 380 381 382 383 384
		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
385
		snprintf(str[2][2],12,"%s/%s",getnumstr(str[3][2],sstats.ftoday),getnumstr(str[3][3],getmail(cfg,1,0,0)));
386 387 388 389 390 391
		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);
	}
392
	snprintf(statbuf,sizeof(statbuf),"%s"
deuce's avatar
deuce committed
393 394 395
			"\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",
396
			heading,
397 398 399 400
			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
401
	uifc.showbuf(WIN_HLP|WIN_L2R|WIN_DYN|WIN_PACK,1,1,80,6,"Statistics",statbuf,curp,barp);
402
/* Node 5 :	Mar 11  Space: 162,024k
403
   Logons: 23/103      Total: 62,610      Timeon: 322/2430    Total: 5,321,900
404 405 406 407 408
   Emails: 4/265       Posts: 4/12811     Fbacks: 2/17	       Users: 1/592
   Uloads: 324k        Files: 1/2195      Dloads: 9,308k      Files: 52 */
	return(0);
}

409 410 411 412 413 414 415 416 417 418
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);
419
			if(j >= 0 && (buf=(char *)malloc(j+1))!=NULL) {
420 421 422 423
				read(buffile,buf,j);
				close(buffile);
				*(buf+j)=0;
				uifc.showbuf(WIN_MID,0,0,76,uifc.scrn_len-2,title,buf,NULL,NULL);
424
				free(buf);
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
				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);
453
	const int num_opts = 12;
454 455 456
	if((opt=(char **)alloca(sizeof(char *)*(num_opts+1)))==NULL)
		allocfail(sizeof(char *)*(num_opts+1));
	for(i=0;i<(num_opts+1);i++)
457
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
458 459 460
			allocfail(MAX_OPLN);

	i=0;
461 462
	strcpy(opt[i++],"Today's callers");
	strcpy(opt[i++],"Yesterday's callers");
463
	strcpy(opt[i++],"Error log");
464 465
	strcpy(opt[i++],"Today's log");
	strcpy(opt[i++],"Yesterday's log");
466
	strcpy(opt[i++],"Spam log");
467
	strcpy(opt[i++],"SBBSecho log");
468
	strcpy(opt[i++],"EchoMail stats");
469
	strcpy(opt[i++],"BinkP stats");
470
	strcpy(opt[i++],"Bad Areas list");
471 472 473 474
	strcpy(opt[i++],"Guru log");
	strcpy(opt[i++],"Hack log");
	opt[i][0]=0;
	i=0;
475
	uifc.helpbuf=	"`View Logs\n"
deuce's avatar
deuce committed
476 477 478 479 480 481 482
	                "`---------\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"
483
	                "`SBBSecho log        : `View the FidoNet EchoMail program log.\n"
484 485
	                "`EchoMail stats      : `view the FidoNet EchoMail statistics.\n"
					"`Binkp stats         : `view the BinkP FidoNet mailer statistics.\n"
486
	                "`Bad Areas list      : `view the list of unknown EchoMail areas.\n"
deuce's avatar
deuce committed
487 488
	                "`Guru log            : `View the transcriptions of chats with the Guru.\n"
	                "`Hack log            : `View the Hack attempt log.";
489

490
	while(1) {
491
		switch(uifc.list(WIN_MID,0,0,0,&i,0,"View Logs",opt))  {
492 493 494
			case -1:
				return(0);
			case 0:
deuce's avatar
deuce committed
495
				sprintf(str,"%slogs/%2.2d%2.2d%2.2d.lol",cfg->logs_dir,tm.tm_mon+1,tm.tm_mday
496 497 498 499
					,TM_YEAR(tm.tm_year));
				view_log(str,"Todays Callers");
				break;
			case 1:
deuce's avatar
deuce committed
500
				sprintf(str,"%slogs/%2.2d%2.2d%2.2d.lol",cfg->logs_dir,tm_yest.tm_mon+1
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
					,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);
524
				view_log(str,"SBBSecho Log");
525 526
				break;
			case 7:
527 528 529 530
				sprintf(str,"%sechostats.ini",cfg->data_dir);
				view_log(str,"EchoMail Stats");
				break;
			case 8:
531 532 533 534
				sprintf(str,"%sbinkstats.ini",cfg->data_dir);
				view_log(str,"BinkP Stats");
				break;
			case 9:
535 536 537
				sprintf(str,"%sbadareas.lst",cfg->data_dir);
				view_log(str,"Bad Area List");
				break;
538
			case 10:
539 540 541
				sprintf(str,"%sguru.log",cfg->logs_dir);
				view_log(str,"Guru Log");
				break;
542
			case 11:
543 544 545 546 547 548 549 550 551 552
				sprintf(str,"%shack.log",cfg->logs_dir);
				view_log(str,"Hack Log");
				break;
		}
	}
}

int do_cmd(char *cmd)
{
	int i;
553 554 555 556
	struct text_info ti;
	char *p;

	gettextinfo(&ti);
557
	p=alloca(ti.screenheight*ti.screenwidth*2);
558
	gettext(1,1,ti.screenwidth,ti.screenheight,p);
559
	suspendciolib();
560
	i=system(cmd);
561 562
	initciolib(ciolib_mode);
	clrscr();
563
	puttext(1,1,ti.screenwidth,ti.screenheight,p);
564
	uifc.scrn(app_title);
565 566 567
	return(i);
}

568
int qwk_callouts(scfg_t *cfg)
569
{
570 571 572 573 574 575 576 577 578
	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
579 580 581
	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++)
582
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
583 584 585
			allocfail(MAX_OPLN);


586 587 588 589
	uifc.helpbuf=	"`QWK Callouts\n"
					"`------------\n\n"
					"Select the Hub and press enter to initiate a call out to\n"
					"the highlighted system.";
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608

	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);
		}
	}
609 610 611
	return(0);
}

612
int run_events(scfg_t *cfg)
613
{
614 615 616 617
	char**	opt;
	int		i,j;
	char	str[1024];

deuce's avatar
deuce committed
618 619 620
	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++)
621
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
622 623 624 625 626 627 628 629
			allocfail(MAX_OPLN);

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

630 631 632
	uifc.helpbuf=	"`Run Events\n"
					"`----------\n\n"
					"To run and event, highlight it and press Enter";
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650

	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);
		}
	}
651 652 653
	return(0);
}

654
int recycle_servers(scfg_t *cfg)
655
{
Rob Swindell's avatar
Rob Swindell committed
656
	char str[MAX_PATH + 1];
657 658
	char **opt;
	int i=0;
Rob Swindell's avatar
Rob Swindell committed
659
	const int opt_count = 6;
660

Rob Swindell's avatar
Rob Swindell committed
661 662
	if((opt=(char **)alloca(sizeof(char *)*(opt_count+1)))==NULL)
		allocfail(sizeof(char *)*(opt_count+1));
663

Rob Swindell's avatar
Rob Swindell committed
664 665 666 667 668 669 670
	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;
671

672 673
	uifc.helpbuf=	"`Recycle Servers\n"
					"`---------------\n\n"
Rob Swindell's avatar
Rob Swindell committed
674
					"To recycle a server, highlight it and press Enter.\n"
675 676
					"This will reload the configuration files for selected\n"
					"server.";
677 678 679

	i=0;
	while(1) {
Rob Swindell's avatar
Rob Swindell committed
680
		const char* ext = "";
681 682 683 684 685
		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
686
				ext = ".term";
687 688
				break;
			case 2:
Rob Swindell's avatar
Rob Swindell committed
689
				ext = ".mail";
690 691
				break;
			case 3:
Rob Swindell's avatar
Rob Swindell committed
692
				ext = ".ftp";
693 694
				break;
			case 4:
Rob Swindell's avatar
Rob Swindell committed
695 696 697 698
				ext = ".web";
				break;
			case 5:
				ext = ".services";
699 700
				break;
		}
Rob Swindell's avatar
Rob Swindell committed
701 702
		SAFEPRINTF2(str, "%srecycle%s", cfg->ctrl_dir, ext);
		ftouch(str);
703
	}
704 705 706
	return(0);
}

707 708 709 710 711 712 713 714 715 716 717 718 719 720
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);
}


721 722 723 724 725
int edit_cfg(scfg_t *cfg)
{
	char**	opt;
	int		i;
	char	cmd[1024];
726
	char	editcmd[1024];
727

728 729 730 731
	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++)
732
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
733 734 735
			allocfail(MAX_OPLN);

	i=0;
736
	strcpy(opt[i++],"sbbs.ini");
737
	strcpy(opt[i++],"modopts.ini");
738 739 740 741 742
	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");
743 744
	strcpy(opt[i++],"mailproc.ini");
	strcpy(opt[i++],"mime_types.ini");
745
	strcpy(opt[i++],"relay.cfg");
746
	strcpy(opt[i++],"sbbsecho.ini");
747
	strcpy(opt[i++],"../data/areas.bbs");
748
	strcpy(opt[i++],"services.ini");
749
	strcpy(opt[i++],"ftpalias.cfg");
750
	strcpy(opt[i++],"sockopts.ini");
751 752
	strcpy(opt[i++],"spambait.cfg");
	opt[i][0]=0;
753
	uifc.helpbuf= "Highlight desired file and hit Enter to edit it.";
754 755
	i=0;
	while(1) {
756
		switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0,"Edit Config File",opt))  {
757 758
			case -1:
				return(0);
759
				break;
760
			default:
761
				sprintf(cmd,"%s %s%s",geteditor(editcmd),cfg->ctrl_dir,opt[i]);
762 763 764 765 766 767
				do_cmd(cmd);
				break;
		}
	}
	return(0);
}
768

769 770 771 772 773
int edit_can(scfg_t *cfg)
{
	char**	opt;
	int		i;
	char	cmd[1024];
774
	char	editcmd[1024];
775

776 777 778 779
	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++)
780
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
781 782 783 784 785 786 787 788 789 790 791 792
			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");
793 794
	strcpy(opt[i++],"../ctrl/twitlist.cfg");
	strcpy(opt[i++],"../ctrl/spamblock.cfg");
795
	opt[i][0]=0;
796
	uifc.helpbuf="Highlight desired file and hit Enter to edit it.";
797 798
	i=0;
	while(1) {
799
		switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0,"Edit Filter File",opt))  {
800 801
			case -1:
				return(0);
802
				break;
803
			default:
804
				sprintf(cmd,"%s %s%s",geteditor(editcmd),cfg->text_dir,opt[i]);
805 806 807 808 809 810
				do_cmd(cmd);
				break;
		}
	}
	return(0);
}
811

812
int main(int argc, char** argv)  {
813

814 815 816 817
	char**	opt;
	char**	mopt;
	int		main_dflt=0;
	int		main_bar=0;
818
	int		sys_cur=0;
deuce's avatar
deuce committed
819
	char	revision[16];
820
	char	str[256],ctrl_dir[MAX_PATH + 1];
deuce's avatar
deuce committed
821 822
	int		i,j;
	node_t	node;
823
	int		nodefile = -1;
824 825
	box_t	boxch;
	scfg_t	cfg;
826
	int		done;
827
	time_t	last_semfile_check = time(NULL);
828
	int		idle_sleep=100;
829

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

deuce's avatar
deuce committed
832 833 834
	/******************/
	/* Ini file stuff */
	/******************/
835
	char	ini_file[MAX_PATH+1];
836
	FILE*				fp=NULL;
837
	bbs_startup_t		bbs_startup;
838

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

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

844
	SAFECOPY(ctrl_dir, get_ctrl_dir(/* warn: */TRUE));
845
	backslash(ctrl_dir);
846

deuce's avatar
deuce committed
847
	gethostname(str,sizeof(str)-1);
848 849

	sbbs_get_ini_fname(ini_file, ctrl_dir, str);
850 851

	/* Initialize BBS startup structure */
deuce's avatar
deuce committed
852 853
	memset(&bbs_startup,0,sizeof(bbs_startup));
	bbs_startup.size=sizeof(bbs_startup);
854
	SAFECOPY(bbs_startup.ctrl_dir,ctrl_dir);
855 856 857 858 859 860

	/* 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
861
	sbbs_read_ini(fp, ini_file,
862
		NULL,		/* global_startup */
863
		NULL, &bbs_startup,
864
		NULL, NULL, /* ftp_startup */
865
		NULL, NULL, /* web_startup */
866 867 868
		NULL, NULL, /* mail_startup */
		NULL, NULL  /* services_startup */
		);
869 870 871 872 873 874

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

	chdir(bbs_startup.ctrl_dir);
875

876
	/* Read .cfg files here */
deuce's avatar
deuce committed
877
	memset(&cfg,0,sizeof(cfg));
878
	cfg.size=sizeof(cfg);
879
	SAFECOPY(cfg.ctrl_dir,bbs_startup.ctrl_dir);
880
	if(!load_cfg(&cfg, /* text: */NULL, /* prep: */TRUE, /* node: */FALSE, str, sizeof(str))) {
881 882 883
		printf("ERROR! %s\n",str);
		exit(1);
	}
884
	prep_dir(cfg.ctrl_dir, cfg.temp_dir, sizeof(cfg.temp_dir));
885

deuce's avatar
deuce committed
886
	memset(&uifc,0,sizeof(uifc));
887
	uifc.mode|=UIFC_NOCTRL;
888 889 890

	uifc.esc_delay=500;

deuce's avatar
deuce committed
891 892 893 894 895 896 897 898
	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;
899
	for(i=1;i<argc;i++) {
deuce's avatar
deuce committed
900 901 902 903 904 905 906 907 908 909 910
		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;
911 912 913
				case 'S':
					idle_sleep=atoi(argv[i]+2);
					break;
914
				case 'I':
deuce's avatar
deuce committed
915 916 917 918 919 920 921 922
					switch(toupper(argv[i][2])) {
						case 'A':
							ciolib_mode=CIOLIB_MODE_ANSI;
							break;
						case 'C':
							ciolib_mode=CIOLIB_MODE_CURSES;
							break;
						case 0: