umonitor.c 15.2 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
128
129
130
		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);
		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","Re-run on logoff",node.misc&NODE_RRUN ? YesStr : NoStr);
131
		sprintf(opt[j++],"%-30s%3s","Down node after logoff",(node.misc&NODE_DOWN || (node.status==NODE_OFFLINE)) ? YesStr : NoStr);
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
		sprintf(opt[j++],"%-30s%3s","Reset private chat",node.misc&NODE_RPCHT ? YesStr : NoStr);
		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;

			case 2:	/* Page disabled */
				node.misc ^= NODE_POFF;
				break;

			case 3:	/* Activity alert */
				node.misc ^= NODE_AOFF;
				break;

			case 4:	/* Re-run */
				node.misc ^= NODE_RRUN;
				break;

			case 5:	/* 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
170
171
172
173
174
175
176
177
178
				break;

			case 6:	/* Reset chat */
				node.misc ^= NODE_RPCHT;
				break;
				
			case -1:
				save=1;
				break;
				
			default:
				uifc.msg("Option not implemented");
				continue;
		}
179
		putnodedat(cfg,nodenum,&node,nodefile);
deuce's avatar
deuce committed
180
	}
deuce's avatar
deuce committed
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
218
219
220
221
222
223
224
225
226
}

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

227
int sendmessage(scfg_t *cfg, int nodenum,node_t *node)  {
228
229
230
	char str[80],str2[80];

	uifc.input(WIN_MID,0,0,"Telegram",str2,58,K_WRAP|K_MSG);
231
	sprintf(str,"\1n\1y\1hMessage From Sysop:\1w %s\r\n",str2);
232
	if(getnodedat(cfg,nodenum,node,NULL))
233
234
235
		return(-1);
	if(node->useron==0)
		return(-1);
236
	putsmsg(cfg, node->useron, str);
237
238
239
	return(0);
}

240
241
242
int clearerrors(scfg_t *cfg, int nodenum, node_t *node) {
	int nodefile;
	if(getnodedat(cfg,nodenum,node,&nodefile)) {
243
244
245
246
		uifc.msg("getnodedat() failed! (Nothing done)");
		return(-1);
	}
	node->errors=0;
247
	putnodedat(cfg,nodenum,node,nodefile);
248
249
250
	return(0);
}

251
int main(int argc, char** argv)  {
252
253
254
255
256
	char**	opt;
	char**	mopt;
	int		main_dflt=0;
	int		main_bar=0;
	char revision[16];
257
	char str[256],ctrl_dir[41],*p;
258
	char title[256];
259
	int i,j;
260
	node_t node;
261
262
	char	*buf;
	int		buffile;
263
264
265
	int		nodefile;
	box_t	boxch;
	scfg_t	cfg;
266
267
268
269
270
271
272
/******************/
/* Ini file stuff */
/******************/
	char	host_name[128]="";
	char	ini_file[MAX_PATH+1];
	FILE*				fp;
	bbs_startup_t		bbs_startup;
273
274

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

276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
    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,"/");

291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
	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, 
311
		NULL, &bbs_startup, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
312
313
314
315
316
317
318
319

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

	chdir(bbs_startup.ctrl_dir);
	
	/* Read .cfg files here */
320
	cfg.size=sizeof(cfg);
321
322
323
324
325
	if(!read_main_cfg(&cfg, str)) {
		printf("ERROR! %s\n",str);
		exit(1);
	}

326
327
328
329
330
	if(!read_xtrn_cfg(&cfg, str)) {
		printf("ERROR! %s\n",str);
		exit(1);
	}

deuce's avatar
deuce committed
331
332
333
334
335
/*	if(!read_node_cfg(&cfg, str)) {
		printf("ERROR! %s\n",str);
		exit(1);
	} */

336
337
338
339
    memset(&uifc,0,sizeof(uifc));

	uifc.esc_delay=500;

deuce's avatar
deuce committed
340
341
342
343
344
345
346
347
	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;
348
349
350
351
352
353
354
355
356
357
358
359
360
361
	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':
362
					/* Set up ex-ascii codes */
deuce's avatar
deuce committed
363
364
365
366
367
368
369
370
					boxch.ls=186; 
					boxch.rs=186;
					boxch.ts=205;
					boxch.bs=205;
					boxch.tl=201;
					boxch.tr=187;
					boxch.bl=200;
					boxch.br=188;
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
					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);
           }
    }

386
387
	signal(SIGPIPE, SIG_IGN);   

388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
	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);

407
408
	sprintf(title,"Synchronet UNIX Monitor %s-%s",revision,PLATFORM_DESC);
	if(uifc.scrn(title)) {
409
410
411
412
413
		printf(" USCRN (len=%d) failed!\n",uifc.scrn_len+1);
		bail(1);
	}

	while(1) {
414
415
416
417
		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
418
				sprintf(mopt[i-1],"%3d: %s",i,nodestatus(&cfg,&node,str,71));
419
		}
deuce's avatar
deuce committed
420
		mopt[i-1][0]=0;
421
422

		uifc.helpbuf=	"`Synchronet Monitor:`\n"
deuce's avatar
deuce committed
423
						"\nCTRL-E displays the error log"
424
425
						"\nF12 spys on the currently selected node"
						"\nF11 send message to the currently selected node"
426
						"\nF10 Chats with the user on the currently selected node"
427
428
429
430
431
432
						"\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)";
433
						
434
		j=uifc.list(WIN_ORG|WIN_MID|WIN_ESC|WIN_ACT|WIN_DYN,0,0,70,&main_dflt,&main_bar
435
436
437
			,title,mopt);

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

		if(j==-2-KEY_F(10)) {	/* Chat */
468
469
470
471
			if(getnodedat(&cfg,main_dflt+1,&node,NULL)) {
				uifc.msg("Error reading node data!");
				continue;
			}
472
			if((node.status==NODE_INUSE) && node.useron)
473
				chat(&cfg,main_dflt+1,&node,&boxch,uifc.timedisplay);
474
475
476
477
			continue;
		}

		if(j==-2-KEY_F(11)) {	/* Send message */
478
			sendmessage(&cfg, main_dflt+1,&node);
479
480
481
482
			continue;
		}
		
		if(j==-2-KEY_F(12)) {	/* Spy */
deuce's avatar
deuce committed
483
			dospy(main_dflt+1,&bbs_startup);
484
485
486
487
488
489
490
491
492
493
494
			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
495
496
		}
		
497
498
499
500
501
502
503
504
505
		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;
		}
506

507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
		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;
		}
		
534
		if(j <= -2)
535
536
			continue;

deuce's avatar
deuce committed
537
		if(j==-1) {
538
			i=0;
539
540
			strcpy(opt[0],YesStr);
			strcpy(opt[1],NoStr);
541
542
543
544
545
			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
546
			i=uifc.list(WIN_MID,0,0,0,&i,0,"Exit Synchronet Monitor",opt);
547
548
549
550
			if(!i)
				bail(0);
			continue;
		}
551
		if(j<cfg.sys_nodes && j>=0) {
552
553
554
555
			i=0;
			strcpy(opt[i++],"Spy on node");
			strcpy(opt[i++],"Node toggles");
			strcpy(opt[i++],"Clear Errors");
556
557
558
559
560
			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
561
			}
562
563
564
565
			opt[i][0]=0;
			i=0;
			uifc.helpbuf=	"`Node Options:`\n"
							"\nToDo: Add help";
566
			switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0,"Node Options",opt))  {
567
				case 0:	/* Spy */
deuce's avatar
deuce committed
568
					dospy(j+1,&bbs_startup);
569
570
571
					break;

				case 1: /* Node Toggles */
572
					node_toggles(&cfg, j+1);
573
574
575
					break;

				case 2:
576
					clearerrors(&cfg, j+1,&node);
577
578
					break;

deuce's avatar
deuce committed
579
				case 3:	/* Send message */
580
					sendmessage(&cfg, j+1,&node);
deuce's avatar
deuce committed
581
582
					break;

deuce's avatar
deuce committed
583
				case 4:
584
					chat(&cfg,main_dflt+1,&node,&boxch,uifc.timedisplay);
deuce's avatar
deuce committed
585
586
					break;
				
587
588
589
590
591
592
593
				case -1:
					break;
					
				default:
					uifc.msg("Option not implemented");
					break;
			}
594
595
		}
	}
596
}