Tue Aug 18 00:42:33 EDT 1998 Nathan Bryant <bryant@cs.usm.maine.edu>
[citadel.git] / citadel / commands.c
1 /*
2  * Citadel/UX
3  *
4  * commands.c - front end for Citadel
5  *
6  * This version is the traditional command parser for room prompts.
7  *
8  */
9
10 #include "sysdep.h"
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <stdio.h>
14 #include <fcntl.h>
15 #include <ctype.h>
16 #include <string.h>
17 #include <sys/types.h>
18 #include <sys/time.h>
19
20 #ifdef POSIX_TERMIO
21 #include <termios.h>
22 #else
23 #include <sgtty.h>
24 #endif
25
26 #ifdef NEED_SELECT_H
27 #include <sys/select.h>
28 #endif
29
30
31 #include <signal.h>
32 #include <errno.h>
33 #include "citadel.h"
34 #include "commands.h"
35
36 struct citcmd {
37         struct citcmd *next;
38         int c_cmdnum;
39         int c_axlevel;
40         char c_keys[5][64];
41         };
42
43 #define IFNEXPERT if ((userflags&US_EXPERT)==0)
44
45
46 extern unsigned room_flags;
47 extern char room_name[];
48 extern struct CtdlServInfo serv_info;
49 extern char axlevel;
50 extern char is_room_aide;
51 extern unsigned userflags;
52 extern char sigcaught;
53 extern char editor_path[];
54 extern char printcmd[];
55 extern char have_xterm;
56 extern char rc_username[];
57 extern char rc_password[];
58 extern char rc_floor_mode;
59 char rc_exp_beep;
60 char rc_exp_cmd[256];
61 extern int lines_printed;
62 extern char express_msgs;
63
64 char *gl_string;
65
66 struct citcmd *cmdlist = NULL;
67
68 void sighandler(int which_sig);
69 void logoff(int code);
70 int struncmp(char *lstr, char *rstr, int len);
71 void formout(char *name);
72 int room_prompt(int qrflags);
73 void back(int spaces);
74 int checkpagin(int lp, int pagin, int height);
75 void color(int colornum);
76
77
78 /* these variables are local to this module */
79 char keepalives_enabled = KA_YES;       /* send NOOPs to server when idle */
80 int ok_to_interrupt = 0;                /* print express msgs asynchronously */
81 time_t AnsiDetect;                      /* when did we send the detect code? */
82 int enable_color = 0;                   /* nonzero for ANSI color */
83
84
85 /*
86  * print_express()  -  print express messages if there are any
87  */
88 void print_express(void) {
89         char buf[256];
90         FILE *outpipe;
91
92         if (express_msgs == 0) return;
93         express_msgs = 0;
94         serv_puts("PEXP");
95         serv_gets(buf);
96         if (buf[0]!='1') return;
97
98         if (strlen(rc_exp_cmd) > 0) {
99                 outpipe = popen(rc_exp_cmd, "w");
100                 if (outpipe != NULL) {
101                         while (serv_gets(buf), strcmp(buf,"000")) {
102                                 fprintf(outpipe, "%s\n", buf);
103                                 }
104                         pclose(outpipe);
105                         return;
106                         }
107                 }
108
109         /* fall back to built-in express message display */
110         if (rc_exp_beep) {
111                 putc(7,stdout);
112                 }
113         color(1);
114         printf("---\n");
115         while (serv_gets(buf), strcmp(buf,"000")) {
116                 printf("%s\n",buf);
117                 }
118         printf("---\n");
119         color(7);
120         }
121
122
123 void set_keepalives(int s)
124 {
125         keepalives_enabled = (char)s;
126         }
127
128 /* 
129  * This loop handles the "keepalive" messages sent to the server when idling.
130  */
131 void do_keepalive(void) {
132         char buf[256];
133         static long idlet = 0L;
134         long now;
135
136         time(&now);
137         if ((now - idlet) < ((long)S_KEEPALIVE)) return;
138         time(&idlet);
139
140         if (keepalives_enabled != KA_NO) {
141                 serv_puts("NOOP");
142                 if (keepalives_enabled == KA_YES) {
143                         serv_gets(buf);
144                         if (buf[3]=='*') {
145                                 express_msgs = 1;
146                                 if (ok_to_interrupt == 1) {
147                                         printf("\r                    \r");
148                                         print_express();
149                                         printf("%s%c ",room_name,
150                                                 room_prompt(room_flags));
151                                         fflush(stdout); 
152                                         }
153                                 }
154                         }
155                 }
156         }
157
158
159 int inkey(void) {               /* get a character from the keyboard, with   */
160         int a;          /* the watchdog timer in effect if necessary */
161         fd_set rfds;
162         struct timeval tv;
163         long start_time, now;
164         char inbuf[2];
165
166         time(&start_time);
167         
168         do {
169
170                 /* This loop waits for keyboard input.  If the keepalive
171                  * timer expires, it sends a keepalive to the server if
172                  * necessary and then waits again.
173                  */
174                 do {
175                         do_keepalive();
176                         fflush(stdout);
177                         FD_ZERO(&rfds);
178                         FD_SET(0,&rfds);
179                         tv.tv_sec = S_KEEPALIVE;
180                         tv.tv_usec = 0;
181
182                         time(&now);
183                         if (((now-start_time) > SLEEPING)
184                            && (SLEEPING != 0) && (getppid()==1)) {
185                                 printf("Sleeping? Call again.\n");
186                                 logoff(SIGALRM);
187                                 }
188
189                         select(1, &rfds, NULL, NULL, &tv);
190                         } while (!FD_ISSET(0, &rfds));
191
192
193
194
195                 /* At this point, there's input, so fetch it.
196                  * (There's a hole in the bucket...)
197                  */
198                 read(0, inbuf, 1);
199                 a = inbuf[0];
200                 if (a==127) a=8;
201                 if (a>126) a=0;
202                 if (a==10) a=13;
203                 if (((a!=4)&&(a!=13)&&(a!=8)&&(a!=NEXT_KEY)&&(a!=STOP_KEY))
204                         && ((a<32)||(a>126))) a=0;
205                 } while(a==0);
206         return(a);
207         }
208
209 void getline(char *string, int lim)     /* Gets a line from the terminal */
210                         /* Pointer to string buffer */
211                         /* Maximum length - if negative, no-show */
212 {
213         int a,b;
214         char flag = 0;
215
216         if (lim<0) { lim=(0-lim); flag=1; }
217         strcpy(string,"");
218         gl_string = string;
219 GLA:    a=inkey(); a=(a&127);
220         if ((a==8)&&(strlen(string)==0)) goto GLA;
221         if ((a!=13)&&(a!=8)&&(strlen(string)==lim)) goto GLA;
222         if ((a==8)&&(string[0]!=0)) {
223                 string[strlen(string)-1]=0;
224                 putc(8,stdout); putc(32,stdout); putc(8,stdout); goto GLA; }
225         if ((a==13)||(a==10)) {
226                 putc(13,stdout);
227                 putc(10,stdout);
228                 return;
229                 }
230         if (a<32) a='.';
231         b=strlen(string);
232         string[b]=a;
233         string[b+1]=0;
234         if (flag==0) putc(a,stdout);
235         if (flag==1) putc('*',stdout);
236         goto GLA;
237         }
238
239
240 /*
241  * strprompt()  -  prompt for a string, print the existing value and
242  *                 allow the user to press return to keep it...
243  */
244 void strprompt(char *prompt, char *str, int len)
245 {
246         char buf[128];
247         print_express();
248         color(3);
249         printf("%s [", prompt);
250         color(1);
251         printf("%s", str);
252         color(3);
253         printf("]: ");
254         color(2);
255         getline(buf,len);
256         color(7);
257         if (buf[0]!=0) strcpy(str,buf);
258         }
259
260 /* 
261  * intprompt()  -  like strprompt(), except for an integer
262  *                 (note that it RETURNS the new value!)
263  */
264 int intprompt(char *prompt, int ival, int imin, int imax)
265 {
266         char buf[16];
267         int i;
268         i = ival;
269         do {
270                 sprintf(buf,"%d",i);
271                 strprompt(prompt,buf,15);
272                 i=atoi(buf);
273                 if (i<imin) printf("*** Must be no less than %d.\n",imin);
274                 if (i>imax) printf("*** Must be no more than %d.\n",imax);
275                 } while((i<imin)||(i>imax));
276         return(i);
277         }
278
279 /* 
280  * newprompt()  -  prompt for a string with no existing value
281  *                 (clears out string buffer first)
282  */
283 void newprompt(char *prompt, char *str, int len)
284 {
285         color(3);
286         printf("%s",prompt);
287         color(2);
288         getline(str,len);
289         color(7);
290         }
291
292
293 int lkey(void) {        /* returns a lower case value */
294         int a;
295         a=inkey();
296         if (isupper(a)) a=tolower(a);
297         return(a);
298         }
299
300 /*
301  * parse the citadel.rc file
302  */
303 void load_command_set(void) {
304         FILE *ccfile;
305         char buf[256];
306         struct citcmd *cptr;
307         int a,d;
308         int b = 0;
309
310
311         /* first, set up some defaults for non-required variables */
312
313         strcpy(editor_path,"");
314         strcpy(printcmd,"");
315         strcpy(rc_username,"");
316         strcpy(rc_password,"");
317         rc_floor_mode = 0;
318         rc_exp_beep = 1;
319         strcpy(rc_exp_cmd, "");
320
321         /* now try to open the citadel.rc file */
322
323         ccfile = NULL;
324         if (getenv("HOME") != NULL) {
325                 sprintf(buf,"%s/.citadelrc",getenv("HOME"));
326                 ccfile = fopen(buf,"r");
327                 }
328         if (ccfile==NULL) {
329                 ccfile = fopen("/usr/local/lib/citadel.rc","r");
330                 }
331         if (ccfile==NULL) {
332                 sprintf(buf,"%s/citadel.rc",BBSDIR);
333                 ccfile = fopen(buf,"r");
334                 }
335         if (ccfile==NULL) {
336                 perror("commands: cannot open citadel.rc");
337                 logoff(errno);
338                 }
339
340         while (fgets(buf, 256, ccfile) != NULL) {
341             while ( (strlen(buf)>0) ? (isspace(buf[strlen(buf)-1])) : 0 )
342                 buf[strlen(buf)-1] = 0;
343
344             if (!struncmp(buf,"editor=",7))
345                 strcpy(editor_path,&buf[7]);
346
347             if (!struncmp(buf,"printcmd=",9))
348                 strcpy(printcmd,&buf[9]);
349
350             if (!struncmp(buf,"expcmd=",7))
351                 strcpy(rc_exp_cmd,&buf[7]);
352
353             if (!struncmp(buf,"local_screen_dimensions=",24))
354                 have_xterm = (char)atoi(&buf[24]);
355
356             if (!struncmp(buf,"use_floors=",11)) {
357                 if (!strucmp(&buf[11],"yes")) rc_floor_mode = RC_YES;
358                 if (!strucmp(&buf[11],"no")) rc_floor_mode = RC_NO;
359                 if (!strucmp(&buf[11],"default")) rc_floor_mode = RC_DEFAULT;
360                 }
361
362             if (!struncmp(buf,"beep=",5)) {
363                 rc_exp_beep = atoi(&buf[5]);
364                 }
365
366             if (!struncmp(buf,"username=",9))
367                 strcpy(rc_username,&buf[9]);
368
369             if (!struncmp(buf,"password=",9))
370                 strcpy(rc_password,&buf[9]);
371
372             if (!struncmp(buf,"cmd=",4)) {
373                 strcpy(buf,&buf[4]);
374
375                 cptr = (struct citcmd *) malloc (sizeof(struct citcmd));
376                 
377                 cptr->c_cmdnum = atoi (buf);
378                 for (d=strlen(buf); d>=0; --d)
379                         if (buf[d]==',') b=d;
380                 strcpy (buf, &buf[b+1]);
381
382                 cptr->c_axlevel = atoi (buf);
383                 for (d=strlen(buf); d>=0; --d)
384                         if (buf[d]==',') b=d;
385                 strcpy (buf, &buf[b+1]);
386
387                 for (a=0; a<5; ++a) cptr->c_keys[a][0] = 0;
388
389                 a = 0;  b = 0;
390                 buf[strlen(buf)+1] = 0;
391                 while (strlen(buf) > 0) {
392                         b = strlen(buf);
393                         for (d=strlen(buf); d>=0; --d)
394                                 if (buf[d]==',') b=d;
395                         strncpy(cptr->c_keys[a],buf,b);
396                         cptr->c_keys[a][b] = 0;
397                         if (buf[b]==',')
398                                 strcpy(buf,&buf[b+1]);
399                         else
400                                 strcpy(buf,"");
401                         ++a;
402                         }
403
404                 cptr->next = cmdlist;
405                 cmdlist = cptr;
406
407                 }
408             }
409         fclose(ccfile);
410         }
411
412
413
414 /*
415  * return the key associated with a command
416  */
417 char keycmd(char *cmdstr)
418 {
419         int a;
420
421         for (a=0; a<strlen(cmdstr); ++a)
422                 if (cmdstr[a]=='&')
423                         return(tolower(cmdstr[a+1]));
424         return(0);
425         }
426
427
428 /*
429  * Output the string from a key command without the ampersand
430  * "mode" should be set to 0 for normal or 1 for <C>ommand key highlighting
431  */
432 char *cmd_expand(char *strbuf, int mode)
433 {
434         int a;
435         static char exp[64];
436         char buf[256];
437                 
438         strcpy(exp,strbuf);
439         
440         for (a=0; a<strlen(exp); ++a) {
441                 if (strbuf[a] == '&') {
442
443                     if (mode == 0) {
444                         strcpy(&exp[a],&exp[a+1]);
445                         }
446
447                     if (mode == 1) {
448                         exp[a] = '<';
449                         strcpy(buf,&exp[a+2]);
450                         exp[a+2] = '>';
451                         exp[a+3] = 0;
452                         strcat(exp,buf);
453                         }
454
455                     }
456
457                 if (!strncmp(&exp[a],"^r",2)) {
458                         strcpy(buf,exp);
459                         strcpy(&exp[a],room_name);
460                         strcat(exp,&buf[a+2]);
461                         }
462
463                 if (!strncmp(&exp[a],"^c",2)) {
464                         exp[a] = ',';
465                         strcpy(&exp[a+1],&exp[a+2]);
466                         }
467
468                 }
469
470         return(exp);
471         }
472
473
474
475 /*
476  * Comparison function to determine if entered commands match a
477  * command loaded from the config file.
478  */
479 int cmdmatch(char *cmdbuf, struct citcmd *cptr, int ncomp)
480 {
481         int a;
482         int cmdax;
483
484         cmdax = 0;
485         if (is_room_aide) cmdax = 1;
486         if (axlevel >=6) cmdax = 2;
487
488         for (a=0; a<ncomp; ++a) {
489                 if ( (tolower(cmdbuf[a]) != keycmd(cptr->c_keys[a]))
490                    || (cptr->c_axlevel > cmdax) )
491                         return(0);
492                 }
493         return(1);
494         }
495
496
497 /*
498  * This function returns 1 if a given command requires a string input
499  */
500 int requires_string(struct citcmd *cptr, int ncomp)
501 {
502         int a;
503         char buf[64];
504         
505         strcpy(buf,cptr->c_keys[ncomp-1]);
506         for (a=0; a<strlen(buf); ++a) {
507                 if (buf[a]==':') return(1);
508                 }
509         return(0);
510         }
511
512
513 /*
514  * Input a command at the main prompt.
515  * This function returns an integer command number.  If the command prompts
516  * for a string then it is placed in the supplied buffer.
517  */
518 int getcmd(char *argbuf)
519 {
520         char cmdbuf[5];
521         int cmdspaces[5];
522         int cmdpos;
523         int ch;
524         int a;
525         int got;
526         struct citcmd *cptr;
527
528         /* if we're running in idiot mode, display a cute little menu */
529         IFNEXPERT formout("mainmenu");
530
531         print_express(); /* print express messages if there are any */
532         strcpy(argbuf, "");
533         cmdpos = 0;
534         for (a=0; a<5; ++a) cmdbuf[a]=0;
535         /* now the room prompt... */
536         ok_to_interrupt = 1;
537         printf("\n%s%c ",room_name,room_prompt(room_flags));
538         fflush(stdout);
539         
540         while(1) {
541                 ch = inkey();
542                 ok_to_interrupt = 0;
543
544                 if ( (ch == 8) && (cmdpos > 0) ) {
545                         back(cmdspaces[cmdpos-1] + 1);
546                         cmdbuf[cmdpos] = 0;
547                         --cmdpos;
548                         }
549
550                 cmdbuf[cmdpos] = tolower(ch);
551
552                 for (cptr = cmdlist; cptr != NULL; cptr = cptr->next) {
553                         if (cmdmatch(cmdbuf,cptr,cmdpos+1)) {
554                                 
555                                 printf("%s",cmd_expand(cptr->c_keys[cmdpos],0));
556                                 cmdspaces[cmdpos] = strlen(
557                                         cmd_expand(cptr->c_keys[cmdpos],0) );
558                                 if (cmdpos<4) 
559                                         if ((cptr->c_keys[cmdpos+1]) != 0)
560                                                 putc(' ',stdout);
561                                 ++cmdpos;
562                                 }
563                         }
564
565                 for (cptr = cmdlist; cptr != NULL; cptr = cptr->next) {
566                         if (cmdmatch(cmdbuf,cptr,5)) {
567                                 if (requires_string(cptr,cmdpos)) {
568                                         getline(argbuf,32);
569                                         }
570                                 else {
571                                         printf("\n");
572                                         }
573                                 return(cptr->c_cmdnum);
574                                 }
575                         }
576
577                 if (ch == '?') {
578                         printf("\rOne of ...                         \n");
579                         for (cptr = cmdlist; cptr != NULL; cptr = cptr->next) {
580                             if (cmdmatch(cmdbuf,cptr,cmdpos)) {
581                                 for (a=0; a<5; ++a) {
582                                     printf("%s ",cmd_expand(cptr->c_keys[a],1));
583                                     }
584                                 printf("\n");
585                                 }
586                             }
587
588                         printf("\n%s%c ",room_name,room_prompt(room_flags));
589                         got = 0;
590                         for (cptr = cmdlist; cptr != NULL; cptr = cptr->next) {
591                             if ((got==0)&&(cmdmatch(cmdbuf,cptr,cmdpos))) {
592                                 for (a=0; a<cmdpos; ++a) {
593                                     printf("%s ",
594                                         cmd_expand(cptr->c_keys[a],0));
595                                     }
596                                 got = 1;
597                                 }
598                             }
599                         }
600
601                 }
602
603         }
604
605
606
607
608
609 /*
610  * set tty modes.  commands are:
611  * 
612  * 0 - set to bbs mode, intr/quit disabled
613  * 1 - set to bbs mode, intr/quit enabled
614  * 2 - save current settings for later restoral
615  * 3 - restore saved settings
616  */
617 #ifdef POSIX_TERMIO
618 void sttybbs(int cmd)           /* SysV version of sttybbs() */
619          {
620         struct termios live;
621         static struct termios saved_settings;
622
623         if ( (cmd == 0) || (cmd == 1) ) {
624                 tcgetattr(0,&live);
625                 live.c_iflag=ISTRIP|IXON|IXANY;
626                 live.c_oflag=OPOST|ONLCR;
627                 live.c_lflag=NOFLSH;
628                 if (cmd==1) live.c_lflag=ISIG|NOFLSH;
629
630                 if (cmd==SB_YES_INTR) {
631                         live.c_cc[VINTR]=NEXT_KEY;
632                         live.c_cc[VQUIT]=STOP_KEY;
633                         signal(SIGINT,*sighandler);
634                         signal(SIGQUIT,*sighandler);
635                         }
636                 else {
637                         signal(SIGINT,SIG_IGN);
638                         signal(SIGQUIT,SIG_IGN);
639                         live.c_cc[VINTR]=(-1);
640                         live.c_cc[VQUIT]=(-1);
641                         }
642
643                 /* do we even need this stuff anymore? */
644                 /* live.c_line=0; */
645                 live.c_cc[VERASE]=8;
646                 live.c_cc[VKILL]=24;
647                 live.c_cc[VEOF]=1;
648                 live.c_cc[VEOL]=255;
649                 live.c_cc[VEOL2]=0;
650                 live.c_cc[VSTART]=0;
651                 tcsetattr(0,TCSADRAIN,&live);
652                 }
653         if (cmd == 2) {
654                 tcgetattr(0,&saved_settings);
655                 }
656         if (cmd == 3) {
657                 tcsetattr(0,TCSADRAIN,&saved_settings);
658                 }
659         }
660 #else
661 void sttybbs(int cmd)           /* BSD version of sttybbs() */
662 {
663         struct sgttyb live;
664         static struct sgttyb saved_settings;
665
666         if ( (cmd == 0) || (cmd == 1) ) {
667                 gtty(0,&live);
668                 live.sg_flags |= CBREAK;
669                 live.sg_flags |= CRMOD;
670                 live.sg_flags |= NL1;
671                 live.sg_flags &= ~ECHO;
672                 if (cmd==1) live.sg_flags |= NOFLSH;
673                 stty(0,&live);
674                 }
675         if (cmd == 2) {
676                 gtty(0,&saved_settings);
677                 }
678         if (cmd == 3) {
679                 stty(0,&saved_settings);
680                 }
681         }
682 #endif
683
684
685 /*
686  * display_help()  -  help file viewer
687  */
688 void display_help(char *name)
689 {
690         formout(name);
691         }
692
693
694 /*
695  * fmout()  -  Citadel text formatter and paginator
696  */
697 int fmout(int width, FILE *fp, char pagin, int height, int starting_lp, char subst)
698                         /* screen width to use */
699                         /* file to read from, or NULL to read from server */
700                         /* nonzero if we should use the paginator */
701                         /* screen height to use */
702                         /* starting value for lines_printed, -1 for global */
703                         /* nonzero if we should use hypertext mode */
704         {
705         int a,b,c,d,old;
706         int real = (-1);
707         char aaa[140];
708         char buffer[512];
709         int eof_flag = 0;
710
711         if (starting_lp >= 0) { 
712                 lines_printed = starting_lp;
713                 }
714         strcpy(aaa,""); old=255;
715         strcpy(buffer,"");
716         c=1; /* c is the current pos */
717
718         sigcaught = 0;
719         sttybbs(1);
720
721 FMTA:   while ( (eof_flag==0) && (strlen(buffer)<126) ) {
722                 if (sigcaught) goto OOPS;
723                 if (fp!=NULL) { /* read from file */
724                         if (feof(fp)) eof_flag = 1;
725                         if (eof_flag==0) {
726                                 a=getc(fp);
727                                 buffer[strlen(buffer)+1] = 0;
728                                 buffer[strlen(buffer)] = a;
729                                 }
730                         }
731                 else {          /* read from server */
732                         d=strlen(buffer);
733                         serv_gets(&buffer[d]);
734 while ( (!isspace(buffer[d])) && (isspace(buffer[strlen(buffer)-1])) )
735         buffer[strlen(buffer)-1]=0;
736                         if (!strcmp(&buffer[d],"000")) {
737                                 buffer[d] = 0;
738                                 eof_flag = 1;
739                                 while(isspace(buffer[strlen(buffer)-1]))
740                                         buffer[strlen(buffer)-1] = 0;
741                                 }
742                         d=strlen(buffer);
743                         buffer[d] = 10;
744                         buffer[d+1] = 0;
745                         }
746                 }
747
748         buffer[strlen(buffer)+1] = 0;
749         a=buffer[0];
750         strcpy(buffer,&buffer[1]);
751         
752         old=real;
753         real=a;
754         if (a<=0) goto FMTEND;
755         
756         if ( ((a==13)||(a==10)) && (old!=13) && (old!=10) ) a=32;
757         if ( ((old==13)||(old==10)) && (isspace(real)) ) {
758                 printf("\n");
759                 ++lines_printed;
760                 lines_printed = checkpagin(lines_printed,pagin,height);
761                 c=1;
762                 }
763         if (a>126) goto FMTA;
764
765         if (a>32) {
766         if ( ((strlen(aaa)+c)>(width-5)) && (strlen(aaa)>(width-5)) ) {
767                 printf("\n%s",aaa); c=strlen(aaa); aaa[0]=0;
768                 ++lines_printed;
769                 lines_printed = checkpagin(lines_printed,pagin,height);
770                 }
771             b=strlen(aaa); aaa[b]=a; aaa[b+1]=0;
772             }
773         if (a==32) {
774                 if ((strlen(aaa)+c)>(width-5)) { 
775                         c=1;
776                         printf("\n");
777                         ++lines_printed;
778                         lines_printed = checkpagin(lines_printed,pagin,height);
779                         }
780                 printf("%s ",aaa); ++c; c=c+strlen(aaa);
781                 strcpy(aaa,"");
782                 goto FMTA;
783                 }
784         if ((a==13)||(a==10)) {
785                 printf("%s\n",aaa);
786                 c=1;
787                 ++lines_printed;
788                 lines_printed = checkpagin(lines_printed,pagin,height);
789                 strcpy(aaa,"");
790                 goto FMTA;
791                 }
792         goto FMTA;
793
794         /* signal caught; drain the server */
795 OOPS:   do {
796                 serv_gets(aaa);
797                 } while(strcmp(aaa,"000"));
798
799 FMTEND: printf("\n");
800         ++lines_printed;
801         lines_printed = checkpagin(lines_printed,pagin,height);
802         return(sigcaught);
803 }
804
805
806 /*
807  * support ANSI color if defined
808  */
809 void color(int colornum)
810 {
811
812 #ifdef ANSI_COLOR
813         if (enable_color) {
814                 fflush(stdout);
815                 printf("%c[3%dm%c[1m", 27, colornum, 27);
816                 fflush(stdout);
817                 }
818 #endif
819         }
820
821 void cls(void) {
822 #ifdef ANSI_COLOR
823         fflush(stdout);
824         printf("%c[2J%c[H", 27, 27);
825         fflush(stdout);
826 #endif
827         }
828
829
830 /*
831  * Detect whether ANSI color is available (answerback)
832  */
833 void send_ansi_detect(void) {
834 #ifdef ANSI_COLOR
835         printf("%c[c", 27);
836         fflush(stdout);
837         time(&AnsiDetect);
838 #endif
839         }
840
841 void look_for_ansi(void) {
842 #ifdef ANSI_COLOR
843         fd_set rfds;
844         struct timeval tv;
845         char abuf[512];
846         time_t now;
847         int a;
848
849         strcpy(abuf, "");
850
851         time(&now);
852         if ( (now - AnsiDetect) < 2 ) sleep(1);
853
854         do {
855                 FD_ZERO(&rfds);
856                 FD_SET(0,&rfds);
857                 tv.tv_sec = 0;
858                 tv.tv_usec = 1;
859
860                 select(1, &rfds, NULL, NULL, &tv);
861                 if (FD_ISSET(0, &rfds)) {
862                         abuf[strlen(abuf)+1] = 0;
863                         read(0, &abuf[strlen(abuf)], 1);
864                         }
865
866                 } while (FD_ISSET(0, &rfds));
867
868         for (a=0; a<strlen(abuf); ++a) {
869                 if ( (abuf[a] == 27) && (abuf[a+1] == '[')
870                    && (abuf[a+2] == '?') ) {
871                         enable_color = 1;
872                         }
873                 }
874 #endif
875         }