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