|
|
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.42 2009/11/09 02:54:55 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 2009 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"
39: #include "telnet.h" // TELNET_GA
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: {
49: char ch,coldkey,c=0,spin=sbbs_random(5);
50: time_t last_telnet_cmd=0;
51:
52: if(!online || !input_thread_running) {
53: YIELD(); // just in case someone is looping on getkey() when they shouldn't
54: return(0);
55: }
56: sys_status&=~SS_ABORT;
57: if((sys_status&SS_USERON || action==NODE_DFLT) && !(mode&(K_GETSTR|K_NOSPIN)))
58: mode|=(useron.misc&SPIN);
59: lncntr=0;
60: timeout=time(NULL);
61: if(mode&K_SPIN)
62: outchar(' ');
63:
64: do {
65: if(sys_status&SS_ABORT) {
66: if(mode&K_SPIN) /* back space once if on spinning cursor */
67: backspace();
68: return(0);
69: }
70:
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);
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: backspace();
223: if(mode&K_COLD && ch>' ' && useron.misc&COLDKEYS) {
224: if(mode&K_UPPER)
225: outchar(toupper(ch));
226: else
227: outchar(ch);
228: while((coldkey=inkey(mode,1000))==0 && online && !(sys_status&SS_ABORT))
229: ;
230: backspace();
231: if(coldkey==BS || coldkey==DEL)
232: continue;
233: if(coldkey>' ')
234: ungetkey(coldkey);
235: }
236: if(mode&K_UPPER)
237: return(toupper(ch));
238: return(ch);
239: }
240: if(sys_status&SS_USERON && !(sys_status&SS_LCHAT)) gettimeleft();
241: else if(online && now-answertime>SEC_LOGON && !(sys_status&SS_LCHAT)) {
242: console&=~(CON_R_ECHOX|CON_L_ECHOX);
243: console|=(CON_R_ECHO|CON_L_ECHO);
244: bputs(text[TakenTooLongToLogon]);
245: hangup();
246: }
247: if(sys_status&SS_USERON && online && (timeleft/60)<(5-timeleft_warn)
248: && !SYSOP && !(sys_status&SS_LCHAT)) {
249: timeleft_warn=5-(timeleft/60);
250: SAVELINE;
251: attr(LIGHTGRAY);
252: bprintf(text[OnlyXminutesLeft]
253: ,((ushort)timeleft/60)+1,(timeleft/60) ? "s" : nulstr);
254: RESTORELINE;
255: }
256:
257: if(!(startup->options&BBS_OPT_NO_TELNET_GA)
258: && now!=last_telnet_cmd && now-timeout>=60 && !((now-timeout)%60)) {
259: // Let's make sure the socket is up
260: // Sending will trigger a socket d/c detection
261: send_telnet_cmd(TELNET_GA,0);
262: last_telnet_cmd=now;
263: }
264:
265: if(online==ON_REMOTE && !(console&CON_NO_INACT)
266: && now-timeout>=cfg.sec_warn) { /* warning */
267: if(sys_status&SS_USERON && cfg.sec_warn!=cfg.sec_hangup) {
268: SAVELINE;
269: bputs(text[AreYouThere]);
270: }
271: else
272: bputs("\7\7");
273: while(!inkey(K_NONE,100) && online && now-timeout>=cfg.sec_warn) {
274: now=time(NULL);
275: if(now-timeout>=cfg.sec_hangup) {
276: if(online==ON_REMOTE) {
277: console|=CON_R_ECHO;
278: console&=~CON_R_ECHOX;
279: }
280: bputs(text[CallBackWhenYoureThere]);
1.1.1.2 ! root 281: logline(LOG_NOTICE,nulstr,"Inactive");
1.1 root 282: hangup();
283: return(0);
284: }
285: }
286: if(sys_status&SS_USERON && cfg.sec_warn!=cfg.sec_hangup) {
287: bputs("\r\1n\1>");
288: RESTORELINE;
289: }
290: timeout=now;
291: }
292:
293: } while(online);
294:
295: return(0);
296: }
297:
298:
299: /****************************************************************************/
300: /* Outputs a string highlighting characters preceeded by a tilde */
301: /****************************************************************************/
1.1.1.2 ! root 302: void sbbs_t::mnemonics(const char *str)
1.1 root 303: {
1.1.1.2 ! root 304: const char *ctrl_a_codes;
1.1 root 305: long l;
306:
307: if(!strchr(str,'~')) {
308: mnestr=str;
309: bputs(str);
310: return;
311: }
312: ctrl_a_codes=strchr(str,1);
313: if(!ctrl_a_codes) {
314: if(str[0]=='@' && str[strlen(str)-1]=='@' && !strchr(str,' ')) {
315: mnestr=str;
316: bputs(str);
317: return;
318: }
319: attr(cfg.color[clr_mnelow]);
320: }
321: l=0L;
322: while(str[l]) {
323: if(str[l]=='~' && str[l+1]!=0) {
324: if(!term_supports(ANSI))
325: outchar('(');
326: l++;
327: if(!ctrl_a_codes)
328: attr(cfg.color[clr_mnehigh]);
329: outchar(str[l]);
330: l++;
331: if(!term_supports(ANSI))
332: outchar(')');
333: if(!ctrl_a_codes)
334: attr(cfg.color[clr_mnelow]);
335: }
336: else {
1.1.1.2 ! root 337: if(str[l]==CTRL_A && str[l+1]!=0) {
! 338: l++;
! 339: if(toupper(str[l])=='Z') /* EOF */
! 340: break;
! 341: ctrl_a(str[l++]);
1.1 root 342: } else
343: outchar(str[l++]);
344: }
345: }
346: if(!ctrl_a_codes)
347: attr(cfg.color[clr_mnecmd]);
348: }
349:
350: /****************************************************************************/
351: /* Prompts user for Y or N (yes or no) and CR is interpreted as a Y */
352: /* Returns 1 for Y or 0 for N */
353: /* Called from quite a few places */
354: /****************************************************************************/
1.1.1.2 ! root 355: bool sbbs_t::yesno(const char *str)
1.1 root 356: {
357: char ch;
358:
1.1.1.2 ! root 359: SAFECOPY(question,str);
1.1 root 360: SYNC;
1.1.1.2 ! root 361: bprintf(text[YesNoQuestion],str);
1.1 root 362: while(online) {
363: if(sys_status&SS_ABORT)
364: ch=text[YN][1];
365: else
366: ch=getkey(K_UPPER|K_COLD);
367: if(ch==text[YN][0] || ch==CR) {
368: if(bputs(text[Yes]))
369: CRLF;
370: lncntr=0;
371: return(true);
372: }
373: if(ch==text[YN][1]) {
374: if(bputs(text[No]))
375: CRLF;
376: lncntr=0;
377: return(false);
378: }
379: }
380: return(true);
381: }
382:
383: /****************************************************************************/
384: /* Prompts user for N or Y (no or yes) and CR is interpreted as a N */
385: /* Returns 1 for N or 0 for Y */
386: /* Called from quite a few places */
387: /****************************************************************************/
1.1.1.2 ! root 388: bool sbbs_t::noyes(const char *str)
1.1 root 389: {
390: char ch;
391:
1.1.1.2 ! root 392: SAFECOPY(question,str);
1.1 root 393: SYNC;
1.1.1.2 ! root 394: bprintf(text[NoYesQuestion],str);
1.1 root 395: while(online) {
396: if(sys_status&SS_ABORT)
397: ch=text[YN][1];
398: else
399: ch=getkey(K_UPPER|K_COLD);
400: if(ch==text[YN][1] || ch==CR) {
401: if(bputs(text[No]))
402: CRLF;
403: lncntr=0;
404: return(true);
405: }
406: if(ch==text[YN][0]) {
407: if(bputs(text[Yes]))
408: CRLF;
409: lncntr=0;
410: return(false);
411: }
412: }
413: return(true);
414: }
415:
416: /****************************************************************************/
417: /* Waits for remote or local user to hit a key that is contained inside str.*/
418: /* 'str' should contain uppercase characters only. When a valid key is hit, */
419: /* it is echoed (upper case) and is the return value. */
420: /* Called from quite a few functions */
421: /****************************************************************************/
1.1.1.2 ! root 422: long sbbs_t::getkeys(const char *keys, ulong max)
1.1 root 423: {
424: char str[81];
425: uchar ch,n=0,c=0;
426: ulong i=0;
427:
428: SAFECOPY(str,keys);
429: strupr(str);
430: while(online) {
431: ch=getkey(K_UPPER);
432: if(max && ch>0x7f) /* extended ascii chars are digits to isdigit() */
433: continue;
434: if(sys_status&SS_ABORT) { /* return -1 if Ctrl-C hit */
435: attr(LIGHTGRAY);
436: CRLF;
437: lncntr=0;
438: return(-1);
439: }
440: if(ch && !n && (strchr(str,ch))) { /* return character if in string */
441: outchar(ch);
442: if(useron.misc&COLDKEYS && ch>' ') {
443: while(online && !(sys_status&SS_ABORT)) {
444: c=getkey(0);
445: if(c==CR || c==BS || c==DEL)
446: break;
447: }
448: if(sys_status&SS_ABORT) {
449: CRLF;
450: return(-1);
451: }
452: if(c==BS || c==DEL) {
453: backspace();
454: continue;
455: }
456: }
457: attr(LIGHTGRAY);
458: CRLF;
459: lncntr=0;
460: return(ch);
461: }
462: if(ch==CR && max) { /* return 0 if no number */
463: attr(LIGHTGRAY);
464: CRLF;
465: lncntr=0;
466: if(n)
467: return(i|0x80000000L); /* return number plus high bit */
468: return(0);
469: }
470: if((ch==BS || ch==DEL) && n) {
471: backspace();
472: i/=10;
473: n--;
474: }
475: else if(max && isdigit(ch) && (i*10)+(ch&0xf)<=max && (ch!='0' || n)) {
476: i*=10;
477: n++;
478: i+=ch&0xf;
479: outchar(ch);
480: if(i*10>max && !(useron.misc&COLDKEYS)) {
481: attr(LIGHTGRAY);
482: CRLF;
483: lncntr=0;
484: return(i|0x80000000L);
485: }
486: }
487: }
488: return(-1);
489: }
490:
491: /****************************************************************************/
492: /* Prints PAUSE message and waits for a key stoke */
493: /****************************************************************************/
494: void sbbs_t::pause()
495: {
496: char ch;
497: uchar tempattrs=curatr; /* was lclatr(-1) */
498: int i,j;
499: long l=K_UPPER;
500:
501: if(sys_status&SS_ABORT)
502: return;
503: lncntr=0;
504: if(online==ON_REMOTE)
505: rioctl(IOFI);
506: bputs(text[Pause]);
507: j=bstrlen(text[Pause]);
1.1.1.2 ! root 508: if(sys_status&SS_USERON && !(useron.misc&(HTML|WIP|NOPAUSESPIN))
1.1 root 509: && !(cfg.node_misc&NM_NOPAUSESPIN))
510: l|=K_SPIN;
511: ch=getkey(l);
512: if(ch==text[YN][1] || ch=='Q')
513: sys_status|=SS_ABORT;
514: else if(ch==LF) // down arrow == display one more line
515: lncntr=rows-2;
516: if(text[Pause][0]!='@')
517: for(i=0;i<j;i++)
518: backspace();
519: getnodedat(cfg.node_num,&thisnode,0);
520: nodesync();
521: attr(tempattrs);
522: }
523:
524: /****************************************************************************/
525: /* Puts a character into the input buffer */
526: /****************************************************************************/
527: void sbbs_t::ungetkey(char ch)
528: {
529: #if 0 /* this way breaks ansi_getxy() */
530: RingBufWrite(&inbuf,(uchar*)&ch,sizeof(uchar));
531: #else
532: keybuf[keybuftop++]=ch;
533: if(keybuftop==KEY_BUFSIZE)
534: keybuftop=0;
535: #endif
536: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.