fix dlen
[citadel.git] / textclient / commands.c
index 0c0cb99ba2d2ea211be7edb7348cf5f0b7217faa..c241f014d70a08c55c24e164cb0df6b889564044 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"
 
-
 // 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"
+           " 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"
+           " 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"
+           " 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"
@@ -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"
-           "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"
@@ -344,9 +337,6 @@ char *helptexts[] = {
            "                                          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"
@@ -449,10 +439,10 @@ struct citcmd *cmdlist = NULL;
 
 
 // these variables are local to this module
-char keepalives_enabled = KA_YES;              // send NOOPs to server when idle
-int ok_to_interrupt = 0;                       // print instant msgs asynchronously
-time_t AnsiDetect;                             // when did we send the detect code?
-int enable_color = 0;                          // nonzero for ANSI color
+char keepalives_enabled = KA_YES;      // send NOOPs to server when idle
+int ok_to_interrupt = 0;       // print instant msgs asynchronously
+time_t AnsiDetect;             // when did we send the detect code?
+int enable_color = 0;          // nonzero for ANSI color
 
 
 // If an interesting key has been pressed, return its value, otherwise 0
@@ -732,10 +722,10 @@ int yesno_d(int d) {
 
 // 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) {
@@ -747,14 +737,15 @@ int ctdl_getline(char *string, int lim, int noshow, int bs) {
                while (num_stars--) {
                        scr_putc('*');
                }
-       } else {
+       }
+       else {
                scr_printf("%s", string);
        }
 
        while (1) {
                ch = inkey();
 
-               if ((ch == 8) && (pos > 0)) {                   // backspace
+               if ((ch == 8) && (pos > 0)) {   // backspace
                        --pos;
                        scr_putc(8);
                        scr_putc(32);
@@ -765,7 +756,7 @@ int ctdl_getline(char *string, int lim, int noshow, int bs) {
                        return (-1);
                }
 
-               else if ((ch == 23) && (pos > 0)) {             // Ctrl-W deletes a word
+               else if ((ch == 23) && (pos > 0)) {     // Ctrl-W deletes a word
                        while ((pos > 0) && !isspace(string[pos])) {
                                --pos;
                                scr_putc(8);
@@ -780,13 +771,13 @@ 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);
                }
 
-               else if (isprint(ch)) {                         // payload characters
+               else if (isprint(ch)) { // payload characters
                        scr_putc((noshow ? '*' : ch));
                        string[pos] = ch;
                        ++pos;
@@ -948,7 +939,8 @@ void load_command_set(void) {
 #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
@@ -997,9 +989,9 @@ void load_command_set(void) {
                        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))
-                               rc_ansi_color = 3;              // user config
+                               rc_ansi_color = 3;      // user config
                }
                if (!strncasecmp(buf, "status_line=", 12)) {
                        if (!strncasecmp(&buf[12], "on", 2))
@@ -1013,7 +1005,7 @@ void load_command_set(void) {
                        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]);
@@ -1278,13 +1270,13 @@ int getcmd(CtdlIPC * ipc, char *argbuf) {
 
                                // If this command is one that changes rooms, then the next lazy-command
                                // (space bar) should be "read new" instead of "goto"
-                               if (    (cptr->c_cmdnum == 5)
-                                       || (cptr->c_cmdnum == 6)
-                                       || (cptr->c_cmdnum == 47)
-                                       || (cptr->c_cmdnum == 52)
-                                       || (cptr->c_cmdnum == 16)
-                                       || (cptr->c_cmdnum == 20)
-                               ) {
+                               if ((cptr->c_cmdnum == 5)
+                                   || (cptr->c_cmdnum == 6)
+                                   || (cptr->c_cmdnum == 47)
+                                   || (cptr->c_cmdnum == 52)
+                                   || (cptr->c_cmdnum == 16)
+                                   || (cptr->c_cmdnum == 20)
+                                   ) {
                                        next_lazy_cmd = 13;
                                }
 
@@ -1346,15 +1338,15 @@ void stty_ctdl(int cmd) {
 
        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;
 
+               // Key bindings
                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;
@@ -1363,9 +1355,11 @@ void stty_ctdl(int cmd) {
                live.c_cc[VSTART] = 0;
                tcsetattr(0, TCSADRAIN, &live);
        }
+
        if (cmd == 2) {
                tcgetattr(0, &saved_settings);
        }
+
        if (cmd == 3) {
                tcsetattr(0, TCSADRAIN, &saved_settings);
        }
@@ -1394,16 +1388,17 @@ void display_help(CtdlIPC * ipc, char *name) {
 
 // fmout() - Citadel text formatter and paginator
 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
-       int subst) {            // nonzero if we should use hypertext mode
+         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
        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);
@@ -1427,22 +1422,30 @@ int fmout(int width,            // screen width to use
 
        // Run the message body
        while (*e) {
+
                // 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++;
-                       if (*e == ' ') {                // paragraph?
+                       if (*e == ' ') {        // paragraph?
                                if (fpout) {
                                        fprintf(fpout, "\n");
-                               } else {
+                               }
+                               else {
                                        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, " ");
                                }
@@ -1455,6 +1458,11 @@ int fmout(int width,             // screen width to use
                        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++;
@@ -1652,7 +1660,8 @@ void keyopt(char *buf) {
                if (buf[i] == '<') {
                        scr_printf("%c", buf[i]);
                        color(BRIGHT_MAGENTA);
-               } else {
+               }
+               else {
                        if (buf[i] == '>' && buf[i + 1] != '>') {
                                color(DIM_WHITE);
                        }