-// 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".
" 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"
" 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"
" 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"
// 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
// 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) {
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);
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);
}
}
- 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;
#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
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))
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 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;
}
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;
live.c_cc[VSTART] = 0;
tcsetattr(0, TCSADRAIN, &live);
}
+
if (cmd == 2) {
tcgetattr(0, &saved_settings);
}
+
if (cmd == 3) {
tcsetattr(0, TCSADRAIN, &saved_settings);
}
// 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);
// 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, " ");
}
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++;
if (buf[i] == '<') {
scr_printf("%c", buf[i]);
color(BRIGHT_MAGENTA);
- } else {
+ }
+ else {
if (buf[i] == '>' && buf[i + 1] != '>') {
color(DIM_WHITE);
}