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