umonitor.c 15.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
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
37
/* 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)		*
 *																			*
 * Copyright 2003 Rob Swindell - http://www.synchro.net/copyright.html		*
 *																			*
 * 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 "sbbs.h"
39
40
#include "conwrap.h"	/* this has to go BEFORE curses.h so getkey() can be macroed around */
#include <curses.h>
41
#include <signal.h>
deuce's avatar
deuce committed
42
43
44
45
46
#include <sys/types.h>
#include <sys/time.h>
#ifdef __QNX__
#include <string.h>
#endif
47
#include <stdio.h>
48
#include <unistd.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
68

/********************/
/* Global Variables */
/********************/
uifcapi_t uifc; /* User Interface (UIFC) Library API */
char tmp[256];
69
70
const char *YesStr="Yes";
const char *NoStr="No";
deuce's avatar
deuce committed
71
box_t boxch;
72
73
74
75
76
77
78
79
80
81
82
83
84
85

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

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

    exit(code);
}

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

104
105
void node_toggles(scfg_t *cfg,int nodenum)  {
	int nodefile;
106
107
108
109
110
111
112
113
114
115
116
117
118
	char**	opt;
	int		i,j;
	node_t	node;
	int		save=0;

	if((opt=(char **)MALLOC(sizeof(char *)*(MAX_OPTS+1)))==NULL)
		allocfail(sizeof(char *)*(MAX_OPTS+1));
	for(i=0;i<(MAX_OPTS+1);i++)
		if((opt[i]=(char *)MALLOC(MAX_OPLN))==NULL)
			allocfail(MAX_OPLN);

	i=0;
	uifc.helpbuf=	"`Node Toggles:`\n"
119
					"\nToDo: Add help (Mention that changes take effect immediately)";
120
	while(save==0) {
121
		if(getnodedat(cfg,nodenum,&node,&nodefile)) {
122
123
124
			uifc.msg("Error reading node data!");
			break;
		}
125
126
127
		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
128
129
130
131
		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);
#if 0	/* There's no reason these should be toggled by the sysop under normal circumstances */
132
133
134
		sprintf(opt[j++],"%-30s%3s","Page disabled",node.misc&NODE_POFF ? YesStr : NoStr);
		sprintf(opt[j++],"%-30s%3s","Activity alert disabled",node.misc&NODE_AOFF ? YesStr : NoStr);
		sprintf(opt[j++],"%-30s%3s","Reset private chat",node.misc&NODE_RPCHT ? YesStr : NoStr);
rswindell's avatar
rswindell committed
135
#endif
136
137
138
139
140
141
142
143
144
145
146
		opt[j][0]=0;

		switch(uifc.list(WIN_MID,0,0,0,&i,0,"Node Toggles",opt)) {
			case 0:	/* Locked */
				node.misc ^= NODE_LOCK;
				break;

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

rswindell's avatar
rswindell committed
147
			case 2:	/* Re-run */
148
149
150
				node.misc ^= NODE_RRUN;
				break;

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

			case -1:
				save=1;
				break;
				
			default:
				uifc.msg("Option not implemented");
				continue;
		}
170
		putnodedat(cfg,nodenum,&node,nodefile);
deuce's avatar
deuce committed
171
	}
deuce's avatar
deuce committed
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
}

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);
	endwin();
	i=spyon(str);
	refresh();
	switch(i) {
		case SPY_NOSOCKET:
			uifc.msg("Could not create socket");
			return(-1);
					
		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);
							
		case SPY_STDINLOST:
			uifc.msg("STDIN has gone away... you probably can't close this window.  :-)");
			return(-1);
							
		case SPY_CLOSED:
			break;
			
		default:
			sprintf(str,"Unknown return code %d",i);
			uifc.msg(str);
			return(-1);
	}
	return(0);
}

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

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

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

242
int main(int argc, char** argv)  {
243
244
245
246
247
	char**	opt;
	char**	mopt;
	int		main_dflt=0;
	int		main_bar=0;
	char revision[16];
248
	char str[256],ctrl_dir[41],*p;
249
	char title[256];
250
	int i,j;
251
	node_t node;
252
253
	char	*buf;
	int		buffile;
254
255
256
	int		nodefile;
	box_t	boxch;
	scfg_t	cfg;
257
258
259
260
261
262
263
/******************/
/* Ini file stuff */
/******************/
	char	host_name[128]="";
	char	ini_file[MAX_PATH+1];
	FILE*				fp;
	bbs_startup_t		bbs_startup;
264
265

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

267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
    printf("\nSynchronet UNIX Monitor %s-%s  Copyright 2003 "
        "Rob Swindell\n",revision,PLATFORM_DESC);

	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,"/");

282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
	gethostname(host_name,sizeof(host_name)-1);
	sprintf(ini_file,"%s%c%s.ini",ctrl_dir,BACKSLASH,host_name);
#if defined(PREFIX)
	if(!fexistcase(ini_file))
		sprintf(ini_file,"%s/etc/sbbs.ini",PREFIX);
#endif
	if(!fexistcase(ini_file))
		sprintf(ini_file,"%s%csbbs.ini",ctrl_dir,BACKSLASH);

	/* 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 */
	sbbs_read_ini(fp, 
302
		NULL, &bbs_startup, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
303
304
305
306
307
308
309
310

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

	chdir(bbs_startup.ctrl_dir);
	
	/* Read .cfg files here */
311
	cfg.size=sizeof(cfg);
312
313
314
315
316
	if(!read_main_cfg(&cfg, str)) {
		printf("ERROR! %s\n",str);
		exit(1);
	}

317
318
319
320
321
	if(!read_xtrn_cfg(&cfg, str)) {
		printf("ERROR! %s\n",str);
		exit(1);
	}

deuce's avatar
deuce committed
322
323
324
325
326
/*	if(!read_node_cfg(&cfg, str)) {
		printf("ERROR! %s\n",str);
		exit(1);
	} */

327
328
329
330
    memset(&uifc,0,sizeof(uifc));

	uifc.esc_delay=500;

deuce's avatar
deuce committed
331
332
333
334
335
336
337
338
	boxch.ls=ACS_VLINE; 
	boxch.rs=ACS_VLINE;
	boxch.ts=ACS_HLINE;
	boxch.bs=ACS_HLINE;
	boxch.tl=ACS_ULCORNER;
	boxch.tr=ACS_URCORNER;
	boxch.bl=ACS_LLCORNER;
	boxch.br=ACS_LRCORNER;
339
340
341
342
343
344
345
346
347
348
349
350
351
352
	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':
353
					/* Set up ex-ascii codes */
deuce's avatar
deuce committed
354
355
356
357
358
359
360
361
					boxch.ls=186; 
					boxch.rs=186;
					boxch.ts=205;
					boxch.bs=205;
					boxch.tl=201;
					boxch.tr=187;
					boxch.bl=200;
					boxch.br=188;
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
					uifc.mode|=UIFC_IBM;
					break;
                default:
                    printf("\nusage: %s [ctrl_dir] [options]"
                        "\n\noptions:\n\n"
                        "-c  =  force color mode\n"
                        "-e# =  set escape delay to #msec\n"
						"-i  =  force IBM charset\n"
                        "-l# =  set screen lines to #\n"
						,argv[0]
                        );
        			exit(0);
           }
    }

377
378
	signal(SIGPIPE, SIG_IGN);   

379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
	uifc.size=sizeof(uifc);
	i=uifcinic(&uifc);  /* curses */
	if(i!=0) {
		printf("uifc library init returned error %d\n",i);
		exit(1);
	}

	if((opt=(char **)MALLOC(sizeof(char *)*(MAX_OPTS+1)))==NULL)
		allocfail(sizeof(char *)*(MAX_OPTS+1));
	for(i=0;i<(MAX_OPTS+1);i++)
		if((opt[i]=(char *)MALLOC(MAX_OPLN))==NULL)
			allocfail(MAX_OPLN);

	if((mopt=(char **)MALLOC(sizeof(char *)*MAX_OPTS))==NULL)
		allocfail(sizeof(char *)*MAX_OPTS);
	for(i=0;i<MAX_OPTS;i++)
		if((mopt[i]=(char *)MALLOC(MAX_OPLN))==NULL)
			allocfail(MAX_OPLN);

398
399
	sprintf(title,"Synchronet UNIX Monitor %s-%s",revision,PLATFORM_DESC);
	if(uifc.scrn(title)) {
400
401
402
403
404
		printf(" USCRN (len=%d) failed!\n",uifc.scrn_len+1);
		bail(1);
	}

	while(1) {
405
406
407
408
		for(i=1;i<=cfg.sys_nodes;i++) {
			if((j=getnodedat(&cfg,i,&node,NULL)))
				sprintf(mopt[i-1],"Error reading node data (%d)!",j);
			else
409
				sprintf(mopt[i-1],"%3d: %s",i,nodestatus(&cfg,&node,str,71));
410
		}
deuce's avatar
deuce committed
411
		mopt[i-1][0]=0;
412
413

		uifc.helpbuf=	"`Synchronet Monitor:`\n"
deuce's avatar
deuce committed
414
						"\nCTRL-E displays the error log"
415
416
						"\nF12 spys on the currently selected node"
						"\nF11 send message to the currently selected node"
417
						"\nF10 Chats with the user on the currently selected node"
418
419
420
421
422
423
						"\nDEL Clear errors on currently selected node"
						"\nCTRL-L Lock node toggle"
						"\nCTRL-R Rerun node"
						"\nCTRL-D Down node toggle"
						"\nCTRL-I Interrupt node"
						"\nToDo: Add more help. (Explain what you're looking at)";
424
						
425
		j=uifc.list(WIN_ORG|WIN_MID|WIN_ESC|WIN_ACT|WIN_DYN,0,0,70,&main_dflt,&main_bar
426
427
428
			,title,mopt);

		if(j==-7) {	/* CTRL-E */
429
			sprintf(str,"%s/error.log",cfg.data_dir);
430
			if(fexist(str)) {
deuce's avatar
deuce committed
431
				if((buffile=sopen(str,O_RDONLY,SH_DENYWR))>=0) {
432
433
434
435
436
					j=filelength(buffile);
					if((buf=(char *)MALLOC(j+1))!=NULL) {
						read(buffile,buf,j);
						close(buffile);
						*(buf+j)=0;
437
						uifc.showbuf(buf,"Error Log",0);
438
439
440
441
						free(buf);
						continue;
					}
					close(buffile);
deuce's avatar
deuce committed
442
					uifc.msg("Error allocating memory for the error log");
443
444
					continue;
				}
deuce's avatar
deuce committed
445
				uifc.msg("Error opening error log");
446
447
448
449
450
451
			}
			else {
				uifc.msg("Error log does not exist");
			}
			continue;
		}
deuce's avatar
deuce committed
452
		
453
		if(j==-2-KEY_DC) {	/* Clear errors */
454
			clearerrors(&cfg, main_dflt+1,&node);
455
456
457
458
			continue;
		}

		if(j==-2-KEY_F(10)) {	/* Chat */
459
460
461
462
			if(getnodedat(&cfg,main_dflt+1,&node,NULL)) {
				uifc.msg("Error reading node data!");
				continue;
			}
463
			if((node.status==NODE_INUSE) && node.useron)
464
				chat(&cfg,main_dflt+1,&node,&boxch,uifc.timedisplay);
465
466
467
468
			continue;
		}

		if(j==-2-KEY_F(11)) {	/* Send message */
469
			sendmessage(&cfg, main_dflt+1,&node);
470
471
472
473
			continue;
		}
		
		if(j==-2-KEY_F(12)) {	/* Spy */
deuce's avatar
deuce committed
474
			dospy(main_dflt+1,&bbs_startup);
475
476
477
478
479
480
481
482
483
484
485
			continue;
		}
		
		if(j==-2-CTRL('l')) {	/* Lock node */
			if(getnodedat(&cfg,main_dflt+1,&node,&nodefile)) {
				uifc.msg("Error reading node data!");
				continue;
			}
			node.misc^=NODE_LOCK;
			putnodedat(&cfg,main_dflt+1,&node,nodefile);
			continue;
deuce's avatar
deuce committed
486
487
		}
		
488
489
490
491
492
493
494
495
496
		if(j==-2-CTRL('r')) {	/* Rerun node */
			if(getnodedat(&cfg,main_dflt+1,&node,&nodefile)) {
				uifc.msg("Error reading node data!");
				continue;
			}
			node.misc^=NODE_RRUN;
			putnodedat(&cfg,main_dflt+1,&node,nodefile);
			continue;
		}
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
		if(j==-2-CTRL('d')) {	/* Down node */
			if(getnodedat(&cfg,main_dflt+1,&node,&nodefile)) {
				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;
			}
			putnodedat(&cfg,main_dflt+1,&node,nodefile);
			continue;
		}

		if(j==-2-CTRL('i')) {	/* Interrupt node */
			if(getnodedat(&cfg,main_dflt+1,&node,&nodefile)) {
				uifc.msg("Error reading node data!");
				continue;
			}
			node.misc^=NODE_INTR;
			putnodedat(&cfg,main_dflt+1,&node,nodefile);
			continue;
		}
		
525
		if(j <= -2)
526
527
			continue;

deuce's avatar
deuce committed
528
		if(j==-1) {
529
			i=0;
530
531
			strcpy(opt[0],YesStr);
			strcpy(opt[1],NoStr);
532
533
534
535
536
			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 ~.";
deuce's avatar
deuce committed
537
			i=uifc.list(WIN_MID,0,0,0,&i,0,"Exit Synchronet Monitor",opt);
538
539
540
541
			if(!i)
				bail(0);
			continue;
		}
542
		if(j<cfg.sys_nodes && j>=0) {
543
544
545
546
			i=0;
			strcpy(opt[i++],"Spy on node");
			strcpy(opt[i++],"Node toggles");
			strcpy(opt[i++],"Clear Errors");
547
548
549
550
551
			if(!getnodedat(&cfg,j+1,&node,NULL)) {
				if((node.status==NODE_INUSE) && node.useron) {
					strcpy(opt[i++],"Send message to user");
					strcpy(opt[i++],"Chat with user");
				}
deuce's avatar
deuce committed
552
			}
553
554
555
556
			opt[i][0]=0;
			i=0;
			uifc.helpbuf=	"`Node Options:`\n"
							"\nToDo: Add help";
557
			switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0,"Node Options",opt))  {
558
				case 0:	/* Spy */
deuce's avatar
deuce committed
559
					dospy(j+1,&bbs_startup);
560
561
562
					break;

				case 1: /* Node Toggles */
563
					node_toggles(&cfg, j+1);
564
565
566
					break;

				case 2:
567
					clearerrors(&cfg, j+1,&node);
568
569
					break;

deuce's avatar
deuce committed
570
				case 3:	/* Send message */
571
					sendmessage(&cfg, j+1,&node);
deuce's avatar
deuce committed
572
573
					break;

deuce's avatar
deuce committed
574
				case 4:
575
					chat(&cfg,main_dflt+1,&node,&boxch,uifc.timedisplay);
deuce's avatar
deuce committed
576
577
					break;
				
578
579
580
581
582
583
584
				case -1:
					break;
					
				default:
					uifc.msg("Option not implemented");
					break;
			}
585
586
		}
	}
587
}