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