]> code.citadel.org Git - citadel.git/blob - citadel/commands.c
* citadel.c: added some experimental code to automatically reconnect
[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%64s\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
197 int yesno(void) { /* Returns 1 for yes, 0 for no */
198 int a;
199         while (1) {
200                 a=inkey(); a=tolower(a);
201                 if (a=='y') { printf("Yes\n"); return(1); }
202                 if (a=='n') { printf("No\n");  return(0); }
203                 }
204         }
205
206 int yesno_d(int d) /* Returns 1 for yes, 0 for no, arg is default value */
207        {
208 int a;
209         while (1) {
210                 a=inkey(); a=tolower(a);
211                 if (a==13) a=(d ? 'y' : 'n');
212                 if (a=='y') { printf("Yes\n"); return(1); }
213                 if (a=='n') { printf("No\n");  return(0); }
214                 }
215         }
216
217
218
219
220 void getline(char *string, int lim)     /* Gets a line from the terminal */
221                         /* Pointer to string buffer */
222                         /* Maximum length - if negative, no-show */
223 {
224         int a,b;
225         char flag = 0;
226
227         if (lim<0) { lim=(0-lim); flag=1; }
228         strcpy(string,"");
229         gl_string = string;
230 GLA:    a=inkey(); a=(a&127);
231         if ((a==8)&&(strlen(string)==0)) goto GLA;
232         if ((a!=13)&&(a!=8)&&(strlen(string)==lim)) goto GLA;
233         if ((a==8)&&(string[0]!=0)) {
234                 string[strlen(string)-1]=0;
235                 putc(8,stdout); putc(32,stdout); putc(8,stdout); goto GLA; }
236         if ((a==13)||(a==10)) {
237                 putc(13,stdout);
238                 putc(10,stdout);
239                 return;
240                 }
241         if (a<32) a='.';
242         b=strlen(string);
243         string[b]=a;
244         string[b+1]=0;
245         if (flag==0) putc(a,stdout);
246         if (flag==1) putc('*',stdout);
247         goto GLA;
248         }
249
250
251 /*
252  * strprompt()  -  prompt for a string, print the existing value and
253  *                 allow the user to press return to keep it...
254  */
255 void strprompt(char *prompt, char *str, int len)
256 {
257         char buf[128];
258         print_express();
259         color(3);
260         printf("%s [", prompt);
261         color(1);
262         printf("%s", str);
263         color(3);
264         printf("]: ");
265         color(2);
266         getline(buf,len);
267         color(7);
268         if (buf[0]!=0) strcpy(str,buf);
269         }
270
271 /*
272  * boolprompt()  -  prompt for a yes/no, print the existing value and
273  *                  allow the user to press return to keep it...
274  */
275 int boolprompt(char *prompt, int prev_val) {
276         color(3);
277         printf("%s [", prompt);
278         color(1);
279         printf("%s", (prev_val ? "Yes" : "No"));
280         color(3);
281         printf("]: ");
282         color(7);
283         return(yesno_d(prev_val));
284         }
285
286 /* 
287  * intprompt()  -  like strprompt(), except for an integer
288  *                 (note that it RETURNS the new value!)
289  */
290 int intprompt(char *prompt, int ival, int imin, int imax)
291 {
292         char buf[16];
293         int i;
294         i = ival;
295         do {
296                 snprintf(buf,sizeof buf,"%d",i);
297                 strprompt(prompt,buf,15);
298                 i=atoi(buf);
299                 if (i<imin) printf("*** Must be no less than %d.\n",imin);
300                 if (i>imax) printf("*** Must be no more than %d.\n",imax);
301                 } while((i<imin)||(i>imax));
302         return(i);
303         }
304
305 /* 
306  * newprompt()  -  prompt for a string with no existing value
307  *                 (clears out string buffer first)
308  */
309 void newprompt(char *prompt, char *str, int len)
310 {
311         color(3);
312         printf("%s",prompt);
313         color(2);
314         getline(str,len);
315         color(7);
316         }
317
318
319 int lkey(void) {        /* returns a lower case value */
320         int a;
321         a=inkey();
322         if (isupper(a)) a=tolower(a);
323         return(a);
324         }
325
326 /*
327  * parse the citadel.rc file
328  */
329 void load_command_set(void) {
330         FILE *ccfile;
331         char buf[256];
332         struct citcmd *cptr;
333         struct citcmd *lastcmd = NULL;
334         int a,d;
335         int b = 0;
336
337
338         /* first, set up some defaults for non-required variables */
339
340         strcpy(editor_path,"");
341         strcpy(printcmd,"");
342         strcpy(rc_username,"");
343         strcpy(rc_password,"");
344         rc_floor_mode = 0;
345         rc_exp_beep = 1;
346         rc_allow_attachments = 0;
347         strcpy(rc_exp_cmd, "");
348         rc_display_message_numbers = 0;
349         rc_force_mail_prompts = 0;
350         rc_ansi_color = 0;
351
352         /* now try to open the citadel.rc file */
353
354         ccfile = NULL;
355         if (getenv("HOME") != NULL) {
356                 snprintf(buf,sizeof buf,"%s/.citadelrc",getenv("HOME"));
357                 ccfile = fopen(buf,"r");
358                 }
359         if (ccfile==NULL) {
360                 ccfile = fopen("/usr/local/lib/citadel.rc","r");
361                 }
362         if (ccfile==NULL) {
363                 snprintf(buf,sizeof buf,"%s/citadel.rc",BBSDIR);
364                 ccfile = fopen(buf,"r");
365                 }
366         if (ccfile==NULL) {
367                 perror("commands: cannot open citadel.rc");
368                 logoff(errno);
369                 }
370
371         while (fgets(buf, 256, ccfile) != NULL) {
372             while ( (strlen(buf)>0) ? (isspace(buf[strlen(buf)-1])) : 0 )
373                 buf[strlen(buf)-1] = 0;
374
375             if (!struncmp(buf,"editor=",7))
376                 strcpy(editor_path,&buf[7]);
377
378             if (!struncmp(buf,"printcmd=",9))
379                 strcpy(printcmd,&buf[9]);
380
381             if (!struncmp(buf,"expcmd=",7))
382                 strcpy(rc_exp_cmd,&buf[7]);
383
384             if (!struncmp(buf,"local_screen_dimensions=",24))
385                 have_xterm = (char)atoi(&buf[24]);
386
387             if (!struncmp(buf,"use_floors=",11)) {
388                 if (!strucmp(&buf[11],"yes")) rc_floor_mode = RC_YES;
389                 if (!strucmp(&buf[11],"no")) rc_floor_mode = RC_NO;
390                 if (!strucmp(&buf[11],"default")) rc_floor_mode = RC_DEFAULT;
391                 }
392
393             if (!struncmp(buf,"beep=",5)) {
394                 rc_exp_beep = atoi(&buf[5]);
395                 }
396
397             if (!struncmp(buf,"allow_attachments=", 18)) {
398                 rc_allow_attachments = atoi(&buf[18]);
399                 }
400
401             if (!struncmp(buf,"display_message_numbers=", 24)) {
402                 rc_display_message_numbers = atoi(&buf[24]);
403                 }
404
405             if (!struncmp(buf,"force_mail_prompts=", 19)) {
406                 rc_force_mail_prompts = atoi(&buf[19]);
407                 }
408
409             if (!struncmp(buf,"ansi_color=", 11)) {
410                 if (!strncasecmp(&buf[11], "on", 2)) 
411                         rc_ansi_color = 1;
412                 if (!strncasecmp(&buf[11], "auto", 4)) 
413                         rc_ansi_color = 2;      /* autodetect */
414                 if (!strncasecmp(&buf[11], "user", 4)) 
415                         rc_ansi_color = 3;      /* user config */
416                 }
417
418             if (!struncmp(buf,"username=",9))
419                 strcpy(rc_username,&buf[9]);
420
421             if (!struncmp(buf,"password=",9))
422                 strcpy(rc_password,&buf[9]);
423
424             if (!struncmp(buf,"cmd=",4)) {
425                 strcpy(buf,&buf[4]);
426
427                 cptr = (struct citcmd *) malloc (sizeof(struct citcmd));
428                 
429                 cptr->c_cmdnum = atoi (buf);
430                 for (d=strlen(buf); d>=0; --d)
431                         if (buf[d]==',') b=d;
432                 strcpy (buf, &buf[b+1]);
433
434                 cptr->c_axlevel = atoi (buf);
435                 for (d=strlen(buf); d>=0; --d)
436                         if (buf[d]==',') b=d;
437                 strcpy (buf, &buf[b+1]);
438
439                 for (a=0; a<5; ++a) cptr->c_keys[a][0] = 0;
440
441                 a = 0;  b = 0;
442                 buf[strlen(buf)+1] = 0;
443                 while (strlen(buf) > 0) {
444                         b = strlen(buf);
445                         for (d=strlen(buf); d>=0; --d)
446                                 if (buf[d]==',') b=d;
447                         strncpy(cptr->c_keys[a],buf,b);
448                         cptr->c_keys[a][b] = 0;
449                         if (buf[b]==',')
450                                 strcpy(buf,&buf[b+1]);
451                         else
452                                 strcpy(buf,"");
453                         ++a;
454                         }
455
456                 cptr->next = NULL;
457                 if (cmdlist == NULL) cmdlist = cptr;
458                 else lastcmd->next = cptr;
459                 lastcmd = cptr;
460                 }
461             }
462         fclose(ccfile);
463         }
464
465
466
467 /*
468  * return the key associated with a command
469  */
470 char keycmd(char *cmdstr)
471 {
472         int a;
473
474         for (a=0; a<strlen(cmdstr); ++a)
475                 if (cmdstr[a]=='&')
476                         return(tolower(cmdstr[a+1]));
477         return(0);
478         }
479
480
481 /*
482  * Output the string from a key command without the ampersand
483  * "mode" should be set to 0 for normal or 1 for <C>ommand key highlighting
484  */
485 char *cmd_expand(char *strbuf, int mode)
486 {
487         int a;
488         static char exp[64];
489         char buf[256];
490                 
491         strcpy(exp,strbuf);
492         
493         for (a=0; a<strlen(exp); ++a) {
494                 if (strbuf[a] == '&') {
495
496                     if (mode == 0) {
497                         strcpy(&exp[a],&exp[a+1]);
498                         }
499
500                     if (mode == 1) {
501                         exp[a] = '<';
502                         strcpy(buf,&exp[a+2]);
503                         exp[a+2] = '>';
504                         exp[a+3] = 0;
505                         strcat(exp,buf);
506                         }
507
508                     }
509
510                 if (!strncmp(&exp[a],"^r",2)) {
511                         strcpy(buf,exp);
512                         strcpy(&exp[a],room_name);
513                         strcat(exp,&buf[a+2]);
514                         }
515
516                 if (!strncmp(&exp[a],"^c",2)) {
517                         exp[a] = ',';
518                         strcpy(&exp[a+1],&exp[a+2]);
519                         }
520
521                 }
522
523         return(exp);
524         }
525
526
527
528 /*
529  * Comparison function to determine if entered commands match a
530  * command loaded from the config file.
531  */
532 int cmdmatch(char *cmdbuf, struct citcmd *cptr, int ncomp)
533 {
534         int a;
535         int cmdax;
536
537         cmdax = 0;
538         if (is_room_aide) cmdax = 1;
539         if (axlevel >=6) cmdax = 2;
540
541         for (a=0; a<ncomp; ++a) {
542                 if ( (tolower(cmdbuf[a]) != keycmd(cptr->c_keys[a]))
543                    || (cptr->c_axlevel > cmdax) )
544                         return(0);
545                 }
546         return(1);
547         }
548
549
550 /*
551  * This function returns 1 if a given command requires a string input
552  */
553 int requires_string(struct citcmd *cptr, int ncomp)
554 {
555         int a;
556         char buf[64];
557         
558         strcpy(buf,cptr->c_keys[ncomp-1]);
559         for (a=0; a<strlen(buf); ++a) {
560                 if (buf[a]==':') return(1);
561                 }
562         return(0);
563         }
564
565
566 /*
567  * Input a command at the main prompt.
568  * This function returns an integer command number.  If the command prompts
569  * for a string then it is placed in the supplied buffer.
570  */
571 int getcmd(char *argbuf)
572 {
573         char cmdbuf[5];
574         int cmdspaces[5];
575         int cmdpos;
576         int ch;
577         int a;
578         int got;
579         int this_lazy_cmd;
580         struct citcmd *cptr;
581
582         /* Switch color support on or off if we're in user mode */
583         if (rc_ansi_color == 3) {
584                 if (userflags & US_COLOR) enable_color = 1;
585                 else enable_color = 0;
586                 }
587
588         /* if we're running in idiot mode, display a cute little menu */
589         IFNEXPERT formout("mainmenu");
590
591         print_express(); /* print express messages if there are any */
592         strcpy(argbuf, "");
593         cmdpos = 0;
594         for (a=0; a<5; ++a) cmdbuf[a]=0;
595         /* now the room prompt... */
596         ok_to_interrupt = 1;
597         printf("\n%s%c ",room_name,room_prompt(room_flags));
598         fflush(stdout);
599         
600         while(1) {
601                 ch = inkey();
602                 ok_to_interrupt = 0;
603
604                 /* Handle the backspace key, but only if there's something
605                  * to backspace over...
606                  */
607                 if ( (ch == 8) && (cmdpos > 0) ) {
608                         back(cmdspaces[cmdpos-1] + 1);
609                         cmdbuf[cmdpos] = 0;
610                         --cmdpos;
611                         }
612
613                 /* Spacebar invokes "lazy traversal" commands */
614                 if ( (ch == 32) && (cmdpos == 0) ) {
615                         this_lazy_cmd = next_lazy_cmd;
616                         if (this_lazy_cmd == 13) next_lazy_cmd = 5;
617                         if (this_lazy_cmd == 5) next_lazy_cmd = 13;
618                         for (cptr = cmdlist; cptr != NULL; cptr = cptr->next) {
619                                 if (cptr->c_cmdnum == this_lazy_cmd) {
620                                         for (a=0; a<5; ++a)
621                                             if (cptr->c_keys[a][0] != 0)
622                                                 printf("%s ", cmd_expand(
623                                                         cptr->c_keys[a], 0));
624                                         printf("\n");
625                                         return(this_lazy_cmd);
626                                         }
627                                 }
628                         printf("\n");
629                         return(this_lazy_cmd);
630                         }
631
632                 /* Otherwise, process the command */
633                 cmdbuf[cmdpos] = tolower(ch);
634
635                 for (cptr = cmdlist; cptr != NULL; cptr = cptr->next) {
636                         if (cmdmatch(cmdbuf,cptr,cmdpos+1)) {
637                                 
638                                 printf("%s",cmd_expand(cptr->c_keys[cmdpos],0));
639                                 cmdspaces[cmdpos] = strlen(
640                                         cmd_expand(cptr->c_keys[cmdpos],0) );
641                                 if (cmdpos<4) 
642                                         if ((cptr->c_keys[cmdpos+1]) != 0)
643                                                 putc(' ',stdout);
644                                 ++cmdpos;
645                                 }
646                         }
647
648                 for (cptr = cmdlist; cptr != NULL; cptr = cptr->next) {
649                         if (cmdmatch(cmdbuf,cptr,5)) {
650                                 /* We've found our command. */
651                                 if (requires_string(cptr,cmdpos)) {
652                                         getline(argbuf,32);
653                                         }
654                                 else {
655                                         printf("\n");
656                                         }
657
658                                 /* If this command is one that changes rooms,
659                                  * then the next lazy-command (space bar)
660                                  * should be "read new" instead of "goto"
661                                  */
662                                 if ((cptr->c_cmdnum==5)
663                                         ||(cptr->c_cmdnum==6)
664                                         ||(cptr->c_cmdnum==47)
665                                         ||(cptr->c_cmdnum==52)
666                                         ||(cptr->c_cmdnum==16)
667                                         ||(cptr->c_cmdnum==20))
668                                                 next_lazy_cmd = 13;
669
670                                 return(cptr->c_cmdnum);
671
672                                 }
673                         }
674
675                 if (ch == '?') {
676                         printf("\rOne of ...                         \n");
677                         for (cptr = cmdlist; cptr != NULL; cptr = cptr->next) {
678                             if (cmdmatch(cmdbuf,cptr,cmdpos)) {
679                                 for (a=0; a<5; ++a) {
680                                     printf("%s ",cmd_expand(cptr->c_keys[a],1));
681                                     }
682                                 printf("\n");
683                                 }
684                             }
685
686                         printf("\n%s%c ",room_name,room_prompt(room_flags));
687                         got = 0;
688                         for (cptr = cmdlist; cptr != NULL; cptr = cptr->next) {
689                             if ((got==0)&&(cmdmatch(cmdbuf,cptr,cmdpos))) {
690                                 for (a=0; a<cmdpos; ++a) {
691                                     printf("%s ",
692                                         cmd_expand(cptr->c_keys[a],0));
693                                     }
694                                 got = 1;
695                                 }
696                             }
697                         }
698
699                 }
700
701         }
702
703
704
705
706
707 /*
708  * set tty modes.  commands are:
709  * 
710  * 0 - set to bbs mode, intr/quit disabled
711  * 1 - set to bbs mode, intr/quit enabled
712  * 2 - save current settings for later restoral
713  * 3 - restore saved settings
714  */
715 #ifdef HAVE_TERMIOS_H
716 void sttybbs(int cmd)           /* SysV version of sttybbs() */
717          {
718         struct termios live;
719         static struct termios saved_settings;
720         static int last_cmd = 0;
721
722         if (cmd == SB_LAST)
723                 cmd = last_cmd;
724         else
725                 last_cmd = cmd;
726
727         if ( (cmd == 0) || (cmd == 1) ) {
728                 tcgetattr(0,&live);
729                 live.c_iflag=ISTRIP|IXON|IXANY;
730                 live.c_oflag=OPOST|ONLCR;
731                 live.c_lflag=ISIG|NOFLSH;
732
733                 if (cmd==SB_YES_INTR) {
734                         live.c_cc[VINTR]=NEXT_KEY;
735                         live.c_cc[VQUIT]=STOP_KEY;
736                         signal(SIGINT,*sighandler);
737                         signal(SIGQUIT,*sighandler);
738                         }
739                 else {
740                         signal(SIGINT,SIG_IGN);
741                         signal(SIGQUIT,SIG_IGN);
742                         live.c_cc[VINTR]=(-1);
743                         live.c_cc[VQUIT]=(-1);
744                         }
745
746                 /* do we even need this stuff anymore? */
747                 /* live.c_line=0; */
748                 live.c_cc[VERASE]=8;
749                 live.c_cc[VKILL]=24;
750                 live.c_cc[VEOF]=1;
751                 live.c_cc[VEOL]=255;
752                 live.c_cc[VEOL2]=0;
753                 live.c_cc[VSTART]=0;
754                 tcsetattr(0,TCSADRAIN,&live);
755                 }
756         if (cmd == 2) {
757                 tcgetattr(0,&saved_settings);
758                 }
759         if (cmd == 3) {
760                 tcsetattr(0,TCSADRAIN,&saved_settings);
761                 }
762         }
763 #else
764 void sttybbs(int cmd)           /* BSD version of sttybbs() */
765 {
766         struct sgttyb live;
767         static struct sgttyb saved_settings;
768
769         if ( (cmd == 0) || (cmd == 1) ) {
770                 gtty(0,&live);
771                 live.sg_flags |= CBREAK;
772                 live.sg_flags |= CRMOD;
773                 live.sg_flags |= NL1;
774                 live.sg_flags &= ~ECHO;
775                 if (cmd==1) live.sg_flags |= NOFLSH;
776                 stty(0,&live);
777                 }
778         if (cmd == 2) {
779                 gtty(0,&saved_settings);
780                 }
781         if (cmd == 3) {
782                 stty(0,&saved_settings);
783                 }
784         }
785 #endif
786
787
788 /*
789  * display_help()  -  help file viewer
790  */
791 void display_help(char *name)
792 {
793         formout(name);
794         }
795
796
797 /*
798  * fmout()  -  Citadel text formatter and paginator
799  */
800 int fmout(int width, FILE *fp, char pagin, int height, int starting_lp, char subst)
801                         /* screen width to use */
802                         /* file to read from, or NULL to read from server */
803                         /* nonzero if we should use the paginator */
804                         /* screen height to use */
805                         /* starting value for lines_printed, -1 for global */
806                         /* nonzero if we should use hypertext mode */
807         {
808         int a,b,c,d,old;
809         int real = (-1);
810         char aaa[140];
811         char buffer[512];
812         int eof_flag = 0;
813
814         if (starting_lp >= 0) { 
815                 lines_printed = starting_lp;
816                 }
817         strcpy(aaa,""); old=255;
818         strcpy(buffer,"");
819         c=1; /* c is the current pos */
820
821         sigcaught = 0;
822         sttybbs(1);
823
824 FMTA:   while ( (eof_flag==0) && (strlen(buffer)<126) ) {
825                 if (sigcaught) goto OOPS;
826                 if (fp!=NULL) { /* read from file */
827                         if (feof(fp)) eof_flag = 1;
828                         if (eof_flag==0) {
829                                 a=getc(fp);
830                                 buffer[strlen(buffer)+1] = 0;
831                                 buffer[strlen(buffer)] = a;
832                                 }
833                         }
834                 else {          /* read from server */
835                         d=strlen(buffer);
836                         serv_gets(&buffer[d]);
837 while ( (!isspace(buffer[d])) && (isspace(buffer[strlen(buffer)-1])) )
838         buffer[strlen(buffer)-1]=0;
839                         if (!strcmp(&buffer[d],"000")) {
840                                 buffer[d] = 0;
841                                 eof_flag = 1;
842                                 while(isspace(buffer[strlen(buffer)-1]))
843                                         buffer[strlen(buffer)-1] = 0;
844                                 }
845                         d=strlen(buffer);
846                         buffer[d] = 10;
847                         buffer[d+1] = 0;
848                         }
849                 }
850
851         buffer[strlen(buffer)+1] = 0;
852         a=buffer[0];
853         strcpy(buffer,&buffer[1]);
854         
855         old=real;
856         real=a;
857         if (a<=0) goto FMTEND;
858         
859         if ( ((a==13)||(a==10)) && (old!=13) && (old!=10) ) a=32;
860         if ( ((old==13)||(old==10)) && (isspace(real)) ) {
861                 printf("\n");
862                 ++lines_printed;
863                 lines_printed = checkpagin(lines_printed,pagin,height);
864                 c=1;
865                 }
866         if (a>126) goto FMTA;
867
868         if (a>32) {
869         if ( ((strlen(aaa)+c)>(width-5)) && (strlen(aaa)>(width-5)) ) {
870                 printf("\n%s",aaa); c=strlen(aaa); aaa[0]=0;
871                 ++lines_printed;
872                 lines_printed = checkpagin(lines_printed,pagin,height);
873                 }
874             b=strlen(aaa); aaa[b]=a; aaa[b+1]=0;
875             }
876         if (a==32) {
877                 if ((strlen(aaa)+c)>(width-5)) { 
878                         c=1;
879                         printf("\n");
880                         ++lines_printed;
881                         lines_printed = checkpagin(lines_printed,pagin,height);
882                         }
883                 printf("%s ",aaa); ++c; c=c+strlen(aaa);
884                 strcpy(aaa,"");
885                 goto FMTA;
886                 }
887         if ((a==13)||(a==10)) {
888                 printf("%s\n",aaa);
889                 c=1;
890                 ++lines_printed;
891                 lines_printed = checkpagin(lines_printed,pagin,height);
892                 strcpy(aaa,"");
893                 goto FMTA;
894                 }
895         goto FMTA;
896
897         /* signal caught; drain the server */
898 OOPS:   do {
899                 serv_gets(aaa);
900                 } while(strcmp(aaa,"000"));
901
902 FMTEND: printf("\n");
903         ++lines_printed;
904         lines_printed = checkpagin(lines_printed,pagin,height);
905         return(sigcaught);
906 }
907
908
909 /*
910  * support ANSI color if defined
911  */
912 void color(int colornum)
913 {
914         if (enable_color) {
915                 printf("\033[3%dm", colornum);
916                 fflush(stdout);
917                 }
918         }
919
920 void cls(int colornum) {
921         if (enable_color) {
922                 printf("\033[4%dm\033[2J\033[H", colornum);
923                 printf("\033[0m"); /* change to 1 for bold colours */
924                 fflush(stdout);
925                 }
926         }
927
928
929 /*
930  * Detect whether ANSI color is available (answerback)
931  */
932 void send_ansi_detect(void) {
933         if (rc_ansi_color == 2) {
934                 printf("\033[c");
935                 fflush(stdout);
936                 time(&AnsiDetect);
937                 }
938         }
939
940 void look_for_ansi(void) {
941         fd_set rfds;
942         struct timeval tv;
943         char abuf[512];
944         time_t now;
945         int a;
946
947         if (rc_ansi_color == 0) {
948                 enable_color = 0;
949                 }
950         else if (rc_ansi_color == 1) {
951                 enable_color = 1;
952                 }
953         else if (rc_ansi_color == 2) {
954
955                 /* otherwise, do the auto-detect */
956
957                 strcpy(abuf, "");
958
959                 time(&now);
960                 if ( (now - AnsiDetect) < 2 ) sleep(1);
961
962                 do {
963                         FD_ZERO(&rfds);
964                         FD_SET(0,&rfds);
965                         tv.tv_sec = 0;
966                         tv.tv_usec = 1;
967
968                         select(1, &rfds, NULL, NULL, &tv);
969                         if (FD_ISSET(0, &rfds)) {
970                                 abuf[strlen(abuf)+1] = 0;
971                                 read(0, &abuf[strlen(abuf)], 1);
972                                 }
973         
974                         } while (FD_ISSET(0, &rfds));
975         
976                 for (a=0; a<strlen(abuf); ++a) {
977                         if ( (abuf[a] == 27) && (abuf[a+1] == '[')
978                         && (abuf[a+2] == '?') ) {
979                                 enable_color = 1;
980                                 }
981                         }
982                 }
983
984         }