diff options
-rw-r--r-- | imap4d/fetch.c | 14 | ||||
-rw-r--r-- | include/mailutils/header.h | 1 | ||||
-rw-r--r-- | include/mailutils/imap.h | 14 | ||||
-rw-r--r-- | include/mailutils/message.h | 75 | ||||
-rw-r--r-- | include/mailutils/mime.h | 3 | ||||
-rw-r--r-- | include/mailutils/sys/message.h | 2 | ||||
-rw-r--r-- | libmailutils/mailbox/Makefile.am | 2 | ||||
-rw-r--r-- | libmailutils/mailbox/bodystruct.c | 325 | ||||
-rw-r--r-- | libmailutils/mailbox/imapenv.c | 138 | ||||
-rw-r--r-- | libmailutils/string/wordsplit.c | 2 | ||||
-rw-r--r-- | libproto/imap/fetch.c | 498 | ||||
-rw-r--r-- | libproto/imap/resplist.c | 9 | ||||
-rw-r--r-- | mu/imap.c | 168 | ||||
-rw-r--r-- | testsuite/Makefile.am | 1 | ||||
-rw-r--r-- | testsuite/bs.c | 169 |
15 files changed, 1353 insertions, 68 deletions
diff --git a/imap4d/fetch.c b/imap4d/fetch.c index fed2e3f21..ad42ff3a9 100644 --- a/imap4d/fetch.c +++ b/imap4d/fetch.c @@ -372,8 +372,9 @@ bodystructure (mu_message_t msg, int extension) if (mu_header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer) == 0) { struct mu_wordsplit ws; - char *s, *p; - + char *p; + size_t len; + ws.ws_delim = " \t\r\n;="; ws.ws_alloc_die = imap4d_ws_alloc_die; if (mu_wordsplit (buffer, &ws, IMAP4D_WS_FLAGS)) @@ -383,18 +384,17 @@ bodystructure (mu_message_t msg, int extension) return RESP_BAD; /* FIXME: a better error handling, maybe? */ } + len = strcspn (ws.ws_wordv[0], "/"); if (mu_c_strcasecmp (ws.ws_wordv[0], "MESSAGE/RFC822") == 0) message_rfc822 = 1; - else if (mu_c_strcasecmp (ws.ws_wordv[0], "TEXT/PLAIN") == 0) + else if (mu_c_strncasecmp (ws.ws_wordv[0], "TEXT", len) == 0) text_plain = 1; - s = strchr (ws.ws_wordv[0], '/'); - if (s) - *s++ = 0; + ws.ws_wordv[0][len++] = 0; p = ws.ws_wordv[0]; io_send_qstring (p); io_sendf (" "); - io_send_qstring (s); + io_send_qstring (ws.ws_wordv[0] + len); /* body parameter parenthesized list: Content-type attributes */ if (ws.ws_wordc > 1) diff --git a/include/mailutils/header.h b/include/mailutils/header.h index ed13ab31b..4117a2913 100644 --- a/include/mailutils/header.h +++ b/include/mailutils/header.h @@ -59,6 +59,7 @@ extern "C" { #define MU_HEADER_CONTENT_DESCRIPTION "Content-Description" #define MU_HEADER_CONTENT_DISPOSITION "Content-Disposition" #define MU_HEADER_CONTENT_MD5 "Content-MD5" +#define MU_HEADER_CONTENT_LOCATION "Content-Location" #define MU_HEADER_MIME_VERSION "MIME-Version" #define MU_HEADER_X_MAILER "X-Mailer" #define MU_HEADER_X_UIDL "X-UIDL" diff --git a/include/mailutils/imap.h b/include/mailutils/imap.h index 63a5eae1b..b6f9e5740 100644 --- a/include/mailutils/imap.h +++ b/include/mailutils/imap.h @@ -236,23 +236,13 @@ struct mu_imap_fetch_body struct mu_imap_fetch_bodystructure { int type; - //FIXME? + struct mu_bodystructure *bs; }; struct mu_imap_fetch_envelope { int type; - struct tm date; - struct mu_timezone tz; - char *subject; - mu_address_t from; - mu_address_t sender; - mu_address_t reply_to; - mu_address_t to; - mu_address_t cc; - mu_address_t bcc; - char *in_reply_to; - char *message_id; + struct mu_imapenvelope *imapenvelope; }; struct mu_imap_fetch_flags diff --git a/include/mailutils/message.h b/include/mailutils/message.h index ced790153..d1a31ecaa 100644 --- a/include/mailutils/message.h +++ b/include/mailutils/message.h @@ -20,6 +20,7 @@ #define _MAILUTILS_MESSAGE_H #include <mailutils/types.h> +#include <mailutils/datetime.h> #ifdef __cplusplus extern "C" { @@ -28,6 +29,64 @@ extern "C" { #define MU_SCAN_SEEK 0x01 #define MU_SCAN_SIZE 0x02 +struct mu_imapenvelope +{ + struct tm date; + struct mu_timezone tz; + char *subject; + mu_address_t from; + mu_address_t sender; + mu_address_t reply_to; + mu_address_t to; + mu_address_t cc; + mu_address_t bcc; + char *in_reply_to; + char *message_id; +}; + +enum mu_message_type + { + mu_message_other, + mu_message_text, /* text/plain */ + mu_message_rfc822, /* message/rfc822 */ + mu_message_multipart /* multipart/mixed */ + }; + +struct mu_bodystructure +{ + enum mu_message_type body_message_type; + char *body_type; + char *body_subtype; + mu_assoc_t body_param; + char *body_id; + char *body_descr; + char *body_encoding; + size_t body_size; + /* Optional */ + char *body_md5; + char *body_disposition; + mu_assoc_t body_disp_param; + char *body_language; + char *body_location; + union + { + struct + { + size_t body_lines; + } text; + struct + { + struct mu_imapenvelope *body_env; + struct mu_bodystructure *body_struct; + size_t body_lines; + } rfc822; + struct + { + mu_list_t body_parts; + } multipart; + } v; +}; + struct mu_message_scan { int flags; @@ -137,6 +196,21 @@ extern int mu_message_set_qid (mu_message_t, int (*_get_qid) (mu_message_t, mu_message_qid_t *), void *owner); + +extern int mu_message_get_imapenvelope (mu_message_t, struct mu_imapenvelope **); +extern void mu_message_imapenvelope_free (struct mu_imapenvelope *); +extern int mu_message_set_imapenvelope (mu_message_t, + int (*_imapenvelope) (mu_message_t, struct mu_imapenvelope **), + void *owner); + +extern void mu_bodystructure_free (struct mu_bodystructure *); +extern void mu_list_free_bodystructure (void *item); + +extern int mu_message_get_bodystructure (mu_message_t, + struct mu_bodystructure **); +extern int mu_message_set_bodystructure (mu_message_t msg, + int (*_bodystructure) (mu_message_t, struct mu_bodystructure **), + void *owner); /* misc functions */ extern int mu_message_create_attachment (const char *content_type, @@ -190,7 +264,6 @@ extern int mu_message_from_stream_with_envelope (mu_message_t *pmsg, mu_envelope_t env); extern int mu_stream_to_message (mu_stream_t instream, mu_message_t *pmsg); - #ifdef __cplusplus } #endif diff --git a/include/mailutils/mime.h b/include/mailutils/mime.h index 9c3d473a2..48989f1e1 100644 --- a/include/mailutils/mime.h +++ b/include/mailutils/mime.h @@ -66,6 +66,9 @@ int mu_base64_decode (const unsigned char *input, size_t input_len, unsigned char **output, size_t * output_len); +int mu_mime_param_assoc_create (mu_assoc_t *passoc); +int mu_mime_param_assoc_add (mu_assoc_t assoc, const char *name); + int mu_mime_header_parse (const char *text, char *charset, char **pvalue, mu_assoc_t *paramtab); int mu_mime_header_parse_subset (const char *text, const char *charset, diff --git a/include/mailutils/sys/message.h b/include/mailutils/sys/message.h index f538fc9bb..6259dbe89 100644 --- a/include/mailutils/sys/message.h +++ b/include/mailutils/sys/message.h @@ -61,6 +61,8 @@ struct _mu_message int (*_get_qid) (mu_message_t, mu_message_qid_t *); int (*_get_num_parts) (mu_message_t, size_t *); int (*_get_part) (mu_message_t, size_t, mu_message_t *); + int (*_imapenvelope) (mu_message_t, struct mu_imapenvelope **); + int (*_bodystructure) (mu_message_t, struct mu_bodystructure **); int (*_is_multipart) (mu_message_t, int *); int (*_lines) (mu_message_t, size_t *, int); int (*_size) (mu_message_t, size_t *); diff --git a/libmailutils/mailbox/Makefile.am b/libmailutils/mailbox/Makefile.am index cb9e775fc..661a92211 100644 --- a/libmailutils/mailbox/Makefile.am +++ b/libmailutils/mailbox/Makefile.am @@ -23,12 +23,14 @@ libmailbox_la_SOURCES = \ mbxitr.c\ attribute.c\ body.c\ + bodystruct.c\ envelope.c\ folder.c\ fsfolder.c\ hdrfirst.c\ hdritr.c\ header.c\ + imapenv.c\ msgcpy.c\ msgattr.c\ msgbody.c\ diff --git a/libmailutils/mailbox/bodystruct.c b/libmailutils/mailbox/bodystruct.c new file mode 100644 index 000000000..c99cbbe4a --- /dev/null +++ b/libmailutils/mailbox/bodystruct.c @@ -0,0 +1,325 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2011 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <stdlib.h> +#include <mailutils/types.h> +#include <mailutils/assoc.h> +#include <mailutils/list.h> +#include <mailutils/message.h> +#include <mailutils/mime.h> +#include <mailutils/header.h> +#include <mailutils/sys/message.h> +#include <mailutils/errno.h> +#include <mailutils/debug.h> +#include <mailutils/nls.h> +#include <mailutils/cstr.h> +#include <mailutils/body.h> + +void +mu_list_free_bodystructure (void *item) +{ + mu_bodystructure_free (item); +} + +void +mu_bodystructure_free (struct mu_bodystructure *bs) +{ + if (!bs) + return; + free (bs->body_type); + free (bs->body_subtype); + mu_assoc_destroy (&bs->body_param); + free (bs->body_id); + free (bs->body_descr); + free (bs->body_encoding); + free (bs->body_md5); + free (bs->body_disposition); + mu_assoc_destroy (&bs->body_disp_param); + free (bs->body_language); + free (bs->body_location); + switch (bs->body_message_type) + { + case mu_message_other: + case mu_message_text: + break; + + case mu_message_rfc822: + mu_message_imapenvelope_free (bs->v.rfc822.body_env); + mu_bodystructure_free (bs->v.rfc822.body_struct); + break; + + case mu_message_multipart: + mu_list_destroy (&bs->v.multipart.body_parts); + } + + free (bs); +} + +static int bodystructure_fill (mu_message_t msg, + struct mu_bodystructure *bs); + +static int +bodystructure_init (mu_message_t msg, struct mu_bodystructure **pbs) +{ + int rc; + struct mu_bodystructure *bs = calloc (1, sizeof (*bs)); + if (!bs) + return ENOMEM; + rc = bodystructure_fill (msg, bs); + if (rc) + mu_bodystructure_free (bs); + else + *pbs = bs; + return rc; +} + +static int +bodystructure_fill (mu_message_t msg, struct mu_bodystructure *bs) +{ + mu_header_t header = NULL; + const char *buffer = NULL; + mu_body_t body = NULL; + int rc; + int is_multipart = 0; + + rc = mu_message_get_header (msg, &header); + if (rc) + return rc; + + if (mu_header_sget_value (header, MU_HEADER_CONTENT_TYPE, &buffer) == 0) + { + char *value; + char *p; + size_t len; + + rc = mu_mime_header_parse (buffer, "UTF-8", &value, &bs->body_param); + if (rc) + return rc; + + len = strcspn (value, "/"); + + if (mu_c_strcasecmp (value, "MESSAGE/RFC822") == 0) + bs->body_message_type = mu_message_rfc822; + else if (mu_c_strncasecmp (value, "TEXT", len) == 0) + bs->body_message_type = mu_message_text; + + p = malloc (len + 1); + if (!p) + return ENOMEM; + memcpy (p, value, len); + p[len] = 0; + + bs->body_type = p; + mu_strupper (bs->body_type); + if (value[len]) + { + bs->body_subtype = strdup (value + len + 1); + if (!bs->body_subtype) + return ENOMEM; + mu_strupper (bs->body_subtype); + } + + /* body parameter parenthesized list: Content-type attributes */ + + rc = mu_message_is_multipart (msg, &is_multipart); + if (rc) + return rc; + if (is_multipart) + bs->body_message_type = mu_message_multipart; + } + else + { + struct mu_mime_param param; + + /* Default? If Content-Type is not present consider as text/plain. */ + bs->body_type = strdup ("TEXT"); + if (!bs->body_type) + return ENOMEM; + bs->body_subtype = strdup ("PLAIN"); + if (!bs->body_subtype) + return ENOMEM; + rc = mu_mime_param_assoc_create (&bs->body_param); + if (rc) + return rc; + memset (¶m, 0, sizeof (param)); + param.value = strdup ("US-ASCII"); + rc = mu_assoc_install (bs->body_param, "CHARSET", ¶m); + if (rc) + { + free (param.value); + return rc; + } + bs->body_message_type = mu_message_text; + } + + if (is_multipart) + { + size_t i, nparts; + + rc = mu_message_get_num_parts (msg, &nparts); + if (rc) + return rc; + + rc = mu_list_create (&bs->v.multipart.body_parts); + if (rc) + return rc; + + mu_list_set_destroy_item (bs->v.multipart.body_parts, + mu_list_free_bodystructure); + + for (i = 1; i <= nparts; i++) + { + mu_message_t partmsg; + struct mu_bodystructure *partbs; + + rc = mu_message_get_part (msg, i, &partmsg); + if (rc) + return rc; + + rc = bodystructure_init (partmsg, &partbs); + if (rc) + return rc; + + rc = mu_list_append (bs->v.multipart.body_parts, partbs); + if (rc) + { + mu_bodystructure_free (partbs); + return rc; + } + } + } + else + { + /* body id: Content-ID. */ + rc = mu_header_aget_value_unfold (header, MU_HEADER_CONTENT_ID, + &bs->body_id); + if (rc && rc != MU_ERR_NOENT) + return rc; + /* body description: Content-Description. */ + rc = mu_header_aget_value_unfold (header, MU_HEADER_CONTENT_DESCRIPTION, + &bs->body_descr); + if (rc && rc != MU_ERR_NOENT) + return rc; + + /* body encoding: Content-Transfer-Encoding. */ + rc = mu_header_aget_value_unfold (header, + MU_HEADER_CONTENT_TRANSFER_ENCODING, + &bs->body_encoding); + if (rc == MU_ERR_NOENT) + { + bs->body_encoding = strdup ("7BIT"); + if (!bs->body_encoding) + return ENOMEM; + } + else if (rc) + return rc; + + /* body size RFC822 format. */ + rc = mu_message_get_body (msg, &body); + if (rc) + return rc; + rc = mu_body_size (body, &bs->body_size); + if (rc) + return rc; + + /* If the mime type was text. */ + if (bs->body_message_type == mu_message_text) + { + rc = mu_body_lines (body, &bs->v.text.body_lines); + if (rc) + return rc; + } + else if (bs->body_message_type == mu_message_rfc822) + { + mu_message_t emsg = NULL; + + /* Add envelope structure of the encapsulated message. */ + rc = mu_message_unencapsulate (msg, &emsg, NULL); + if (rc) + return rc; + rc = mu_message_get_imapenvelope (emsg, &bs->v.rfc822.body_env); + if (rc) + return rc; + /* Add body structure of the encapsulated message. */ + rc = bodystructure_init (emsg, &bs->v.rfc822.body_struct); + if (rc) + return rc; + /* Size in text lines of the encapsulated message. */ + rc = mu_message_lines (emsg, &bs->v.rfc822.body_lines); + mu_message_destroy (&emsg, NULL); + } + } + + /* body MD5: Content-MD5. */ + rc = mu_header_aget_value_unfold (header, MU_HEADER_CONTENT_MD5, + &bs->body_md5); + if (rc && rc != MU_ERR_NOENT) + return rc; + + /* body disposition: Content-Disposition. */ + rc = mu_header_sget_value (header, MU_HEADER_CONTENT_DISPOSITION, + &buffer); + if (rc == 0) + { + rc = mu_mime_header_parse (buffer, "UTF-8", &bs->body_disposition, + &bs->body_disp_param); + if (rc) + return rc; + } + else if (rc != MU_ERR_NOENT) + return rc; + /* body language: Content-Language. */ + rc = mu_header_aget_value_unfold (header, MU_HEADER_CONTENT_LANGUAGE, + &bs->body_language); + if (rc && rc != MU_ERR_NOENT) + return rc; + rc = mu_header_aget_value_unfold (header, MU_HEADER_CONTENT_LOCATION, + &bs->body_location); + if (rc && rc != MU_ERR_NOENT) + return rc; + + return 0; +} + +int +mu_message_get_bodystructure (mu_message_t msg, + struct mu_bodystructure **pbs) +{ + if (msg == NULL) + return EINVAL; + if (pbs == NULL) + return MU_ERR_OUT_PTR_NULL; + if (msg->_bodystructure) + return msg->_bodystructure (msg, pbs); + return bodystructure_init (msg, pbs); +} + +int +mu_message_set_bodystructure (mu_message_t msg, + int (*_bodystructure) (mu_message_t, struct mu_bodystructure **), + void *owner) +{ + if (msg == NULL) + return EINVAL; + if (msg->owner != owner) + return EACCES; + msg->_bodystructure = _bodystructure; + return 0; +} diff --git a/libmailutils/mailbox/imapenv.c b/libmailutils/mailbox/imapenv.c new file mode 100644 index 000000000..efd49b9c8 --- /dev/null +++ b/libmailutils/mailbox/imapenv.c @@ -0,0 +1,138 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2011 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <stdlib.h> +#include <mailutils/types.h> +#include <mailutils/header.h> +#include <mailutils/envelope.h> +#include <mailutils/address.h> +#include <mailutils/message.h> +#include <mailutils/sys/message.h> +#include <mailutils/errno.h> + +void +mu_message_imapenvelope_free (struct mu_imapenvelope *env) +{ + if (!env) + return; + free (env->subject); + mu_address_destroy (&env->from); + mu_address_destroy (&env->sender); + mu_address_destroy (&env->reply_to); + mu_address_destroy (&env->to); + mu_address_destroy (&env->cc); + mu_address_destroy (&env->bcc); + free (env->in_reply_to); + free (env->message_id); + free (env); +} + +int +mu_message_get_imapenvelope (mu_message_t msg, struct mu_imapenvelope **pimapenvelope) +{ + struct mu_imapenvelope *imapenvelope; + int rc; + + if (msg == NULL) + return EINVAL; + if (imapenvelope == NULL) + return MU_ERR_OUT_PTR_NULL; + if (msg->_imapenvelope) + return msg->_imapenvelope (msg, pimapenvelope); + + imapenvelope = calloc (1, sizeof (imapenvelope[0])); + if (!imapenvelope) + return ENOMEM; + do + { + mu_header_t hdr; + mu_envelope_t env; + const char *s; + + if ((rc = mu_message_get_envelope (msg, &env))) + break; + if ((rc = mu_envelope_sget_date (env, &s))) + break; + if ((rc = mu_scan_datetime (s, MU_DATETIME_FROM, + &imapenvelope->date, &imapenvelope->tz, + NULL))) + break; + + if ((rc = mu_message_get_header (msg, &hdr))) + break; + + rc = mu_header_get_address (hdr, MU_HEADER_FROM, &imapenvelope->from); + if (rc && rc != MU_ERR_NOENT) + break; + + rc = mu_header_get_address (hdr, MU_HEADER_SENDER, &imapenvelope->sender); + if (rc && rc != MU_ERR_NOENT) + break; + + rc = mu_header_get_address (hdr, MU_HEADER_REPLY_TO, &imapenvelope->reply_to); + if (rc && rc != MU_ERR_NOENT) + break; + + rc = mu_header_get_address (hdr, MU_HEADER_TO, &imapenvelope->to); + if (rc && rc != MU_ERR_NOENT) + break; + + rc = mu_header_get_address (hdr, MU_HEADER_CC, &imapenvelope->cc); + if (rc && rc != MU_ERR_NOENT) + break; + + rc = mu_header_get_address (hdr, MU_HEADER_BCC, &imapenvelope->bcc); + if (rc && rc != MU_ERR_NOENT) + break; + + rc = mu_header_aget_value_unfold (hdr, MU_HEADER_SUBJECT, + &imapenvelope->subject); + if (rc && rc != MU_ERR_NOENT) + break; + + rc = mu_header_aget_value_unfold (hdr, MU_HEADER_IN_REPLY_TO, + &imapenvelope->in_reply_to); + if (rc && rc != MU_ERR_NOENT) + break; + + rc = mu_header_aget_value_unfold (hdr, MU_HEADER_MESSAGE_ID, + &imapenvelope->message_id); + } + while (0); + if (rc) + mu_message_imapenvelope_free (imapenvelope); + else + *pimapenvelope = imapenvelope; + return rc; +} + +int +mu_message_set_imapenvelope (mu_message_t msg, + int (*_imapenvelope) (mu_message_t, + struct mu_imapenvelope **), + void *owner) +{ + if (msg == NULL) + return EINVAL; + if (msg->owner != owner) + return EACCES; + msg->_imapenvelope = _imapenvelope; + return 0; +} diff --git a/libmailutils/string/wordsplit.c b/libmailutils/string/wordsplit.c index 12af7257e..0acf2a345 100644 --- a/libmailutils/string/wordsplit.c +++ b/libmailutils/string/wordsplit.c @@ -184,7 +184,7 @@ alloc_space (struct mu_wordsplit *wsp, size_t count) else if (wsp->ws_wordn < offs + wsp->ws_wordc + count) { newalloc = offs + wsp->ws_wordc + - count > ALLOC_INCR ? count : ALLOC_INCR; + (count > ALLOC_INCR ? count : ALLOC_INCR); ptr = realloc (wsp->ws_wordv, newalloc * sizeof (ptr[0])); } else diff --git a/libproto/imap/fetch.c b/libproto/imap/fetch.c index b1994ae48..e44804110 100644 --- a/libproto/imap/fetch.c +++ b/libproto/imap/fetch.c @@ -25,6 +25,9 @@ #include <mailutils/address.h> #include <mailutils/cstr.h> #include <mailutils/cctype.h> +#include <mailutils/message.h> +#include <mailutils/mime.h> +#include <mailutils/assoc.h> #include <mailutils/imap.h> #include <mailutils/sys/imap.h> @@ -67,19 +70,11 @@ _free_fetch_response (void *ptr) break; case MU_IMAP_FETCH_BODYSTRUCTURE: - /* FIXME */ + mu_bodystructure_free (resp->bodystructure.bs); break; case MU_IMAP_FETCH_ENVELOPE: - free (resp->envelope.subject); - mu_address_destroy (&resp->envelope.from); - mu_address_destroy (&resp->envelope.sender); - mu_address_destroy (&resp->envelope.reply_to); - mu_address_destroy (&resp->envelope.to); - mu_address_destroy (&resp->envelope.cc); - mu_address_destroy (&resp->envelope.bcc); - free (resp->envelope.in_reply_to); - free (resp->envelope.message_id); + mu_message_imapenvelope_free (resp->envelope.imapenvelope); break; case MU_IMAP_FETCH_FLAGS: @@ -228,8 +223,9 @@ _body_mapper (union mu_imap_fetch_response *resp, partv = calloc (partc, sizeof (partv[0])); for (i = 0, p = section; i < partc; i++) { - partv[i] = strtoul (p, &p, 10); - p++; + char *q; + partv[i] = strtoul (p, &q, 10); + p = q + 1; } } @@ -327,12 +323,438 @@ _date_mapper (union mu_imap_fetch_response *resp, return 0; } -/* FIXME */ -#define _bodystructure_mapper NULL +static int parse_bodystructure (struct imap_list_element *elt, + struct mu_bodystructure **pbs); + +struct body_field_map +{ + size_t offset; /* Offset of the target member of mu_bodystructure */ + int (*mapper) (struct imap_list_element *, void *); +}; + +static int +parse_bs_list (struct imap_list_element *elt, + struct mu_bodystructure *bs, + struct body_field_map *map) +{ + int rc; + mu_iterator_t itr; + + rc = mu_list_get_iterator (elt->v.list, &itr); + if (rc) + return rc; + for (mu_iterator_first (itr); + map->mapper && !mu_iterator_is_done (itr); + mu_iterator_next (itr), map++) + { + struct imap_list_element *tok; + mu_iterator_current (itr, (void**)&tok); + rc = map->mapper (tok, (char*)bs + map->offset); + if (rc) + break; + } + mu_iterator_destroy (&itr); + return rc; +} + +static int +_map_body_param (void **itmv, size_t itmc, void *call_data) +{ + mu_assoc_t assoc = call_data; + struct mu_mime_param param; + struct imap_list_element *key, *val; + int rc; + + if (itmc != 2) + return MU_ERR_PARSE; + + key = itmv[0]; + val = itmv[1]; + if (key->type != imap_eltype_string || val->type != imap_eltype_string) + return MU_ERR_PARSE; + + rc = mu_rfc2047_decode_param ("UTF-8", val->v.string, ¶m); + if (rc) + { + param.lang = param.cset = NULL; + param.value = strdup (val->v.string); + if (!param.value) + return ENOMEM; + } + return mu_assoc_install (assoc, key->v.string, ¶m); +} + +static int +_body_field_text_mapper (struct imap_list_element *tok, void *ptr) +{ + char *s; + + if (_mu_imap_list_element_is_nil (tok)) + s = NULL; + else if (tok->type != imap_eltype_string) + return MU_ERR_PARSE; + else if (!(s = strdup (tok->v.string))) + return ENOMEM; + *(char**) ptr = s; + return 0; +} + +static int +_body_field_size_mapper (struct imap_list_element *tok, void *ptr) +{ + unsigned long n; + + if (_mu_imap_list_element_is_nil (tok)) + n = 0; + else if (tok->type != imap_eltype_string) + return MU_ERR_PARSE; + else + { + char *s; + + errno = 0; + n = strtoul (tok->v.string, &s, 10); + if (*s || errno) + return MU_ERR_PARSE; + } + *(size_t*) ptr = n; + return 0; +} + +static int +_body_field_param_mapper (struct imap_list_element *tok, void *ptr) +{ + mu_assoc_t param; + int rc = mu_mime_param_assoc_create (¶m); + if (rc) + return rc; + *(mu_assoc_t*) ptr = param; + if (_mu_imap_list_element_is_nil (tok)) + return 0; + if (tok->type != imap_eltype_list) + return MU_ERR_PARSE; + return mu_list_gmap (tok->v.list, _map_body_param, 2, param); +} + +static int +_body_field_disposition_mapper (struct imap_list_element *tok, void *ptr) +{ + int rc; + struct mu_bodystructure *bs = ptr; + struct imap_list_element *elt; + + if (_mu_imap_list_element_is_nil (tok)) + return 0; + if (tok->type != imap_eltype_list) + return MU_ERR_PARSE; + elt = _mu_imap_list_at (tok->v.list, 0); + if (_mu_imap_list_element_is_nil (elt)) + bs->body_disposition = NULL; + else if (elt->type != imap_eltype_string) + return MU_ERR_PARSE; + else if ((bs->body_disposition = strdup (elt->v.string)) == NULL) + return ENOMEM; + + rc = mu_mime_param_assoc_create (&bs->body_disp_param); + if (rc) + return rc; + + elt = _mu_imap_list_at (tok->v.list, 1); + if (_mu_imap_list_element_is_nil (elt)) + return 0; + else if (elt->type != imap_eltype_list) + return MU_ERR_PARSE; + return mu_list_gmap (elt->v.list, _map_body_param, 2, bs->body_disp_param); +} + +static int parse_envelope (struct imap_list_element *elt, + struct mu_imapenvelope **penv); + +static int +_body_field_imapenvelope_mapper (struct imap_list_element *tok, void *ptr) +{ + return parse_envelope (tok, ptr); +} + +static int +_body_field_bodystructure_mapper (struct imap_list_element *tok, void *ptr) +{ + return parse_bodystructure (tok, ptr); +} + +/* Simple text or message/rfc822 body. + + Sample TEXT body structure: + + ("TEXT" "PLAIN" ("CHARSET" "US-ASCII" "NAME" "cc.diff") + "<960723163407.20117h@cac.washington.edu>" "Compiler diff" + "BASE64" 4554 73) + + Elements: + + 0 "TEXT" body_type + 1 "PLAIN" body_subtype + 2 (...) body_param + 3 "<9607...>" body_id + 4 "Compiler diff" body_descr + 5 "BASE64" body_encoding + 6 4554 body_size + 7 73 v.text.body_lines + [Optional] + 8 body_md5 + 9 body_disposition; + 10 body_language; + 11 body_location; +*/ + +struct body_field_map base_field_map[] = { + { mu_offsetof (struct mu_bodystructure, body_type), + _body_field_text_mapper }, + { mu_offsetof (struct mu_bodystructure, body_subtype), + _body_field_text_mapper }, + { mu_offsetof (struct mu_bodystructure, body_param), + _body_field_param_mapper }, + { mu_offsetof (struct mu_bodystructure, body_id), + _body_field_text_mapper }, + { mu_offsetof (struct mu_bodystructure, body_descr), + _body_field_text_mapper }, + { mu_offsetof (struct mu_bodystructure, body_encoding), + _body_field_text_mapper }, + { mu_offsetof (struct mu_bodystructure, body_size), + _body_field_size_mapper }, + { mu_offsetof (struct mu_bodystructure, body_md5), + _body_field_text_mapper }, + { 0, _body_field_disposition_mapper }, + { mu_offsetof (struct mu_bodystructure, body_language), + _body_field_text_mapper }, + { mu_offsetof (struct mu_bodystructure, body_location), + _body_field_text_mapper }, + { 0, NULL } +}; + +struct body_field_map text_field_map[] = { + { mu_offsetof (struct mu_bodystructure, body_type), + _body_field_text_mapper }, + { mu_offsetof (struct mu_bodystructure, body_subtype), + _bo |