]> code.citadel.org Git - citadel.git/blobdiff - textclient/commands.c
Fix ansi auto-detect
[citadel.git] / textclient / commands.c
index 0c0cb99ba2d2ea211be7edb7348cf5f0b7217faa..dfc3f0601892736373c41d53bf1f57e7d3177c30 100644 (file)
@@ -1,19 +1,11 @@
-// This file contains functions which implement parts of the
-// text-mode user interface.
+// This file contains functions which implement parts of the text-mode user interface.
 //
 //
-// Copyright (c) 1987-2022 by the citadel.org team
+// Copyright (c) 1987-2024 by the citadel.org team
 //
 //
-// This program is open source software.  Use, duplication, and/or
-// disclosure are subject to the GNU General Purpose License version 3.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
+// This program is open source software.  Use, duplication, or disclosure is subject to the GNU General Public License version 3.
 
 #include "textclient.h"
 
 
 #include "textclient.h"
 
-
 // The help "files" are now just an embedded set of Very Long Strings.  helpnames[] is
 // an array of "file names" and helptexts[] is the "content".
 
 // The help "files" are now just an embedded set of Very Long Strings.  helpnames[] is
 // an array of "file names" and helptexts[] is the "content".
 
@@ -42,11 +34,14 @@ char *helptexts[] = {
            " G         Goto next room which has UNREAD messages.\n"
            " H         Help. Same as '?'\n"
            " I         Reads the Information file for this room.\n"
            " G         Goto next room which has UNREAD messages.\n"
            " H         Help. Same as '?'\n"
            " I         Reads the Information file for this room.\n"
+           " J         Jump to any named room (same as <.G>oto)\n"
            " K         List of Known rooms.\n"
            " L         Reads the last five messages in the room.\n"
            " K         List of Known rooms.\n"
            " L         Reads the last five messages in the room.\n"
+           " M         Go to your private Mail room\n"
            " N         Reads all new messages in the room.\n"
            " O         Reads all old messages, backwards.\n"
            " P         Page another user (send an instant message)\n"
            " N         Reads all new messages in the room.\n"
            " O         Reads all old messages, backwards.\n"
            " P         Page another user (send an instant message)\n"
+           " Q         Quiet mode on/off (disables receiving instant messages)\n"
            " R         Reads all messages in the room, in reverse order.\n"
            " S         Skips current room without making its messages old.\n"
            " T         Terminate (logout)\n"
            " R         Reads all messages in the room, in reverse order.\n"
            " S         Skips current room without making its messages old.\n"
            " T         Terminate (logout)\n"
@@ -60,9 +55,7 @@ char *helptexts[] = {
            " In addition, there are dot commands. You hit the . (dot), then press the\n"
            "first letter of each word of the command. As you hit the letters, the words\n"
            "pop onto your screen. Exceptions: after you hit .Help or .Goto, the remainder\n"
            " In addition, there are dot commands. You hit the . (dot), then press the\n"
            "first letter of each word of the command. As you hit the letters, the words\n"
            "pop onto your screen. Exceptions: after you hit .Help or .Goto, the remainder\n"
-           "of the command is a help file name or room name.\n"
-           "    \n"
-           "      *** USE  .<H>elp ?    for additional help *** \n",
+           "of the command is a help file name or room name.\n" "    \n" "      *** USE  .<H>elp ?    for additional help *** \n",
 
        // <.H>elp ADMIN
        "The following commands are available only to Admins.  A subset of these\n"
 
        // <.H>elp ADMIN
        "The following commands are available only to Admins.  A subset of these\n"
@@ -344,9 +337,6 @@ char *helptexts[] = {
            "                                          you can specify a partial match\n"
            "\n"
            " <.> <R>ead <T>extfile formatted          File 'download' commands.\n"
            "                                          you can specify a partial match\n"
            "\n"
            " <.> <R>ead <T>extfile formatted          File 'download' commands.\n"
-           " <.> <R>ead file using <X>modem   \n"
-           " <.> <R>ead file using <Y>modem   \n"
-           " <.> <R>ead file using <Z>modem   \n"
            " <.> <R>ead <F>ile unformatted   \n"
            " <.> <R>ead <D>irectory   \n"
            "\n"
            " <.> <R>ead <F>ile unformatted   \n"
            " <.> <R>ead <D>irectory   \n"
            "\n"
@@ -433,6 +423,7 @@ int rc_display_message_numbers;
 int rc_force_mail_prompts;
 int rc_remember_passwords;
 int rc_ansi_color;
 int rc_force_mail_prompts;
 int rc_remember_passwords;
 int rc_ansi_color;
+int rc_sixel;
 int rc_color_use_bg;
 int rc_prompt_control = 0;
 time_t rc_idle_threshold = (time_t) 900;
 int rc_color_use_bg;
 int rc_prompt_control = 0;
 time_t rc_idle_threshold = (time_t) 900;
@@ -493,7 +484,7 @@ void display_instant_messages(void) {
        char sender[64];
        char node[64];
        char *listing = NULL;
        char sender[64];
        char node[64];
        char *listing = NULL;
-       int r;                  // IPC result code
+       int r;                                  // IPC result code
 
        if (instant_msgs == 0) {
                return;
 
        if (instant_msgs == 0) {
                return;
@@ -732,10 +723,10 @@ int yesno_d(int d) {
 
 // Function to read a line of text from the terminal.
 //
 
 // Function to read a line of text from the terminal.
 //
-// string              Pointer to string buffer
-// lim                 Maximum length
-// noshow              Echo asterisks instead of keystrokes?
-// bs                  Allow backspacing out of the prompt? (returns -1 if this happens)
+// string               Pointer to string buffer
+// lim                  Maximum length
+// noshow               Echo asterisks instead of keystrokes?
+// bs                   Allow backspacing out of the prompt? (returns -1 if this happens)
 //
 // returns: string length
 int ctdl_getline(char *string, int lim, int noshow, int bs) {
 //
 // returns: string length
 int ctdl_getline(char *string, int lim, int noshow, int bs) {
@@ -747,7 +738,8 @@ int ctdl_getline(char *string, int lim, int noshow, int bs) {
                while (num_stars--) {
                        scr_putc('*');
                }
                while (num_stars--) {
                        scr_putc('*');
                }
-       } else {
+       }
+       else {
                scr_printf("%s", string);
        }
 
                scr_printf("%s", string);
        }
 
@@ -780,7 +772,7 @@ int ctdl_getline(char *string, int lim, int noshow, int bs) {
                        }
                }
 
                        }
                }
 
-               else if (ch == 10) {                            // return
+               else if (ch == 10) {    // return
                        string[pos] = 0;
                        scr_printf("\n");
                        return (pos);
                        string[pos] = 0;
                        scr_printf("\n");
                        return (pos);
@@ -869,8 +861,9 @@ void newprompt(char *prompt, char *str, int len) {
 int lkey(void) {
        int a;
        a = inkey();
 int lkey(void) {
        int a;
        a = inkey();
-       if (isupper(a))
+       if (isupper(a)) {
                a = tolower(a);
                a = tolower(a);
+       }
        return (a);
 }
 
        return (a);
 }
 
@@ -898,6 +891,7 @@ void load_command_set(void) {
        rc_display_message_numbers = 0;
        rc_force_mail_prompts = 0;
        rc_ansi_color = 0;
        rc_display_message_numbers = 0;
        rc_force_mail_prompts = 0;
        rc_ansi_color = 0;
+       rc_sixel = 0;
        rc_color_use_bg = 0;
        strcpy(rc_url_cmd, "");
        strcpy(rc_open_cmd, "");
        rc_color_use_bg = 0;
        strcpy(rc_url_cmd, "");
        strcpy(rc_open_cmd, "");
@@ -948,7 +942,8 @@ void load_command_set(void) {
 #ifdef HAVE_OPENSSL
                        else if (!strcasecmp(&buf[8], "no")) {
                                rc_encrypt = RC_NO;
 #ifdef HAVE_OPENSSL
                        else if (!strcasecmp(&buf[8], "no")) {
                                rc_encrypt = RC_NO;
-                       } else if (!strcasecmp(&buf[8], "default")) {
+                       }
+                       else if (!strcasecmp(&buf[8], "default")) {
                                rc_encrypt = RC_DEFAULT;
                        }
 #endif
                                rc_encrypt = RC_DEFAULT;
                        }
 #endif
@@ -997,14 +992,18 @@ void load_command_set(void) {
                        if (!strncasecmp(&buf[11], "on", 2))
                                rc_ansi_color = 1;
                        if (!strncasecmp(&buf[11], "auto", 4))
                        if (!strncasecmp(&buf[11], "on", 2))
                                rc_ansi_color = 1;
                        if (!strncasecmp(&buf[11], "auto", 4))
-                               rc_ansi_color = 2;              // autodetect
+                               rc_ansi_color = 2;      // autodetect
                        if (!strncasecmp(&buf[11], "user", 4))
                        if (!strncasecmp(&buf[11], "user", 4))
-                               rc_ansi_color = 3;              // user config
+                               rc_ansi_color = 3;      // user config
                }
                if (!strncasecmp(buf, "status_line=", 12)) {
                        if (!strncasecmp(&buf[12], "on", 2))
                                enable_status_line = 1;
                }
                }
                if (!strncasecmp(buf, "status_line=", 12)) {
                        if (!strncasecmp(&buf[12], "on", 2))
                                enable_status_line = 1;
                }
+               if (!strncasecmp(buf, "use_sixel=", 10)) {
+                       if (!strncasecmp(&buf[10], "on", 2))
+                               rc_sixel = 1;
+               }
                if (!strncasecmp(buf, "use_background=", 15)) {
                        if (!strncasecmp(&buf[15], "on", 2))
                                rc_color_use_bg = 9;
                if (!strncasecmp(buf, "use_background=", 15)) {
                        if (!strncasecmp(&buf[15], "on", 2))
                                rc_color_use_bg = 9;
@@ -1013,7 +1012,7 @@ void load_command_set(void) {
                        if (!strncasecmp(&buf[15], "on", 2))
                                rc_prompt_control = 1;
                        if (!strncasecmp(&buf[15], "user", 4))
                        if (!strncasecmp(&buf[15], "on", 2))
                                rc_prompt_control = 1;
                        if (!strncasecmp(&buf[15], "user", 4))
-                               rc_prompt_control = 3;          // user config
+                               rc_prompt_control = 3;  // user config
                }
                if (!strncasecmp(buf, "username=", 9))
                        strcpy(rc_username, &buf[9]);
                }
                if (!strncasecmp(buf, "username=", 9))
                        strcpy(rc_username, &buf[9]);
@@ -1185,10 +1184,12 @@ int getcmd(CtdlIPC * ipc, char *argbuf) {
 
        // Switch color support on or off if we're in user mode
        if (rc_ansi_color == 3) {
 
        // Switch color support on or off if we're in user mode
        if (rc_ansi_color == 3) {
-               if (userflags & US_COLOR)
+               if (userflags & US_COLOR) {
                        enable_color = 1;
                        enable_color = 1;
-               else
+               }
+               else {
                        enable_color = 0;
                        enable_color = 0;
+               }
        }
 
        // if we're running in idiot mode, display a cute little menu
        }
 
        // if we're running in idiot mode, display a cute little menu
@@ -1294,7 +1295,6 @@ int getcmd(CtdlIPC * ipc, char *argbuf) {
                                }
 
                                return (cptr->c_cmdnum);
                                }
 
                                return (cptr->c_cmdnum);
-
                        }
                }
 
                        }
                }
 
@@ -1330,7 +1330,7 @@ int getcmd(CtdlIPC * ipc, char *argbuf) {
 // set tty modes.  commands are:
 // 
 // 01- set to Citadel mode
 // set tty modes.  commands are:
 // 
 // 01- set to Citadel mode
-// 2 - save current settings for later restoral
+// 2 - save current settings for later restore
 // 3 - restore saved settings
 void stty_ctdl(int cmd) {
        struct termios live;
 // 3 - restore saved settings
 void stty_ctdl(int cmd) {
        struct termios live;
@@ -1346,15 +1346,15 @@ void stty_ctdl(int cmd) {
 
        if ((cmd == 0) || (cmd == 1)) {
                tcgetattr(0, &live);
 
        if ((cmd == 0) || (cmd == 1)) {
                tcgetattr(0, &live);
+
+               // Character-by-character input instead of line mode
                live.c_iflag = ISTRIP | IXON | IXANY;
                live.c_oflag = OPOST | ONLCR;
                live.c_lflag = ISIG | NOFLSH;
 
                live.c_iflag = ISTRIP | IXON | IXANY;
                live.c_oflag = OPOST | ONLCR;
                live.c_lflag = ISIG | NOFLSH;
 
+               // Key bindings
                live.c_cc[VINTR] = 0;
                live.c_cc[VQUIT] = 0;
                live.c_cc[VINTR] = 0;
                live.c_cc[VQUIT] = 0;
-
-               // do we even need this stuff anymore?
-               // live.c_line=0;
                live.c_cc[VERASE] = 8;
                live.c_cc[VKILL] = 24;
                live.c_cc[VEOF] = 1;
                live.c_cc[VERASE] = 8;
                live.c_cc[VKILL] = 24;
                live.c_cc[VEOF] = 1;
@@ -1363,9 +1363,11 @@ void stty_ctdl(int cmd) {
                live.c_cc[VSTART] = 0;
                tcsetattr(0, TCSADRAIN, &live);
        }
                live.c_cc[VSTART] = 0;
                tcsetattr(0, TCSADRAIN, &live);
        }
+
        if (cmd == 2) {
                tcgetattr(0, &saved_settings);
        }
        if (cmd == 2) {
                tcgetattr(0, &saved_settings);
        }
+
        if (cmd == 3) {
                tcsetattr(0, TCSADRAIN, &saved_settings);
        }
        if (cmd == 3) {
                tcsetattr(0, TCSADRAIN, &saved_settings);
        }
@@ -1397,13 +1399,15 @@ int fmout(int width,            // screen width to use
        FILE * fpin,            // file to read from, or NULL to format given text
        char *text,             // text to be formatted (when fpin is NULL
        FILE * fpout,           // file to write to, or NULL to write to screen
        FILE * fpin,            // file to read from, or NULL to format given text
        char *text,             // text to be formatted (when fpin is NULL
        FILE * fpout,           // file to write to, or NULL to write to screen
-       int subst) {            // nonzero if we should use hypertext mode
+       int subst               // nonzero if we should use hypertext mode
+) {
        char *buffer = NULL;    // The current message
        char *word = NULL;      // What we are about to actually print
        char *e;                // Pointer to position in text
        char old = 0;           // The previous character
        int column = 0;         // Current column
        size_t i;               // Generic counter
        char *buffer = NULL;    // The current message
        char *word = NULL;      // What we are about to actually print
        char *e;                // Pointer to position in text
        char old = 0;           // The previous character
        int column = 0;         // Current column
        size_t i;               // Generic counter
+       int in_quote = 0;
 
        // Space for a single word, which can be at most screenwidth
        word = (char *) calloc(1, width);
 
        // Space for a single word, which can be at most screenwidth
        word = (char *) calloc(1, width);
@@ -1427,22 +1431,30 @@ int fmout(int width,            // screen width to use
 
        // Run the message body
        while (*e) {
 
        // Run the message body
        while (*e) {
+
                // Catch characters that shouldn't be there at all
                if (*e == '\r') {
                        e++;
                        continue;
                }
                // Catch characters that shouldn't be there at all
                if (*e == '\r') {
                        e++;
                        continue;
                }
-               if (*e == '\n') {                       // newline?
+
+               if ((in_quote) && (*e == '\n') && (enable_color)) {
+                       in_quote = 0;
+                       scr_printf("\033[22m\033[22m");
+               }
+
+               if (*e == '\n') {       // newline?
                        e++;
                        e++;
-                       if (*e == ' ') {                // paragraph?
+                       if (*e == ' ') {        // paragraph?
                                if (fpout) {
                                        fprintf(fpout, "\n");
                                if (fpout) {
                                        fprintf(fpout, "\n");
-                               } else {
+                               }
+                               else {
                                        scr_printf("\n");
                                }
                                column = 0;
                        }
                                        scr_printf("\n");
                                }
                                column = 0;
                        }
-                       else if (old != ' ') {          // Don't print two spaces
+                       else if (old != ' ') {  // Don't print two spaces
                                if (fpout) {
                                        fprintf(fpout, " ");
                                }
                                if (fpout) {
                                        fprintf(fpout, " ");
                                }
@@ -1455,6 +1467,11 @@ int fmout(int width,             // screen width to use
                        continue;
                }
 
                        continue;
                }
 
+               if ((*e == '>') && (column <= 1) && (!fpout) && (enable_color)) {
+                       in_quote = 1;
+                       scr_printf("\033[2m\033[2m");
+               }
+
                // Or are we looking at a space?
                if (*e == ' ') {
                        e++;
                // Or are we looking at a space?
                if (*e == ' ') {
                        e++;
@@ -1566,11 +1583,12 @@ void color(int colornum) {
                // terminals. - Changed to ORIGINAL_PAIR as this actually
                // wound up looking horrible on black-on-white terminals, not
                // to mention transparent terminals.
                // terminals. - Changed to ORIGINAL_PAIR as this actually
                // wound up looking horrible on black-on-white terminals, not
                // to mention transparent terminals.
-               if (colornum == ORIGINAL_PAIR)
+               if (colornum == ORIGINAL_PAIR) {
                        printf("\033[0;39;49m");
                        printf("\033[0;39;49m");
-               else
+               }
+               else {
                        printf("\033[%d;3%d;4%dm", (colornum & 8) ? 1 : 0, (colornum & 7), rc_color_use_bg);
                        printf("\033[%d;3%d;4%dm", (colornum & 8) ? 1 : 0, (colornum & 7), rc_color_use_bg);
-
+               }
        }
 }
 
        }
 }
 
@@ -1593,6 +1611,7 @@ void send_ansi_detect(void) {
 }
 
 
 }
 
 
+// Turn ANSI color (etc.) support on, or off, or auto-detect support, depending on the configuration
 void look_for_ansi(void) {
        fd_set rfds;
        struct timeval tv;
 void look_for_ansi(void) {
        fd_set rfds;
        struct timeval tv;
@@ -1600,21 +1619,19 @@ void look_for_ansi(void) {
        time_t now;
        int a, rv;
 
        time_t now;
        int a, rv;
 
-       if (rc_ansi_color == 0) {
+       if (rc_ansi_color == 0) {                       // Configured to never use color
                enable_color = 0;
        }
                enable_color = 0;
        }
-       else if (rc_ansi_color == 1) {
+       else if (rc_ansi_color == 1) {                  // Configured to always use color
                enable_color = 1;
        }
                enable_color = 1;
        }
-       else if (rc_ansi_color == 2) {
-
-               /* otherwise, do the auto-detect */
+       else if (rc_ansi_color == 2) {                  // Configured to auto-detect ANSI color support
 
                strcpy(abuf, "");
 
                strcpy(abuf, "");
-
                time(&now);
                time(&now);
-               if ((now - AnsiDetect) < 2)
+               if ((now - AnsiDetect) < 2) {
                        sleep(1);
                        sleep(1);
+               }
 
                do {
                        FD_ZERO(&rfds);
 
                do {
                        FD_ZERO(&rfds);
@@ -1634,8 +1651,10 @@ void look_for_ansi(void) {
                } while (FD_ISSET(0, &rfds));
 
                for (a = 0; !IsEmptyStr(&abuf[a]); ++a) {
                } while (FD_ISSET(0, &rfds));
 
                for (a = 0; !IsEmptyStr(&abuf[a]); ++a) {
-                       if ((abuf[a] == 27) && (abuf[a + 1] == '[')
-                           && (abuf[a + 2] == '?')) {
+                       if (    (abuf[a] == 27)
+                               && (abuf[a + 1] == '[')
+                               && (abuf[a + 2] == '?')
+                       ) {                                     // ANSI support was detected!
                                enable_color = 1;
                        }
                }
                                enable_color = 1;
                        }
                }
@@ -1652,7 +1671,8 @@ void keyopt(char *buf) {
                if (buf[i] == '<') {
                        scr_printf("%c", buf[i]);
                        color(BRIGHT_MAGENTA);
                if (buf[i] == '<') {
                        scr_printf("%c", buf[i]);
                        color(BRIGHT_MAGENTA);
-               } else {
+               }
+               else {
                        if (buf[i] == '>' && buf[i + 1] != '>') {
                                color(DIM_WHITE);
                        }
                        if (buf[i] == '>' && buf[i + 1] != '>') {
                                color(DIM_WHITE);
                        }