how absolutely rubbish my coding style was in the late 1980s. I did
a few bits of cleanup but most of that code ought to be rewritten.
The good news is that unlike WebCit, I believe we can redo the text
client in place over a period of time.
This is a text mode user interface for the Citadel system. It presents
a Citadel site to users in the form of a traditional BBS.
This is a text mode user interface for the Citadel system. It presents
a Citadel site to users in the form of a traditional BBS.
-All code is Copyright (c) 1987-2021 by the citadel.org team.
+All code is Copyright (c) 1987-2022 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 open source software. Use, duplication, and/or
disclosure are subject to the GNU General Purpose License version 3.
// Text client functions for reading and writing of messages
//
// Text client functions for reading and writing of messages
//
-// Copyright (c) 1987-2020 by the citadel.org team
+// Beware: this is really old and crappy code, written in the
+// late 1980s when my coding style was absolute garbage. It
+// works, but we probably should replace most of it.
+//
+// Copyright (c) 1987-2022 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 open source software. Use, duplication, and/or
// disclosure are subject to the GNU General Purpose License version 3.
struct parts *last_message_parts = NULL; /* Parts from last msg */
struct parts *last_message_parts = NULL; /* Parts from last msg */
-void ka_sigcatch(int signum)
-{
+void ka_sigcatch(int signum) {
alarm(S_KEEPALIVE);
signal(SIGALRM, ka_sigcatch);
CtdlIPCNoop(ipc_for_signal_handlers);
alarm(S_KEEPALIVE);
signal(SIGALRM, ka_sigcatch);
CtdlIPCNoop(ipc_for_signal_handlers);
/*
* server keep-alive version of wait() (needed for external editor)
*/
/*
* server keep-alive version of wait() (needed for external editor)
*/
-pid_t ka_wait(int *kstatus)
-{
+pid_t ka_wait(int *kstatus) {
pid_t p;
alarm(S_KEEPALIVE);
pid_t p;
alarm(S_KEEPALIVE);
/*
* version of system() that uses ka_wait()
*/
/*
* version of system() that uses ka_wait()
*/
-int ka_system(char *shc)
-{
+int ka_system(char *shc) {
pid_t childpid;
pid_t waitpid;
int retcode;
pid_t childpid;
pid_t waitpid;
int retcode;
/*
* add a word to the buffer...
*/
/*
* add a word to the buffer...
*/
-void add_word(struct cittext *textlist, char *wordbuf)
-{
+void add_word(struct cittext *textlist, char *wordbuf) {
struct cittext *ptr;
ptr = textlist;
struct cittext *ptr;
ptr = textlist;
/*
* begin editing of an opened file pointed to by fp
*/
/*
* begin editing of an opened file pointed to by fp
*/
-void citedit(FILE * fp)
-{
+void citedit(FILE * fp) {
int a, prev, finished, b, last_space;
int appending = 0;
struct cittext *textlist = NULL;
int a, prev, finished, b, last_space;
int appending = 0;
struct cittext *textlist = NULL;
add_newline(textlist);
add_word(textlist, "");
}
add_newline(textlist);
add_word(textlist, "");
}
wordbuf[strlen(wordbuf) + 1] = 0;
wordbuf[strlen(wordbuf)] = a;
}
wordbuf[strlen(wordbuf) + 1] = 0;
wordbuf[strlen(wordbuf)] = a;
}
scr_putc(32);
scr_putc(8);
}
scr_putc(32);
scr_putc(8);
}
+ }
+ else if (a == 23) {
do {
wordbuf[strlen(wordbuf) - 1] = 0;
scr_putc(8);
scr_putc(32);
scr_putc(8);
} while (!IsEmptyStr(wordbuf) && wordbuf[strlen(wordbuf) - 1] != ' ');
do {
wordbuf[strlen(wordbuf) - 1] = 0;
scr_putc(8);
scr_putc(32);
scr_putc(8);
} while (!IsEmptyStr(wordbuf) && wordbuf[strlen(wordbuf) - 1] != ' ');
+ }
+ else if (a == 13) {
scr_printf("\n");
if (IsEmptyStr(wordbuf))
finished = 1;
scr_printf("\n");
if (IsEmptyStr(wordbuf))
finished = 1;
add_word(textlist, wordbuf);
strcpy(wordbuf, "");
}
add_word(textlist, wordbuf);
strcpy(wordbuf, "");
}
scr_putc(a);
wordbuf[strlen(wordbuf) + 1] = 0;
wordbuf[strlen(wordbuf)] = a;
scr_putc(a);
wordbuf[strlen(wordbuf) + 1] = 0;
wordbuf[strlen(wordbuf)] = a;
scr_putc(8);
}
scr_printf("\n%s", wordbuf);
scr_putc(8);
}
scr_printf("\n%s", wordbuf);
add_word(textlist, wordbuf);
strcpy(wordbuf, "");
scr_printf("\n");
add_word(textlist, wordbuf);
strcpy(wordbuf, "");
scr_printf("\n");
/*
* Free the struct parts
*/
/*
* Free the struct parts
*/
-void free_parts(struct parts *p)
-{
+void free_parts(struct parts *p) {
struct parts *a_part = p;
while (a_part) {
struct parts *a_part = p;
while (a_part) {
* It only handles strings encoded from UTF-8 as Quoted-printable.
* We can do this "in place" because the converted string will always be smaller than the source string.
*/
* It only handles strings encoded from UTF-8 as Quoted-printable.
* We can do this "in place" because the converted string will always be smaller than the source string.
*/
-void mini_2047_decode(char *s)
-{
+void mini_2047_decode(char *s) {
if (!s) { // no null strings allowed!
return;
}
if (!s) { // no null strings allowed!
return;
}
if (strcasecmp(message->room, room_name) && (IsEmptyStr(message->email))) {
if (dest) {
fprintf(dest, "in %s> ", message->room);
if (strcasecmp(message->room, room_name) && (IsEmptyStr(message->email))) {
if (dest) {
fprintf(dest, "in %s> ", message->room);
color(DIM_WHITE);
scr_printf("in ");
color(BRIGHT_MAGENTA);
color(DIM_WHITE);
scr_printf("in ");
color(BRIGHT_MAGENTA);
if (!IsEmptyStr(message->recipient)) {
if (dest) {
fprintf(dest, "to %s ", message->recipient);
if (!IsEmptyStr(message->recipient)) {
if (dest) {
fprintf(dest, "to %s ", message->recipient);
color(DIM_WHITE);
scr_printf("to ");
color(BRIGHT_CYAN);
color(DIM_WHITE);
scr_printf("to ");
color(BRIGHT_CYAN);
- /* Set the reply-to address to an Internet e-mail address if possible
- */
+ // Set the reply-to address to an Internet e-mail address if possible
if ((message->email != NULL) && (!IsEmptyStr(message->email))) {
if (!IsEmptyStr(message->author)) {
snprintf(reply_to, sizeof reply_to, "%s <%s>", message->author, message->email);
if ((message->email != NULL) && (!IsEmptyStr(message->email))) {
if (!IsEmptyStr(message->author)) {
snprintf(reply_to, sizeof reply_to, "%s <%s>", message->author, message->email);
- /* But if we can't do that, set it to a Citadel address.
- */
+ // But if we can't do that, set it to a Citadel address.
if (!strcmp(reply_to, NO_REPLY_TO)) {
strncpy(reply_to, message->author, sizeof(reply_to));
}
if (!strcmp(reply_to, NO_REPLY_TO)) {
strncpy(reply_to, message->author, sizeof(reply_to));
}
if (!IsEmptyStr(message->subject)) {
if (dest) {
fprintf(dest, "Subject: %s\n", message->subject);
if (!IsEmptyStr(message->subject)) {
if (dest) {
fprintf(dest, "Subject: %s\n", message->subject);
color(DIM_WHITE);
scr_printf("Subject: ");
color(BRIGHT_CYAN);
color(DIM_WHITE);
scr_printf("Subject: ");
color(BRIGHT_CYAN);
/*
* replace string function for the built-in editor
*/
/*
* replace string function for the built-in editor
*/
-void replace_string(char *filename, long int startpos)
-{
+void replace_string(char *filename, long int startpos) {
char buf[512];
char srch_str[128];
char rplc_str[128];
char buf[512];
char srch_str[128];
char rplc_str[128];
-/*
- * Function to begin composing a new message
- */
-int client_make_message(CtdlIPC * ipc, char *filename, /* temporary file name */
- char *recipient, /* NULL if it's not mail */
- int is_anonymous, int format_type, int mode, char *subject, /* buffer to store subject line */
- int subject_required)
-{
+// Function to begin composing a new message
+int client_make_message(CtdlIPC * ipc,
+ char *filename, // temporary file name
+ char *recipient, // NULL if it's not mail
+ int is_anonymous,
+ int format_type,
+ int mode,
+ char *subject, // buffer to store subject line
+ int subject_required
+) {
FILE *fp;
int a, b, e_ex_code;
long beg;
FILE *fp;
int a, b, e_ex_code;
long beg;
if (room_flags & QR_ANONONLY && !recipient) {
snprintf(header, sizeof header, " ****");
if (room_flags & QR_ANONONLY && !recipient) {
snprintf(header, sizeof header, " ****");
- } else {
- snprintf(header, sizeof header, " %s from %s", datestr, (is_anonymous ? "[anonymous]" : fullname)
- );
+ }
+ else {
+ snprintf(header, sizeof header, " %s from %s", datestr, (is_anonymous ? "[anonymous]" : fullname));
if (!IsEmptyStr(recipient)) {
size_t tmp = strlen(header);
snprintf(&header[tmp], sizeof header - tmp, " to %s", recipient);
if (!IsEmptyStr(recipient)) {
size_t tmp = strlen(header);
snprintf(&header[tmp], sizeof header - tmp, " to %s", recipient);
if (beg < 0)
scr_printf("failed to get stream position %s\n", strerror(errno));
fclose(fp);
if (beg < 0)
scr_printf("failed to get stream position %s\n", strerror(errno));
fclose(fp);
fp = fopen(filename, "w");
if (fp == NULL) {
fp = fopen(filename, "w");
if (fp == NULL) {
- scr_printf("*** Error opening temp file!\n %s: %s\n", filename, strerror(errno)
- );
+ scr_printf("*** Error opening temp file!\n %s: %s\n", filename, strerror(errno));
return (1);
}
fclose(fp);
}
}
return (1);
}
fclose(fp);
}
}
case 0:
fp = fopen(filename, "r+");
case 0:
fp = fopen(filename, "r+");
if (file_checksum(filename) == cksum) {
scr_printf("*** Aborted message.\n");
e_ex_code = 1;
if (file_checksum(filename) == cksum) {
scr_printf("*** Aborted message.\n");
e_ex_code = 1;
}
b = keymenu("Entry command (? for options)",
}
b = keymenu("Entry command (? for options)",
- "<A>bort|"
- "<C>ontinue|" "<S>ave message|" "<P>rint formatted|" "add s<U>bject|" "<R>eplace string|" "<H>old message");
+ "<A>bort|"
+ "<C>ontinue|"
+ "<S>ave message|"
+ "<P>rint formatted|"
+ "add s<U>bject|"
+ "<R>eplace string|"
+ "<H>old message"
+ );
if (b == 'a')
goto MEABT;
if (b == 'a')
goto MEABT;
- MEABT:scr_printf("Are you sure? ");
+MEABT: scr_printf("Are you sure? ");
if (yesno() == 0) {
goto ME1;
}
if (yesno() == 0) {
goto ME1;
}
- MEABT2:unlink(filename);
+MEABT2: unlink(filename);
/*
* Make sure there's room in msg_arr[] for at least one more.
*/
/*
* Make sure there's room in msg_arr[] for at least one more.
*/
-void check_msg_arr_size(void)
-{
+void check_msg_arr_size(void) {
if ((num_msgs + 1) > msg_arr_size) {
msg_arr_size += 512;
msg_arr = realloc(msg_arr, ((sizeof(long)) * msg_arr_size));
if ((num_msgs + 1) > msg_arr_size) {
msg_arr_size += 512;
msg_arr = realloc(msg_arr, ((sizeof(long)) * msg_arr_size));
* break_big_lines() - break up lines that are >1024 characters
* otherwise the server will truncate
*/
* break_big_lines() - break up lines that are >1024 characters
* otherwise the server will truncate
*/
-void break_big_lines(char *msg)
-{
+void break_big_lines(char *msg) {
char *ptr;
char *break_here;
char *ptr;
char *break_here;
int entmsg(CtdlIPC * ipc, int is_reply, /* nonzero if this was a <R>eply command */
int c, /* mode */
int masquerade /* prompt for a non-default display name? */
int entmsg(CtdlIPC * ipc, int is_reply, /* nonzero if this was a <R>eply command */
int c, /* mode */
int masquerade /* prompt for a non-default display name? */
char buf[SIZ];
int a, b;
int need_recp = 0;
char buf[SIZ];
int a, b;
int need_recp = 0;
if (!IsEmptyStr(reply_subject)) {
if (!strncasecmp(reply_subject, "Re: ", 3)) {
strcpy(message.subject, reply_subject);
if (!IsEmptyStr(reply_subject)) {
if (!strncasecmp(reply_subject, "Re: ", 3)) {
strcpy(message.subject, reply_subject);
snprintf(message.subject, sizeof message.subject, "Re: %s", reply_subject);
}
}
snprintf(message.subject, sizeof message.subject, "Re: %s", reply_subject);
}
}
if (axlevel >= AxProbU) {
if (is_reply) {
strcpy(buf, reply_to);
if (axlevel >= AxProbU) {
if (is_reply) {
strcpy(buf, reply_to);
newprompt("Enter recipient: ", buf, SIZ - 100);
if (IsEmptyStr(buf)) {
return (1);
}
}
newprompt("Enter recipient: ", buf, SIZ - 100);
if (IsEmptyStr(buf)) {
return (1);
}
}
}
strcpy(message.recipient, buf);
}
strcpy(message.recipient, buf);
r = CtdlIPCGetMessages(ipc, LastMessages, 1, NULL, &msgarr, buf);
if (r / 100 != 1) {
scr_printf("%s\n", buf);
r = CtdlIPCGetMessages(ipc, LastMessages, 1, NULL, &msgarr, buf);
if (r / 100 != 1) {
scr_printf("%s\n", buf);
for (num_msgs = 0; msgarr[num_msgs]; num_msgs++);
}
for (num_msgs = 0; msgarr[num_msgs]; num_msgs++);
}
r = CtdlIPCGetMessages(ipc, NewMessages, 0, NULL, &msgarr, buf);
if (r / 100 != 1) {
scr_printf("%s\n", buf);
r = CtdlIPCGetMessages(ipc, NewMessages, 0, NULL, &msgarr, buf);
if (r / 100 != 1) {
scr_printf("%s\n", buf);
for (num_msgs = 0; msgarr[num_msgs]; num_msgs++);
}
for (num_msgs = 0; msgarr[num_msgs]; num_msgs++);
}
msgarr = NULL;
/* In the Mail> room, this algorithm always counts one message
msgarr = NULL;
/* In the Mail> room, this algorithm always counts one message
if (b == 1) {
scr_printf("*** 1 additional message has been entered " "in this room by another user.\n");
if (b == 1) {
scr_printf("*** 1 additional message has been entered " "in this room by another user.\n");
scr_printf("*** %d additional messages have been entered " "in this room by other users.\n", b);
}
free(message.text);
scr_printf("*** %d additional messages have been entered " "in this room by other users.\n", b);
}
free(message.text);
/*
* Do editing on a quoted file
*/
/*
* Do editing on a quoted file
*/
-void process_quote(void)
-{
+void process_quote(void) {
FILE *qfile, *tfile;
char buf[128];
int line, qstart, qend;
FILE *qfile, *tfile;
char buf[128];
int line, qstart, qend;
- /* Unlink the second temp file as soon as it's opened, so it'll get
- * deleted even if the program dies
- */
+ // Unlink the second temp file as soon as it's opened, so it'll get
+ // deleted even if the program dies
qfile = fopen(temp2, "r");
unlink(temp2);
qfile = fopen(temp2, "r");
unlink(temp2);
/*
* List the URLs which were embedded in the previous message
*/
/*
* List the URLs which were embedded in the previous message
*/
-void list_urls(CtdlIPC * ipc)
-{
+void list_urls(CtdlIPC * ipc) {
int i;
char cmd[SIZ];
int rv;
int i;
char cmd[SIZ];
int rv;
scr_printf("%3d %s\n", i + 1, urls[i]);
}
scr_printf("%3d %s\n", i + 1, urls[i]);
}
- if ((i = num_urls) != 1)
+ if ((i = num_urls) != 1) {
i = intprompt("Display which one", 1, 1, num_urls);
i = intprompt("Display which one", 1, 1, num_urls);
snprintf(cmd, sizeof cmd, rc_url_cmd, urls[i - 1]);
rv = system(cmd);
snprintf(cmd, sizeof cmd, rc_url_cmd, urls[i - 1]);
rv = system(cmd);
/*
* Run image viewer in background
*/
/*
* Run image viewer in background
*/
-int do_image_view(const char *filename)
-{
+int do_image_view(const char *filename) {
char cmd[SIZ];
pid_t childpid;
char cmd[SIZ];
pid_t childpid;
/*
* View an image attached to a message
*/
/*
* View an image attached to a message
*/
-void image_view(CtdlIPC * ipc, unsigned long msg)
-{
+void image_view(CtdlIPC * ipc, unsigned long msg) {
struct parts *ptr = last_message_parts;
char part[SIZ];
int found = 0;
struct parts *ptr = last_message_parts;
char part[SIZ];
int found = 0;
/*
* Read the messages in the current room
*/
/*
* Read the messages in the current room
*/
-void readmsgs(CtdlIPC * ipc, enum MessageList c, /* see listing in citadel_ipc.h */
- enum MessageDirection rdir, /* 1=Forward (-1)=Reverse */
- int q /* Number of msgs to read (if c==3) */
- )
-{
+void readmsgs(CtdlIPC *ipc,
+ enum MessageList c, // see listing in citadel_ipc.h
+ enum MessageDirection rdir, // 1=Forward (-1)=Reverse
+ int q // Number of msgs to read (if c==3)
+) {
int a, e, f, g, start;
int savedpos;
int hold_sw = 0;
int a, e, f, g, start;
int savedpos;
int hold_sw = 0;
r = CtdlIPCGetMessages(ipc, c, q, NULL, &msg_arr, cmd);
if (r / 100 != 1) {
scr_printf("%s\n", cmd);
r = CtdlIPCGetMessages(ipc, c, q, NULL, &msg_arr, cmd);
if (r / 100 != 1) {
scr_printf("%s\n", cmd);
for (num_msgs = 0; msg_arr[num_msgs]; num_msgs++);
}
for (num_msgs = 0; msg_arr[num_msgs]; num_msgs++);
}
if ((quotflag) || (arcflag)) {
screenwidth = hold_sw;
}
if ((quotflag) || (arcflag)) {
screenwidth = hold_sw;
}
highest_msg_read = msg_arr[a];
if (quotflag) {
fclose(dest);
highest_msg_read = msg_arr[a];
if (quotflag) {
fclose(dest);
&& (((room_flags & QR_MAILBOX) == 0)
|| (rc_force_mail_prompts == 0))) {
e = 'n';
&& (((room_flags & QR_MAILBOX) == 0)
|| (rc_force_mail_prompts == 0))) {
e = 'n';
color(DIM_WHITE);
scr_printf("(");
color(BRIGHT_WHITE);
color(DIM_WHITE);
scr_printf("(");
color(BRIGHT_WHITE);
" N Next (continue with next message)\n"
" Y My Next (continue with next message you authored)\n"
" B Back (go back to previous message)\n");
" N Next (continue with next message)\n"
" Y My Next (continue with next message you authored)\n"
" B Back (go back to previous message)\n");
- if ((is_room_aide)
- || (room_flags & QR_MAILBOX)
- || (room_flags2 & QR2_COLLABDEL)
- ) {
+ if ((is_room_aide) || (room_flags & QR_MAILBOX) || (room_flags2 & QR2_COLLABDEL)) {
scr_printf(" D Delete this message\n" " M Move message to another room\n");
}
scr_printf(" C Copy message to another room\n");
scr_printf(" D Delete this message\n" " M Move message to another room\n");
}
scr_printf(" C Copy message to another room\n");
scr_printf("%s\n", cmd);
if (r / 100 == 2)
msg_arr[a] = 0L;
scr_printf("%s\n", cmd);
if (r / 100 == 2)
msg_arr[a] = 0L;
goto RMSGREAD;
}
if (r / 100 != 2) /* r will be init'ed, FIXME */
goto RMSGREAD;
}
if (r / 100 != 2) /* r will be init'ed, FIXME */
r = CtdlIPCAttachmentDownload(ipc, msg_arr[a], filename, &attachment, progress, cmd);
if (r / 100 != 2) {
scr_printf("%s\n", cmd);
r = CtdlIPCAttachmentDownload(ipc, msg_arr[a], filename, &attachment, progress, cmd);
if (r / 100 != 2) {
scr_printf("%s\n", cmd);
extract_token(filename, cmd, 2, '|', sizeof filename);
/*
* Part 1 won't have a filename; use the
extract_token(filename, cmd, 2, '|', sizeof filename);
/*
* Part 1 won't have a filename; use the
rv = system(cmd);
if (rv != 0)
scr_printf("failed to save %s Reason %d\n", cmd, rv);
rv = system(cmd);
if (rv != 0)
scr_printf("failed to save %s Reason %d\n", cmd, rv);
- } else { /* save attachment to disk */
+ }
+ else { /* save attachment to disk */
destination_directory(save_to, filename);
save_buffer(attachment, extract_unsigned_long(cmd, 0), save_to);
}
destination_directory(save_to, filename);
save_buffer(attachment, extract_unsigned_long(cmd, 0), save_to);
}
scr_printf("%s\n", cmd);
if (r / 100 == 2)
msg_arr[a] = 0L;
scr_printf("%s\n", cmd);
if (r / 100 == 2)
msg_arr[a] = 0L;
/*
* View and edit a system message
*/
/*
* View and edit a system message
*/
-void edit_system_message(CtdlIPC * ipc, char *which_message)
-{
+void edit_system_message(CtdlIPC * ipc, char *which_message) {
char desc[SIZ];
char read_cmd[SIZ];
char write_cmd[SIZ];
char desc[SIZ];
char read_cmd[SIZ];
char write_cmd[SIZ];
/*
* Loads the contents of a file into memory. Caller must free the allocated memory.
*/
/*
* Loads the contents of a file into memory. Caller must free the allocated memory.
*/
-char *load_message_from_file(FILE * src)
-{
+char *load_message_from_file(FILE * src) {
size_t i;
size_t got = 0;
char *dest = NULL;
size_t i;
size_t got = 0;
char *dest = NULL;
blockquote {
background-color: #f5f5f5 !important;
color: navy !important;
blockquote {
background-color: #f5f5f5 !important;
color: navy !important;
+ margin-bottom: 0px;
+ padding-bottom: 0px;
}
blockquote blockquote {
}
blockquote blockquote {