|
|
1.1 root 1: /* con_out.cpp */
2:
3: /* Synchronet console output routines */
4:
5: /* $Id: con_out.cpp,v 1.3 2000/11/14 02:16:57 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 2000 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:
39: /**********************************************************************/
40: /* Functions that pertain to console i/o - color, strings, chars etc. */
41: /* Called from functions everywhere */
42: /**********************************************************************/
43:
44: #include "sbbs.h"
45:
46: /***************************************************/
47: /* Seven bit table for EXASCII to ASCII conversion */
48: /***************************************************/
49: const char *sbtbl="CUeaaaaceeeiiiAAEaAooouuyOUcLYRfaiounNao?--24!<>"
50: "###||||++||++++++--|-+||++--|-+----++++++++##[]#"
51: "abrpEout*ono%0ENE+><rj%=o..+n2* ";
52:
53: /****************************************************************************/
54: /* Outputs a NULL terminated string locally and remotely (if applicable) */
55: /* Handles ctrl-a characters */
56: /****************************************************************************/
57: int sbbs_t::bputs(char *str)
58: {
59: int i;
60: ulong l=0;
61:
62: while(str[l]) {
63: if(str[l]==1) { /* ctrl-a */
64: ctrl_a(str[++l]); /* skip the ctrl-a */
65: l++; /* skip the attribute code */
66: continue; }
67: if(str[l]=='@') { /* '@' */
68: if(str==mnestr /* Mnemonic string or */
69: || (str>=text[0] /* Straight out of TEXT.DAT */
70: && str<=text[TOTAL_TEXT-1])) {
71: i=atcodes(str+l); /* return 0 if not valid @ code */
72: l+=i; /* i is length of code string */
73: if(i) /* if valid string, go to top */
74: continue; }
75: for(i=0;i<TOTAL_TEXT;i++)
76: if(str==text[i])
77: break;
78: if(i<TOTAL_TEXT) { /* Replacement text */
79: i=atcodes(str+l);
80: l+=i;
81: if(i)
82: continue; } }
83: outchar(str[l++]); }
84: return(l);
85: }
86:
87: /****************************************************************************/
88: /* Outputs a NULL terminated string locally and remotely (if applicable) */
89: /* Does not expand ctrl-a characters (raw) */
90: /* Max length of str is 64 kbytes */
91: /****************************************************************************/
92: int sbbs_t::rputs(char *str)
93: {
94: ulong l=0;
95:
96: while(str[l])
97: outchar(str[l++]);
98: return(l);
99: }
100:
101: /****************************************************************************/
102: /* Performs printf() using bbs bputs function */
103: /****************************************************************************/
104: int sbbs_t::bprintf(char *fmt, ...)
105: {
106: va_list argptr;
107: char sbuf[1024];
108:
109: if(!strchr(fmt,'%'))
110: return(bputs(fmt));
111: va_start(argptr,fmt);
112: vsprintf(sbuf,fmt,argptr);
113: va_end(argptr);
114: return(bputs(sbuf));
115: }
116:
117: /****************************************************************************/
118: /* Performs printf() using bbs rputs function */
119: /****************************************************************************/
120: int sbbs_t::rprintf(char *fmt, ...)
121: {
122: va_list argptr;
123: char sbuf[1024];
124:
125: va_start(argptr,fmt);
126: vsprintf(sbuf,fmt,argptr);
127: va_end(argptr);
128: return(rputs(sbuf));
129: }
130:
131: /****************************************************************************/
132: /* Outputs character locally and remotely (if applicable), preforming echo */
133: /* translations (X's and r0dent emulation) if applicable. */
134: /****************************************************************************/
135: void sbbs_t::outchar(char ch)
136: {
137: int i;
138:
139: if(console&CON_ECHO_OFF)
140: return;
141: if(ch==ESC)
142: outchar_esc=1;
143: else if(outchar_esc==1) {
144: if(ch=='[')
145: outchar_esc++;
146: else
147: outchar_esc=0; }
148: else
149: outchar_esc=0;
150: if(useron.misc&NO_EXASCII && ch&0x80)
151: ch=sbtbl[(uchar)ch^0x80]; /* seven bit table */
152: if(ch==FF && lncntr>1 && !tos) {
153: lncntr=0;
154: CRLF;
155: pause();
156: while(lncntr && online && !(sys_status&SS_ABORT))
157: pause(); }
158: if(sys_status&SS_CAP /* Writes to Capture File */
159: && (sys_status&SS_ANSCAP || (ch!=ESC /* && !lclaes() */)))
160: fwrite(&ch,1,1,capfile);
161:
162: #if 0
163: if(console&CON_L_ECHO) {
164: if(console&CON_L_ECHOX && (uchar)ch>=SP)
165: putch('X');
166: else if(cfg.node_misc&NM_NOBEEP && ch==BEL); /* Do nothing if beep */
167: else if(ch==BEL) {
168: sbbs_beep(2000,110);
169: nosound(); }
170: else putch(ch); }
171: #endif
172:
173: if(online==ON_REMOTE && console&CON_R_ECHO) {
174: if(console&CON_R_ECHOX && (uchar)ch>=SP)
175: ch='X';
176: if(ch==FF && useron.misc&ANSI) {
177: putcom("\x1b[2J\x1b[H"); /* clear screen, home cursor */
178: }
179: else {
180: i=0;
181: while(outcom(ch)&TXBOF && i<1440) { /* 3 minute pause delay */
182: if(!online)
183: break;
184: i++;
185: if(sys_status&SS_SYSPAGE)
186: sbbs_beep(i,80);
187: else
188: mswait(80); }
189: if(i==1440) { /* timeout - beep flush outbuf */
190: i=rioctl(TXBC);
191: lprintf("timeout(outchar) %04X %04X\r\n",i,rioctl(IOFO));
192: outcom(BEL);
193: rioctl(IOCS|PAUSE); } } }
194: if(ch==LF) {
195: lncntr++;
196: lbuflen=0;
197: tos=0;
198: } else if(ch==FF) {
199: lncntr=0;
200: lbuflen=0;
201: tos=1;
202: } else {
203: if(!lbuflen)
204: latr=curatr;
205: if(lbuflen<LINE_BUFSIZE)
206: lbuf[lbuflen++]=ch; }
207:
208: if(lncntr==rows-1 && ((useron.misc&UPAUSE && !(sys_status&SS_PAUSEOFF))
209: || sys_status&SS_PAUSEON)) {
210: lncntr=0;
211: pause(); }
212:
213: }
214:
215: void sbbs_t::center(char *instr)
216: {
217: char str[256];
218: int i,j;
219:
220: sprintf(str,"%.*s",sizeof(str)-1,instr);
221: truncsp(str);
222: j=bstrlen(str);
223: for(i=0;i<(80-j)/2;i++)
224: outchar(SP);
225: bputs(str);
226: CRLF;
227: }
228:
229:
230: /****************************************************************************/
231: /* performs the correct attribute modifications for the Ctrl-A code */
232: /****************************************************************************/
233: void sbbs_t::ctrl_a(char x)
234: {
235: int i;
236: char tmp1[128],atr=curatr;
237: struct tm * tm;
238:
239: if(x && (uchar)x<ESC) { /* Ctrl-A through Ctrl-Z for users with MF only */
240: if(!(useron.flags1&FLAG(x+64)))
241: console^=(CON_ECHO_OFF);
242: return; }
243: if((uchar)x>=0x7f) {
244: if(useron.misc&ANSI)
245: bprintf("\x1b[%uC",(uchar)x-0x7f);
246: else
247: for(i=0;i<(uchar)x-0x7f;i++)
248: outchar(SP);
249: return; }
250: switch(toupper(x)) {
251: case '!': /* level 10 or higher */
252: if(useron.level<10)
253: console^=CON_ECHO_OFF;
254: break;
255: case '@': /* level 20 or higher */
256: if(useron.level<20)
257: console^=CON_ECHO_OFF;
258: break;
259: case '#': /* level 30 or higher */
260: if(useron.level<30)
261: console^=CON_ECHO_OFF;
262: break;
263: case '$': /* level 40 or higher */
264: if(useron.level<40)
265: console^=CON_ECHO_OFF;
266: break;
267: case '%': /* level 50 or higher */
268: if(useron.level<50)
269: console^=CON_ECHO_OFF;
270: break;
271: case '^': /* level 60 or higher */
272: if(useron.level<60)
273: console^=CON_ECHO_OFF;
274: break;
275: case '&': /* level 70 or higher */
276: if(useron.level<70)
277: console^=CON_ECHO_OFF;
278: break;
279: case '*': /* level 80 or higher */
280: if(useron.level<80)
281: console^=CON_ECHO_OFF;
282: break;
283: case '(': /* level 90 or higher */
284: if(useron.level<90)
285: console^=CON_ECHO_OFF;
286: break;
287: case ')': /* turn echo back on */
288: console&=~CON_ECHO_OFF;
289: break;
290: case '-': /* turn off all attributes if */
291: if(atr&(HIGH|BLINK|(LIGHTGRAY<<4))) /* high intensity, blink or */
292: attr(LIGHTGRAY); /* background bits are set */
293: break;
294: case '_': /* turn off all attributes if */
295: if(atr&(BLINK|(LIGHTGRAY<<4))) /* blink or background is set */
296: attr(LIGHTGRAY);
297: break;
298: case 'P': /* Pause */
299: pause();
300: break;
301: case 'Q': /* Pause reset */
302: lncntr=0;
303: break;
304: case 'T': /* Time */
305: now=time(NULL);
306: tm=gmtime(&now);
307: if(tm!=NULL)
308: bprintf("%02d:%02d %s"
309: ,tm->tm_hour==0 ? 12
310: : tm->tm_hour>12 ? tm->tm_hour-12
311: : tm->tm_hour, tm->tm_min, tm->tm_hour>11 ? "pm":"am");
312: break;
313: case 'D': /* Date */
314: now=time(NULL);
315: bputs(unixtodstr(&cfg,now,tmp1));
316: break;
317: case ',': /* Delay 1/10 sec */
318: mswait(100);
319: break;
320: case ';': /* Delay 1/2 sec */
321: mswait(500);
322: break;
323: case '.': /* Delay 2 secs */
324: mswait(2000);
325: break;
326: case 'S': /* Synchronize */
327: ASYNC;
328: break;
329: case 'L': /* CLS (form feed) */
330: CLS;
331: break;
332: case '>': /* CLREOL */
333: if(useron.misc&ANSI)
334: bputs("\x1b[K");
335: #if 0
336: else {
337: i=j=lclwx(); /* commented out */
338: while(i++<79)
339: outchar(SP);
340: while(j++<79)
341: outchar(BS); }
342: #endif
343: break;
344: case '<': /* Non-destructive backspace */
345: outchar(BS);
346: break;
347: case '[': /* Carriage return */
348: outchar(CR);
349: break;
350: case ']': /* Line feed */
351: outchar(LF);
352: break;
353: case 'A': /* Ctrl-A */
354: outchar(1);
355: break;
356: case 'H': /* High intensity */
357: atr|=HIGH;
358: attr(atr);
359: break;
360: case 'I': /* Blink */
361: atr|=BLINK;
362: attr(atr);
363: break;
364: case 'N': /* Normal */
365: attr(LIGHTGRAY);
366: break;
367: case 'R':
368: atr=(atr&0xf8)|RED;
369: attr(atr);
370: break;
371: case 'G':
372: atr=(atr&0xf8)|GREEN;
373: attr(atr);
374: break;
375: case 'B':
376: atr=(atr&0xf8)|BLUE;
377: attr(atr);
378: break;
379: case 'W': /* White */
380: atr=(atr&0xf8)|LIGHTGRAY;
381: attr(atr);
382: break;
383: case 'C':
384: atr=(atr&0xf8)|CYAN;
385: attr(atr);
386: break;
387: case 'M':
388: atr=(atr&0xf8)|MAGENTA;
389: attr(atr);
390: break;
391: case 'Y': /* Yellow */
392: atr=(atr&0xf8)|BROWN;
393: attr(atr);
394: break;
395: case 'K': /* Black */
396: atr=(atr&0xf8)|BLACK;
397: attr(atr);
398: break;
399: case '0': /* Black Background */
400: atr=(atr&0x8f)|(uchar)(BLACK<<4);
401: attr(atr);
402: break;
403: case '1': /* Red Background */
404: atr=(atr&0x8f)|(uchar)(RED<<4);
405: attr(atr);
406: break;
407: case '2': /* Green Background */
408: atr=(atr&0x8f)|(uchar)(GREEN<<4);
409: attr(atr);
410: break;
411: case '3': /* Yellow Background */
412: atr=(atr&0x8f)|(uchar)(BROWN<<4);
413: attr(atr);
414: break;
415: case '4': /* Blue Background */
416: atr=(atr&0x8f)|(uchar)(BLUE<<4);
417: attr(atr);
418: break;
419: case '5': /* Magenta Background */
420: atr=(atr&0x8f)|(uchar)(MAGENTA<<4);
421: attr(atr);
422: break;
423: case '6': /* Cyan Background */
424: atr=(atr&0x8f)|(uchar)(CYAN<<4);
425: attr(atr);
426: break;
427: case '7': /* White Background */
428: atr=(atr&0x8f)|(uchar)(LIGHTGRAY<<4);
429: attr(atr);
430: break; }
431: }
432:
433: /***************************************************************************/
434: /* Changes local and remote text attributes accounting for monochrome */
435: /***************************************************************************/
436: /****************************************************************************/
437: /* Sends ansi codes to change remote ansi terminal's colors */
438: /* Only sends necessary codes - tracks remote terminal's current attributes */
439: /* through the 'curatr' variable */
440: /****************************************************************************/
441: void sbbs_t::attr(int atr)
442: {
443:
444: if(!(useron.misc&ANSI))
445: return;
446: if(!(useron.misc&COLOR)) { /* eliminate colors if user doesn't have them */
447: if(atr&LIGHTGRAY) /* if any foreground bits set, set all */
448: atr|=LIGHTGRAY;
449: if(atr&(LIGHTGRAY<<4)) /* if any background bits set, set all */
450: atr|=(LIGHTGRAY<<4);
451: if(atr&LIGHTGRAY && atr&(LIGHTGRAY<<4))
452: atr&=~LIGHTGRAY; /* if background is solid, foreground is black */
453: if(!atr)
454: atr|=LIGHTGRAY; } /* don't allow black on black */
455: if(curatr==atr) /* text hasn't changed. don't send codes */
456: return;
457:
458: if((!(atr&HIGH) && curatr&HIGH) || (!(atr&BLINK) && curatr&BLINK)
459: || atr==LIGHTGRAY) {
460: bputs("\x1b[0m");
461: curatr=LIGHTGRAY; }
462:
463: if(atr==LIGHTGRAY) /* no attributes */
464: return;
465:
466: if(atr&BLINK) { /* special attributes */
467: if(!(curatr&BLINK))
468: bputs(ansi(BLINK)); }
469: if(atr&HIGH) {
470: if(!(curatr&HIGH))
471: bputs(ansi(HIGH)); }
472:
473: if((atr&0x7)==BLACK) { /* foreground colors */
474: if((curatr&0x7)!=BLACK)
475: bputs(ansi(BLACK)); }
476: else if((atr&0x7)==RED) {
477: if((curatr&0x7)!=RED)
478: bputs(ansi(RED)); }
479: else if((atr&0x7)==GREEN) {
480: if((curatr&0x7)!=GREEN)
481: bputs(ansi(GREEN)); }
482: else if((atr&0x7)==BROWN) {
483: if((curatr&0x7)!=BROWN)
484: bputs(ansi(BROWN)); }
485: else if((atr&0x7)==BLUE) {
486: if((curatr&0x7)!=BLUE)
487: bputs(ansi(BLUE)); }
488: else if((atr&0x7)==MAGENTA) {
489: if((curatr&0x7)!=MAGENTA)
490: bputs(ansi(MAGENTA)); }
491: else if((atr&0x7)==CYAN) {
492: if((curatr&0x7)!=CYAN)
493: bputs(ansi(CYAN)); }
494: else if((atr&0x7)==LIGHTGRAY) {
495: if((curatr&0x7)!=LIGHTGRAY)
496: bputs(ansi(LIGHTGRAY)); }
497:
498: if((atr&0x70)==(BLACK<<4)) { /* background colors */
499: if((curatr&0x70)!=(BLACK<<4))
500: bputs("\x1b[40m"); }
501: else if((atr&0x70)==(RED<<4)) {
502: if((curatr&0x70)!=(RED<<4))
503: bputs(ansi(RED<<4)); }
504: else if((atr&0x70)==(GREEN<<4)) {
505: if((curatr&0x70)!=(GREEN<<4))
506: bputs(ansi(GREEN<<4)); }
507: else if((atr&0x70)==(BROWN<<4)) {
508: if((curatr&0x70)!=(BROWN<<4))
509: bputs(ansi(BROWN<<4)); }
510: else if((atr&0x70)==(BLUE<<4)) {
511: if((curatr&0x70)!=(BLUE<<4))
512: bputs(ansi(BLUE<<4)); }
513: else if((atr&0x70)==(MAGENTA<<4)) {
514: if((curatr&0x70)!=(MAGENTA<<4))
515: bputs(ansi(MAGENTA<<4)); }
516: else if((atr&0x70)==(CYAN<<4)) {
517: if((curatr&0x70)!=(CYAN<<4))
518: bputs(ansi(CYAN<<4)); }
519: else if((atr&0x70)==(LIGHTGRAY<<4)) {
520: if((curatr&0x70)!=(LIGHTGRAY<<4))
521: bputs(ansi(LIGHTGRAY<<4)); }
522:
523: curatr=atr;
524: }
525:
526: /****************************************************************************/
527: /* Checks to see if user has hit Pause or Abort. Returns 1 if user aborted. */
528: /* If the user hit Pause, waits for a key to be hit. */
529: /* Emulates remote XON/XOFF flow control on local console */
530: /* Preserves SS_ABORT flag state, if already set. */
531: /* Called from various listing procedures that wish to check for abort */
532: /****************************************************************************/
533: bool sbbs_t::msgabort()
534: {
535: if(sys_status&SS_SYSPAGE) {
536: sbbs_beep(sbbs_random(800),1);
537: }
538:
539: checkline();
540: if(sys_status&SS_ABORT)
541: return(true);
542: #if 0 // no longer necessary
543: if(online==ON_REMOTE && rioctl(IOSTATE)&ABORT) {
544: rioctl(IOCS|ABORT);
545: sys_status|=SS_ABORT;
546: return(true); }
547: #endif
548: if(!online)
549: return(true);
550: return(false);
551: }
552:
553:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.