]> code.citadel.org Git - citadel.git/blobdiff - citadel/textclient/messages.c
mini rfc2047 decoder for the text client
[citadel.git] / citadel / textclient / messages.c
index 2f463ffbe0cf08094f86e56acf9041536163db4b..e20888f29097636081056310e7231ad5efafb93f 100644 (file)
@@ -1,8 +1,15 @@
 /*
- * $Id$
+ * Text client functions for reading and writing of messages
  *
- * Citadel message support routines
- * see COPYING for copyright information
+ * Copyright (c) 1987-2012 by the citadel.org team
+ *
+ * This program is open source software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public 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.
  */
 
 #include "sysdep.h"
@@ -350,7 +357,10 @@ void citedit(FILE *fp)
        putc(10, fp);
        fflush(fp);
        rv = ftruncate(fileno(fp), ftell(fp));
+       if (rv < 0)
+               scr_printf("failed to set message buffer: %s\n", strerror(errno));
 
+       
        /* and deallocate the memory we used */
        while (textlist != NULL) {
                ptr = textlist->next;
@@ -377,6 +387,50 @@ void free_parts(struct parts *p)
 }
 
 
+/*
+ * This is a mini RFC2047 decoder.
+ * It only handles strings encoded from UTF-8 as Quoted-printable.
+ */
+void mini_2047_decode(char *s) {
+       if (!s) return;
+
+       char *qstart = strstr(s, "=?UTF-8?Q?");
+       if (!qstart) return;
+
+       char *qend = strstr(s, "?=");
+       if (!qend) return;
+
+       if (qend <= qstart) return;
+
+       strcpy(qstart, &qstart[10]);
+       qend -= 10;
+
+       char *p = qstart;
+       while (p < qend) {
+
+               if (p[0] == '=') {
+
+                       char ch[3];
+                       ch[0] = p[1];
+                       ch[1] = p[2];
+                       ch[2] = p[3];
+                       int c;
+                       sscanf(ch, "%02x", &c);
+                       p[0] = c;
+                       strcpy(&p[1], &p[3]);
+                       qend -= 2;
+               }
+
+               if (p[0] == '_') {
+                       p[0] = ' ';
+               }
+               
+               ++p;
+       }
+
+       strcpy(qend, &qend[2]);
+}
+
 /*
  * Read a message from the server
  */
@@ -413,9 +467,7 @@ int read_message(CtdlIPC *ipc,
 
        r = CtdlIPCGetSingleMessage(ipc, num, (pagin == READ_HEADER ? 1 : 0), 4, &message, buf);
        if (r / 100 != 1) {
-               err_printf("*** msg #%ld: %d %s\n", num, r, buf);
-               ++lines_printed;
-               lines_printed = checkpagin(lines_printed, pagin, screenheight);
+               scr_printf("*** msg #%ld: %d %s\n", num, r, buf);
                stty_ctdl(0);
                free(message->text);
                free_parts(message->attachments);
@@ -427,8 +479,6 @@ int read_message(CtdlIPC *ipc,
                fprintf(dest, "\n ");
        } else {
                scr_printf("\n");
-               ++lines_printed;
-               lines_printed = checkpagin(lines_printed, pagin, screenheight);
                if (pagin != 2)
                        scr_printf(" ");
        }
@@ -438,34 +488,35 @@ int read_message(CtdlIPC *ipc,
 
        /* View headers only */
        if (pagin == 2) {
-               pprintf("nhdr=%s\nfrom=%s\ntype=%d\nmsgn=%s\n",
+               scr_printf("nhdr=%s\nfrom=%s\ntype=%d\nmsgn=%s\n",
                                message->nhdr ? "yes" : "no",
                                message->author, message->type,
                                message->msgid);
                if (!IsEmptyStr(message->subject)) {
-                       pprintf("subj=%s\n", message->subject);
+                       scr_printf("subj=%s\n", message->subject);
                }
                if (!IsEmptyStr(message->email)) {
-                       pprintf("rfca=%s\n", message->email);
+                       scr_printf("rfca=%s\n", message->email);
                }
-               pprintf("hnod=%s\nroom=%s\nnode=%s\ntime=%s",
+               scr_printf("hnod=%s\nroom=%s\nnode=%s\ntime=%s",
                                message->hnod, message->room,
                                message->node, 
                                asctime(localtime(&message->time)));
                if (!IsEmptyStr(message->recipient)) {
-                       pprintf("rcpt=%s\n", message->recipient);
+                       scr_printf("rcpt=%s\n", message->recipient);
                }
                if (message->attachments) {
                        struct parts *ptr;
 
                        for (ptr = message->attachments; ptr; ptr = ptr->next) {
-                               pprintf("part=%s|%s|%s|%s|%s|%ld\n",
+                               scr_printf("part=%s|%s|%s|%s|%s|%ld\n",
                                        ptr->name, ptr->filename, ptr->number,
                                        ptr->disposition, ptr->mimetype,
-                                       ptr->length);
+                                       ptr->length
+                               );
                        }
                }
-               pprintf("\n");
+               scr_printf("\n");
                stty_ctdl(0);
                free(message->text);
                free_parts(message->attachments);
@@ -589,12 +640,6 @@ int read_message(CtdlIPC *ipc,
                         message->author, message->node);
        }
 
-       if (!dest) {
-               ++lines_printed;
-               lines_printed = checkpagin(lines_printed, pagin, screenheight);
-       }
-
-
        if (message->msgid != NULL) {
                safestrncpy(reply_inreplyto, message->msgid, sizeof reply_inreplyto);
        }
@@ -607,16 +652,13 @@ int read_message(CtdlIPC *ipc,
                safestrncpy(reply_subject, message->subject, sizeof reply_subject);
                if (!IsEmptyStr(message->subject)) {
                        if (dest) {
-                               fprintf(dest, "Subject: %s\n",
-                                                       message->subject);
+                               fprintf(dest, "Subject: %s\n", message->subject);
                        } else {
                                color(DIM_WHITE);
                                scr_printf("Subject: ");
                                color(BRIGHT_CYAN);
+                               mini_2047_decode(message->subject);
                                scr_printf("%s\n", message->subject);
-                               ++lines_printed;
-                               lines_printed = checkpagin(lines_printed,
-                                               pagin, screenheight);
                        }
                }
        }
@@ -669,8 +711,7 @@ int read_message(CtdlIPC *ipc,
         * Here we go
         */
        if (format_type == 0) {
-               fr = fmout(screenwidth, NULL, message->text, dest,
-                          ((pagin == 1) ? 1 : 0), screenheight, (-1), 1);
+               fr = fmout(screenwidth, NULL, message->text, dest, 1);
        } else {
                /* renderer for text/plain */
 
@@ -693,11 +734,6 @@ int read_message(CtdlIPC *ipc,
                                        fprintf(dest, "%s\n", lineptr);
                                } else {
                                        scr_printf("%s\n", lineptr);
-                                       lines_printed = lines_printed + 1 +
-                                           (linelen / screenwidth);
-                                       lines_printed =
-                                           checkpagin(lines_printed, pagin,
-                                                      screenheight);
                                }
                        }
                        if (lineptr[0] == 0) final_line_is_blank = 1;
@@ -712,8 +748,6 @@ int read_message(CtdlIPC *ipc,
                }
                else {
                        scr_printf("\n");
-                       ++lines_printed;
-                       lines_printed = checkpagin(lines_printed, pagin, screenheight);
                        fr = sigcaught;         
                }
        }
@@ -731,15 +765,15 @@ int read_message(CtdlIPC *ipc,
                                   && (!IsEmptyStr(ptr->mimetype))
                                ) {
                                        color(DIM_WHITE);
-                                       pprintf("Part ");
+                                       scr_printf("Part ");
                                        color(BRIGHT_MAGENTA);
-                                       pprintf("%s", ptr->number);
+                                       scr_printf("%s", ptr->number);
                                        color(DIM_WHITE);
-                                       pprintf(": ");
+                                       scr_printf(": ");
                                        color(BRIGHT_CYAN);
-                                       pprintf("%s", ptr->filename);
+                                       scr_printf("%s", ptr->filename);
                                        color(DIM_WHITE);
-                                       pprintf(" (%s, %ld bytes)\n", ptr->mimetype, ptr->length);
+                                       scr_printf(" (%s, %ld bytes)\n", ptr->mimetype, ptr->length);
                                        if (!strncmp(ptr->mimetype, "image/", 6)) {
                                                has_images++;
                                        }
@@ -809,6 +843,10 @@ void replace_string(char *filename, long int startpos)
                        rpos = ftell(fp);
                        fseek(fp, wpos, 0);
                        rv = fwrite((char *) buf, 128, 1, fp);
+                       if (rv < 0) {
+                               scr_printf("failed to replace string: %s\n", strerror(errno));
+                               break; /*whoopsi! */
+                       }
                        strcpy(buf, &buf[128]);
                        wpos = ftell(fp);
                        fseek(fp, rpos, 0);
@@ -828,14 +866,14 @@ void replace_string(char *filename, long int startpos)
  * 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)
-{
+                       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;
@@ -846,13 +884,14 @@ int client_make_message(CtdlIPC *ipc,
 
        if (mode >= 2)
        {
-               if((mode-2) < MAX_EDITORS && !IsEmptyStr(editor_paths[mode-2])) {
+               if ((mode-2) < MAX_EDITORS && !IsEmptyStr(editor_paths[mode-2]))
+               {
                        editor_path = editor_paths[mode-2];
-               } else if (!IsEmptyStr(editor_paths[0])) {
+               } else if (!IsEmptyStr(editor_paths[0]))
+               {
                        editor_path = editor_paths[0];
                } else {
-                       err_printf("*** No editor available, "
-                               "using built-in editor\n");
+                       scr_printf("*** No editor available; using built-in editor.\n");
                        mode = 0;
                }
        }
@@ -884,8 +923,6 @@ int client_make_message(CtdlIPC *ipc,
                newprompt("Subject: ", subject, 70);
        }
 
-       beg = 0L;
-
        if (mode == 1) {
                scr_printf("(Press ctrl-d when finished)\n");
        }
@@ -893,16 +930,18 @@ int client_make_message(CtdlIPC *ipc,
        if (mode == 0) {
                fp = fopen(filename, "r");
                if (fp != NULL) {
-                       fmout(screenwidth, fp, NULL, NULL, 0,
-                               screenheight, 0, 0);
+                       fmout(screenwidth, fp, NULL, NULL, 0);
                        beg = ftell(fp);
+                       if (beg < 0)
+                               scr_printf("failed to get stream position %s\n", 
+                                          strerror(errno));
                        fclose(fp);
                } else {
                        fp = fopen(filename, "w");
                        if (fp == NULL) {
-                               err_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);
@@ -914,9 +953,9 @@ ME1:        switch (mode) {
        case 0:
                fp = fopen(filename, "r+");
                if (fp == NULL) {
-                       err_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);
                }
                citedit(fp);
@@ -926,7 +965,7 @@ ME1:        switch (mode) {
        case 1:
                fp = fopen(filename, "a");
                if (fp == NULL) {
-                       err_printf("*** Error opening temp file!\n"
+                       scr_printf("*** Error opening temp file!\n"
                                "    %s: %s\n",
                                filename, strerror(errno));
                        return(1);
@@ -950,7 +989,6 @@ ME1:        switch (mode) {
        case 2:
        default:        /* allow 2+ modes */
                e_ex_code = 1;  /* start with a failed exit code */
-               screen_reset();
                stty_ctdl(SB_RESTORE);
                editor_pid = fork();
                cksum = file_checksum(filename);
@@ -970,13 +1008,12 @@ ME1:     switch (mode) {
                        } while ((b != editor_pid) && (b >= 0));
                editor_pid = (-1);
                stty_ctdl(0);
-               screen_set();
                break;
        }
 
 MECR:  if (mode >= 2) {
                if (file_checksum(filename) == cksum) {
-                       err_printf("*** Aborted message.\n");
+                       scr_printf("*** Aborted message.\n");
                        e_ex_code = 1;
                }
                if (e_ex_code == 0) {
@@ -986,9 +1023,14 @@ MECR:     if (mode >= 2) {
        }
 
        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 == 'c') goto ME1;
@@ -1004,10 +1046,11 @@ MECR:   if (mode >= 2) {
                }
                fp = fopen(filename, "r");
                if (fp != NULL) {
-                       fmout(screenwidth, fp, NULL, NULL,
-                             ((userflags & US_PAGINATOR) ? 1 : 0),
-                             screenheight, 0, 0);
+                       fmout(screenwidth, fp, NULL, NULL, 0);
                        beg = ftell(fp);
+                       if (beg < 0)
+                               scr_printf("failed to get stream position %s\n", 
+                                          strerror(errno));
                        fclose(fp);
                }
                goto MECR;
@@ -1124,6 +1167,37 @@ int entmsg(CtdlIPC *ipc,
                newprompt("Display name for this message: ", message.author, 40);
        }
 
+       if (is_reply) {
+
+               if (!IsEmptyStr(reply_subject)) {
+                       if (!strncasecmp(reply_subject,
+                          "Re: ", 3)) {
+                               strcpy(message.subject, reply_subject);
+                       }
+                       else {
+                               snprintf(message.subject,
+                                       sizeof message.subject,
+                                       "Re: %s",
+                                       reply_subject);
+                       }
+               }
+
+               /* Trim down excessively long lists of thread references.  We eliminate the
+                * second one in the list so that the thread root remains intact.
+                */
+               int rrtok = num_tokens(reply_references, '|');
+               int rrlen = strlen(reply_references);
+               if ( ((rrtok >= 3) && (rrlen > 900)) || (rrtok > 10) ) {
+                       remove_token(reply_references, 1, '|');
+               }
+
+               snprintf(message.references, sizeof message.references, "%s%s%s",
+                       reply_references,
+                       (IsEmptyStr(reply_references) ? "" : "|"),
+                       reply_inreplyto
+               );
+       }
+
        r = CtdlIPCPostMessage(ipc, 0, &subject_required, &message, buf);
 
        if (r / 100 != 2 && r / 10 != 57) {
@@ -1161,37 +1235,6 @@ int entmsg(CtdlIPC *ipc,
        }
        strcpy(message.recipient, buf);
 
-       if (is_reply) {
-
-               if (!IsEmptyStr(reply_subject)) {
-                       if (!strncasecmp(reply_subject,
-                          "Re: ", 3)) {
-                               strcpy(message.subject, reply_subject);
-                       }
-                       else {
-                               snprintf(message.subject,
-                                       sizeof message.subject,
-                                       "Re: %s",
-                                       reply_subject);
-                       }
-               }
-
-               /* Trim down excessively long lists of thread references.  We eliminate the
-                * second one in the list so that the thread root remains intact.
-                */
-               int rrtok = num_tokens(reply_references, '|');
-               int rrlen = strlen(reply_references);
-               if ( ((rrtok >= 3) && (rrlen > 900)) || (rrtok > 10) ) {
-                       remove_token(reply_references, 1, '|');
-               }
-
-               snprintf(message.references, sizeof message.references, "%s%s%s",
-                       reply_references,
-                       (IsEmptyStr(reply_references) ? "" : "|"),
-                       reply_inreplyto
-               );
-       }
-
        if (room_flags & QR_ANONOPT) {
                scr_printf("Anonymous (Y/N)? ");
                if (yesno() == 1)
@@ -1230,7 +1273,7 @@ int entmsg(CtdlIPC *ipc,
        fp = fopen(temp, "r");
 
        if (!fp || !(message.text = load_message_from_file(fp))) {
-               err_printf("*** Internal error while trying to save message!\n"
+               scr_printf("*** Internal error while trying to save message!\n"
                        "%s: %s\n",
                        temp, strerror(errno));
                unlink(temp);
@@ -1369,6 +1412,8 @@ void list_urls(CtdlIPC *ipc)
 
        snprintf(cmd, sizeof cmd, rc_url_cmd, urls[i - 1]);
        rv = system(cmd);
+       if (rv != 0) 
+               scr_printf("failed to '%s' by %d\n", cmd, rv);
        scr_printf("\n");
 }
 
@@ -1504,7 +1549,7 @@ void readmsgs(CtdlIPC *ipc,
        enum MessageDirection rdir,     /* 1=Forward (-1)=Reverse */
        int q           /* Number of msgs to read (if c==3) */
 ) {
-       int a, b, e, f, g, start;
+       int a, e, f, g, start;
        int savedpos;
        int hold_sw = 0;
        char arcflag = 0;
@@ -1522,11 +1567,6 @@ void readmsgs(CtdlIPC *ipc,
        static int att_seq = 0;         /* Attachment download sequence number */
        int rv = 0;                     /* silence the stupid warn_unused_result warnings */
 
-       if (c < 0)
-               b = (num_msgs - 1);
-       else
-               b = 0;
-
        CtdlMakeTempFileName(prtfile, sizeof prtfile);
 
        if (msg_arr) {
@@ -1550,8 +1590,6 @@ void readmsgs(CtdlIPC *ipc,
                return;
        }
 
-       lines_printed = 0;
-
        /* this loop cycles through each message... */
        start = ((rdir == 1) ? 0 : (num_msgs - 1));
        for (a = start; ((a < num_msgs) && (a >= 0)); a = a + rdir) {
@@ -1588,7 +1626,7 @@ RAGAIN:           pagin = ((arcflag == 0)
                if ((quotflag) || (arcflag)) {
                        screenwidth = hold_sw;
                }
-RMSGREAD:      scr_flush();
+RMSGREAD:
                highest_msg_read = msg_arr[a];
                if (quotflag) {
                        fclose(dest);
@@ -1609,11 +1647,9 @@ RMSGREAD:        scr_flush();
                                if (freopen(prtfile, "r", stdin) == NULL) {
                                        /* we probably should handle the error condition here */
                                }
-                               screen_reset();
                                stty_ctdl(SB_RESTORE);
                                ka_system(printcmd);
                                stty_ctdl(SB_NO_INTR);
-                               screen_set();
                                unlink(prtfile);
                                exit(0);
                        }
@@ -1650,7 +1686,6 @@ RMSGREAD: scr_flush();
                        keyopt("<?>help -> ");
 
                        do {
-                               lines_printed = 2;
                                e = (inkey() & 127);
                                e = tolower(e);
 /* return key same as <N> */ if (e == 10)
@@ -1741,7 +1776,6 @@ RMSGREAD: scr_flush();
                                scr_printf("\r%79s\r", "");
                        else
                                scr_printf("\n");
-                       scr_flush();
                }
 DONE_QUOTING:  switch (e) {
                case '?':
@@ -1839,6 +1873,8 @@ DONE_QUOTING:     switch (e) {
                                        save_buffer(attachment, extract_unsigned_long(cmd, 0), save_to);
                                        snprintf(cmd, sizeof cmd, rc_open_cmd, save_to);
                                        rv = system(cmd);
+                                       if (rv != 0)
+                                               scr_printf("failed to save %s Reason %d\n", cmd, rv);
                                }
                                else {                  /* save attachment to disk */
                                        destination_directory(save_to, filename);
@@ -1949,10 +1985,9 @@ void check_message_base(CtdlIPC *ipc)
        }
 
        while (transcript && !IsEmptyStr(transcript)) {
-               lines_printed = 1;
                extract_token(buf, transcript, 0, '\n', sizeof buf);
                remove_token(transcript, 0, '\n');
-               pprintf("%s\n", buf);
+               scr_printf("%s\n", buf);
        }
        if (transcript) free(transcript);
        return;