|
|
1.1 root 1: /* getkey.cpp */
2:
3: /* Synchronet single-key console functions */
4:
5: /* $Id: getkey.cpp,v 1.37 2006/08/23 01:45:05 rswindell Exp $ */
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: * *
11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html *
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]);
281: logline(nulstr,"Inactive");
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: /****************************************************************************/
302: void sbbs_t::mnemonics(char *str)
303: {
304: char *ctrl_a_codes;
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 {
337: if(str[l]==CTRL_A /* ctrl-a */
338: && str[l+1]!=0) { /* valid */
339: ctrl_a(str[++l]); /* skip the ctrl-a */
340: l++; /* skip the attribute code */
341: } else
342: outchar(str[l++]);
343: }
344: }
345: if(!ctrl_a_codes)
346: attr(cfg.color[clr_mnecmd]);
347: }
348:
349: /****************************************************************************/
350: /* Prompts user for Y or N (yes or no) and CR is interpreted as a Y */
351: /* Returns 1 for Y or 0 for N */
352: /* Called from quite a few places */
353: /****************************************************************************/
354: bool sbbs_t::yesno(char *str)
355: {
356: char ch;
357:
358: strcpy(question,str);
359: SYNC;
360: if(useron.misc&WIP) {
361: strip_ctrl(question);
362: menu("yesno");
363: }
364: else
365: bprintf(text[YesNoQuestion],str);
366: while(online) {
367: if(sys_status&SS_ABORT)
368: ch=text[YN][1];
369: else
370: ch=getkey(K_UPPER|K_COLD);
371: if(ch==text[YN][0] || ch==CR) {
372: if(bputs(text[Yes]))
373: CRLF;
374: lncntr=0;
375: return(true);
376: }
377: if(ch==text[YN][1]) {
378: if(bputs(text[No]))
379: CRLF;
380: lncntr=0;
381: return(false);
382: }
383: }
384: return(true);
385: }
386:
387: /****************************************************************************/
388: /* Prompts user for N or Y (no or yes) and CR is interpreted as a N */
389: /* Returns 1 for N or 0 for Y */
390: /* Called from quite a few places */
391: /****************************************************************************/
392: bool sbbs_t::noyes(char *str)
393: {
394: char ch;
395:
396: strcpy(question,str);
397: SYNC;
398: if(useron.misc&WIP) {
399: strip_ctrl(question);
400: menu("noyes");
401: }
402: else
403: bprintf(text[NoYesQuestion],str);
404: while(online) {
405: if(sys_status&SS_ABORT)
406: ch=text[YN][1];
407: else
408: ch=getkey(K_UPPER|K_COLD);
409: if(ch==text[YN][1] || ch==CR) {
410: if(bputs(text[No]))
411: CRLF;
412: lncntr=0;
413: return(true);
414: }
415: if(ch==text[YN][0]) {
416: if(bputs(text[Yes]))
417: CRLF;
418: lncntr=0;
419: return(false);
420: }
421: }
422: return(true);
423: }
424:
425: /****************************************************************************/
426: /* Waits for remote or local user to hit a key that is contained inside str.*/
427: /* 'str' should contain uppercase characters only. When a valid key is hit, */
428: /* it is echoed (upper case) and is the return value. */
429: /* Called from quite a few functions */
430: /****************************************************************************/
431: long sbbs_t::getkeys(char *keys, ulong max)
432: {
433: char str[81];
434: uchar ch,n=0,c=0;
435: ulong i=0;
436:
437: SAFECOPY(str,keys);
438: strupr(str);
439: while(online) {
440: ch=getkey(K_UPPER);
441: if(max && ch>0x7f) /* extended ascii chars are digits to isdigit() */
442: continue;
443: if(sys_status&SS_ABORT) { /* return -1 if Ctrl-C hit */
444: attr(LIGHTGRAY);
445: CRLF;
446: lncntr=0;
447: return(-1);
448: }
449: if(ch && !n && (strchr(str,ch))) { /* return character if in string */
450: outchar(ch);
451: if(useron.misc&COLDKEYS && ch>' ') {
452: while(online && !(sys_status&SS_ABORT)) {
453: c=getkey(0);
454: if(c==CR || c==BS || c==DEL)
455: break;
456: }
457: if(sys_status&SS_ABORT) {
458: CRLF;
459: return(-1);
460: }
461: if(c==BS || c==DEL) {
462: backspace();
463: continue;
464: }
465: }
466: attr(LIGHTGRAY);
467: CRLF;
468: lncntr=0;
469: return(ch);
470: }
471: if(ch==CR && max) { /* return 0 if no number */
472: attr(LIGHTGRAY);
473: CRLF;
474: lncntr=0;
475: if(n)
476: return(i|0x80000000L); /* return number plus high bit */
477: return(0);
478: }
479: if((ch==BS || ch==DEL) && n) {
480: backspace();
481: i/=10;
482: n--;
483: }
484: else if(max && isdigit(ch) && (i*10)+(ch&0xf)<=max && (ch!='0' || n)) {
485: i*=10;
486: n++;
487: i+=ch&0xf;
488: outchar(ch);
489: if(i*10>max && !(useron.misc&COLDKEYS)) {
490: attr(LIGHTGRAY);
491: CRLF;
492: lncntr=0;
493: return(i|0x80000000L);
494: }
495: }
496: }
497: return(-1);
498: }
499:
500: /****************************************************************************/
501: /* Prints PAUSE message and waits for a key stoke */
502: /****************************************************************************/
503: void sbbs_t::pause()
504: {
505: char ch;
506: uchar tempattrs=curatr; /* was lclatr(-1) */
507: int i,j;
508: long l=K_UPPER;
509:
510: if(sys_status&SS_ABORT)
511: return;
512: lncntr=0;
513: if(online==ON_REMOTE)
514: rioctl(IOFI);
515: bputs(text[Pause]);
516: j=bstrlen(text[Pause]);
517: if(sys_status&SS_USERON && !(useron.misc&(WIP|NOPAUSESPIN))
518: && !(cfg.node_misc&NM_NOPAUSESPIN))
519: l|=K_SPIN;
520: ch=getkey(l);
521: if(ch==text[YN][1] || ch=='Q')
522: sys_status|=SS_ABORT;
523: else if(ch==LF) // down arrow == display one more line
524: lncntr=rows-2;
525: if(text[Pause][0]!='@')
526: for(i=0;i<j;i++)
527: backspace();
528: getnodedat(cfg.node_num,&thisnode,0);
529: nodesync();
530: attr(tempattrs);
531: }
532:
533: /****************************************************************************/
534: /* Puts a character into the input buffer */
535: /****************************************************************************/
536: void sbbs_t::ungetkey(char ch)
537: {
538: #if 0 /* this way breaks ansi_getxy() */
539: RingBufWrite(&inbuf,(uchar*)&ch,sizeof(uchar));
540: #else
541: keybuf[keybuftop++]=ch;
542: if(keybuftop==KEY_BUFSIZE)
543: keybuftop=0;
544: #endif
545: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.