From db4bd92400cbe8149f33991e98fd58d20c088736 Mon Sep 17 00:00:00 2001 From: Art Cancro Date: Fri, 21 Oct 2005 19:13:55 +0000 Subject: [PATCH] * 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. --- citadel/ChangeLog | 5 ++ citadel/auth.c | 4 -- citadel/citserver.c | 20 -------- citadel/clientsocket.c | 4 -- citadel/imap_fetch.c | 2 +- citadel/mime_parser.c | 26 +++++----- citadel/msgbase.c | 93 ++++++++++++++++++++++++++++++----- citadel/msgbase.h | 7 ++- citadel/serv_autocompletion.c | 2 +- citadel/serv_fulltext.c | 2 +- citadel/serv_pop3.c | 6 +-- citadel/serv_smtp.c | 2 +- citadel/techdoc/protocol.txt | 9 ++++ 13 files changed, 121 insertions(+), 61 deletions(-) diff --git a/citadel/ChangeLog b/citadel/ChangeLog index 1f7e1ac53..e1afd2ed7 100644 --- a/citadel/ChangeLog +++ b/citadel/ChangeLog @@ -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 diff --git a/citadel/auth.c b/citadel/auth.c index 38fdd3aab..3a9dbf481 100644 --- a/citadel/auth.c +++ b/citadel/auth.c @@ -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 diff --git a/citadel/citserver.c b/citadel/citserver.c index 275a6c351..aa366e25f 100644 --- a/citadel/citserver.c +++ b/citadel/citserver.c @@ -5,10 +5,6 @@ * */ -#ifdef DLL_EXPORT -#define IN_LIBCIT -#endif - #include "sysdep.h" #include #include @@ -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); diff --git a/citadel/clientsocket.c b/citadel/clientsocket.c index 89682ccc4..c90134f74 100644 --- a/citadel/clientsocket.c +++ b/citadel/clientsocket.c @@ -8,10 +8,6 @@ * */ -#ifdef DLL_EXPORT -#define IN_LIBCIT -#endif - #include "sysdep.h" #include #include diff --git a/citadel/imap_fetch.c b/citadel/imap_fetch.c index 5dc321359..0e55b1a0f 100644 --- a/citadel/imap_fetch.c +++ b/citadel/imap_fetch.c @@ -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; diff --git a/citadel/mime_parser.c b/citadel/mime_parser.c index beffe3c93..edbdc52cb 100644 --- a/citadel/mime_parser.c +++ b/citadel/mime_parser.c @@ -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 #include #include @@ -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!! */ diff --git a/citadel/msgbase.c b/citadel/msgbase.c index cf9f72d30..51d78547b 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -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); } diff --git a/citadel/msgbase.h b/citadel/msgbase.h index ab01d27d9..600b684dc 100644 --- a/citadel/msgbase.h +++ b/citadel/msgbase.h @@ -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); diff --git a/citadel/serv_autocompletion.c b/citadel/serv_autocompletion.c index b7e198b96..cb1aed5c5 100644 --- a/citadel/serv_autocompletion.c +++ b/citadel/serv_autocompletion.c @@ -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 */ } } diff --git a/citadel/serv_fulltext.c b/citadel/serv_fulltext.c index 50ee1e02f..29ea751ce 100644 --- a/citadel/serv_fulltext.c +++ b/citadel/serv_fulltext.c @@ -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; diff --git a/citadel/serv_pop3.c b/citadel/serv_pop3.c index 231e42025..3e76c8abd 100644 --- a/citadel/serv_pop3.c +++ b/citadel/serv_pop3.c @@ -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; diff --git a/citadel/serv_smtp.c b/citadel/serv_smtp.c index 00d5c6789..fcfd49fa1 100644 --- a/citadel/serv_smtp.c +++ b/citadel/serv_smtp.c @@ -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; diff --git a/citadel/techdoc/protocol.txt b/citadel/techdoc/protocol.txt index 7dfcf4024..0c69ad7c4 100644 --- a/citadel/techdoc/protocol.txt +++ b/citadel/techdoc/protocol.txt @@ -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. + -- 2.30.2