atcodes.cpp 45.3 KB
Newer Older
1
/* Synchronet "@code" functions */
2
// vi: tabstop=4
3
4
5
6
7
8
9

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
10
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 *																			*
 * 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.	*
 ****************************************************************************/

#include "sbbs.h"
#include "cmdshell.h"
39
40
#include "utf8.h"
#include "unicode.h"
41
#include "cp437defs.h"
42

43
44
45
46
47
48
49
#if defined(_WINSOCKAPI_)
	extern WSADATA WSAData;
	#define SOCKLIB_DESC WSAData.szDescription
#else
	#define	SOCKLIB_DESC NULL
#endif

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
static char* separate_thousands(const char* src, char *dest, size_t maxlen, char sep)
{
	if(strlen(src) * 1.3 > maxlen)
		return (char*)src;
	const char* tail = src;
	while(*tail && isdigit(*tail))
		tail++;
	if(tail == src)
		return (char*)src;
	size_t digits = tail - src;
	char* d = dest;
	for(size_t i = 0; i < digits; d++, i++) {
		*d = src[i];
		if(i && i + 3 < digits && (digits - (i + 1)) % 3 == 0)
			*(++d) = sep;
	}
	*d = 0;
	strcpy(d, tail);
	return dest;
}

71
72
73
/****************************************************************************/
/* Returns 0 if invalid @ code. Returns length of @ code if valid.          */
/****************************************************************************/
74
int sbbs_t::show_atcode(const char *instr)
75
{
76
	char	str[128],str2[128],*tp,*sp,*p;
77
    int     len;
78
	int		disp_len;
79
80
	bool	padded_left=false;
	bool	padded_right=false;
81
	bool	centered=false;
82
	bool	zero_padded=false;
rswindell's avatar
rswindell committed
83
	bool	truncated = true;
rswindell's avatar
rswindell committed
84
	bool	doubled = false;
85
	bool	thousep = false;	// thousands-separated
86
	long	pmode = 0;
87
	const char *cp;
88

89
	SAFECOPY(str,instr);
90
91
92
	tp=strchr(str+1,'@');
	if(!tp)                 /* no terminating @ */
		return(0);
93
	sp=strchr(str+1,' ');
94
95
96
97
98
99
	if(sp && sp<tp)         /* space before terminating @ */
		return(0);
	len=(tp-str)+1;
	(*tp)=0;
	sp=(str+1);

100
	disp_len=len;
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
	if((p = strchr(sp, '|')) != NULL) {
		if(strchr(p, 'T') != NULL)
			thousep = true;
		if(strchr(p, 'L') != NULL)
			padded_left = true;
		else if(strchr(p, 'R') != NULL)
			padded_right = true;
		else if(strchr(p, 'C') != NULL)
			centered = true;
		else if(strchr(p, 'W') != NULL)
			doubled = true;
		else if(strchr(p, 'Z') != NULL)
			zero_padded = true;
		else if(strchr(p, '>') != NULL)
			truncated = false;
	}
	else if(strchr(sp, ':') != NULL)
118
119
		p = NULL;
	else if((p=strstr(sp,"-L"))!=NULL)
120
121
122
		padded_left=true;
	else if((p=strstr(sp,"-R"))!=NULL)
		padded_right=true;
123
124
	else if((p=strstr(sp,"-C"))!=NULL)
		centered=true;
rswindell's avatar
rswindell committed
125
	else if((p=strstr(sp,"-W"))!=NULL)	/* wide */
rswindell's avatar
rswindell committed
126
		doubled=true;
127
128
	else if((p=strstr(sp,"-Z"))!=NULL)
		zero_padded=true;
129
130
	else if((p=strstr(sp,"-T"))!=NULL)
		thousep=true;
rswindell's avatar
rswindell committed
131
	else if((p=strstr(sp,"->"))!=NULL)	/* wrap */
rswindell's avatar
rswindell committed
132
		truncated = false;
133
	if(p!=NULL) {
134
		char* lp = p;
135
		while(*lp && !isdigit((uchar)*lp))
136
			lp++;
137
		if(*lp && isdigit((uchar)*lp))
rswindell's avatar
rswindell committed
138
			disp_len=atoi(lp);
139
		*p=0;
140
	}
141

142
	cp = atcode(sp, str2, sizeof(str2), &pmode);
143
	if(cp==NULL)
144
145
		return(0);

146
147
148
149
	char separated[128];
	if(thousep)
		cp = separate_thousands(cp, separated, sizeof(separated), ',');

rswindell's avatar
rswindell committed
150
151
152
153
154
155
156
157
158
159
160
	if(p==NULL || truncated == false)
		disp_len = strlen(cp);

	if(truncated) {
		if(column + disp_len > cols - 1) {
			if(column >= cols - 1)
				disp_len = 0;
			else
				disp_len = (cols - 1) - column;
		}
	}
161
162
163
164
165
166
	if(pmode & P_UTF8) {
		if(term_supports(UTF8))
			disp_len += strlen(cp) - utf8_str_total_width(cp);
		else
			disp_len += strlen(cp) - utf8_str_count_width(cp, /* min: */1, /* max: */2);
	}
167
	if(padded_left)
168
		bprintf(pmode, "%-*.*s",disp_len,disp_len,cp);
169
	else if(padded_right)
170
		bprintf(pmode, "%*.*s",disp_len,disp_len,cp);
171
	else if(centered) {
rswindell's avatar
rswindell committed
172
		int vlen = strlen(cp);
173
174
		if(vlen < disp_len) {
			int left = (disp_len - vlen) / 2;
175
			bprintf(pmode, "%*s%-*s", left, "", disp_len - left, cp);
176
		} else
177
			bprintf(pmode, "%.*s", disp_len, cp);
rswindell's avatar
rswindell committed
178
179
	} else if(doubled) {
		wide(cp);
180
	} else if(zero_padded) {
181
182
		int vlen = strlen(cp);
		if(vlen < disp_len)
183
			bprintf(pmode, "%-.*s%s", (int)(disp_len - strlen(cp)), "0000000000", cp);
184
		else
185
			bprintf(pmode, "%.*s", disp_len, cp);
186
	} else
187
		bprintf(pmode, "%.*s", disp_len, cp);
188
189
190
191

	return(len);
}

rswindell's avatar
rswindell committed
192
193
194
195
196
197
198
199
200
static const char* getpath(scfg_t* cfg, const char* path)
{
	for(int i = 0; i < cfg->total_dirs; i++) {
		if(stricmp(cfg->dir[i]->code, path) == 0)
			return cfg->dir[i]->path;
	}
	return path;
}

201
const char* sbbs_t::atcode(char* sp, char* str, size_t maxlen, long* pmode)
202
{
203
	char*	tp = NULL;
204
	uint	i;
205
206
	uint	ugrp;
	uint	usub;
207
208
209
210
211
212
213
	long	l;
    stats_t stats;
    node_t  node;
	struct	tm tm;

	str[0]=0;

214
215
	if(strncmp(sp, "U+", 2) == 0) {	// UNICODE
		enum unicode_codepoint codepoint = (enum unicode_codepoint)strtoul(sp + 2, &tp, 16);
rswindell's avatar
rswindell committed
216
		if(tp == NULL || *tp == 0)
217
			outchar(codepoint, unicode_to_cp437(codepoint));
rswindell's avatar
rswindell committed
218
219
		else if(*tp == ':')
			outchar(codepoint, tp + 1);
220
221
		else {
			char fallback = (char)strtoul(tp + 1, NULL, 16);
rswindell's avatar
rswindell committed
222
			if(*tp == ',')
223
224
225
226
227
228
229
230
231
232
233
234
				outchar(codepoint, fallback);
			else if(*tp == '!') {
				char ch = unicode_to_cp437(codepoint);
				if(ch != 0)
					fallback = ch;
				outchar(codepoint, fallback);
			}
			else return NULL; // Invalid @-code
		}
		return nulstr;
	}

235
236
237
238
239
	if(strcmp(sp, "CHECKMARK") == 0) {
		outchar(UNICODE_CHECK_MARK, CP437_CHECK_MARK);
		return nulstr;
	}

rswindell's avatar
rswindell committed
240
241
242
243
	if(strcmp(sp, "ELLIPSIS") == 0) {
		outchar(UNICODE_HORIZONTAL_ELLIPSIS, "...");
		return nulstr;
	}
244
	if(strcmp(sp, "COPY") == 0) {
rswindell's avatar
rswindell committed
245
246
247
248
249
250
251
		outchar(UNICODE_COPYRIGHT_SIGN, "(C)");
		return nulstr;
	}
	if(strcmp(sp, "SOUNDCOPY") == 0) {
		outchar(UNICODE_SOUND_RECORDING_COPYRIGHT, "(P)");
		return nulstr;
	}
rswindell's avatar
rswindell committed
252
253
254
255
	if(strcmp(sp, "REGISTERED") == 0) {
		outchar(UNICODE_REGISTERED_SIGN, "(R)");
		return nulstr;
	}
rswindell's avatar
rswindell committed
256
257
258
259
260
	if(strcmp(sp, "TRADEMARK") == 0) {
		outchar(UNICODE_TRADE_MARK_SIGN, "(TM)");
		return nulstr;
	}
	if(strcmp(sp, "DEGREE_C") == 0) {
rswindell's avatar
rswindell committed
261
		outchar(UNICODE_DEGREE_CELSIUS, "\xF8""C");
rswindell's avatar
rswindell committed
262
263
264
		return nulstr;
	}
	if(strcmp(sp, "DEGREE_F") == 0) {
rswindell's avatar
rswindell committed
265
		outchar(UNICODE_DEGREE_FAHRENHEIT, "\xF8""F");
rswindell's avatar
rswindell committed
266
267
268
		return nulstr;
	}

rswindell's avatar
rswindell committed
269
270
271
272
273
	if(strncmp(sp, "WIDE:", 5) == 0) {
		wide(sp + 5);
		return(nulstr);
	}

274
	if(!strcmp(sp,"VER"))
275
		return(VERSION);
276

277
	if(!strcmp(sp,"REV")) {
278
		safe_snprintf(str,maxlen,"%c",REVISION);
279
280
		return(str);
	}
281

282
	if(!strcmp(sp,"FULL_VER")) {
283
		safe_snprintf(str,maxlen,"%s%c%s",VERSION,REVISION,beta_version);
284
		truncsp(str);
285
#if defined(_DEBUG)
286
		strcat(str," Debug");
287
#endif
288
		return(str);
289
290
	}

291
	if(!strcmp(sp,"VER_NOTICE"))
292
		return(VERSION_NOTICE);
293

294
295
	if(!strcmp(sp,"OS_VER"))
		return(os_version(str));
296
297

#ifdef JAVASCRIPT
298
299
	if(!strcmp(sp,"JS_VER"))
		return((char *)JS_GetImplementationVersion());
300
301
#endif

302
303
	if(!strcmp(sp,"PLATFORM"))
		return(PLATFORM_DESC);
304

305
306
	if(!strcmp(sp,"COPYRIGHT"))
		return(COPYRIGHT_NOTICE);
307

308
	if(!strcmp(sp,"COMPILER")) {
309
310
311
		char compiler[32];
		DESCRIBE_COMPILER(compiler);
		strncpy(str, compiler, maxlen);
312
		return(str);
313
314
	}

315
	if(!strcmp(sp,"UPTIME")) {
316
		extern volatile time_t uptime;
317
318
319
320
		time_t up=0;
		now = time(NULL);
		if (uptime != 0 && now >= uptime)
			up = now-uptime;
321
322
		char   days[64]="";
		if((up/(24*60*60))>=2) {
323
	        sprintf(days,"%lu days ",(ulong)(up/(24L*60L*60L)));
324
325
			up%=(24*60*60);
		}
326
		safe_snprintf(str,maxlen,"%s%lu:%02lu"
327
	        ,days
328
329
			,(ulong)(up/(60L*60L))
			,(ulong)((up/60L)%60L)
330
			);
331
		return(str);
332
333
	}

334
	if(!strcmp(sp,"SERVED")) {
335
		extern volatile ulong served;
336
		safe_snprintf(str,maxlen,"%lu",served);
337
338
339
		return(str);
	}

340
	if(!strcmp(sp,"SOCKET_LIB"))
341
		return(socklib_version(str,SOCKLIB_DESC));
342

343
	if(!strcmp(sp,"MSG_LIB")) {
344
		safe_snprintf(str,maxlen,"SMBLIB %s",smb_lib_ver());
345
346
		return(str);
	}
347

348
349
	if(!strcmp(sp,"BBS") || !strcmp(sp,"BOARDNAME"))
		return(cfg.sys_name);
350

351
	if(!strcmp(sp,"BAUD") || !strcmp(sp,"BPS")) {
352
		safe_snprintf(str,maxlen,"%lu",cur_output_rate ? cur_output_rate : cur_rate);
353
354
		return(str);
	}
355

rswindell's avatar
rswindell committed
356
357
358
359
360
361
362
363
	if(!strcmp(sp,"COLS")) {
		safe_snprintf(str,maxlen,"%lu",cols);
		return(str);
	}
	if(!strcmp(sp,"ROWS")) {
		safe_snprintf(str,maxlen,"%lu",rows);
		return(str);
	}
364
365
366
367
368
	if(strcmp(sp,"TERM") == 0)
		return term_type();

	if(strcmp(sp,"CHARSET") == 0)
		return term_charset();
rswindell's avatar
rswindell committed
369

370
371
	if(!strcmp(sp,"CONN"))
		return(connection);
372

373
374
	if(!strcmp(sp,"SYSOP"))
		return(cfg.sys_op);
375

376
377
	if(!strcmp(sp,"LOCATION"))
		return(cfg.sys_location);
378

379
	if(strcmp(sp,"NODE") == 0 || strcmp(sp,"NN") == 0) {
380
		safe_snprintf(str,maxlen,"%u",cfg.node_num);
381
382
		return(str);
	}
383
	if(strcmp(sp, "TNODES") == 0 || strcmp(sp, "TNODE") == 0 || strcmp(sp, "TN") == 0) {
384
		safe_snprintf(str,maxlen,"%u",cfg.sys_nodes);
385
386
		return(str);
	}
387
388
389
390
391
392
393
394
	if(strcmp(sp, "ANODES") == 0 || strcmp(sp, "ANODE") == 0 || strcmp(sp, "AN") == 0) {
		safe_snprintf(str, maxlen, "%u", count_nodes(/* self: */true));
		return str;
	}
	if(strcmp(sp, "ONODES") == 0 || strcmp(sp, "ONODE") == 0 || strcmp(sp, "ON") == 0) {
		safe_snprintf(str, maxlen, "%u", count_nodes(/* self: */false));
		return str;
	}
395

rswindell's avatar
rswindell committed
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
	if(strcmp(sp, "PWDAYS") == 0) {
		if(cfg.sys_pwdays) {
			safe_snprintf(str, maxlen, "%u", cfg.sys_pwdays);
			return str;
		}
		return text[Unlimited];
	}

	if(strcmp(sp, "AUTODEL") == 0) {
		if(cfg.sys_autodel) {
			safe_snprintf(str, maxlen, "%u", cfg.sys_autodel);
			return str;
		}
		return text[Unlimited];
	}

412
413
414
415
416
417
	if(strcmp(sp, "PAGER") == 0)
		return (thisnode.misc&NODE_POFF) ? text[Off] : text[On];

	if(strcmp(sp, "ALERTS") == 0)
		return (thisnode.misc&NODE_AOFF) ? text[Off] : text[On];

418
419
420
	if(strcmp(sp, "SPLITP") == 0)
		return (useron.chat&CHAT_SPLITP) ? text[On] : text[Off];

421
422
	if(!strcmp(sp,"INETADDR"))
		return(cfg.sys_inetaddr);
423

424
425
426
	if(!strcmp(sp,"HOSTNAME"))
		return(startup->host_name);

427
	if(!strcmp(sp,"FIDOADDR")) {
428
		if(cfg.total_faddrs)
429
			return(smb_faddrtoa(&cfg.faddr[0],str));
430
		return(nulstr);
431
432
	}

433
	if(!strcmp(sp,"EMAILADDR"))
434
		return(usermailaddr(&cfg, str
435
			,cfg.inetmail_misc&NMAIL_ALIAS ? useron.alias : useron.name));
436

437
438
	if(!strcmp(sp,"QWKID"))
		return(cfg.sys_id);
439

440
	if(!strcmp(sp,"TIME") || !strcmp(sp,"SYSTIME")) {
441
		now=time(NULL);
442
		memset(&tm,0,sizeof(tm));
443
		localtime_r(&now,&tm);
444
		if(cfg.sys_misc&SM_MILITARY)
445
446
			safe_snprintf(str,maxlen,"%02d:%02d:%02d"
		        	,tm.tm_hour,tm.tm_min,tm.tm_sec);
447
		else
448
			safe_snprintf(str,maxlen,"%02d:%02d %s"
449
450
451
				,tm.tm_hour==0 ? 12
				: tm.tm_hour>12 ? tm.tm_hour-12
				: tm.tm_hour, tm.tm_min, tm.tm_hour>11 ? "pm":"am");
452
		return(str);
453
454
	}

rswindell's avatar
rswindell committed
455
456
457
	if(!strcmp(sp,"TIMEZONE"))
		return(smb_zonestr(sys_timezone(&cfg),str));

458
	if(!strcmp(sp,"DATE") || !strcmp(sp,"SYSDATE")) {
459
		return(unixtodstr(&cfg,time32(NULL),str));
460
	}
461

rswindell's avatar
rswindell committed
462
463
464
	if(!strcmp(sp,"DATETIME"))
		return(timestr(time(NULL)));

rswindell's avatar
rswindell committed
465
466
467
468
469
	if(!strcmp(sp,"DATETIMEZONE")) {
		char zone[32];
		safe_snprintf(str, maxlen, "%s %s", timestr(time(NULL)), smb_zonestr(sys_timezone(&cfg),zone));
		return str;
	}
470
471
472
473
	
	if(strcmp(sp, "DATEFMT") == 0) {
		return cfg.sys_misc&SM_EURODATE ? "DD/MM/YY" : "MM/DD/YY";
	}
rswindell's avatar
rswindell committed
474

475
	if(!strcmp(sp,"TMSG")) {
476
477
		l=0;
		for(i=0;i<cfg.total_subs;i++)
478
			l+=getposts(&cfg,i); 		/* l=total posts */
479
		safe_snprintf(str,maxlen,"%lu",l);
480
481
		return(str);
	}
482

483
	if(!strcmp(sp,"TUSER")) {
484
		safe_snprintf(str,maxlen,"%u",total_users(&cfg));
485
486
		return(str);
	}
487

488
	if(!strcmp(sp,"TFILE")) {
489
490
		l=0;
		for(i=0;i<cfg.total_dirs;i++)
491
			l+=getfiles(&cfg,i);
492
		safe_snprintf(str,maxlen,"%lu",l);
493
494
		return(str);
	}
495

496
	if(strncmp(sp, "FILES:", 6) == 0) {	// Number of files in specified directory
rswindell's avatar
rswindell committed
497
		const char* path = getpath(&cfg, sp + 6);
498
		safe_snprintf(str, maxlen, "%lu", getfilecount(path));
rswindell's avatar
rswindell committed
499
		return str;
500
501
502
503
504
505
506
	}

	if(strcmp(sp, "FILES") == 0) {	// Number of files in current directory
		safe_snprintf(str, maxlen, "%lu", (ulong)getfiles(&cfg, usrdir[curlib][curdir[curlib]]));
		return str;
	}

rswindell's avatar
rswindell committed
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
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
	if(strncmp(sp, "FILESIZE:", 9) == 0) {
		const char* path = getpath(&cfg, sp + 9);
		byte_estimate_to_str(getfilesizetotal(path), str, maxlen, /* unit: */1, /* precision: */1);
		return str;
	}

	if(strcmp(sp, "FILESIZE") == 0) {
		byte_estimate_to_str(getfilesizetotal(cfg.dir[usrdir[curlib][curdir[curlib]]]->path)
			,str, maxlen, /* unit: */1, /* precision: */1);
		return str;
	}

	if(strncmp(sp, "FILEBYTES:", 10) == 0) {	// Number of bytes in current file directory
		const char* path = getpath(&cfg, sp + 10);
		safe_snprintf(str, maxlen, "%" PRIu64, getfilesizetotal(path));
		return str;
	}

	if(strcmp(sp, "FILEBYTES") == 0) {	// Number of bytes in current file directory
		safe_snprintf(str, maxlen, "%" PRIu64
			,getfilesizetotal(cfg.dir[usrdir[curlib][curdir[curlib]]]->path));
		return str;
	}

	if(strncmp(sp, "FILEKB:", 7) == 0) {	// Number of kibibytes in current file directory
		const char* path = getpath(&cfg, sp + 7);
		safe_snprintf(str, maxlen, "%1.1f", getfilesizetotal(path) / 1024.0);
		return str;
	}

	if(strcmp(sp, "FILEKB") == 0) {	// Number of kibibytes in current file directory
		safe_snprintf(str, maxlen, "%1.1f"
			,getfilesizetotal(cfg.dir[usrdir[curlib][curdir[curlib]]]->path) / 1024.0);
		return str;
	}

	if(strncmp(sp, "FILEMB:", 7) == 0) {	// Number of mebibytes in current file directory
		const char* path = getpath(&cfg, sp + 7);
		safe_snprintf(str, maxlen, "%1.1f", getfilesizetotal(path) / (1024.0 * 1024.0));
		return str;
	}

	if(strcmp(sp, "FILEMB") == 0) {	// Number of mebibytes in current file directory
		safe_snprintf(str, maxlen, "%1.1f"
			,getfilesizetotal(cfg.dir[usrdir[curlib][curdir[curlib]]]->path) / (1024.0 * 1024.0));
		return str;
	}

	if(strncmp(sp, "FILEGB:", 7) == 0) {	// Number of gibibytes in current file directory
		const char* path = getpath(&cfg, sp + 7);
		safe_snprintf(str, maxlen, "%1.1f", getfilesizetotal(path) / (1024.0 * 1024.0 * 1024.0));
		return str;
	}

	if(strcmp(sp, "FILEGB") == 0) {	// Number of gibibytes in current file directory
		safe_snprintf(str, maxlen, "%1.1f"
			,getfilesizetotal(cfg.dir[usrdir[curlib][curdir[curlib]]]->path) / (1024.0 * 1024.0 * 1024.0));
		return str;
	}

567
	if(!strcmp(sp,"TCALLS") || !strcmp(sp,"NUMCALLS")) {
568
		getstats(&cfg,0,&stats);
569
		safe_snprintf(str,maxlen,"%lu", (ulong)stats.logons);
570
571
		return(str);
	}
572

573
	if(!strcmp(sp,"PREVON") || !strcmp(sp,"LASTCALLERNODE")
574
		|| !strcmp(sp,"LASTCALLERSYSTEM"))
575
		return(lastuseron);
576

rswindell's avatar
rswindell committed
577
	if(!strcmp(sp,"CLS") || !strcmp(sp,"CLEAR")) {
578
		CLS;
579
580
		return(nulstr);
	}
581

582
	if(!strcmp(sp,"PAUSE") || !strcmp(sp,"MORE")) {
583
		pause();
584
585
		return(nulstr);
	}
586

587
	if(!strcmp(sp,"RESETPAUSE")) {
588
		lncntr=0;
589
590
		return(nulstr);
	}
591

592
	if(!strcmp(sp,"NOPAUSE") || !strcmp(sp,"POFF")) {
593
		sys_status^=SS_PAUSEOFF;
594
595
		return(nulstr);
	}
596

597
	if(!strcmp(sp,"PON") || !strcmp(sp,"AUTOMORE")) {
598
		sys_status^=SS_PAUSEON;
599
600
		return(nulstr);
	}
601

rswindell's avatar
rswindell committed
602
603
604
605
606
607
608
	if(strncmp(sp, "FILL:", 5) == 0) {
		sp += 5;
		while(*sp && online && column < cols - 1)
			bputs(sp, P_TRUNCATE);
		return nulstr;
	}

609
610
611
612
613
	if(strncmp(sp, "POS:", 4) == 0) {	// PCBoard	(nn is 1 based)
		i = atoi(sp + 4);
		if(i >= 1)	// Convert to 0-based
			i--;
		for(l = i - column; l > 0; l--)
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
			outchar(' ');
		return nulstr;
	}

	if(strncmp(sp, "DELAY:", 6) == 0) {	// PCBoard
		mswait(atoi(sp + 6) * 100);
		return nulstr;
	}

	if(strcmp(sp, "YESCHAR") == 0) {	// PCBoard
		safe_snprintf(str, maxlen, "%c", text[YNQP][0]);
		return str;
	}

	if(strcmp(sp, "NOCHAR") == 0) {		// PCBoard
		safe_snprintf(str, maxlen, "%c", text[YNQP][1]);
		return str;
	}

	if(strcmp(sp, "QUITCHAR") == 0) {
		safe_snprintf(str, maxlen, "%c", text[YNQP][2]);
		return str;
	}

638
639
640
641
642
	if(strncmp(sp, "BPS:", 4) == 0) {
		set_output_rate((enum output_rate)atoi(sp + 4));
		return nulstr;
	}

643
644
645
646
	/* NOSTOP */

	/* STOP */

647
648
	if(!strcmp(sp,"BELL") || !strcmp(sp,"BEEP"))
		return("\a");
649

650
651
652
	if(!strcmp(sp,"EVENT")) {
		if(event_time==0)
			return("<none>");
653
		return(timestr(event_time));
654
	}
655
656
657

	/* LASTCALL */

658
	if(!strncmp(sp,"NODE",4)) {
659
660
661
		i=atoi(sp+4);
		if(i && i<=cfg.sys_nodes) {
			getnodedat(i,&node,0);
662
663
			printnodedat(i,&node);
		}
664
665
		return(nulstr);
	}
666

667
	if(!strcmp(sp,"WHO")) {
668
		whos_online(true);
669
670
		return(nulstr);
	}
671
672
673

	/* User Codes */

674
675
	if(!strcmp(sp,"USER") || !strcmp(sp,"ALIAS") || !strcmp(sp,"NAME"))
		return(useron.alias);
676

677
	if(!strcmp(sp,"FIRST")) {
678
		safe_snprintf(str,maxlen,"%s",useron.alias);
679
		tp=strchr(str,' ');
680
		if(tp) *tp=0;
681
		return(str);
682
	}
683

684
	if(!strcmp(sp,"USERNUM")) {
685
		safe_snprintf(str,maxlen,"%u",useron.number);
686
687
		return(str);
	}
688

689
	if(!strcmp(sp,"PHONE") || !strcmp(sp,"HOMEPHONE")
690
		|| !strcmp(sp,"DATAPHONE") || !strcmp(sp,"DATA"))
691
		return(useron.phone);
692

693
694
	if(!strcmp(sp,"ADDR1"))
		return(useron.address);
695

696
697
	if(!strcmp(sp,"FROM"))
		return(useron.location);
698

699
	if(!strcmp(sp,"CITY")) {
700
		safe_snprintf(str,maxlen,"%s",useron.location);
701
		char* p=strchr(str,',');
702
703
		if(p) {
			*p=0;
704
705
			return(str);
		}
706
707
		return(nulstr);
	}
708

709
710
	if(!strcmp(sp,"STATE")) {
		char* p=strchr(useron.location,',');
711
712
		if(p) {
			p++;
713
			if(*p==' ')
714
				p++;
715
716
			return(p);
		}
717
718
		return(nulstr);
	}
719

720
721
	if(!strcmp(sp,"CPU"))
		return(useron.comp);
722

723
724
	if(!strcmp(sp,"HOST"))
		return(client_name);
725

726
727
	if(!strcmp(sp,"BDATE"))
		return(useron.birth);
728

729
	if(!strcmp(sp,"AGE")) {
730
		safe_snprintf(str,maxlen,"%u",getage(&cfg,useron.birth));
731
732
		return(str);
	}
rswindell's avatar
rswindell committed
733

734
	if(!strcmp(sp,"CALLS") || !strcmp(sp,"NUMTIMESON")) {
735
		safe_snprintf(str,maxlen,"%u",useron.logons);
736
737
		return(str);
	}
738

rswindell's avatar
rswindell committed
739
740
741
742
743
744
745
	if(strcmp(sp, "PWAGE") == 0) {
		time_t age = time(NULL) - useron.pwmod;
		safe_snprintf(str, maxlen, "%ld", (long)(age/(24*60*60)));
		return str;
	}

	if(strcmp(sp, "PWDATE") == 0 || strcmp(sp, "MEMO") == 0)
746
		return(unixtodstr(&cfg,useron.pwmod,str));
747

748
	if(!strcmp(sp,"SEC") || !strcmp(sp,"SECURITY")) {
749
		safe_snprintf(str,maxlen,"%u",useron.level);
750
751
		return(str);
	}
752

753
754
	if(!strcmp(sp,"SINCE"))
		return(unixtodstr(&cfg,useron.firston,str));
755

756
	if(!strcmp(sp,"TIMEON") || !strcmp(sp,"TIMEUSED")) {
757
		now=time(NULL);
758
		safe_snprintf(str,maxlen,"%lu",(ulong)(now-logontime)/60L);
759
760
		return(str);
	}
761

762
	if(!strcmp(sp,"TUSED")) {              /* Synchronet only */
763
		now=time(NULL);
764
		return(sectostr((uint)(now-logontime),str)+1);
765
	}
766

767
	if(!strcmp(sp,"TLEFT")) {              /* Synchronet only */
768
		gettimeleft();
769
		return(sectostr(timeleft,str)+1);
770
	}
771

772
	if(!strcmp(sp,"TPERD"))                /* Synchronet only */
rswindell's avatar
Add:    
rswindell committed
773
		return(sectostr(cfg.level_timeperday[useron.level],str)+4);
774

775
	if(!strcmp(sp,"TPERC"))                /* Synchronet only */
rswindell's avatar
Add:    
rswindell committed
776
		return(sectostr(cfg.level_timepercall[useron.level],str)+4);
777

rswindell's avatar
Add:    
rswindell committed
778
	if(strcmp(sp, "MPERC") == 0 || strcmp(sp, "TIMELIMIT") == 0) {
779
		safe_snprintf(str,maxlen,"%u",cfg.level_timepercall[useron.level]);
780
781
		return(str);
	}
782

rswindell's avatar
Add:    
rswindell committed
783
784
785
786
787
	if(strcmp(sp, "MPERD") == 0) {
		safe_snprintf(str,maxlen,"%u",cfg.level_timeperday[useron.level]);
		return str;
	}

rswindell's avatar
Add:    
rswindell committed
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
	if(strcmp(sp, "MAXCALLS") == 0) {
		safe_snprintf(str,maxlen,"%u",cfg.level_callsperday[useron.level]);
		return str;
	}

	if(strcmp(sp, "MAXPOSTS") == 0) {
		safe_snprintf(str,maxlen,"%u",cfg.level_postsperday[useron.level]);
		return str;
	}

	if(strcmp(sp, "MAXMAILS") == 0) {
		safe_snprintf(str,maxlen,"%u",cfg.level_emailperday[useron.level]);
		return str;
	}

	if(strcmp(sp, "MAXLINES") == 0) {
		safe_snprintf(str,maxlen,"%u",cfg.level_linespermsg[useron.level]);
		return str;
	}

808
	if(!strcmp(sp,"MINLEFT") || !strcmp(sp,"LEFT") || !strcmp(sp,"TIMELEFT")) {
809
		gettimeleft();
810
		safe_snprintf(str,maxlen,"%lu",timeleft/60);
811
812
		return(str);
	}
813

814
	if(!strcmp(sp,"LASTON"))
815
		return(timestr(useron.laston));
816

817
818
	if(!strcmp(sp,"LASTDATEON"))
		return(unixtodstr(&cfg,useron.laston,str));
819

820
	if(!strcmp(sp,"LASTTIMEON")) {
821
		memset(&tm,0,sizeof(tm));
822
		localtime32(&useron.laston,&tm);
823
824
825
826
827
828
829
830
		if(cfg.sys_misc&SM_MILITARY)
			safe_snprintf(str,maxlen,"%02d:%02d:%02d"
				,tm.tm_hour, tm.tm_min, tm.tm_sec);
		else
			safe_snprintf(str,maxlen,"%02d:%02d %s"
				,tm.tm_hour==0 ? 12
				: tm.tm_hour>12 ? tm.tm_hour-12
				: tm.tm_hour, tm.tm_min, tm.tm_hour>11 ? "pm":"am");
831
		return(str);
832
833
	}

rswindell's avatar
rswindell committed
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
	if(!strcmp(sp,"FIRSTON"))
		return(timestr(useron.firston));

	if(!strcmp(sp,"FIRSTDATEON"))
		return(unixtodstr(&cfg,useron.firston,str));

	if(!strcmp(sp,"FIRSTTIMEON")) {
		memset(&tm,0,sizeof(tm));
		localtime32(&useron.firston,&tm);
		if(cfg.sys_misc&SM_MILITARY)
			safe_snprintf(str,maxlen,"%02d:%02d:%02d"
				,tm.tm_hour, tm.tm_min, tm.tm_sec);
		else
			safe_snprintf(str,maxlen,"%02d:%02d %s"
				,tm.tm_hour==0 ? 12
				: tm.tm_hour>12 ? tm.tm_hour-12
				: tm.tm_hour, tm.tm_min, tm.tm_hour>11 ? "pm":"am");
		return(str);
	}

854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
	if(strcmp(sp, "EMAILS") == 0) {
		safe_snprintf(str, maxlen, "%u", useron.emails);
		return str;
	}

	if(strcmp(sp, "FBACKS") == 0) {
		safe_snprintf(str, maxlen, "%u", useron.fbacks);
		return str;
	}

	if(strcmp(sp, "ETODAY") == 0) {
		safe_snprintf(str, maxlen, "%u", useron.etoday);
		return str;
	}

	if(strcmp(sp, "PTODAY") == 0) {
		safe_snprintf(str, maxlen, "%u", useron.ptoday);
		return str;
	}

	if(strcmp(sp, "LTODAY") == 0) {
		safe_snprintf(str, maxlen, "%u", useron.ltoday);
		return str;
	}

rswindell's avatar
Add:    
rswindell committed
879
	if(strcmp(sp, "MTODAY") == 0) {
880
881
882
883
		safe_snprintf(str, maxlen, "%u", useron.ttoday);
		return str;
	}

rswindell's avatar
Add:    
rswindell committed
884
885
886
887
888
889
	if(strcmp(sp, "MTOTAL") == 0) {
		safe_snprintf(str, maxlen, "%u", useron.timeon);
		return str;
	}

	if(strcmp(sp, "TTODAY") == 0)
rswindell's avatar
Add:    
rswindell committed
890
		return sectostr(useron.ttoday, str) + 3;
rswindell's avatar
Add:    
rswindell committed
891
892

	if(strcmp(sp, "TTOTAL") == 0)
rswindell's avatar
Add:    
rswindell committed
893
		return sectostr(useron.timeon, str) + 3;
rswindell's avatar
Add:    
rswindell committed
894

895
896
897
898
899
	if(strcmp(sp, "TLAST") == 0) {
		safe_snprintf(str, maxlen, "%u", useron.tlast);
		return str;
	}

rswindell's avatar
Add:    
rswindell committed
900
	if(strcmp(sp, "MEXTRA") == 0) {
901
902
903
		safe_snprintf(str, maxlen, "%u", useron.textra);
		return str;
	}
rswindell's avatar
rswindell committed
904

rswindell's avatar
Add:    
rswindell committed
905
906
907
908
909
910
911
912
913
914
915
	if(strcmp(sp, "TEXTRA") == 0)
		return sectostr(useron.textra, str) + 3;

	if(strcmp(sp, "MBANKED") == 0) {
		safe_snprintf(str, maxlen, "%u", useron.min);
		return str;
	}

	if(strcmp(sp, "TBANKED") == 0)
		return sectostr(useron.min, str) + 3;

916
	if(!strcmp(sp,"MSGLEFT") || !strcmp(sp,"MSGSLEFT")) {
917
		safe_snprintf(str,maxlen,"%u",useron.posts);
918
919
		return(str);
	}
920

921
	if(!strcmp(sp,"MSGREAD")) {
922
		safe_snprintf(str,maxlen,"%lu",posts_read);
923
924
		return(str);
	}
925

926
	if(!strcmp(sp,"FREESPACE")) {
927
		safe_snprintf(str,maxlen,"%lu",getfreediskspace(cfg.temp_dir,0));
928
929
930
931
		return(str);
	}

	if(!strcmp(sp,"FREESPACEK")) {
932
		safe_snprintf(str,maxlen,"%lu",getfreediskspace(cfg.temp_dir,1024));
933
934
		return(str);
	}
935

936
	if(!strcmp(sp,"UPBYTES")) {
937
		safe_snprintf(str,maxlen,"%lu",useron.ulb);
938
939
		return(str);
	}
940

941
	if(!strcmp(sp,"UPK")) {
942
		safe_snprintf(str,maxlen,"%lu",useron.ulb/1024L);
943
944
		return(str);
	}
945

946
	if(!strcmp(sp,"UPS") || !strcmp(sp,"UPFILES")) {
947
		safe_snprintf(str,maxlen,"%u",useron.uls);
948
949
		return(str);
	}
950

951
	if(!strcmp(sp,"DLBYTES")) {
952
		safe_snprintf(str,maxlen,"%lu",useron.dlb);
953
954
		return(str);
	}
955

956
	if(!strcmp(sp,"DOWNK")) {
957
		safe_snprintf(str,maxlen,"%lu",useron.dlb/1024L);
958
959
		return(str);
	}