umonitor.c 35.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
/* umonitor.c */

/* Synchronet for *nix node activity monitor */

/* $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 2010 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
37
 *																			*
 * 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.	*
 ****************************************************************************/

38
#include <signal.h>
deuce's avatar
deuce committed
39
#include <sys/types.h>
40
#include <time.h>
deuce's avatar
deuce committed
41
42
43
#ifdef __QNX__
#include <string.h>
#endif
44
#include <stdio.h>
45
46
47
48

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

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

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

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

85
86
87
88
void bail(int code)
{
    if(code) {
        puts("\nHit a key...");
89
        getch();
90
91
92
93
94
95
96
97
98
99
	}
    uifc.bail();

    exit(code);
}

void allocfail(uint size)
{
    printf("\7Error allocating %u bytes of memory.\n",size);
    bail(1);
100
101
}

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

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

	i=0;
116
117
118
119
120
121
122
123
124
125
126
127
128
	uifc.helpbuf=	"`Node Toggles\n"
	                "`------------`\n\n"
					"`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.";
129
	while(save==0) {
130
		if(getnodedat(cfg,nodenum,&node,&nodefile)) {
131
132
133
			uifc.msg("Error reading node data!");
			break;
		}
134
135
136
		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
137
138
139
		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);
140
141
		opt[j][0]=0;

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

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

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

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

			case -1:
				save=1;
				break;
169

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

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

	if(bbs_startup->temp_dir[0])
    	snprintf(str,sizeof(str),"%slocalspy%d.sock", bbs_startup->temp_dir, nodenum);
	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);
191

deuce's avatar
deuce committed
192
193
194
195
196
197
198
199
200
201
202
203
		case SPY_NOCONNECT:
			sprintf(str2,"Failed to connect to %s",str);
			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);
204

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

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

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

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

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

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

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

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

320
int drawstats(scfg_t *cfg, int nodenum, node_t *node, int *curp, int *barp) {
321
322
323
324
325
326
327
328
	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];
	char	usrname[128];
	ulong	free;
	uint	i,l,m;
	time_t	t;
329
	int		shownode=1;
330
331

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

	getstats(cfg, 0, &sstats);
	t=time(NULL);
	strftime(str[0][0],12,"%b %e",localtime(&t));
	free=getfreediskspace(cfg->temp_dir,1024);
	if(free<1000) {
		free=getfreediskspace(cfg->temp_dir,0);
		getsizestr(str[0][1],free,TRUE);
346
	}
347
348
	else
		getsizestr(str[0][1],free,FALSE);
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
	if(shownode) {
		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);
		snprintf(str[2][0],12,"%s/%s",getnumstr(str[3][2],sstats.etoday),getnumstr(str[3][3],getmail(cfg,0,0)));
		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));
		snprintf(str[2][2],12,"%s/%s",getnumstr(str[3][2],sstats.ftoday),getnumstr(str[3][3],getmail(cfg,1,0)));
		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 {
		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);
		snprintf(str[2][0],12,"%s/%s",getnumstr(str[3][2],sstats.etoday),getnumstr(str[3][3],getmail(cfg,0,0)));
		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));
		snprintf(str[2][2],12,"%s/%s",getnumstr(str[3][2],sstats.ftoday),getnumstr(str[3][3],getmail(cfg,1,0)));
		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);
	}
deuce's avatar
deuce committed
387
388
389
390
	snprintf(statbuf,sizeof(statbuf),"`Node #`: %-3d %6s  `Space`: %s"
			"\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",
391
392
393
394
395
			nodenum,str[0][0],str[0][1],
			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
396
	uifc.showbuf(WIN_HLP|WIN_L2R|WIN_DYN|WIN_PACK,1,1,80,6,"Statistics",statbuf,curp,barp);
397
/* Node 5 :	Mar 11  Space: 162,024k
398
   Logons: 23/103      Total: 62,610      Timeon: 322/2430    Total: 5,321,900
399
400
401
402
403
   Emails: 4/265       Posts: 4/12811     Fbacks: 2/17	       Users: 1/592
   Uloads: 324k        Files: 1/2195      Dloads: 9,308k      Files: 52 */
	return(0);
}

404
405
406
407
408
409
410
411
412
413
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);
414
			if((buf=(char *)alloca(j+1))!=NULL) {
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
				read(buffile,buf,j);
				close(buffile);
				*(buf+j)=0;
				uifc.showbuf(WIN_MID,0,0,76,uifc.scrn_len-2,title,buf,NULL,NULL);
				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);
deuce's avatar
deuce committed
447
448
449
	if((opt=(char **)alloca(sizeof(char *)*(9+1)))==NULL)
		allocfail(sizeof(char *)*(9+1));
	for(i=0;i<(9+1);i++)
450
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
451
452
453
			allocfail(MAX_OPLN);

	i=0;
454
455
	strcpy(opt[i++],"Today's callers");
	strcpy(opt[i++],"Yesterday's callers");
456
	strcpy(opt[i++],"Error log");
457
458
	strcpy(opt[i++],"Today's log");
	strcpy(opt[i++],"Yesterday's log");
459
460
461
462
463
464
	strcpy(opt[i++],"Spam log");
	strcpy(opt[i++],"SBBSEcho log");
	strcpy(opt[i++],"Guru log");
	strcpy(opt[i++],"Hack log");
	opt[i][0]=0;
	i=0;
465
466
467
468
469
470
471
472
473
474
475
	uifc.helpbuf=	"`View Logs\n"
					"`---------\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"
					"`SBBSEcho log        : `View the SBBSecho tosser log.\n"
					"`Guru log            : `View the transcriptions of chats with the Guru.\n"
					"`Hack log            : `View the Hack attempt log.";
476

477
	while(1) {
478
		switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0,"View Logs",opt))  {
479
480
481
			case -1:
				return(0);
			case 0:
deuce's avatar
deuce committed
482
				sprintf(str,"%slogs/%2.2d%2.2d%2.2d.lol",cfg->logs_dir,tm.tm_mon+1,tm.tm_mday
483
484
485
486
					,TM_YEAR(tm.tm_year));
				view_log(str,"Todays Callers");
				break;
			case 1:
deuce's avatar
deuce committed
487
				sprintf(str,"%slogs/%2.2d%2.2d%2.2d.lol",cfg->logs_dir,tm_yest.tm_mon+1
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
					,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);
				view_log(str,"SBBSEcho Log");
				break;
			case 7:
				sprintf(str,"%sguru.log",cfg->logs_dir);
				view_log(str,"Guru Log");
				break;
			case 8:
				sprintf(str,"%shack.log",cfg->logs_dir);
				view_log(str,"Hack Log");
				break;
		}
	}
}

int do_cmd(char *cmd)
{
	int i;
528
529
530
531
	struct text_info ti;
	char *p;

	gettextinfo(&ti);
532
	p=alloca(ti.screenheight*ti.screenwidth*2);
533
	gettext(1,1,ti.screenwidth,ti.screenheight,p);
534
	i=system(cmd);
535
	puttext(1,1,ti.screenwidth,ti.screenheight,p);
536
537
538
	return(i);
}

539
int qwk_callouts(scfg_t *cfg)
540
{
541
542
543
544
545
546
547
548
549
	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
550
551
552
	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++)
553
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
554
555
556
			allocfail(MAX_OPLN);


557
558
559
560
	uifc.helpbuf=	"`QWK Callouts\n"
					"`------------\n\n"
					"Select the Hub and press enter to initiate a call out to\n"
					"the highlighted system.";
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579

	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);
		}
	}
580
581
582
	return(0);
}

583
int run_events(scfg_t *cfg)
584
{
585
586
587
588
	char**	opt;
	int		i,j;
	char	str[1024];

deuce's avatar
deuce committed
589
590
591
	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++)
592
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
593
594
595
596
597
598
599
600
			allocfail(MAX_OPLN);

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

601
602
603
	uifc.helpbuf=	"`Run Events\n"
					"`----------\n\n"
					"To run and event, highlight it and press Enter";
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621

	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);
		}
	}
622
623
624
	return(0);
}

625
int recycle_servers(scfg_t *cfg)
626
{
627
628
629
630
	char str[1024];
	char **opt;
	int i=0;

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

	i=0;
	strcpy(opt[i++],"FTP server");
	strcpy(opt[i++],"Mail server");
	strcpy(opt[i++],"Services");
	strcpy(opt[i++],"Telnet server");
	strcpy(opt[i++],"Web server");
	opt[i][0]=0;

645
646
647
648
649
	uifc.helpbuf=	"`Recycle Servers\n"
					"`---------------\n\n"
					"To rerun a server, highlight it and press Enter.\n"
					"This will reload the configuration files for selected\n"
					"server.";
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678

	i=0;
	while(1) {
		switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0,"Recycle Servers",opt))  {
			case -1:
				return(0);
				break;
			case 0:
				sprintf(str,"%sftpsrvr.rec",cfg->ctrl_dir);
				ftouch(str);
				break;
			case 1:
				sprintf(str,"%smailsrvr.rec",cfg->ctrl_dir);
				ftouch(str);
				break;
			case 2:
				sprintf(str,"%sservices.rec",cfg->ctrl_dir);
				ftouch(str);
				break;
			case 3:
				sprintf(str,"%stelnet.rec",cfg->ctrl_dir);
				ftouch(str);
				break;
			case 4:
				sprintf(str,"%swebsrvr.rec",cfg->ctrl_dir);
				ftouch(str);
				break;
		}
	}
679
680
681
	return(0);
}

682
683
684
685
686
687
688
689
690
691
692
693
694
695
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);
}


696
697
698
699
700
int edit_cfg(scfg_t *cfg)
{
	char**	opt;
	int		i;
	char	cmd[1024];
701
	char	editcmd[1024];
702

deuce's avatar
deuce committed
703
704
705
	if((opt=(char **)alloca(sizeof(char *)*(17+1)))==NULL)
		allocfail(sizeof(char *)*(17+1));
	for(i=0;i<(17+1);i++)
706
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
707
708
709
			allocfail(MAX_OPLN);

	i=0;
710
	strcpy(opt[i++],"sbbs.ini");
711
712
713
714
715
	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");
716
717
	strcpy(opt[i++],"mailproc.ini");
	strcpy(opt[i++],"mime_types.ini");
718
719
	strcpy(opt[i++],"relay.cfg");
	strcpy(opt[i++],"sbbsecho.cfg");
720
	strcpy(opt[i++],"services.ini");
721
	strcpy(opt[i++],"ftpalias.cfg");
722
	strcpy(opt[i++],"sockopts.ini");
723
724
725
726
	strcpy(opt[i++],"spambait.cfg");
	strcpy(opt[i++],"spamblock.cfg");
	strcpy(opt[i++],"twitlist.cfg");
	opt[i][0]=0;
727
	uifc.helpbuf= "Highlight desired file and hit Enter to edit it.";
728
729
730
731
732
	i=0;
	while(1) {
		switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0,"System Options",opt))  {
			case -1:
				return(0);
733
				break;
734
			default:
735
				sprintf(cmd,"%s %s%s",geteditor(editcmd),cfg->ctrl_dir,opt[i]);
736
737
738
739
740
741
				do_cmd(cmd);
				break;
		}
	}
	return(0);
}
742

743
744
745
746
747
int edit_can(scfg_t *cfg)
{
	char**	opt;
	int		i;
	char	cmd[1024];
748
	char	editcmd[1024];
749

deuce's avatar
deuce committed
750
751
752
	if((opt=(char **)alloca(sizeof(char *)*(9+1)))==NULL)
		allocfail(sizeof(char *)*(9+1));
	for(i=0;i<(9+1);i++)
753
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
754
755
756
757
758
759
760
761
762
763
764
765
766
			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");
	opt[i][0]=0;
767
	uifc.helpbuf="Highlight desired file and hit Enter to edit it.";
768
769
770
771
772
	i=0;
	while(1) {
		switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0,"System Options",opt))  {
			case -1:
				return(0);
773
				break;
774
			default:
775
				sprintf(cmd,"%s %s%s",geteditor(editcmd),cfg->text_dir,opt[i]);
776
777
778
779
780
781
				do_cmd(cmd);
				break;
		}
	}
	return(0);
}
782

783
int main(int argc, char** argv)  {
784

785
786
787
788
	char**	opt;
	char**	mopt;
	int		main_dflt=0;
	int		main_bar=0;
deuce's avatar
deuce committed
789
790
791
792
793
	char	revision[16];
	char	str[256],ctrl_dir[41],*p;
	char	title[256];
	int		i,j;
	node_t	node;
794
795
796
	int		nodefile;
	box_t	boxch;
	scfg_t	cfg;
797
	int		done;
deuce's avatar
deuce committed
798
	int		ciolib_mode=CIOLIB_MODE_AUTO;
799

deuce's avatar
deuce committed
800
801
802
	/******************/
	/* Ini file stuff */
	/******************/
803
804
805
	char	ini_file[MAX_PATH+1];
	FILE*				fp;
	bbs_startup_t		bbs_startup;
806
807

	sscanf("$Revision$", "%*s %s", revision);
808

rswindell's avatar
rswindell committed
809
810
    printf("\nSynchronet UNIX Monitor %s-%s  Copyright %s "
        "Rob Swindell\n",revision,PLATFORM_DESC,__DATE__+7);
811
812
813
814
815
816
817
818
819
820
821
822
823

	p=getenv("SBBSCTRL");
	if(p==NULL) {
		printf("\7\nSBBSCTRL environment variable is not set.\n");
		printf("This environment variable must be set to your CTRL directory.");
		printf("\nExample: SET SBBSCTRL=/sbbs/ctrl\n");
		exit(1); }

	sprintf(ctrl_dir,"%.40s",p);
	if(ctrl_dir[strlen(ctrl_dir)-1]!='\\'
		&& ctrl_dir[strlen(ctrl_dir)-1]!='/')
		strcat(ctrl_dir,"/");

deuce's avatar
deuce committed
824
	gethostname(str,sizeof(str)-1);
825
826

	sbbs_get_ini_fname(ini_file, ctrl_dir, str);
827
828
829
830
831
832
833
834
835
836
837

	/* Initialize BBS startup structure */
    memset(&bbs_startup,0,sizeof(bbs_startup));
    bbs_startup.size=sizeof(bbs_startup);
    strcpy(bbs_startup.ctrl_dir,ctrl_dir);

	/* 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 */
838
	sbbs_read_ini(fp,
839
		NULL,		/* global_startup */
840
		NULL, &bbs_startup,
841
		NULL, NULL, /* ftp_startup */
842
		NULL, NULL, /* web_startup */
843
844
845
		NULL, NULL, /* mail_startup */
		NULL, NULL  /* services_startup */
		);
846
847
848
849
850
851

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

	chdir(bbs_startup.ctrl_dir);
852

853
	/* Read .cfg files here */
854
    memset(&cfg,0,sizeof(cfg));
855
	cfg.size=sizeof(cfg);
856
857
	SAFECOPY(cfg.ctrl_dir,bbs_startup.ctrl_dir);
	if(!load_cfg(&cfg, NULL, TRUE, str)) {
858
859
860
		printf("ERROR! %s\n",str);
		exit(1);
	}
861
	prep_dir(cfg.data_dir, cfg.temp_dir, sizeof(cfg.temp_dir));
862

863
    memset(&uifc,0,sizeof(uifc));
864
	uifc.mode|=UIFC_NOCTRL;
865
866
867

	uifc.esc_delay=500;

868
	boxch.ls=186;
869
870
871
872
873
874
875
	boxch.rs=186;
	boxch.ts=205;
	boxch.bs=205;
	boxch.tl=201;
	boxch.tr=187;
	boxch.bl=200;
	boxch.br=188;
876
877
878
879
880
881
882
883
884
885
886
887
888
889
	for(i=1;i<argc;i++) {
        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;
				case 'I':
deuce's avatar
deuce committed
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
					switch(toupper(argv[i][2])) {
						case 'A':
							ciolib_mode=CIOLIB_MODE_ANSI;
							break;
						case 'C':
							ciolib_mode=CIOLIB_MODE_CURSES;
							break;
						case 0:
							printf("NOTICE: The -i option is depreciated, use -if instead\r\n");
							SLEEP(2000);
						case 'F':
							ciolib_mode=CIOLIB_MODE_CURSES_IBM;
							break;
						case 'X':
							ciolib_mode=CIOLIB_MODE_X;
							break;
						case 'W':
							ciolib_mode=CIOLIB_MODE_CONIO;
							break;
						default:
							goto USAGE;
					}
912
913
					break;
                default:
deuce's avatar
deuce committed
914
					USAGE:
915
916
917
918
                    printf("\nusage: %s [ctrl_dir] [options]"
                        "\n\noptions:\n\n"
                        "-c  =  force color mode\n"
                        "-e# =  set escape delay to #msec\n"
deuce's avatar
deuce committed
919
920
921
922
923
924
925
926
927
						"-iX =  set interface mode to X (default=auto) where X is one of:\r\n"
#ifdef __unix__
						"       X = X11 mode\r\n"
						"       C = Curses mode\r\n"
						"       F = Curses mode with forced IBM charset\r\n"
#else
						"       W = Win32 native mode\r\n"
#endif
						"       A = ANSI mode\r\n"
928
929
930
931
932
933
934
                        "-l# =  set screen lines to #\n"
						,argv[0]
                        );
        			exit(0);
           }
    }

deuce's avatar
deuce committed
935
#ifdef SIGPIPE
936
	signal(SIGPIPE, SIG_IGN);
deuce's avatar
deuce committed
937
#endif
938

939
	uifc.size=sizeof(uifc);
deuce's avatar
deuce committed
940
941
942
943
944
	i=initciolib(ciolib_mode);
	if(i!=0) {
    	printf("ciolib library init returned error %d\n",i);
    	exit(1);
	}
deuce's avatar
deuce committed
945
	i=uifcini32(&uifc);  /* curses */
946
947
948
949
950
	if(i!=0) {
		printf("uifc library init returned error %d\n",i);
		exit(1);
	}

deuce's avatar
deuce committed
951
952
953
	if((opt=(char **)alloca(sizeof(char *)*(10+1)))==NULL)
		allocfail(sizeof(char *)*(10+1));
	for(i=0;i<(10+1);i++)
954
		if((opt[i]=(char *)alloca(MAX_OPLN))==NULL)
955
956
			allocfail(MAX_OPLN);

deuce's avatar
deuce committed
957
958
959
	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++)
960
		if((mopt[i]=(char *)alloca(MAX_OPLN))==NULL)
961
962
			allocfail(MAX_OPLN);

963
964
	sprintf(title,"Synchronet UNIX Monitor %s-%s",revision,PLATFORM_DESC);
	if(uifc.scrn(title)) {
965
966
967
968
969
		printf(" USCRN (len=%d) failed!\n",uifc.scrn_len+1);
		bail(1);
	}

	while(1) {
970
		strcpy(mopt[0],"System Options");
971
972
		for(i=1;i<=cfg.sys_nodes;i++) {
			if((j=getnodedat(&cfg,i,&node,NULL)))
973
				sprintf(mopt[i],"Error reading node data (%d)!",j);
974
			else
975
				sprintf(mopt[i],"%3d: %s",i,nodestatus(&cfg,&node,str,71));
976
		}
977
		mopt[i][0]=0;
978

979
		uifc.helpbuf=	"`Synchronet UNIX Monitor\n"
980
		                "`------------------\n"
981
		                "Welcome to the Synchronet UNIX Monitor.\n"
982
983
984
985
986
987
988
989
990
991
992
993
994
		                "Displayed on this screen are the statitics for the BBS\n"
		                "You can scroll through the list starting at \"System Options\" \n"
		                "Pressing Enter on each will give a menu of option to perform.\n"
		                "Additionally these keys are available from this screen:\n\n"
						"`CTRL-E : `Displays the error log\n"
						"`F12    : `Spys on the currently selected node\n"
						"`F11    : `Send message to the currently selected node\n"
						"`F10    : `Chats with the user on the currently selected node\n"
						"`DEL    : `Clear errors on currently selected node\n"
						"`CTRL-L : `Lock node toggle\n"
						"`CTRL-R : `Rerun node\n"
						"`CTRL-D : `Down node toggle\n"
						"`CTRL-I : `Interrupt node\n";
deuce's avatar
deuce committed
995

996
		drawstats(&cfg, main_dflt, &node, &main_dflt, &main_bar);
deuce's avatar
deuce committed
997

998
		j=uifc.list(WIN_L2R|WIN_ESC|WIN_ACT|WIN_DYN,0,5,70,&main_dflt,&main_bar
999
1000
			,title,mopt);

deuce's avatar
deuce committed
1001
1002
1003
		if(j == -2)
			continue;

1004
		if(j==-7) {	/* CTRL-E */
1005
			sprintf(str,"%s/error.log",cfg.data_dir);
1006
			view_log(str,"Error Log");
1007
1008
			continue;
		}
1009

1010
1011
1012
1013
		if(j==0) {
			/* System Options */
			i=0;
			strcpy(opt[i++],"Run SCFG");
1014
			strcpy(opt[i++],"Run User Editor");
1015
			strcpy(opt[i++],"Run SyncTERM");
1016
1017
1018
1019
			strcpy(opt[i++],"View logs");
			strcpy(opt[i++],"Force QWK Net callout");
			strcpy(opt[i++],"Run event");
			strcpy(opt[i++],"Recycle servers");
1020
			strcpy(opt[i++],"Edit CFG/INI files");
1021
1022
			strcpy(opt[i++],"Edit trashcan files");
			opt[i][0]=0;
1023
1024
1025
1026
			uifc.helpbuf=	"`System Options`\n"
			                "`------------`\n\n"
							"`Run SCFG              : `Run the Synchronet Configuration Utility.\n"
							"`Run User Editor       : `Call up the User Editor.\n"
deuce's avatar
deuce committed
1027
							"`Run SyncTERM          : `Run SyncTERM for RLogin.  SyncTERM must be\n"
1028
							"                        in the exec directory.\n"
1029
1030
1031
1032
1033
1034
1035
1036
							"`View logs             : `View the various system logs.\n"
							"`Force QWK Net callout : `Force a callout to QWK Net Hub.  Select which\n"
							"                        Hub from a popup list of configured Hubs.\n"
							"`Run Event             : `Call up a menu of system events that can be\n"
							"                        manually.\n"
							"`Recycle Servers       : `Have the Servers reload their configuration \n"
							"                        files.\n"
							"`Edit trashcan files   : `Edit the various .can files.  i.e.; ip.can";
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054

			done=0;
			i=0;
			while(!done) {
				switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0,"System Options",opt))  {
					case -1:
						done=1;
						break;
					case 0:
						sprintf(str,"%sscfg ",cfg.exec_dir);
						for(j=1; j<argc; j++) {
							strcat(str,"'");
							strcat(str,argv[j]);
							strcat(str,"' ");
						}
						do_cmd(str);
						break;
					case 1:
1055
						sprintf(str,"%suedit ",cfg.exec_dir);
1056
1057
1058
1059
1060
1061
						for(j=1; j<argc; j++) {
							strcat(str,"'");
							strcat(str,argv[j]);
							strcat(str,"' ");
						}
						do_cmd(str);
1062
1063
						break;
					case 2:
1064
1065
1066
1067
1068
1069
1070
						sprintf(str,"%ssyncterm",cfg.exec_dir);
						for(j=1; j<argc; j++) {
							strcat(str,"'");
							strcat(str,argv[j]);
							strcat(str,"' ");
						}
						do_cmd(str);
1071
1072
						break;
					case 3:
1073
						view_logs(&cfg);
1074
1075
						break;
					case 4:
1076
						qwk_callouts(&cfg);
1077
1078
						break;
					case 5:
1079
						run_events(&cfg);
1080
1081
						break;
					case 6:
1082
						recycle_servers(&cfg);
1083
1084
						break;
					case 7:
1085
1086
1087
						edit_cfg(&cfg);
						break;
					case 8:
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
						edit_can(&cfg);
						break;
				}
			}
			continue;
		}

		if(j==-1) {
			i=0;
			strcpy(opt[0],YesStr);
			strcpy(opt[1],NoStr);
			opt[2][0]=0;
			uifc.helpbuf=	"`Exit Synchronet UNIX Monitor:`\n"
							"\n"
							"\nIf you want to exit the Synchronet UNIX monitor utility,"
							"\nselect `Yes`. Otherwise, select `No` or hit ~ ESC ~.";
			i=uifc.list(WIN_MID,0,0,0,&i,0,"Exit Synchronet Monitor",opt);
			if(!i)
				bail(0);
			continue;
		}

		/* Everything after this point is invalid for the System Options */
		if(main_dflt==0)
			continue;

1114
		if(j==-2-CIO_KEY_DC) {	/* Clear errors */
1115
			clearerrors(&cfg, main_dflt,&node);
1116
1117
1118
			continue;
		}

1119
		if(j==-2-CIO_KEY_F(10)) {	/* Chat */
1120
			if(getnodedat(&cfg,main_dflt,&node,NULL)) {
1121
1122
1123
				uifc.msg("Error reading node data!");
				continue;
			}
1124
			if((node.status==NODE_INUSE) && node.useron)
1125
				chat(&cfg,main_dflt,&node,&boxch,NULL);
1126
1127
1128
			continue;
		}

1129
		if(j==-2-CIO_KEY_F(11)) {	/* Send message */
1130
			sendmessage(&cfg, main_dflt,&node);
1131
1132
			continue;
		}
1133

1134
		if(j==-2-CIO_KEY_F(12)) {	/* Spy */
1135
			dospy(main_dflt,&bbs_startup);
1136
1137
			continue;
		}
1138

1139
		if(j==-2-CTRL('l')) {	/* Lock node */
1140
			if(getnodedat(&cfg,main_dflt,&node,&nodefile)) {
1141
1142
1143
1144
				uifc.msg("Error reading node data!");
				continue;
			}
			node.misc^=NODE_LOCK;
1145
			putnodedat(&cfg,main_dflt,&node,nodefile);
1146
			continue;
deuce's avatar
deuce committed
1147
		}
1148

1149
		if(j==-2-CTRL('r')) {	/* Rerun node */
1150
			if(getnodedat(&cfg,main_dflt,&node,&nodefile)) {
1151
1152
1153
1154
				uifc.msg("Error reading node data!");
				continue;
			}
			node.misc^=NODE_RRUN;
1155
			putnodedat(&cfg,main_dflt,&node,nodefile);
1156
1157
			continue;
		}
1158

1159
		if(j==-2-CTRL('d')) {	/* Down node */
1160
			if(getnodedat(&cfg,main_dflt,&node,&nodefile)) {
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
				uifc.msg("Error reading node data!");
				continue;
			}
			if(node.status != NODE_WFC && node.status != NODE_OFFLINE)
				node.misc ^= NODE_DOWN;
			else {
				if(node.status!=NODE_OFFLINE)
					node.status=NODE_OFFLINE;
				else
					node.status=NODE_WFC;
			}
1172
			putnodedat(&cfg,main_dflt,&node,nodefile);
1173
1174
1175
1176
			continue;
		}

		if(j==-2-CTRL('i')) {	/* Interrupt node */
1177
			if(getnodedat(&cfg,main_dflt,&node,&nodefile)) {
1178
1179
1180
1181
				uifc.msg("Error reading node data!");
				continue;
			}
			node.misc^=NODE_INTR;
1182
			putnodedat(&cfg,main_dflt,&node,nodefile);
1183
1184
			continue;
		}
1185

1186
		if(j <= -2)
1187
1188
			continue;

1189
		if(j<=cfg.sys_nodes && j>0) {
1190
1191
1192
1193
1194
1195
		  if((node.status==NODE_INUSE) && node.useron) {
      		i=0;
   			strcpy(opt[i++],"Edit User");
   			strcpy(opt[i++],"Spy on node");
			strcpy(opt[i++],"Send message to user");
			strcpy(opt[i++],"Chat with user");
1196
1197
			strcpy(opt[i++],"Node toggles");
			strcpy(opt[i++],"Clear Errors");
1198
1199
			strcpy(opt[i++],"View node log");
			strcpy(opt[i++],"View crash log");