Create some directories to hold the source files for the utility
[citadel.git] / citadel / messages.c
index 97529331e094fd5a1e61e3e3485be2103ed1bd94..fdd8d46b4c2649ad23967994f283bbddf4d04138 100644 (file)
@@ -2,7 +2,7 @@
  * $Id$
  *
  * Citadel message support routines
- * see copyright.txt for copyright information
+ * see COPYING for copyright information
  */
 
 #include "sysdep.h"
 #endif
 
 #include <stdarg.h>
+#include <libcitadel.h>
 #include "citadel.h"
 #include "citadel_ipc.h"
 #include "citadel_decls.h"
 #include "messages.h"
 #include "commands.h"
 #include "rooms.h"
-#include "tools.h"
-#include "html.h"
 #ifndef HAVE_SNPRINTF
 #include "snprintf.h"
 #endif
@@ -53,6 +52,8 @@
 
 char reply_to[SIZ];
 char reply_subject[SIZ];
+char reply_references[SIZ];
+char reply_inreplyto[SIZ];
 
 struct cittext {
        struct cittext *next;
@@ -70,6 +71,7 @@ int msg_arr_size = 0;
 int num_msgs;
 char rc_alt_semantics;
 extern char room_name[];
+extern char tempdir[];
 extern unsigned room_flags;
 extern unsigned room_flags2;
 extern long highest_msg_read;
@@ -217,6 +219,7 @@ void citedit(CtdlIPC *ipc, FILE * fp)
        struct cittext *textlist = NULL;
        struct cittext *ptr;
        char wordbuf[MAXWORDBUF];
+       int rv = 0;
 
        /* first, load the text into the buffer */
        fseek(fp, 0L, 0);
@@ -345,7 +348,7 @@ void citedit(CtdlIPC *ipc, FILE * fp)
        }
        putc(10, fp);
        fflush(fp);
-       ftruncate(fileno(fp), ftell(fp));
+       rv = ftruncate(fileno(fp), ftell(fp));
 
        /* and deallocate the memory we used */
        while (textlist != NULL) {
@@ -404,10 +407,10 @@ int read_message(CtdlIPC *ipc,
 
        strcpy(reply_to, NO_REPLY_TO);
        strcpy(reply_subject, "");
+       strcpy(reply_references, "");
+       strcpy(reply_inreplyto, "");
 
-       r = CtdlIPCGetSingleMessage(ipc, num, (pagin == READ_HEADER ? 1 : 0),
-                               (can_do_msg4 ? 4 : 0),
-                               &message, buf);
+       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;
@@ -569,7 +572,7 @@ int read_message(CtdlIPC *ipc,
 
        /* Set the reply-to address to an Internet e-mail address if possible
         */
-       if (message->email != NULL) if (!IsEmptyStr(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);
                }
@@ -590,9 +593,17 @@ int read_message(CtdlIPC *ipc,
                lines_printed = checkpagin(lines_printed, pagin, screenheight);
        }
 
+
+       if (message->msgid != NULL) {
+               safestrncpy(reply_inreplyto, message->msgid, sizeof reply_inreplyto);
+       }
+
+       if (message->references != NULL) if (!IsEmptyStr(message->references)) {
+               safestrncpy(reply_references, message->references, sizeof reply_references);
+       }
+
        if (message->subject != NULL) {
-               safestrncpy(reply_subject, message->subject,
-                                               sizeof reply_subject);
+               safestrncpy(reply_subject, message->subject, sizeof reply_subject);
                if (!IsEmptyStr(message->subject)) {
                        if (dest) {
                                fprintf(dest, "Subject: %s\n",
@@ -707,7 +718,7 @@ int read_message(CtdlIPC *ipc,
        }
 
        /* Enumerate any attachments */
-       if ( (pagin == 1) && (can_do_msg4) && (message->attachments) ) {
+       if ( (pagin == 1) && (message->attachments) ) {
                struct parts *ptr;
 
                for (ptr = message->attachments; ptr; ptr = ptr->next) {
@@ -763,18 +774,21 @@ void replace_string(char *filename, long int startpos)
        char *ptr;
        int substitutions = 0;
        long msglen = 0L;
+       int rv;
 
        scr_printf("Enter text to be replaced:\n: ");
        ctdl_getline(srch_str, (sizeof(srch_str)-1) );
-       if (IsEmptyStr(srch_str))
+       if (IsEmptyStr(srch_str)) {
                return;
+       }
 
        scr_printf("Enter text to replace it with:\n: ");
        ctdl_getline(rplc_str, (sizeof(rplc_str)-1) );
 
        fp = fopen(filename, "r+");
-       if (fp == NULL)
+       if (fp == NULL) {
                return;
+       }
 
        wpos = startpos;
        fseek(fp, startpos, 0);
@@ -793,18 +807,19 @@ void replace_string(char *filename, long int startpos)
                if (strlen(buf) > 384) {
                        rpos = ftell(fp);
                        fseek(fp, wpos, 0);
-                       fwrite((char *) buf, 128, 1, fp);
+                       rv = fwrite((char *) buf, 128, 1, fp);
                        strcpy(buf, &buf[128]);
                        wpos = ftell(fp);
                        fseek(fp, rpos, 0);
                }
        }
        fseek(fp, wpos, 0);
-       if (!IsEmptyStr(buf))
-               fwrite((char *) buf, strlen(buf), 1, fp);
+       if (!IsEmptyStr(buf)) {
+               rv = fwrite((char *) buf, strlen(buf), 1, fp);
+       }
        wpos = ftell(fp);
        fclose(fp);
-       truncate(filename, wpos);
+       rv = truncate(filename, wpos);
        scr_printf("<R>eplace made %d substitution(s).\n\n", substitutions);
 }
 
@@ -1092,6 +1107,7 @@ int entmsg(CtdlIPC *ipc,
        strcpy(message.recipient, "");
        strcpy(message.author, "");
        strcpy(message.subject, "");
+       strcpy(message.references, "");
        message.text = "";              /* point to "", changes later */
        message.anonymous = 0;
        message.type = mode;
@@ -1138,6 +1154,7 @@ int entmsg(CtdlIPC *ipc,
        strcpy(message.recipient, buf);
 
        if (is_reply) {
+
                if (!IsEmptyStr(reply_subject)) {
                        if (!strncasecmp(reply_subject,
                           "Re: ", 3)) {
@@ -1150,6 +1167,21 @@ int entmsg(CtdlIPC *ipc,
                                        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) {
@@ -1276,19 +1308,23 @@ void process_quote(void)
 
        /* Display the quotable text with line numbers added */
        line = 0;
-       fgets(buf, 128, qfile);
+       if (fgets(buf, 128, qfile) == NULL) {
+               /* we're skipping a line here */
+       }
        while (fgets(buf, 128, qfile) != NULL) {
-               scr_printf("%2d %s", ++line, buf);
+               scr_printf("%3d %s", ++line, buf);
        }
-       scr_printf("Begin quoting at [ 1] : ");
-       ctdl_getline(buf, 3);
+       scr_printf("Begin quoting at [1] : ");
+       ctdl_getline(buf, 4);
        qstart = (buf[0] == 0) ? (1) : atoi(buf);
        scr_printf("  End quoting at [%d] : ", line);
-       ctdl_getline(buf, 3);
+       ctdl_getline(buf, 4);
        qend = (buf[0] == 0) ? (line) : atoi(buf);
        rewind(qfile);
        line = 0;
-       fgets(buf, 128, qfile);
+       if (fgets(buf, 128, qfile) == NULL) {
+               /* we're skipping a line here */
+       }
        tfile = fopen(temp, "w");
        while (fgets(buf, 128, qfile) != NULL) {
                if ((++line >= qstart) && (line <= qend))
@@ -1309,6 +1345,7 @@ void list_urls(CtdlIPC *ipc)
 {
        int i;
        char cmd[SIZ];
+       int rv;
 
        if (num_urls == 0) {
                scr_printf("There were no URL's in the previous message.\n\n");
@@ -1323,7 +1360,7 @@ void list_urls(CtdlIPC *ipc)
                i = intprompt("Display which one", 1, 1, num_urls);
 
        snprintf(cmd, sizeof cmd, rc_url_cmd, urls[i - 1]);
-       system(cmd);
+       rv = system(cmd);
        scr_printf("\n");
 }
 
@@ -1472,8 +1509,10 @@ void readmsgs(CtdlIPC *ipc,
        char filename[PATH_MAX];
        char save_to[PATH_MAX];
        void *attachment = NULL;        /* Downloaded attachment */
-       FILE *dest = NULL;      /* Alternate destination other than screen */
+       FILE *dest = NULL;              /* Alternate destination other than screen */
        int r;                          /* IPC response code */
+       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);
@@ -1549,6 +1588,8 @@ RMSGREAD: scr_flush();
                        quotflag = 0;
                        enable_color = hold_color;
                        process_quote();
+                       e = 'r';
+                       goto DONE_QUOTING;
                }
                if (arcflag) {
                        fclose(dest);
@@ -1557,7 +1598,9 @@ RMSGREAD: scr_flush();
                        enable_color = hold_color;
                        f = fork();
                        if (f == 0) {
-                               freopen(prtfile, "r", stdin);
+                               if (freopen(prtfile, "r", stdin) == NULL) {
+                                       /* we probably should handle the error condition here */
+                               }
                                screen_reset();
                                stty_ctdl(SB_RESTORE);
                                ka_system(printcmd);
@@ -1591,7 +1634,7 @@ RMSGREAD: scr_flush();
                        color(DIM_WHITE);
                        scr_printf(") ");
 
-                       keyopt("<B>ack <A>gain <Q>uote <R>eply <N>ext <S>top ");
+                       keyopt("<B>ack <A>gain <R>eply reply<Q>uoted <N>ext <S>top ");
                        if (rc_url_cmd[0] && num_urls)
                                keyopt("<U>RLview ");
                        if (has_images > 0 && !IsEmptyStr(imagecmd))
@@ -1633,7 +1676,7 @@ RMSGREAD: scr_flush();
                                 && (e != 'q') && (e != 'b') && (e != 'h')
                                 && (e != 'r') && (e != 'f') && (e != '?')
                                 && (e != 'u') && (e != 'c') && (e != 'y')
-                                && (e != 'i'));
+                                && (e != 'i') && (e != 'o') );
                        switch (e) {
                        case 's':
                                scr_printf("Stop");
@@ -1657,7 +1700,7 @@ RMSGREAD: scr_flush();
                                scr_printf("Print");
                                break;
                        case 'q':
-                               scr_printf("Quote");
+                               scr_printf("reply Quoted");
                                break;
                        case 'b':
                                scr_printf("Back");
@@ -1668,6 +1711,9 @@ RMSGREAD: scr_flush();
                        case 'r':
                                scr_printf("Reply");
                                break;
+                       case 'o':
+                               scr_printf("Open attachments");
+                               break;
                        case 'f':
                                scr_printf("File");
                                break;
@@ -1689,7 +1735,7 @@ RMSGREAD: scr_flush();
                                scr_printf("\n");
                        scr_flush();
                }
-               switch (e) {
+DONE_QUOTING:  switch (e) {
                case '?':
                        scr_printf("Options available here:\n"
                                " ?  Help (prints this message)\n"
@@ -1709,13 +1755,14 @@ RMSGREAD:       scr_flush();
                        if (!IsEmptyStr(printcmd))
                                scr_printf(" P  Print this message\n");
                        scr_printf(
-                               " Q  Quote portions of this message for your next post\n"
+                               " Q  Reply to this message, quoting portions of it\n"
                                " H  Headers (display message headers only)\n");
                        if (is_mail)
                                scr_printf(" R  Reply to this message\n");
-                       if (rc_allow_attachments)
-                               scr_printf
-                                   (" F  (save attachments to a file)\n");
+                       if (rc_allow_attachments) {
+                               scr_printf(" O  (Open attachments)\n");
+                               scr_printf(" F  (save attachments to a File)\n");
+                       }
                        if (!IsEmptyStr(rc_url_cmd))
                                scr_printf(" U  (list URL's for display)\n");
                        if (!IsEmptyStr(imagecmd) && has_images > 0)
@@ -1759,9 +1806,9 @@ RMSGREAD: scr_flush();
                        if (r / 100 != 2)       /* r will be init'ed, FIXME */
                                goto RMSGREAD;  /* the logic here sucks */
                        break;
+               case 'o':
                case 'f':
-                       newprompt("Which section? ", filename,
-                                 ((sizeof filename) - 1));
+                       newprompt("Which section? ", filename, ((sizeof filename) - 1));
                        r = CtdlIPCAttachmentDownload(ipc, msg_arr[a],
                                        filename, &attachment, progress, cmd);
                        if (r / 100 != 2) {
@@ -1772,12 +1819,23 @@ RMSGREAD:       scr_flush();
                                 * Part 1 won't have a filename; use the
                                 * subject of the message instead. IO
                                 */
-                               if (IsEmptyStr(filename))
+                               if (IsEmptyStr(filename)) {
                                        strcpy(filename, reply_subject);
-                               destination_directory(save_to, filename);
-                               save_buffer(attachment,
-                                               extract_unsigned_long(cmd, 0),
-                                               save_to);
+                               }
+                               if (e == 'o') {         /* open attachment */
+                                       mkdir(tempdir, 0700);
+                                       snprintf(save_to, sizeof save_to, "%s/%04x.%s",
+                                               tempdir,
+                                               ++att_seq,
+                                               filename);
+                                       save_buffer(attachment, extract_unsigned_long(cmd, 0), save_to);
+                                       snprintf(cmd, sizeof cmd, rc_open_cmd, save_to);
+                                       rv = system(cmd);
+                               }
+                               else {                  /* save attachment to disk */
+                                       destination_directory(save_to, filename);
+                                       save_buffer(attachment, extract_unsigned_long(cmd, 0), save_to);
+                               }
                        }
                        if (attachment) {
                                free(attachment);