|
|
1.1 root 1: /* getkey.cpp */
2:
3: /* Synchronet single-key console functions */
4:
1.1.1.2 ! root 5: /* $Id: getkey.cpp,v 1.30 2004/10/21 08:13:27 rswindell Exp $ */
1.1 root 6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
1.1.1.2 ! root 11: * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html *
1.1 root 12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: #include "sbbs.h"
1.1.1.2 ! root 39: #include "telnet.h" // TELNET_GA
1.1 root 40:
41: /****************************************************************************/
42: /* Waits for remote or local user to hit a key. Inactivity timer is checked */
43: /* and hangs up if inactive for 4 minutes. Returns key hit, or uppercase of */
44: /* key hit if mode&K_UPPER or key out of KEY BUFFER. Does not print key. */
45: /* Called from functions all over the place. */
46: /****************************************************************************/
47: char sbbs_t::getkey(long mode)
48: {
1.1.1.2 ! root 49: char ch,coldkey,c=0,spin=sbbs_random(5);
! 50: time_t last_telnet_cmd=0;
1.1 root 51:
1.1.1.2 ! root 52: if(!online || !input_thread_running) {
! 53: YIELD(); // just in case someone is looping on getkey() when they shouldn't
1.1 root 54: return(0);
1.1.1.2 ! root 55: }
1.1 root 56: sys_status&=~SS_ABORT;
57: if((sys_status&SS_USERON || action==NODE_DFLT) && !(mode&K_GETSTR))
58: mode|=(useron.misc&SPIN);
59: lncntr=0;
60: timeout=time(NULL);
61: if(mode&K_SPIN)
62: outchar(' ');
1.1.1.2 ! root 63:
1.1 root 64: do {
65: if(sys_status&SS_ABORT) {
66: if(mode&K_SPIN) /* back space once if on spinning cursor */
67: bputs("\b \b");
1.1.1.2 ! root 68: return(0);
1.1 root 69: }
70:
1.1.1.2 ! root 71: if(mode&K_SPIN) {
! 72: if(useron.misc&NO_EXASCII) {
! 73: switch(c++) {
! 74: case 0:
! 75: outchar(BS);
! 76: outchar('|');
! 77: break;
! 78: case 1:
! 79: outchar(BS);
! 80: outchar('/');
! 81: break;
! 82: case 2:
! 83: outchar(BS);
! 84: outchar('-');
! 85: break;
! 86: case 3:
! 87: outchar(BS);
! 88: outchar('\\');
! 89: c=0;
! 90: break;
! 91: }
! 92: } else {
! 93: switch(spin) {
! 94: case 0:
! 95: switch(c++) {
! 96: case 0:
! 97: outchar(BS);
! 98: outchar('�');
! 99: break;
! 100: case 1:
! 101: outchar(BS);
! 102: outchar('/');
! 103: break;
! 104: case 2:
! 105: outchar(BS);
! 106: outchar('�');
! 107: break;
! 108: case 3:
! 109: outchar(BS);
! 110: outchar('\\');
! 111: c=0;
! 112: break;
! 113: }
! 114: break;
! 115: case 1:
! 116: switch(c++) {
! 117: case 0:
! 118: outchar(BS);
! 119: outchar('�');
! 120: break;
! 121: case 1:
! 122: outchar(BS);
! 123: outchar('�');
! 124: break;
! 125: case 2:
! 126: outchar(BS);
! 127: outchar('�');
! 128: break;
! 129: case 3:
! 130: outchar(BS);
! 131: outchar('�');
! 132: break;
! 133: case 4:
! 134: outchar(BS);
! 135: outchar('�');
! 136: break;
! 137: case 5:
! 138: outchar(BS);
! 139: outchar('�');
! 140: c=0;
! 141: break;
! 142: }
! 143: break;
! 144: case 2:
! 145: switch(c++) {
! 146: case 0:
! 147: outchar(BS);
! 148: outchar('-');
! 149: break;
! 150: case 1:
! 151: outchar(BS);
! 152: outchar('=');
! 153: break;
! 154: case 2:
! 155: outchar(BS);
! 156: outchar('�');
! 157: break;
! 158: case 3:
! 159: outchar(BS);
! 160: outchar('=');
! 161: c=0;
! 162: break;
! 163: }
! 164: break;
! 165: case 3:
! 166: switch(c++) {
! 167: case 0:
! 168: outchar(BS);
! 169: outchar('�');
! 170: break;
! 171: case 1:
! 172: outchar(BS);
! 173: outchar('�');
! 174: break;
! 175: case 2:
! 176: outchar(BS);
! 177: outchar('�');
! 178: break;
! 179: case 3:
! 180: outchar(BS);
! 181: outchar('�');
! 182: c=0;
! 183: break;
! 184: }
! 185: break;
! 186: case 4:
! 187: switch(c++) {
! 188: case 0:
! 189: outchar(BS);
! 190: outchar('�');
! 191: break;
! 192: case 1:
! 193: outchar(BS);
! 194: outchar('�');
! 195: break;
! 196: case 2:
! 197: outchar(BS);
! 198: outchar('�');
! 199: break;
! 200: case 3:
! 201: outchar(BS);
! 202: outchar('�');
! 203: c=0;
! 204: break;
! 205: }
! 206: break;
! 207: }
! 208: }
! 209: }
! 210: ch=inkey(mode,mode&K_SPIN ? 250:1000);
1.1 root 211: if(sys_status&SS_ABORT)
212: return(0);
213: now=time(NULL);
214: if(ch) {
215: if(mode&K_NUMBER && isprint(ch) && !isdigit(ch))
216: continue;
217: if(mode&K_ALPHA && isprint(ch) && !isalpha(ch))
218: continue;
219: if(mode&K_NOEXASC && ch&0x80)
220: continue;
221: if(mode&K_SPIN)
222: bputs("\b \b");
1.1.1.2 ! root 223: if(mode&K_COLD && ch>' ' && useron.misc&COLDKEYS) {
1.1 root 224: if(mode&K_UPPER)
225: outchar(toupper(ch));
226: else
227: outchar(ch);
1.1.1.2 ! root 228: while((coldkey=inkey(mode,1000))==0 && online && !(sys_status&SS_ABORT))
! 229: ;
1.1 root 230: bputs("\b \b");
1.1.1.2 ! root 231: if(coldkey==BS || coldkey==DEL)
1.1 root 232: continue;
1.1.1.2 ! root 233: if(coldkey>' ')
! 234: ungetkey(coldkey);
! 235: }
1.1 root 236: if(mode&K_UPPER)
237: return(toupper(ch));
1.1.1.2 ! root 238: return(ch);
! 239: }
1.1 root 240: if(sys_status&SS_USERON && !(sys_status&SS_LCHAT)) gettimeleft();
241: else if(online &&
242: ((cfg.node_dollars_per_call && now-answertime>SEC_BILLING)
243: || (now-answertime>SEC_LOGON && !(sys_status&SS_LCHAT)))) {
244: console&=~(CON_R_ECHOX|CON_L_ECHOX);
245: console|=(CON_R_ECHO|CON_L_ECHO);
246: bputs(text[TakenTooLongToLogon]);
1.1.1.2 ! root 247: hangup();
! 248: }
1.1 root 249: if(sys_status&SS_USERON && online && (timeleft/60)<(5-timeleft_warn)
250: && !SYSOP && !(sys_status&SS_LCHAT)) {
251: timeleft_warn=5-(timeleft/60);
252: SAVELINE;
253: attr(LIGHTGRAY);
254: bprintf(text[OnlyXminutesLeft]
255: ,((ushort)timeleft/60)+1,(timeleft/60) ? "s" : nulstr);
1.1.1.2 ! root 256: RESTORELINE;
! 257: }
1.1 root 258:
1.1.1.2 ! root 259: if(!(startup->options&BBS_OPT_NO_TELNET_GA)
! 260: && now!=last_telnet_cmd && now-timeout>=60 && !((now-timeout)%60)) {
! 261: // Let's make sure the socket is up
! 262: // Sending will trigger a socket d/c detection
! 263: send_telnet_cmd(TELNET_GA,0);
! 264: last_telnet_cmd=now;
! 265: }
! 266:
! 267: if(online==ON_REMOTE && !(console&CON_NO_INACT)
! 268: && now-timeout>=cfg.sec_warn) { /* warning */
! 269: if(sys_status&SS_USERON && cfg.sec_warn!=cfg.sec_hangup) {
1.1 root 270: SAVELINE;
1.1.1.2 ! root 271: bputs(text[AreYouThere]);
! 272: }
1.1 root 273: else
274: bputs("\7\7");
1.1.1.2 ! root 275: while(!inkey(K_NONE,100) && online && now-timeout>=cfg.sec_warn) {
1.1 root 276: now=time(NULL);
277: if(now-timeout>=cfg.sec_hangup) {
278: if(online==ON_REMOTE) {
279: console|=CON_R_ECHO;
1.1.1.2 ! root 280: console&=~CON_R_ECHOX;
! 281: }
1.1 root 282: bputs(text[CallBackWhenYoureThere]);
283: logline(nulstr,"Inactive");
284: hangup();
1.1.1.2 ! root 285: return(0);
! 286: }
! 287: }
! 288: if(sys_status&SS_USERON && cfg.sec_warn!=cfg.sec_hangup) {
1.1 root 289: bputs("\r\1n\1>");
1.1.1.2 ! root 290: RESTORELINE;
! 291: }
! 292: timeout=now;
! 293: }
! 294:
! 295: } while(online);
1.1 root 296:
297: return(0);
298: }
299:
300:
301: /****************************************************************************/
302: /* Outputs a string highlighting characters preceeded by a tilde */
303: /****************************************************************************/
304: void sbbs_t::mnemonics(char *str)
305: {
306: char *ctrl_a_codes;
307: long l;
308:
309: if(!strchr(str,'~')) {
310: mnestr=str;
311: bputs(str);
1.1.1.2 ! root 312: return;
! 313: }
1.1 root 314: ctrl_a_codes=strchr(str,1);
315: if(!ctrl_a_codes) {
1.1.1.2 ! root 316: if(str[0]=='@' && str[strlen(str)-1]=='@' && !strchr(str,' ')) {
1.1 root 317: mnestr=str;
318: bputs(str);
1.1.1.2 ! root 319: return;
! 320: }
! 321: attr(cfg.color[clr_mnelow]);
! 322: }
1.1 root 323: l=0L;
324: while(str[l]) {
1.1.1.2 ! root 325: if(str[l]=='~' && str[l+1]!=0) {
1.1 root 326: if(!(useron.misc&ANSI))
327: outchar('(');
328: l++;
329: if(!ctrl_a_codes)
330: attr(cfg.color[clr_mnehigh]);
331: outchar(str[l]);
332: l++;
333: if(!(useron.misc&ANSI))
334: outchar(')');
335: if(!ctrl_a_codes)
1.1.1.2 ! root 336: attr(cfg.color[clr_mnelow]);
! 337: }
1.1 root 338: else {
1.1.1.2 ! root 339: if(str[l]==CTRL_A /* ctrl-a */
! 340: && str[l+1]!=0) { /* valid */
1.1 root 341: ctrl_a(str[++l]); /* skip the ctrl-a */
1.1.1.2 ! root 342: l++; /* skip the attribute code */
! 343: } else
! 344: outchar(str[l++]);
! 345: }
! 346: }
1.1 root 347: if(!ctrl_a_codes)
348: attr(cfg.color[clr_mnecmd]);
349: }
350:
351: /****************************************************************************/
352: /* Prompts user for Y or N (yes or no) and CR is interpreted as a Y */
353: /* Returns 1 for Y or 0 for N */
354: /* Called from quite a few places */
355: /****************************************************************************/
356: bool sbbs_t::yesno(char *str)
357: {
358: char ch;
359:
360: strcpy(question,str);
361: SYNC;
362: if(useron.misc&WIP) {
363: strip_ctrl(question);
1.1.1.2 ! root 364: menu("yesno");
! 365: }
1.1 root 366: else
367: bprintf(text[YesNoQuestion],str);
368: while(online) {
369: if(sys_status&SS_ABORT)
370: ch=text[YN][1];
371: else
372: ch=getkey(K_UPPER|K_COLD);
373: if(ch==text[YN][0] || ch==CR) {
374: if(bputs(text[Yes]))
375: CRLF;
376: lncntr=0;
1.1.1.2 ! root 377: return(true);
! 378: }
1.1 root 379: if(ch==text[YN][1]) {
380: if(bputs(text[No]))
381: CRLF;
382: lncntr=0;
1.1.1.2 ! root 383: return(false);
! 384: }
! 385: }
1.1 root 386: return(true);
387: }
388:
389: /****************************************************************************/
390: /* Prompts user for N or Y (no or yes) and CR is interpreted as a N */
391: /* Returns 1 for N or 0 for Y */
392: /* Called from quite a few places */
393: /****************************************************************************/
394: bool sbbs_t::noyes(char *str)
395: {
396: char ch;
397:
398: strcpy(question,str);
399: SYNC;
400: if(useron.misc&WIP) {
401: strip_ctrl(question);
1.1.1.2 ! root 402: menu("noyes");
! 403: }
1.1 root 404: else
405: bprintf(text[NoYesQuestion],str);
406: while(online) {
407: if(sys_status&SS_ABORT)
408: ch=text[YN][1];
409: else
410: ch=getkey(K_UPPER|K_COLD);
411: if(ch==text[YN][1] || ch==CR) {
412: if(bputs(text[No]))
413: CRLF;
414: lncntr=0;
1.1.1.2 ! root 415: return(true);
! 416: }
1.1 root 417: if(ch==text[YN][0]) {
418: if(bputs(text[Yes]))
419: CRLF;
420: lncntr=0;
1.1.1.2 ! root 421: return(false);
! 422: }
! 423: }
1.1 root 424: return(true);
425: }
426:
427: /****************************************************************************/
428: /* Waits for remote or local user to hit a key that is contained inside str.*/
429: /* 'str' should contain uppercase characters only. When a valid key is hit, */
430: /* it is echoed (upper case) and is the return value. */
431: /* Called from quite a few functions */
432: /****************************************************************************/
433: long sbbs_t::getkeys(char *keys, ulong max)
434: {
435: char str[81];
1.1.1.2 ! root 436: uchar ch,n=0,c=0;
1.1 root 437: ulong i=0;
438:
1.1.1.2 ! root 439: SAFECOPY(str,keys);
1.1 root 440: strupr(str);
441: while(online) {
442: ch=getkey(K_UPPER);
443: if(max && ch>0x7f) /* extended ascii chars are digits to isdigit() */
444: continue;
445: if(sys_status&SS_ABORT) { /* return -1 if Ctrl-C hit */
446: attr(LIGHTGRAY);
447: CRLF;
448: lncntr=0;
1.1.1.2 ! root 449: return(-1);
! 450: }
1.1 root 451: if(ch && !n && (strchr(str,ch))) { /* return character if in string */
452: outchar(ch);
1.1.1.2 ! root 453: if(useron.misc&COLDKEYS && ch>' ') {
1.1 root 454: while(online && !(sys_status&SS_ABORT)) {
455: c=getkey(0);
1.1.1.2 ! root 456: if(c==CR || c==BS || c==DEL)
! 457: break;
! 458: }
1.1 root 459: if(sys_status&SS_ABORT) {
460: CRLF;
1.1.1.2 ! root 461: return(-1);
! 462: }
! 463: if(c==BS || c==DEL) {
1.1 root 464: bputs("\b \b");
1.1.1.2 ! root 465: continue;
! 466: }
! 467: }
1.1 root 468: attr(LIGHTGRAY);
469: CRLF;
470: lncntr=0;
1.1.1.2 ! root 471: return(ch);
! 472: }
1.1 root 473: if(ch==CR && max) { /* return 0 if no number */
474: attr(LIGHTGRAY);
475: CRLF;
476: lncntr=0;
477: if(n)
478: return(i|0x80000000L); /* return number plus high bit */
1.1.1.2 ! root 479: return(0);
! 480: }
! 481: if((ch==BS || ch==DEL) && n) {
1.1 root 482: bputs("\b \b");
483: i/=10;
1.1.1.2 ! root 484: n--;
! 485: }
1.1 root 486: else if(max && isdigit(ch) && (i*10)+(ch&0xf)<=max && (ch!='0' || n)) {
487: i*=10;
488: n++;
489: i+=ch&0xf;
490: outchar(ch);
491: if(i*10>max && !(useron.misc&COLDKEYS)) {
492: attr(LIGHTGRAY);
493: CRLF;
494: lncntr=0;
1.1.1.2 ! root 495: return(i|0x80000000L);
! 496: }
! 497: }
! 498: }
1.1 root 499: return(-1);
500: }
501:
502: /****************************************************************************/
503: /* Prints PAUSE message and waits for a key stoke */
504: /****************************************************************************/
505: void sbbs_t::pause()
506: {
507: char ch;
508: uchar tempattrs=curatr; /* was lclatr(-1) */
509: int i,j;
510: long l=K_UPPER;
511:
512: RIOSYNC(0);
513: if(sys_status&SS_ABORT)
514: return;
515: lncntr=0;
516: if(online==ON_REMOTE)
517: rioctl(IOFI);
518: bputs(text[Pause]);
519: j=bstrlen(text[Pause]);
1.1.1.2 ! root 520: if(sys_status&SS_USERON && !(useron.misc&(WIP|NOPAUSESPIN))
1.1 root 521: && !(cfg.node_misc&NM_NOPAUSESPIN))
522: l|=K_SPIN;
523: ch=getkey(l);
524: if(ch==text[YN][1] || ch=='Q')
525: sys_status|=SS_ABORT;
526: else if(ch==LF) // down arrow == display one more line
527: lncntr=rows-2;
528: if(text[Pause][0]!='@')
529: for(i=0;i<j;i++)
530: bputs("\b \b");
531: getnodedat(cfg.node_num,&thisnode,0);
532: nodesync();
533: attr(tempattrs);
534: }
535:
536: /****************************************************************************/
537: /* Puts a character into the input buffer */
538: /****************************************************************************/
539: void sbbs_t::ungetkey(char ch)
540: {
541:
542: keybuf[keybuftop++]=ch;
543: if(keybuftop==KEY_BUFSIZE)
544: keybuftop=0;
545: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.