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