* MSG4 (and CtdlOutputMsg() as well) now accepts an optional MIME part
authorArt Cancro <ajc@citadel.org>
Fri, 21 Oct 2005 19:13:55 +0000 (19:13 +0000)
committerArt Cancro <ajc@citadel.org>
Fri, 21 Oct 2005 19:13:55 +0000 (19:13 +0000)
  specifier, allowing the client to fetch an encapsulated message
  attached as message/rfc822 instead of the top-level message.

13 files changed:
citadel/ChangeLog
citadel/auth.c
citadel/citserver.c
citadel/clientsocket.c
citadel/imap_fetch.c
citadel/mime_parser.c
citadel/msgbase.c
citadel/msgbase.h
citadel/serv_autocompletion.c
citadel/serv_fulltext.c
citadel/serv_pop3.c
citadel/serv_smtp.c
citadel/techdoc/protocol.txt

index 1f7e1ac53cf32b05e3b50284b1960c1940872e4b..e1afd2ed737fafcdc9c92d94c3d725c516608c0d 100644 (file)
@@ -1,3 +1,8 @@
+Fri Oct 21 15:12:45 EDT 2005 ajc
+* MSG4 (and CtdlOutputMsg() as well) now accepts an optional MIME part
+  specifier, allowing the client to fetch an encapsulated message
+  attached as message/rfc822 instead of the top-level message.
+
 Thu Oct 20 17:55:12 EDT 2005 ajc
 * ft_wordbreaker.c: added a list of "noise words" to ignore.  This is
   admittedly EN/US specific, so if anyone wants to contribute noise words
index 38fdd3aabff29f5c3e9e41c4006a90afe22f55cf..3a9dbf481140a0cc89e3626d971400c7886a68d3 100644 (file)
@@ -7,10 +7,6 @@
  *
  */
 
-#ifdef DLL_EXPORT
-#define IN_LIBCIT
-#endif
-
 #if defined(__linux) || defined(__sun) /* needed for crypt(): */
 #define _XOPEN_SOURCE
 #define _XOPEN_SOURCE_EXTENDED 1
index 275a6c351d5d38fd6e9bbc68eafc5fc4bfe2e96c..aa366e25f7571faf44f4e38d744ec7e7f8178597 100644 (file)
@@ -5,10 +5,6 @@
  *
  */
 
-#ifdef DLL_EXPORT
-#define IN_LIBCIT
-#endif
-
 #include "sysdep.h"
 #include <stdlib.h>
 #include <unistd.h>
@@ -1295,22 +1291,6 @@ void do_command_loop(void) {
                cmd_isme(&cmdbuf[5]);
        }
 
-       else if (!strncasecmp(cmdbuf, "FUCK", 4)) {
-               cprintf("100\n");
-
-               struct CtdlMessage *msg;
-               msg = CtdlFetchMessage(3115, 1);
-               cprintf("\nCtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ONLY, 0, 1);\n--\n");
-               CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ONLY, 0, 1);
-               cprintf("--\nCtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_NONE, 0, 1);\n--\n");
-               CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_NONE, 0, 1);
-               cprintf("--\nCtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1);\n--\n");
-               CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1);
-               cprintf("--\n");
-               cprintf("000\n");
-               CtdlFreeMessage(msg);
-       }
-
        else if (!DLoader_Exec_Cmd(cmdbuf)) {
                cprintf("%d Unrecognized or unsupported command.\n",
                        ERROR + CMD_NOT_SUPPORTED);
index 89682ccc40de7238b5171a2efd8418760c44eebb..c90134f74175991a657d79f308cd3bec6077b179 100644 (file)
@@ -8,10 +8,6 @@
  *
  */
 
-#ifdef DLL_EXPORT
-#define IN_LIBCIT
-#endif
-
 #include "sysdep.h"
 #include <stdlib.h>
 #include <unistd.h>
index 5dc32135983dc5c1cbfd05286834682b440ba788..0e55b1a0facd1e9239ab719afc1aec16e93ffd88 100644 (file)
@@ -176,7 +176,7 @@ void imap_fetch_rfc822(long msgnum, char *whichfmt) {
                CC->redirect_alloc = SIZ;
                CtdlOutputMsg(msgnum, MT_RFC822,
                        (need_body ? HEADERS_ALL : HEADERS_ONLY),
-                       0, 1);
+                       0, 1, NULL);
                if (!need_body) cprintf("\r\n");        /* extra trailing newline */
                IMAP->cached_rfc822_data = CC->redirect_buffer;
                IMAP->cached_rfc822_len = CC->redirect_len;
index beffe3c934964d68bfd25dee6bc6f2005301b0ca..edbdc52cb0bc0773d17ad246128d9e7ebac32ccf 100644 (file)
@@ -1,17 +1,13 @@
 /*
  * $Id$
  *
- * This is the MIME parser for Citadel.  Sometimes it actually works.
+ * This is the MIME parser for Citadel.
  *
  * Copyright (c) 1998-2005 by Art Cancro
  * This code is distributed under the terms of the GNU General Public License.
  *
  */
 
-#ifdef DLL_EXPORT
-#define IN_LIBCIT
-#endif
-
 #include <stdlib.h>
 #include <unistd.h>
 #include <stdio.h>
@@ -482,9 +478,9 @@ void the_mime_parser(char *partnum,
                        ++length;
                }
                part_end = content_end;
-                /* fix an off-by-one error */
-                --part_end;
-                --length;
+               /* fix an off-by-one error */
+               --part_end;
+               --length;
                
                /* Truncate if the header told us to */
                if ( (content_length > 0) && (length > content_length) ) {
@@ -504,12 +500,16 @@ void the_mime_parser(char *partnum,
        
                /* lprintf(CTDL_DEBUG, "mime_decode part=%s, len=%d, type=%s, charset=%s, encoding=%s\n",
                        partnum, length, content_type, charset, encoding); */
+
+               /* Ok, we've got a non-multipart part here, so do something with it.
+                */
                mime_decode(partnum,
-                           part_start, length,
-                           content_type, charset, encoding, disposition,
-                           name, filename,
-                           CallBack, NULL, NULL,
-                           userdata, dont_decode);
+                       part_start, length,
+                       content_type, charset, encoding, disposition,
+                       name, filename,
+                       CallBack, NULL, NULL,
+                       userdata, dont_decode
+               );
        }
 
 end_parser:    /* free the buffers!  end the oppression!! */
index cf9f72d30b1fb6e3d6f78e612a957bce0fbc1fe7..51d78547b73f0d7ca55045e18f9d07d2fd7b4d07 100644 (file)
@@ -1231,6 +1231,37 @@ void output_preferred(char *name, char *filename, char *partnum, char *disp,
 }
 
 
+struct encapmsg {
+       char desired_section[64];
+       char *msg;
+       size_t msglen;
+};
+
+
+/*
+ * Callback function for
+ */
+void extract_encapsulated_message(char *name, char *filename, char *partnum, char *disp,
+                  void *content, char *cbtype, char *cbcharset, size_t length,
+                  char *encoding, void *cbuserdata)
+{
+       struct encapmsg *encap;
+
+       encap = (struct encapmsg *)cbuserdata;
+
+       /* Only proceed if this is the desired section... */
+       if (!strcasecmp(encap->desired_section, partnum)) {
+               encap->msglen = length;
+               encap->msg = malloc(length + 2);
+               memcpy(encap->msg, content, length);
+               return;
+       }
+
+}
+
+
+
+
 /*
  * Get a message off disk.  (returns om_* values found in msgbase.h)
  * 
@@ -1239,13 +1270,17 @@ int CtdlOutputMsg(long msg_num,         /* message number (local) to fetch */
                int mode,               /* how would you like that message? */
                int headers_only,       /* eschew the message body? */
                int do_proto,           /* do Citadel protocol responses? */
-               int crlf                /* Use CRLF newlines instead of LF? */
+               int crlf,               /* Use CRLF newlines instead of LF? */
+               char *section           /* NULL or a message/rfc822 section */
 ) {
        struct CtdlMessage *TheMessage = NULL;
        int retcode = om_no_such_msg;
+       struct encapmsg encap;
 
-       lprintf(CTDL_DEBUG, "CtdlOutputMsg() msgnum=%ld, mode=%d\n", 
-               msg_num, mode);
+       lprintf(CTDL_DEBUG, "CtdlOutputMsg() msgnum=%ld, mode=%d, section=%s\n", 
+               msg_num, mode,
+               (section ? section : "<>")
+       );
 
        if ((!(CC->logged_in)) && (!(CC->internal_pgm))) {
                if (do_proto) cprintf("%d Not logged in.\n",
@@ -1272,11 +1307,45 @@ int CtdlOutputMsg(long msg_num,         /* message number (local) to fetch */
                        ERROR + MESSAGE_NOT_FOUND, msg_num);
                return(om_no_such_msg);
        }
-       
-       retcode = CtdlOutputPreLoadedMsg(
-                       TheMessage, mode,
-                       headers_only, do_proto, crlf);
 
+       /* Here is the weird form of this command, to process only an
+        * encapsulated message/rfc822 section.
+        */
+       if (section) {
+               memset(&encap, 0, sizeof encap);
+               safestrncpy(encap.desired_section, section, sizeof encap.desired_section);
+               mime_parser(TheMessage->cm_fields['M'],
+                       NULL,
+                       *extract_encapsulated_message,
+                       NULL, NULL, (void *)&encap, 0
+               );
+               CtdlFreeMessage(TheMessage);
+               TheMessage = NULL;
+
+               if (encap.msg) {
+                       encap.msg[encap.msglen] = 0;
+                       TheMessage = convert_internet_message(encap.msg);
+                       encap.msg = NULL;       /* no free() here, TheMessage owns it now */
+
+                       /* Now we let it fall through to the bottom of this
+                        * function, because TheMessage now contains the
+                        * encapsulated message instead of the top-level
+                        * message.  Isn't that neat?
+                        */
+
+               }
+               else {
+                       if (do_proto) cprintf("%d msg %ld has no part %s\n",
+                               ERROR + MESSAGE_NOT_FOUND, msg_num, section);
+                       retcode = om_no_such_msg;
+               }
+
+       }
+
+       /* Ok, output the message now */
+       retcode = CtdlOutputPreLoadedMsg(
+               TheMessage, mode,
+               headers_only, do_proto, crlf);
        CtdlFreeMessage(TheMessage);
 
        return(retcode);
@@ -1666,7 +1735,7 @@ void cmd_msg0(char *cmdbuf)
        msgid = extract_long(cmdbuf, 0);
        headers_only = extract_int(cmdbuf, 1);
 
-       CtdlOutputMsg(msgid, MT_CITADEL, headers_only, 1, 0);
+       CtdlOutputMsg(msgid, MT_CITADEL, headers_only, 1, 0, NULL);
        return;
 }
 
@@ -1682,7 +1751,7 @@ void cmd_msg2(char *cmdbuf)
        msgid = extract_long(cmdbuf, 0);
        headers_only = extract_int(cmdbuf, 1);
 
-       CtdlOutputMsg(msgid, MT_RFC822, headers_only, 1, 1);
+       CtdlOutputMsg(msgid, MT_RFC822, headers_only, 1, 1, NULL);
 }
 
 
@@ -1732,9 +1801,11 @@ void cmd_msg3(char *cmdbuf)
 void cmd_msg4(char *cmdbuf)
 {
        long msgid;
+       char section[64];
 
        msgid = extract_long(cmdbuf, 0);
-       CtdlOutputMsg(msgid, MT_MIME, 0, 1, 0);
+       extract_token(section, cmdbuf, 1, '|', sizeof section);
+       CtdlOutputMsg(msgid, MT_MIME, 0, 1, 0, (section[0] ? section : NULL) );
 }
 
 
@@ -1762,7 +1833,7 @@ void cmd_opna(char *cmdbuf)
        extract_token(desired_section, cmdbuf, 1, '|', sizeof desired_section);
        safestrncpy(CC->download_desired_section, desired_section,
                sizeof CC->download_desired_section);
-       CtdlOutputMsg(msgid, MT_DOWNLOAD, 0, 1, 1);
+       CtdlOutputMsg(msgid, MT_DOWNLOAD, 0, 1, 1, NULL);
 }                      
 
 
index ab01d27d92d9dcf0674fc117a040340fd5fba6b6..600b684dc3e273bc648aaff262a4ae5a14858cf1 100644 (file)
@@ -117,12 +117,15 @@ int CtdlOutputMsg(long msg_num,           /* message number (local) to fetch */
                int mode,               /* how would you like that message? */
                int headers_only,       /* eschew the message body? */
                int do_proto,           /* do Citadel protocol responses? */
-               int crlf);
+               int crlf,               /* 0=LF, 1=CRLF */
+               char *section           /* output a message/rfc822 section */
+);
 int CtdlOutputPreLoadedMsg(struct CtdlMessage *,
                int mode,               /* how would you like that message? */
                int headers_only,       /* eschew the message body? */
                int do_proto,           /* do Citadel protocol responses? */
-               int crlf);
+               int crlf                /* 0=LF, 1=CRLF */
+);
 int CtdlCopyMsgToRoom(long msgnum, char *dest);
 int CtdlDoIHavePermissionToDeleteMessagesFromThisRoom(void);
 int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf, size_t n);
index b7e198b96857a6c60abd1d3bc74b036f0df2ef1a..cb1aed5c54bdfad3342d1ca1c0740b7a1eee0caf 100644 (file)
@@ -195,7 +195,7 @@ void cmd_auto(char *argbuf) {
        }
        
        cprintf("000\n");
-       if (strcmp(&CC->room.QRname, hold_rm)) {
+       if (strcmp(CC->room.QRname, hold_rm)) {
                getroom(&CC->room, hold_rm);    /* return to saved room */
        }
 }
index 50ee1e02fd83be45ebef7f66f1a298fcc7d47be7..29ea751cec6d7ca0286695ee4e2059f82fa35ae8 100644 (file)
@@ -118,7 +118,7 @@ void ft_index_message(long msgnum, int op) {
        CC->redirect_buffer = malloc(SIZ);
        CC->redirect_len = 0;
        CC->redirect_alloc = SIZ;
-       CtdlOutputMsg(msgnum, MT_CITADEL, HEADERS_ALL, 0, 1);
+       CtdlOutputMsg(msgnum, MT_CITADEL, HEADERS_ALL, 0, 1, NULL);
        msgtext = CC->redirect_buffer;
        CC->redirect_buffer = NULL;
        CC->redirect_len = 0;
index 231e42025419ba618ef5654d439bd155ccc20e35..3e76c8abdcb7232873093be55104c0f8b7c31535 100644 (file)
@@ -156,7 +156,7 @@ void pop3_add_message(long msgnum, void *userdata) {
                CC->redirect_buffer = malloc(SIZ);
                CC->redirect_len = 0;
                CC->redirect_alloc = SIZ;
-               CtdlOutputMsg(msgnum, MT_RFC822, HEADERS_ALL, 0, 1);
+               CtdlOutputMsg(msgnum, MT_RFC822, HEADERS_ALL, 0, 1, NULL);
                smi.meta_rfc822_length = CC->redirect_len;
                free(CC->redirect_buffer);
                CC->redirect_buffer = NULL;
@@ -370,7 +370,7 @@ void pop3_retr(char *argbuf) {
        }
 
        cprintf("+OK Message %d:\r\n", which_one);
-       CtdlOutputMsg(POP3->msgs[which_one - 1].msgnum, MT_RFC822, HEADERS_ALL, 0, 1);
+       CtdlOutputMsg(POP3->msgs[which_one - 1].msgnum, MT_RFC822, HEADERS_ALL, 0, 1, NULL);
        cprintf(".\r\n");
 }
 
@@ -403,7 +403,7 @@ void pop3_top(char *argbuf) {
        CC->redirect_len = 0;
        CC->redirect_alloc = SIZ;
        CtdlOutputMsg(POP3->msgs[which_one - 1].msgnum,
-                       MT_RFC822, HEADERS_ALL, 0, 1);
+                       MT_RFC822, HEADERS_ALL, 0, 1, NULL);
        msgtext = CC->redirect_buffer;
        CC->redirect_buffer = NULL;
        CC->redirect_len = 0;
index 00d5c6789e8f08522281fa5f902ae10b41a383a4..fcfd49fa16f03433574802ee23d670575221d100 100644 (file)
@@ -940,7 +940,7 @@ void smtp_try(const char *key, const char *addr, int *status,
        CC->redirect_buffer = malloc(SIZ);
        CC->redirect_len = 0;
        CC->redirect_alloc = SIZ;
-       CtdlOutputMsg(msgnum, MT_RFC822, HEADERS_ALL, 0, 1);
+       CtdlOutputMsg(msgnum, MT_RFC822, HEADERS_ALL, 0, 1, NULL);
        msgtext = CC->redirect_buffer;
        msg_size = CC->redirect_len;
        CC->redirect_buffer = NULL;
index 7dfcf40246c88165accbb7598d77a3c7b1c62c25..0c69ad7c4da9d917a1c016b7a787bf2afe16f316 100644 (file)
@@ -1877,6 +1877,15 @@ will output RFC822-like MIME part headers such as "Content-type:" and
 "Content-length:".  MIME formats are chosen and/or converted based on the
 client's preferred format settings, which are set using the MSGP command,
 described below.
+ The MSG4 command also accepts an optional second argument, which may be the
+MIME part specifier of an encapsulated message/rfc822 message.  This is useful
+for fetching the encapsulated message instead of the top-level message, for
+example, when someone has forwarded a message as an attachment.  Note that the
+only way for the client to know the part specifier is to fetch the top-level
+message and then look for attachments of type message/rfc822, and then call
+MSG4 again with that part specifier.
+