Newer
Older
/* Synchronet "@code" functions */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 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 *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#include "sbbs.h"
#include "cmdshell.h"
#include "utf8.h"
#include "unicode.h"
#include "cp437defs.h"
#include "ver.h"
#if defined(_WINSOCKAPI_)
extern WSADATA WSAData;
#define SOCKLIB_DESC WSAData.szDescription
#else
#define SOCKLIB_DESC NULL
#endif
struct atcode_format {
int disp_len;

rswindell
committed
enum {
none,
left,
right,
center
} align = none;
bool zero_padded=false;
bool thousep = false; // thousands-separated
bool uppercase = false;

rswindell
committed
bool width_specified = false;
char* parse(char* sp) {
char* p;
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
disp_len=strlen(sp) + 2;
if((p = strchr(sp, '|')) != NULL) {
if(strchr(p, 'T') != NULL)
thousep = true;
if(strchr(p, 'U') != NULL)
uppercase = true;
if(strchr(p, 'L') != NULL)
align = left;
else if(strchr(p, 'R') != NULL)
align = right;
else if(strchr(p, 'C') != NULL)
align = center;
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)
p = NULL;
else if((p=strstr(sp,"-L"))!=NULL)
align = left;
else if((p=strstr(sp,"-R"))!=NULL)
align = right;
else if((p=strstr(sp,"-C"))!=NULL)
align = center;
else if((p=strstr(sp,"-W"))!=NULL) /* wide */
doubled=true;
else if((p=strstr(sp,"-Z"))!=NULL)
zero_padded=true;
else if((p=strstr(sp,"-T"))!=NULL)
thousep=true;
else if((p=strstr(sp,"-U"))!=NULL)
uppercase=true;
else if((p=strstr(sp,"->"))!=NULL) /* wrap */
truncated = false;
if(p!=NULL) {
char* lp = p;
lp++; // skip the '|' or '-'
while(*lp == '>'|| IS_ALPHA(*lp))
lp++;
if(*lp)
width_specified = true;
while(*lp && !IS_DIGIT(*lp))
lp++;
if(*lp && IS_DIGIT(*lp)) {
disp_len=atoi(lp);
width_specified = true;
}
*p=0;
}
return p;
}
};
/****************************************************************************/
/* Returns 0 if invalid @ code. Returns length of @ code if valid. */
/****************************************************************************/
int sbbs_t::show_atcode(const char *instr, JSObject* obj)
{
char str[128],str2[128],*tp,*sp,*p;
int len;
atcode_format fmt;
const char *cp;
if(*instr != '@')
return 0;
tp=strchr(str+1,'@');
if(!tp) /* no terminating @ */
return(0);
if(sp && sp<tp) /* space before terminating @ */
return(0);
len=(tp-str)+1;
(*tp)=0;
sp=(str+1);

rswindell
committed
if(*sp == '~' && *(sp + 1)) { // Mouse hot-spot (hungry)
sp++;
tp = strchr(sp + 1, '~');
if(tp == NULL)
tp = sp;
else {
*tp = 0;
tp++;
}
c_unescape_str(tp);

rswindell
committed
add_hotspot(tp, /* hungry: */true, column, column + strlen(sp) - 1, row);
bputs(sp);
return len;
}
if(*sp == '`' && *(sp + 1)) { // Mouse hot-spot (strict)
sp++;
tp = strchr(sp + 1, '`');
if(tp == NULL)
tp = sp;
else {
*tp = 0;
tp++;
}
c_unescape_str(tp);
add_hotspot(tp, /* hungry: */false, column, column + strlen(sp) - 1, row);
// @!x@ for Ctrl-A x equivalent(s) */
if(*sp == '!') {
for(p = sp + 1; *p != '\0' && *p != '@'; p++)
ctrl_a(*p);
return len;
}
p = fmt.parse(sp);
cp = atcode(sp, str2, sizeof(str2), &pmode, fmt.align == fmt.center, obj);
if(cp==NULL)
char separated[128];
if(fmt.thousep)
cp = separate_thousands(cp, separated, sizeof(separated), ',');
if(fmt.uppercase) {
SAFECOPY(upper, cp);
strupr(upper);
cp = upper;
}
if(p==NULL || fmt.truncated == false || (fmt.width_specified == false && fmt.align == fmt.none))
fmt.disp_len = strlen(cp);
if(fmt.uppercase && fmt.align == fmt.none)
fmt.align = fmt.left;

rswindell
committed
if(fmt.truncated && strchr(cp, '\n') == NULL) {
if(column + fmt.disp_len > cols - 1) {
fmt.disp_len = 0;
fmt.disp_len = (cols - 1) - column;
if(pmode & P_UTF8) {
if(term_supports(UTF8))
fmt.disp_len += strlen(cp) - utf8_str_total_width(cp, unicode_zerowidth);
else
fmt.disp_len += strlen(cp) - utf8_str_count_width(cp, /* min: */1, /* max: */2, unicode_zerowidth);
}
if(fmt.align == fmt.left)
bprintf(pmode, "%-*.*s",fmt.disp_len,fmt.disp_len,cp);
else if(fmt.align == fmt.right)
bprintf(pmode, "%*.*s",fmt.disp_len,fmt.disp_len,cp);
else if(fmt.align == fmt.center) {
if(vlen < fmt.disp_len) {
int left = (fmt.disp_len - vlen) / 2;
bprintf(pmode, "%*s%-*s", left, "", fmt.disp_len - left, cp);
bprintf(pmode, "%.*s", fmt.disp_len, cp);
} else if(fmt.doubled) {
} else if(fmt.zero_padded) {
int vlen = strlen(cp);
if(vlen < fmt.disp_len)
bprintf(pmode, "%-.*s%s", (int)(fmt.disp_len - strlen(cp)), "0000000000", cp);
else
bprintf(pmode, "%.*s", fmt.disp_len, cp);
bprintf(pmode, "%.*s", fmt.disp_len, cp);
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;
}
const char* sbbs_t::formatted_atcode(const char* sp, char* str, size_t maxlen)
{
char tmp[128];
char buf[256];
atcode_format fmt;
SAFECOPY(tmp, sp);
char* p = fmt.parse(tmp);
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
const char* cp = atcode(tmp, buf, sizeof buf);
if(cp == nullptr)
return nullptr;
char separated[128];
if(fmt.thousep)
cp = separate_thousands(cp, separated, sizeof(separated), ',');
char upper[128];
if(fmt.uppercase) {
SAFECOPY(upper, cp);
strupr(upper);
cp = upper;
}
if(p==NULL || fmt.truncated == false || (fmt.width_specified == false && fmt.align == fmt.none))
fmt.disp_len = strlen(cp);
if(fmt.align == fmt.left)
snprintf(str, maxlen, "%-*.*s", fmt.disp_len, fmt.disp_len, cp);
else if(fmt.align == fmt.right)
snprintf(str, maxlen, "%*.*s", fmt.disp_len, fmt.disp_len, cp);
else if(fmt.align == fmt.center) {
int vlen = strlen(cp);
if(vlen < fmt.disp_len) {
int left = (fmt.disp_len - vlen) / 2;
snprintf(str, maxlen, "%*s%-*s", left, "", fmt.disp_len - left, cp);
} else
snprintf(str, maxlen, "%.*s", fmt.disp_len, cp);
// } else if(fmt.doubled) { // Unsupported in this context
// wide(cp);
} else if(fmt.zero_padded) {
int vlen = strlen(cp);
if(vlen < fmt.disp_len)
snprintf(str, maxlen, "%-.*s%s", (int)(fmt.disp_len - strlen(cp)), "0000000000", cp);
else
snprintf(str, maxlen, "%.*s", fmt.disp_len, cp);
} else
snprintf(str, maxlen, "%.*s", fmt.disp_len, cp);
return str;
}

Rob Swindell
committed
const char* sbbs_t::atcode(const char* sp, char* str, size_t maxlen, int* pmode, bool centered, JSObject* obj)

Rob Swindell
committed
char tmp[128];
char* tp = NULL;

Rob Swindell
committed
int i;
uint ugrp;
uint usub;
long l;
stats_t stats;
node_t node;
struct tm tm;
str[0]=0;
if(strcmp(sp, "SHOW") == 0) {
console &= ~CON_ECHO_OFF;
return nulstr;
}
if(strncmp(sp, "SHOW:", 5) == 0) {
uchar* ar = arstr(NULL, sp + 5, &cfg, NULL);
if(ar != NULL) {
if(!chk_ar(ar, &useron, &client))
console |= CON_ECHO_OFF;
else
console &= ~CON_ECHO_OFF;
free(ar);
}
return nulstr;
}
if(strcmp(sp, "HOT") == 0) { // Auto-mouse hot-spot attribute
hot_attr = curatr;
return nulstr;

rswindell
committed
if(strncmp(sp, "HOT:", 4) == 0) { // Auto-mouse hot-spot attribute

rswindell
committed
if(stricmp(sp, "hungry") == 0) {
hungry_hotspots = true;
hot_attr = curatr;
}
else if(stricmp(sp, "strict") == 0) {
hungry_hotspots = false;
hot_attr = curatr;
}
else if(stricmp(sp, "off") == 0)
hot_attr = 0;
else
hot_attr = attrstr(sp);

rswindell
committed
return nulstr;
}
if(strcmp(sp, "CLEAR_HOT") == 0) {
clear_hotspots();
return nulstr;
}

rswindell
committed
if(strncmp(sp, "U+", 2) == 0) { // UNICODE
enum unicode_codepoint codepoint = (enum unicode_codepoint)strtoul(sp + 2, &tp, 16);
outchar(codepoint, unicode_to_cp437(codepoint));
else if(*tp == ':')
outchar(codepoint, tp + 1);
else {
char fallback = (char)strtoul(tp + 1, NULL, 16);
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;
}
if(strcmp(sp, "CHECKMARK") == 0) {
outchar(UNICODE_CHECK_MARK, CP437_CHECK_MARK);
return nulstr;
}
if(strcmp(sp, "ELLIPSIS") == 0) {
outchar(UNICODE_HORIZONTAL_ELLIPSIS, "...");
return nulstr;
}
if(strcmp(sp, "COPY") == 0) {
outchar(UNICODE_COPYRIGHT_SIGN, "(C)");
return nulstr;
}
if(strcmp(sp, "SOUNDCOPY") == 0) {
outchar(UNICODE_SOUND_RECORDING_COPYRIGHT, "(P)");
return nulstr;
}
if(strcmp(sp, "REGISTERED") == 0) {
outchar(UNICODE_REGISTERED_SIGN, "(R)");
return nulstr;
}
if(strcmp(sp, "TRADEMARK") == 0) {
outchar(UNICODE_TRADE_MARK_SIGN, "(TM)");
return nulstr;
}
if(strcmp(sp, "DEGREE_C") == 0) {
return nulstr;
}
if(strcmp(sp, "DEGREE_F") == 0) {
if(strncmp(sp, "WIDE:", 5) == 0) {
wide(sp + 5);
return(nulstr);
}
safe_snprintf(str,maxlen,"%c",REVISION);
safe_snprintf(str,maxlen,"%s%c%s",VERSION,REVISION,beta_version);

rswindell
committed
#if defined(_DEBUG)

rswindell
committed
#endif

rswindell
committed
}
if(!strcmp(sp,"VER_NOTICE"))

rswindell
committed
return(os_version(str, maxlen));
if(strcmp(sp,"OS_CPU") == 0)
return(os_cpuarch(str, maxlen));

rswindell
committed
#ifdef JAVASCRIPT
if(!strcmp(sp,"JS_VER"))
return((char *)JS_GetImplementationVersion());

rswindell
committed
#endif
if(!strcmp(sp,"PLATFORM"))
return(PLATFORM_DESC);

rswindell
committed
if(!strcmp(sp,"COPYRIGHT"))
return(COPYRIGHT_NOTICE);

rswindell
committed
char compiler[32];
DESCRIBE_COMPILER(compiler);
strncpy(str, compiler, maxlen);

rswindell
committed
}
if(strcmp(sp, "GIT_HASH") == 0)
return git_hash;
if(strcmp(sp, "GIT_BRANCH") == 0)
return git_branch;
if(strcmp(sp, "GIT_DATE") == 0)
return git_date;
if(strcmp(sp, "BUILD_DATE") == 0)
return __DATE__;
if(strcmp(sp, "BUILD_TIME") == 0)
return __TIME__;
extern volatile time_t uptime;
time_t up=0;
now = time(NULL);
if (uptime != 0 && now >= uptime)
up = now-uptime;
char days[64]="";
if((up/(24*60*60))>=2) {
sprintf(days,"%u days ",(uint)(up/(24L*60L*60L)));
up%=(24*60*60);
}
safe_snprintf(str,maxlen,"%s%u:%02u"
,(uint)(up/(60L*60L))
,(uint)((up/60L)%60L)
if(!strcmp(sp,"SERVED")) {
extern volatile uint served;
safe_snprintf(str,maxlen,"%u",served);
return(str);
}
if(!strcmp(sp,"SOCKET_LIB"))
return(socklib_version(str,SOCKLIB_DESC));

rswindell
committed
safe_snprintf(str,maxlen,"SMBLIB %s",smb_lib_ver());

rswindell
committed
if(!strcmp(sp,"BBS") || !strcmp(sp,"BOARDNAME"))
return(cfg.sys_name);
if(!strcmp(sp,"BAUD") || !strcmp(sp,"BPS")) {
safe_snprintf(str,maxlen,"%u",cur_output_rate ? cur_output_rate : cur_rate);
if(!strcmp(sp,"CPS")) {
safe_snprintf(str,maxlen,"%u",cur_cps);
return(str);
}
safe_snprintf(str,maxlen,"%u",cols);
safe_snprintf(str,maxlen,"%u",rows);
if(strcmp(sp,"TERM") == 0)
return term_type();
if(strcmp(sp,"CHARSET") == 0)
return term_charset();
if(!strcmp(sp,"CONN"))
return(connection);
if(!strcmp(sp,"SYSOP"))
return(cfg.sys_op);
if(strcmp(sp, "SYSAVAIL") == 0)
return text[sysop_available(&cfg) ? LiSysopAvailable : LiSysopNotAvailable];
if(strcmp(sp, "SYSAVAILYN") == 0)
return text[sysop_available(&cfg) ? Yes : No];
if(!strcmp(sp,"LOCATION"))
return(cfg.sys_location);
if(strcmp(sp,"NODE") == 0 || strcmp(sp,"NN") == 0) {
safe_snprintf(str,maxlen,"%u",cfg.node_num);
if(strcmp(sp, "TNODES") == 0 || strcmp(sp, "TNODE") == 0 || strcmp(sp, "TN") == 0) {
safe_snprintf(str,maxlen,"%u",cfg.sys_nodes);
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;
}
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];
}
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];
if(strcmp(sp, "SPLITP") == 0)
return (useron.chat&CHAT_SPLITP) ? text[On] : text[Off];
if(!strcmp(sp,"INETADDR"))
return(cfg.sys_inetaddr);
if(!strcmp(sp,"HOSTNAME"))
return server_host_name();
return(smb_faddrtoa(&cfg.faddr[0],str));
if(!strcmp(sp,"EMAILADDR"))
,(cfg.inetmail_misc&NMAIL_ALIAS) || (useron.rest&FLAG('O')) ? useron.alias : useron.name));
if(strcmp(sp, "NETMAIL") == 0)
return useron.netmail;

Rob Swindell
committed
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
if(strcmp(sp, "TERMTYPE") == 0)
return term_type(&useron, term_supports(), str, maxlen);
if(strcmp(sp, "TERMROWS") == 0)
return term_rows(&useron, str, maxlen);
if(strcmp(sp, "TERMCOLS") == 0)
return term_cols(&useron, str, maxlen);
if(strcmp(sp, "AUTOTERM") == 0)
return (useron.misc & AUTOTERM) ? text[On] : text[Off];
if(strcmp(sp, "ANSI") == 0)
return (useron.misc & ANSI) ? text[On] : text[Off];
if(strcmp(sp, "ASCII") == 0)
return (useron.misc & NO_EXASCII) ? text[On] : text[Off];
if(strcmp(sp, "COLOR") == 0)
return (useron.misc & COLOR) ? text[On] : text[Off];
if(strcmp(sp, "ICE") == 0)
return (useron.misc & ICE_COLOR) ? text[On] : text[Off];
if(strcmp(sp, "RIP") == 0)
return (useron.misc & RIP) ? text[On] : text[Off];
if(strcmp(sp, "PETSCII") == 0)
return (useron.misc & PETSCII) ? text[On] : text[Off];
if(strcmp(sp, "SWAPDEL") == 0)
return (useron.misc & SWAP_DELETE) ? text[On] : text[Off];
if(strcmp(sp, "UTF8") == 0)
return (useron.misc & UTF8) ? text[On] : text[Off];
if(strcmp(sp, "MOUSE") == 0)
return (useron.misc & MOUSE) ? text[On] : text[Off];
if(strcmp(sp, "UPAUSE") == 0)
return (useron.misc & UPAUSE) ? text[On] : text[Off];
if(strcmp(sp, "SPIN") == 0)
return (useron.misc & SPIN) ? text[On] : text[Off];
if(strcmp(sp, "PAUSESPIN") == 0)
return (useron.misc & NOPAUSESPIN) ? text[Off] : text[On];
if(strcmp(sp, "EXPERT") == 0)
return (useron.misc & EXPERT) ? text[On] : text[Off];
if(strcmp(sp, "HOTKEYS") == 0)
return (useron.misc & COLDKEYS) ? text[Off] : text[On];
if(strcmp(sp, "MSGCLS") == 0)
return (useron.misc & CLRSCRN) ? text[On] : text[Off];
if(strcmp(sp, "FWD") == 0)
return (useron.misc & NETMAIL) ? text[On] : text[Off];

Rob Swindell
committed
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
if(strcmp(sp, "REMSUBS") == 0)
return (useron.misc & CURSUB) ? text[On] : text[Off];
if(strcmp(sp, "FILEDESC") == 0)
return (useron.misc & EXTDESC) ? text[On] : text[Off];
if(strcmp(sp, "FILEFLAG") == 0)
return (useron.misc & BATCHFLAG) ? text[On] : text[Off];
if(strcmp(sp, "AUTOHANG") == 0)
return (useron.misc & AUTOHANG) ? text[On] : text[Off];
if(strcmp(sp, "AUTOLOGON") == 0)
return (useron.misc & AUTOLOGON) ? text[On] : text[Off];
if(strcmp(sp, "QUIET") == 0)
return (useron.misc & QUIET) ? text[On] : text[Off];
if(strcmp(sp, "ASKNSCAN") == 0)
return (useron.misc & ASK_NSCAN) ? text[On] : text[Off];
if(strcmp(sp, "ASKSSCAN") == 0)
return (useron.misc & ASK_SSCAN) ? text[On] : text[Off];
if(strcmp(sp, "ANFSCAN") == 0)
return (useron.misc & ANFSCAN) ? text[On] : text[Off];
if(strcmp(sp, "EDITOR") == 0)
return (useron.xedit < 1 || useron.xedit >= cfg.total_xedits) ? text[None] : cfg.xedit[useron.xedit - 1]->name;
if(strcmp(sp, "SHELL") == 0)
return cfg.shell[useron.shell]->name;
if(strcmp(sp, "TMP") == 0)
return useron.tmpext;
if(strcmp(sp, "PROT") == 0) {
safe_snprintf(str, maxlen, "%c", useron.prot);
return str;
}

Rob Swindell
committed
if(strcmp(sp, "PROTNAME") == 0)
return protname(useron.prot);
if(strcmp(sp, "SEX") == 0) {
safe_snprintf(str, maxlen, "%c", useron.sex);
return str;
}
if(strcmp(sp, "GENDERS") == 0) {
return cfg.new_genders;
}
if(!strcmp(sp,"QWKID"))
return(cfg.sys_id);
if(!strcmp(sp,"TIME") || !strcmp(sp,"SYSTIME")) {
memset(&tm,0,sizeof(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");
if(!strcmp(sp,"TIMEZONE"))
return(smb_zonestr(sys_timezone(&cfg),str));
if(!strcmp(sp,"DATE") || !strcmp(sp,"SYSDATE")) {
return(unixtodstr(&cfg,time32(NULL),str));
if(strncmp(sp, "DATE:", 5) == 0 || strncmp(sp, "TIME:", 5) == 0) {

Rob Swindell
committed
SAFECOPY(tmp, sp + 5);
c_unescape_str(tmp);
now = time(NULL);
memset(&tm, 0, sizeof(tm));
localtime_r(&now, &tm);

Rob Swindell
committed
strftime(str, maxlen, tmp, &tm);
return str;
}
if(!strcmp(sp,"DATETIME"))
return(timestr(time(NULL)));
if(!strcmp(sp,"DATETIMEZONE")) {
char zone[32];
safe_snprintf(str, maxlen, "%s %s", timestr(time(NULL)), smb_zonestr(sys_timezone(&cfg),zone));
return str;
}
if(strcmp(sp, "DATEFMT") == 0) {
return date_format(&cfg, str, maxlen);
if(strcmp(sp, "BDATEFMT") == 0 || strcmp(sp, "BIRTHFMT") == 0) {
return birthdate_format(&cfg, str, maxlen);
if(strcmp(sp, "GENDERS") == 0)
return cfg.new_genders;
l=0;
for(i=0;i<cfg.total_subs;i++)
l+=getposts(&cfg,i); /* l=total posts */
safe_snprintf(str,maxlen,"%lu",l);
safe_snprintf(str,maxlen,"%u",total_users(&cfg));
l=0;
for(i=0;i<cfg.total_dirs;i++)
safe_snprintf(str,maxlen,"%lu",l);
if(strncmp(sp, "FILES:", 6) == 0) { // Number of files in specified directory
const char* path = getpath(&cfg, sp + 6);
safe_snprintf(str, maxlen, "%u", getfilecount(path));
}
if(strcmp(sp, "FILES") == 0) { // Number of files in current directory
safe_snprintf(str, maxlen, "%u", getfiles(&cfg, usrdir[curlib][curdir[curlib]]));
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
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;
}
if(!strcmp(sp,"TCALLS") || !strcmp(sp,"NUMCALLS")) {
safe_snprintf(str,maxlen,"%u", stats.logons);
if(!strcmp(sp,"PREVON") || !strcmp(sp,"LASTCALLERNODE")
|| !strcmp(sp,"LASTCALLERSYSTEM"))

Rob Swindell
committed
if(strcmp(sp, "GETDIM") == 0) {
ansi_getlines();
return nulstr;
}
if(strcmp(sp, "GETKEY") == 0) {
getkey();
return(nulstr);
}
if(strcmp(sp, "CONTINUE") == 0) {
char ch = getkey(K_UPPER);
if(ch == no_key() || ch == quit_key())
if(strncmp(sp, "WAIT:", 5) == 0) {
if(!strcmp(sp,"PAUSE") || !strcmp(sp,"MORE")) {
lncntr=0;
if(!strcmp(sp,"NOPAUSE") || !strcmp(sp,"POFF")) {
if(!strcmp(sp,"PON") || !strcmp(sp,"AUTOMORE")) {

Rob Swindell
committed
SAFECOPY(tmp, sp + 5);
int margin = centered ? column : 1;
if(margin < 1) margin = 1;

Rob Swindell
committed
c_unescape_str(tmp);
while(*tmp && online && column < cols - margin)
bputs(tmp, P_TRUNCATE);
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--)
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", yes_key());
return str;
}
if(strcmp(sp, "NOCHAR") == 0) { // PCBoard
safe_snprintf(str, maxlen, "%c", no_key());
return str;
}
if(strcmp(sp, "QUITCHAR") == 0) {
safe_snprintf(str, maxlen, "%c", quit_key());
if(strncmp(sp, "BPS:", 4) == 0) {
set_output_rate((enum output_rate)atoi(sp + 4));
return nulstr;
}
if(strncmp(sp, "TEXT:", 5) == 0) {
i = atoi(sp + 5);
if(i >= 1 && i <= TOTAL_TEXT)
return text[i - 1];
return get_text(sp + 5);
/* NOSTOP */
/* STOP */
if(!strcmp(sp,"BELL") || !strcmp(sp,"BEEP"))
return("\a");
if(!strcmp(sp,"EVENT")) {
if(event_time==0)
return("<none>");
return(timestr(event_time));
if(strcmp(sp, "NODE_USER") == 0)
return thisnode.misc&NODE_ANON ? text[UNKNOWN_USER] : useron.alias;
if(!strncmp(sp,"NODE",4) && IS_DIGIT(sp[4])) {
i=atoi(sp+4);
if(i && i<=cfg.sys_nodes) {
getnodedat(i,&node,0);
printnodedat(i,&node);
}