Newer
Older
/* getkey.cpp */
/* Synchronet single-key console functions */
/* $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. *
****************************************************************************/
#include "sbbs.h"
/****************************************************************************/
/* Waits for remote or local user to hit a key. Inactivity timer is checked */
/* and hangs up if inactive for 4 minutes. Returns key hit, or uppercase of */
/* key hit if mode&K_UPPER or key out of KEY BUFFER. Does not print key. */
/* Called from functions all over the place. */
/****************************************************************************/
char sbbs_t::getkey(long mode)
{
char ch,coldkey,c=0,spin=sbbs_random(5);
time_t last_telnet_cmd=0;
if(!online || !input_thread_running) {
YIELD(); // just in case someone is looping on getkey() when they shouldn't
}
sys_status&=~SS_ABORT;
if((sys_status&SS_USERON || action==NODE_DFLT) && !(mode&K_GETSTR))
mode|=(useron.misc&SPIN);
lncntr=0;
timeout=time(NULL);
if(mode&K_SPIN)
outchar(' ');
do {
checkline(); /* check to make sure remote user is still online */
if(sys_status&SS_ABORT) {
if(mode&K_SPIN) /* back space once if on spinning cursor */
bputs("\b \b");
if(mode&K_SPIN)
switch(spin) {
case 0:
switch(c++) {
case 0:
outchar(BS);
outchar('');
break;
outchar(BS);
outchar('/');
break;
outchar(BS);
outchar('');
break;
outchar(BS);
outchar('\\');
c=0;
break;
break;
case 1:
switch(c++) {
case 0:
outchar(BS);
outchar('');
break;
outchar(BS);
outchar('');
break;
outchar(BS);
outchar('');
break;
outchar(BS);
outchar('');
break;
outchar(BS);
outchar('');
break;
outchar(BS);
outchar('');
c=0;
break;
break;
case 2:
switch(c++) {
case 0:
outchar(BS);
outchar('-');
break;
outchar(BS);
outchar('=');
break;
outchar(BS);
outchar('');
break;
outchar(BS);
outchar('=');
c=0;
break;
break;
case 3:
switch(c++) {
case 0:
outchar(BS);
outchar('');
break;
outchar(BS);
outchar('');
break;
outchar(BS);
outchar('');
break;
outchar(BS);
outchar('');
c=0;
break;
break;
case 4:
switch(c++) {
case 0:
outchar(BS);
outchar('');
break;
outchar(BS);
outchar('');
break;
outchar(BS);
outchar('');
break;
outchar(BS);
outchar('');
c=0;
break;
ch=inkey(mode,mode&K_SPIN ? 250:1000);
if(sys_status&SS_ABORT)
return(0);
now=time(NULL);
if(ch) {
if(mode&K_NUMBER && isprint(ch) && !isdigit(ch))
continue;
if(mode&K_ALPHA && isprint(ch) && !isalpha(ch))
continue;
if(mode&K_NOEXASC && ch&0x80)
continue;
if(mode&K_SPIN)
bputs("\b \b");
if(mode&K_COLD && ch>SP && useron.misc&COLDKEYS) {
if(mode&K_UPPER)
outchar(toupper(ch));
else
outchar(ch);
while((coldkey=inkey(mode,1000))==0 && online && !(sys_status&SS_ABORT))
;
if(coldkey==BS || coldkey==DEL)
if(mode&K_UPPER)
return(toupper(ch));
if(sys_status&SS_USERON && !(sys_status&SS_LCHAT)) gettimeleft();
else if(online &&
((cfg.node_dollars_per_call && now-answertime>SEC_BILLING)
|| (now-answertime>SEC_LOGON && !(sys_status&SS_LCHAT)))) {
console&=~(CON_R_ECHOX|CON_L_ECHOX);
console|=(CON_R_ECHO|CON_L_ECHO);
bputs(text[TakenTooLongToLogon]);
if(sys_status&SS_USERON && online && (timeleft/60)<(5-timeleft_warn)
&& !SYSOP && !(sys_status&SS_LCHAT)) {
timeleft_warn=5-(timeleft/60);
SAVELINE;
attr(LIGHTGRAY);
bprintf(text[OnlyXminutesLeft]
,((ushort)timeleft/60)+1,(timeleft/60) ? "s" : nulstr);
if(!(startup->options&BBS_OPT_NO_TELNET_GA)
&& now!=last_telnet_cmd && now-timeout>=60 && !((now-timeout)%60)) {
// Let's make sure the socket is up
// Sending will trigger a socket d/c detection
send_telnet_cmd(TELNET_GA,0);
last_telnet_cmd=now;
}
if(online==ON_REMOTE && !(console&CON_NO_INACT)
&& now-timeout>=cfg.sec_warn) { /* warning */

rswindell
committed
if(sys_status&SS_USERON && cfg.sec_warn!=cfg.sec_hangup) {

rswindell
committed
bputs(text[AreYouThere]);
}
while(!inkey(K_NONE,100) && online && now-timeout>=cfg.sec_warn) {
now=time(NULL);
if(now-timeout>=cfg.sec_hangup) {
if(online==ON_REMOTE) {
console|=CON_R_ECHO;

rswindell
committed
console&=~CON_R_ECHOX;
}
bputs(text[CallBackWhenYoureThere]);
logline(nulstr,"Inactive");
hangup();

rswindell
committed
return(0);
}
}
if(sys_status&SS_USERON && cfg.sec_warn!=cfg.sec_hangup) {

rswindell
committed
RESTORELINE;
}
timeout=now;
}
return(0);
}
/****************************************************************************/
/* Outputs a string highlighting characters preceeded by a tilde */
/****************************************************************************/
void sbbs_t::mnemonics(char *str)
{
char *ctrl_a_codes;
long l;
if(!strchr(str,'~')) {
mnestr=str;
bputs(str);
ctrl_a_codes=strchr(str,1);
if(!ctrl_a_codes) {
if(str[0]=='@' && str[strlen(str)-1]=='@' && !strchr(str,SP)) {
mnestr=str;
bputs(str);
return;
}
attr(cfg.color[clr_mnelow]);
}
if(str[l]=='~' && str[l+1]!=0) {
if(!(useron.misc&ANSI))
outchar('(');
l++;
if(!ctrl_a_codes)
attr(cfg.color[clr_mnehigh]);
outchar(str[l]);
l++;
if(!(useron.misc&ANSI))
outchar(')');
if(!ctrl_a_codes)
attr(cfg.color[clr_mnelow]);
}
if(str[l]==CTRL_A /* ctrl-a */
&& str[l+1]!=0) { /* valid */
ctrl_a(str[++l]); /* skip the ctrl-a */
l++; /* skip the attribute code */
} else
outchar(str[l++]);
}
}
if(!ctrl_a_codes)
attr(cfg.color[clr_mnecmd]);
}
/****************************************************************************/
/* Prompts user for Y or N (yes or no) and CR is interpreted as a Y */
/* Returns 1 for Y or 0 for N */
/* Called from quite a few places */
/****************************************************************************/
bool sbbs_t::yesno(char *str)
{
char ch;
strcpy(question,str);
SYNC;
if(useron.misc&WIP) {
strip_ctrl(question);
else
bprintf(text[YesNoQuestion],str);
while(online) {
if(sys_status&SS_ABORT)
ch=text[YN][1];
else
ch=getkey(K_UPPER|K_COLD);
if(ch==text[YN][0] || ch==CR) {
if(bputs(text[Yes]))
CRLF;
lncntr=0;
if(ch==text[YN][1]) {
if(bputs(text[No]))
CRLF;
lncntr=0;
return(false);
}
}
return(true);
}
/****************************************************************************/
/* Prompts user for N or Y (no or yes) and CR is interpreted as a N */
/* Returns 1 for N or 0 for Y */
/* Called from quite a few places */
/****************************************************************************/
bool sbbs_t::noyes(char *str)
{
char ch;
strcpy(question,str);
SYNC;
if(useron.misc&WIP) {
strip_ctrl(question);
else
bprintf(text[NoYesQuestion],str);
while(online) {
if(sys_status&SS_ABORT)
ch=text[YN][1];
else
ch=getkey(K_UPPER|K_COLD);
if(ch==text[YN][1] || ch==CR) {
if(bputs(text[No]))
CRLF;
lncntr=0;
if(ch==text[YN][0]) {
if(bputs(text[Yes]))
CRLF;
lncntr=0;
return(false);
}
}
return(true);
}
/****************************************************************************/
/* Waits for remote or local user to hit a key that is contained inside str.*/
/* 'str' should contain uppercase characters only. When a valid key is hit, */
/* it is echoed (upper case) and is the return value. */
/* Called from quite a few functions */
/****************************************************************************/

rswindell
committed
long sbbs_t::getkeys(char *keys, ulong max)
uchar ch,n=0,c=0;

rswindell
committed
ulong i=0;
SAFECOPY(str,keys);
strupr(str);
while(online) {
ch=getkey(K_UPPER);
if(max && ch>0x7f) /* extended ascii chars are digits to isdigit() */
continue;
if(sys_status&SS_ABORT) { /* return -1 if Ctrl-C hit */
attr(LIGHTGRAY);
CRLF;
lncntr=0;
if(ch && !n && (strchr(str,ch))) { /* return character if in string */
outchar(ch);
if(useron.misc&COLDKEYS && ch>SP) {
while(online && !(sys_status&SS_ABORT)) {
c=getkey(0);
if(c==CR || c==BS || c==DEL)
break;
}
if(sys_status&SS_ABORT) {
CRLF;
return(-1);
}
if(c==BS || c==DEL) {
attr(LIGHTGRAY);
CRLF;
lncntr=0;
if(ch==CR && max) { /* return 0 if no number */
attr(LIGHTGRAY);
CRLF;
lncntr=0;
if(n)
return(i|0x80000000L); /* return number plus high bit */
return(0);
}
if((ch==BS || ch==DEL) && n) {
else if(max && isdigit(ch) && (i*10)+(ch&0xf)<=max && (ch!='0' || n)) {
i*=10;
n++;
i+=ch&0xf;
outchar(ch);
if(i*10>max && !(useron.misc&COLDKEYS)) {
attr(LIGHTGRAY);
CRLF;
lncntr=0;
return(i|0x80000000L);
}
}
}
477
478
479
480
481
482
483
484
485
486
487
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
return(-1);
}
/****************************************************************************/
/* Prints PAUSE message and waits for a key stoke */
/****************************************************************************/
void sbbs_t::pause()
{
char ch;
uchar tempattrs=curatr; /* was lclatr(-1) */
int i,j;
long l=K_UPPER;
RIOSYNC(0);
if(sys_status&SS_ABORT)
return;
lncntr=0;
if(online==ON_REMOTE)
rioctl(IOFI);
bputs(text[Pause]);
j=bstrlen(text[Pause]);
if(sys_status&SS_USERON && !(useron.misc&NO_EXASCII) && !(useron.misc&WIP)
&& !(cfg.node_misc&NM_NOPAUSESPIN))
l|=K_SPIN;
ch=getkey(l);
if(ch==text[YN][1] || ch=='Q')
sys_status|=SS_ABORT;
else if(ch==LF) // down arrow == display one more line
lncntr=rows-2;
if(text[Pause][0]!='@')
for(i=0;i<j;i++)
bputs("\b \b");
getnodedat(cfg.node_num,&thisnode,0);
nodesync();
attr(tempattrs);
}
/****************************************************************************/
/* Puts a character into the input buffer */
/****************************************************************************/
void sbbs_t::ungetkey(char ch)
{
keybuf[keybuftop++]=ch;
if(keybuftop==KEY_BUFSIZE)
keybuftop=0;
}