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