summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2011-12-22 12:31:25 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2011-12-22 12:40:45 +0200
commite218f1ec00749701a00c074c4574a75a6f156d2b (patch)
tree2e2bcfaeefbd30fd5cc55d01cd95e3c792e4dc60
parent690b1bf8506e50cb85d2634ba2db2fddbff99dfe (diff)
downloadmailutils-e218f1ec00749701a00c074c4574a75a6f156d2b.tar.gz
mailutils-e218f1ec00749701a00c074c4574a75a6f156d2b.tar.bz2
Implement imap (client) bodystructure and envelope.
* libmailutils/string/wordsplit.c (alloc_space): Fix reallocation calculations. * imap4d/fetch.c (bodystructure): Output number of lines for any TEXT part, not only TEXT/PLAIN. * include/mailutils/header.h (MU_HEADER_CONTENT_LOCATION): New define. * include/mailutils/imap.h (mu_imap_fetch_bodystructure): Implement. (mu_imap_fetch_envelope): Replace data fields with a single pointer to struct mu_imapenvelope. * include/mailutils/message.h: Include datetime.h (mu_imapenvelope, mu_bodystructure): New structs. (mu_message_type): New type. (mu_message_get_imapenvelope,mu_message_imapenvelope_free) (mu_message_set_imapenvelope) (mu_bodystructure_free,mu_list_free_bodystructure) (mu_message_get_bodystructure) (mu_message_set_bodystructure): New protos. * include/mailutils/mime.h (mu_mime_param_assoc_create) (mu_mime_param_assoc_add): New protos. * include/mailutils/sys/message.h (_mu_message)<_imapenvelope> <_bodystructure>: New methods. * libmailutils/mailbox/bodystruct.c: New file. * libmailutils/mailbox/imapenv.c: New file. * libmailutils/mailbox/Makefile.am (libmailbox_la_SOURCES): Add new sources. * libproto/imap/fetch.c: Implement bodystructure. * mu/imap.c: Likewise. * testsuite/bs.c: New file. * testsuite/Makefile.am (noinst_PROGRAMS): Add bs.
-rw-r--r--imap4d/fetch.c14
-rw-r--r--include/mailutils/header.h1
-rw-r--r--include/mailutils/imap.h14
-rw-r--r--include/mailutils/message.h75
-rw-r--r--include/mailutils/mime.h3
-rw-r--r--include/mailutils/sys/message.h2
-rw-r--r--libmailutils/mailbox/Makefile.am2
-rw-r--r--libmailutils/mailbox/bodystruct.c325
-rw-r--r--libmailutils/mailbox/imapenv.c138
-rw-r--r--libmailutils/string/wordsplit.c2
-rw-r--r--libproto/imap/fetch.c498
-rw-r--r--libproto/imap/resplist.c9
-rw-r--r--mu/imap.c168
-rw-r--r--testsuite/Makefile.am1
-rw-r--r--testsuite/bs.c169
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 (&param, 0, sizeof (param));
+ param.value = strdup ("US-ASCII");
+ rc = mu_assoc_install (bs->body_param, "CHARSET", &param);
+ 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, &param);
+ 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, &param);
+}
+
+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 (&param);
+ 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),
+ _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, v.text.body_lines),
+ _body_field_size_mapper },
+ { mu_offsetof (struct mu_bodystructure, body_md5),
+ _body_field_text_mapper },
+ { mu_offsetof (struct mu_bodystructure, body_disposition),
+ _body_field_text_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 message_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, v.rfc822.body_env),
+ _body_field_imapenvelope_mapper },
+ { mu_offsetof (struct mu_bodystructure, v.rfc822.body_struct),
+ _body_field_bodystructure_mapper },
+ { mu_offsetof (struct mu_bodystructure, v.rfc822.body_lines),
+ _body_field_size_mapper },
+ { mu_offsetof (struct mu_bodystructure, body_md5),
+ _body_field_text_mapper },
+ { mu_offsetof (struct mu_bodystructure, body_disposition),
+ _body_field_text_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 multipart_field_map[] = {
+ /* Body type is processed separately */
+ { mu_offsetof (struct mu_bodystructure, body_subtype),
+ _body_field_text_mapper },
+ { mu_offsetof (struct mu_bodystructure, body_param),
+ _body_field_param_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 }
+};
+
+#define BSTOK_BODY_TYPE 0
+#define BSTOK_BODY_SUBTYPE 1
+
+static int
+_parse_bodystructure_simple (struct imap_list_element *elt,
+ struct mu_bodystructure *bs)
+{
+ size_t n;
+ struct imap_list_element *tok, *subtype;
+ struct body_field_map *map;
+
+ mu_list_count (elt->v.list, &n);
+ if (n < 8)
+ return MU_ERR_PARSE;
+
+ tok = _mu_imap_list_at (elt->v.list, BSTOK_BODY_TYPE);
+ if (!tok || tok->type != imap_eltype_string)
+ return MU_ERR_PARSE;
+ subtype = _mu_imap_list_at (elt->v.list, BSTOK_BODY_SUBTYPE);
+ if (!subtype || subtype->type != imap_eltype_string)
+ return MU_ERR_PARSE;
+
+ if (mu_c_strcasecmp (tok->v.string, "TEXT") == 0)
+ {
+ bs->body_message_type = mu_message_text;
+ map = text_field_map;
+ }
+ else if (mu_c_strcasecmp (tok->v.string, "MESSAGE") == 0 &&
+ mu_c_strcasecmp (subtype->v.string, "RFC822") == 0)
+ {
+ bs->body_message_type = mu_message_rfc822;
+ map = message_field_map;
+ }
+ else
+ {
+ bs->body_message_type = mu_message_other;
+ map = base_field_map;
+ }
+
+ return parse_bs_list (elt, bs, map);
+}
+
+/* Example multipart:
+ (("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 1152
+ 23)
+ ("TEXT" "PLAIN" ("CHARSET" "US-ASCII" "NAME" "cc.diff")
+ "<960723163407.20117h@cac.washington.edu>" "Compiler diff"
+ "BASE64" 4554 73)
+ "MIXED")
+
+*/
+static int
+_parse_bodystructure_mixed (struct imap_list_element *elt,
+ struct mu_bodystructure *bs)
+{
+ int rc;
+ struct imap_list_element *tok;
+ mu_iterator_t itr;
+ struct body_field_map *map = multipart_field_map;
+
+ bs->body_message_type = mu_message_multipart;
+ if (!(bs->body_type = strdup ("MULTIPART")))
+ return ENOMEM;
+
+ 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);
+
+ rc = mu_list_get_iterator (elt->v.list, &itr);
+ if (rc)
+ return rc;
+ for (mu_iterator_first (itr);
+ !mu_iterator_is_done (itr);
+ mu_iterator_next (itr))
+ {
+ struct mu_bodystructure *bspart;
+
+ mu_iterator_current (itr, (void**) &tok);
+ if (!tok)
+ return MU_ERR_PARSE;
+ if (tok->type != imap_eltype_list)
+ break;
+ rc = parse_bodystructure (tok, &bspart);
+ if (rc)
+ return rc;
+ rc = mu_list_append (bs->v.multipart.body_parts, bspart);
+ if (rc)
+ {
+ mu_bodystructure_free (bspart);
+ return rc;
+ }
+ }
+
+ if (mu_iterator_is_done (itr))
+ return MU_ERR_PARSE;
+
+ for (; 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)
+ return rc;
+ }
+ mu_iterator_destroy (&itr);
+ return 0;
+}
+
+static int
+parse_bodystructure (struct imap_list_element *elt,
+ struct mu_bodystructure **pbs)
+{
+ int rc;
+ struct mu_bodystructure *bs;
+ struct imap_list_element *tok;
+
+ if (elt->type != imap_eltype_list)
+ return MU_ERR_FAILURE;
+ bs = calloc (1, sizeof (*bs));
+ if (!bs)
+ return ENOMEM;
+ tok = _mu_imap_list_at (elt->v.list, 0);
+ if (tok->type == imap_eltype_string)
+ rc = _parse_bodystructure_simple (elt, bs);
+ else
+ rc = _parse_bodystructure_mixed (elt, bs);
+
+ if (rc)
+ mu_bodystructure_free (bs);
+ else
+ *pbs = bs;
+ return rc;
+}
+
+static int
+_bodystructure_mapper (union mu_imap_fetch_response *resp,
+ struct imap_list_element *elt,
+ struct parse_response_env *parse_env)
+{
+ return parse_bodystructure (elt, &resp->bodystructure.bs);
+}
struct fill_env
{
- struct mu_imap_fetch_envelope *envelope;
+ struct mu_imapenvelope *imapenvelope;
size_t n;
};
@@ -435,7 +857,8 @@ _fill_response (void *item, void *data)
int rc;
struct imap_list_element *elt = item;
struct fill_env *env = data;
-
+ struct mu_imapenvelope *imapenvelope = env->imapenvelope;
+
switch (env->n++)
{
case env_date:
@@ -445,8 +868,8 @@ _fill_response (void *item, void *data)
{
if (mu_scan_datetime (elt->v.string,
MU_DATETIME_SCAN_RFC822,
- &env->envelope->date,
- &env->envelope->tz, NULL))
+ &imapenvelope->date,
+ &imapenvelope->tz, NULL))
rc = MU_ERR_FAILURE;
else
rc = 0;
@@ -454,58 +877,67 @@ _fill_response (void *item, void *data)
break;
case env_subject:
- rc = elt_to_string (elt, &env->envelope->subject);
+ rc = elt_to_string (elt, &imapenvelope->subject);
break;
case env_from:
- rc = elt_to_address (elt, &env->envelope->from);
+ rc = elt_to_address (elt, &imapenvelope->from);
break;
case env_sender:
- rc = elt_to_address (elt, &env->envelope->sender);
+ rc = elt_to_address (elt, &imapenvelope->sender);
break;
case env_reply_to:
- rc = elt_to_address (elt, &env->envelope->reply_to);
+ rc = elt_to_address (elt, &imapenvelope->reply_to);
break;
case env_to:
- rc = elt_to_address (elt, &env->envelope->to);
+ rc = elt_to_address (elt, &imapenvelope->to);
break;
case env_cc:
- rc = elt_to_address (elt, &env->envelope->cc);
+ rc = elt_to_address (elt, &imapenvelope->cc);
break;
case env_bcc:
- rc = elt_to_address (elt, &env->envelope->bcc);
+ rc = elt_to_address (elt, &imapenvelope->bcc);
break;
case env_in_reply_to:
- rc = elt_to_string (elt, &env->envelope->in_reply_to);
+ rc = elt_to_string (elt, &imapenvelope->in_reply_to);
break;
case env_message_id:
- rc = elt_to_string (elt, &env->envelope->message_id);
+ rc = elt_to_string (elt, &imapenvelope->message_id);
break;
}
return rc;
}
-
+
static int
-_envelope_mapper (union mu_imap_fetch_response *resp,
- struct imap_list_element *elt,
- struct parse_response_env *parse_env)
+parse_envelope (struct imap_list_element *elt, struct mu_imapenvelope **penv)
{
struct fill_env env;
if (elt->type != imap_eltype_list)
return MU_ERR_FAILURE;
- env.envelope = &resp->envelope;
+ env.imapenvelope = calloc (1, sizeof (*env.imapenvelope));
+ if (!env.imapenvelope)
+ return ENOMEM;
env.n = 0;
mu_list_foreach (elt->v.list, _fill_response, &env);
+ *penv = env.imapenvelope;
return 0;
}
+
+static int
+_envelope_mapper (union mu_imap_fetch_response *resp,
+ struct imap_list_element *elt,
+ struct parse_response_env *parse_env)
+{
+ return parse_envelope (elt, &resp->envelope.imapenvelope);
+}
struct mapper_tab
{
@@ -517,7 +949,7 @@ struct mapper_tab
static struct mapper_tab mapper_tab[] = {
#define S(s) s, (sizeof (s) - 1)
- { S("BODYSTRUCTURE"), },
+ { S("BODYSTRUCTURE"), MU_IMAP_FETCH_BODYSTRUCTURE, _bodystructure_mapper },
{ S("BODY"), MU_IMAP_FETCH_BODY, _body_mapper },
{ S("ENVELOPE"), MU_IMAP_FETCH_ENVELOPE, _envelope_mapper },
{ S("FLAGS"), MU_IMAP_FETCH_FLAGS, _flags_mapper },
diff --git a/libproto/imap/resplist.c b/libproto/imap/resplist.c
index 65d78dc29..2f9dc8008 100644
--- a/libproto/imap/resplist.c
+++ b/libproto/imap/resplist.c
@@ -297,4 +297,13 @@ _mu_imap_list_nth_element_is_string (mu_list_t list, size_t n,
strcmp (elt->v.string, str) == 0;
}
+int
+_mu_imap_list_nth_element_is_string_ci (mu_list_t list, size_t n,
+ const char *str)
+{
+ struct imap_list_element *elt = _mu_imap_list_at (list, n);
+ return elt && elt->type == imap_eltype_string &&
+ mu_c_strcasecmp (elt->v.string, str) == 0;
+}
+
diff --git a/mu/imap.c b/mu/imap.c
index cf49b4be7..9e6e38793 100644
--- a/mu/imap.c
+++ b/mu/imap.c
@@ -225,7 +225,143 @@ format_date (mu_stream_t str, char *name,
}
mu_stream_printf (str, "\n");
}
+
+#define S(str) ((str) ? (str) : "")
+
+static void
+print_param (mu_stream_t ostr, const char *prefix, mu_assoc_t assoc,
+ int indent)
+{
+ mu_iterator_t itr;
+ int i;
+
+ mu_stream_printf (ostr, "%*s%s:\n", indent, "", prefix);
+ indent += 4;
+ if (mu_assoc_get_iterator (assoc, &itr))
+ return;
+ for (i = 0, mu_iterator_first (itr);
+ !mu_iterator_is_done (itr);
+ i++, mu_iterator_next (itr))
+ {
+ const char *name;
+ struct mu_mime_param *p;
+
+ mu_iterator_current_kv (itr, (const void **)&name, (void**)&p);
+ mu_stream_printf (ostr, "%*s%d: %s=%s\n", indent, "", i, name, p->value);
+ }
+ mu_iterator_destroy (&itr);
+}
+
+struct print_data
+{
+ mu_stream_t ostr;
+ int num;
+ int level;
+};
+
+static void print_bs (mu_stream_t ostr,
+ struct mu_bodystructure *bs, int level);
+
+static int
+print_item (void *item, void *data)
+{
+ struct mu_bodystructure *bs = item;
+ struct print_data *pd = data;
+ mu_stream_printf (pd->ostr, "%*sPart #%d\n", (pd->level-1) << 2, "",
+ pd->num);
+ print_bs (pd->ostr, bs, pd->level);
+ ++pd->num;
+ return 0;
+}
+
+static void
+print_address (mu_stream_t ostr, const char *title, mu_address_t addr,
+ int indent)
+{
+ mu_stream_printf (ostr, "%*s%s: ", indent, "", title);
+ mu_stream_format_address (mu_strout, addr);
+ mu_stream_printf (ostr, "\n");
+}
+
+static void
+print_imapenvelope (mu_stream_t ostr, struct mu_imapenvelope *env, int level)
+{
+ int indent = (level << 2);
+
+ mu_stream_printf (ostr, "%*sEnvelope:\n", indent, "");
+ indent += 4;
+ mu_stream_printf (ostr, "%*sTime: ", indent, "");
+ mu_c_streamftime (mu_strout, "%c%n", &env->date, &env->tz);
+ mu_stream_printf (ostr, "%*sSubject: %s\n", indent, "", S(env->subject));
+ print_address (ostr, "From", env->from, indent);
+ print_address (ostr, "Sender", env->sender, indent);
+ print_address (ostr, "Reply-to", env->reply_to, indent);
+ print_address (ostr, "To", env->to, indent);
+ print_address (ostr, "Cc", env->cc, indent);
+ print_address (ostr, "Bcc", env->bcc, indent);
+ mu_stream_printf (ostr, "%*sIn-Reply-To: %s\n", indent, "",
+ S(env->in_reply_to));
+ mu_stream_printf (ostr, "%*sMessage-ID: %s\n", indent, "",
+ S(env->message_id));
+}
+static void
+print_bs (mu_stream_t ostr, struct mu_bodystructure *bs, int level)
+{
+ int indent = level << 2;
+ mu_stream_printf (ostr, "%*sbody_type=%s\n", indent, "", S(bs->body_type));
+ mu_stream_printf (ostr, "%*sbody_subtype=%s\n", indent, "",
+ S(bs->body_subtype));
+ print_param (ostr, "Parameters", bs->body_param, indent);
+ mu_stream_printf (ostr, "%*sbody_id=%s\n", indent, "", S(bs->body_id));
+ mu_stream_printf (ostr, "%*sbody_descr=%s\n", indent, "", S(bs->body_descr));
+ mu_stream_printf (ostr, "%*sbody_encoding=%s\n", indent, "",
+ S(bs->body_encoding));
+ mu_stream_printf (ostr, "%*sbody_size=%lu\n", indent, "",
+ (unsigned long) bs->body_size);
+ /* Optional */
+ mu_stream_printf (ostr, "%*sbody_md5=%s\n", indent, "", S(bs->body_md5));
+ mu_stream_printf (ostr, "%*sbody_disposition=%s\n", indent, "",
+ S(bs->body_disposition));
+ print_param (ostr, "Disposition Parameters", bs->body_disp_param, indent);
+ mu_stream_printf (ostr, "%*sbody_language=%s\n", indent, "",
+ S(bs->body_language));
+ mu_stream_printf (ostr, "%*sbody_location=%s\n", indent, "",
+ S(bs->body_location));
+
+ mu_stream_printf (ostr, "%*sType ", indent, "");
+ switch (bs->body_message_type)
+ {
+ case mu_message_other:
+ mu_stream_printf (ostr, "mu_message_other\n");
+ break;
+
+ case mu_message_text:
+ mu_stream_printf (ostr, "mu_message_text:\n%*sbody_lines=%lu\n",
+ indent + 4, "",
+ (unsigned long) bs->v.text.body_lines);
+ break;
+
+ case mu_message_rfc822:
+ mu_stream_printf (ostr, "mu_message_rfc822:\n%*sbody_lines=%lu\n",
+ indent + 4, "",
+ (unsigned long) bs->v.rfc822.body_lines);
+ print_imapenvelope (ostr, bs->v.rfc822.body_env, level + 1);
+ print_bs (ostr, bs->v.rfc822.body_struct, level + 1);
+ break;
+
+ case mu_message_multipart:
+ {
+ struct print_data pd;
+ pd.ostr = ostr;
+ pd.num = 0;
+ pd.level = level + 1;
+ mu_stream_printf (ostr, "mu_message_multipart:\n");
+ mu_list_foreach (bs->v.multipart.body_parts, print_item, &pd);
+ }
+ }
+}
+
static int
fetch_response_printer (void *item, void *data)
{
@@ -252,31 +388,35 @@ fetch_response_printer (void *item, void *data)
case MU_IMAP_FETCH_BODYSTRUCTURE:
/* FIXME */
- mu_stream_printf (str, "BODYSTRUCTURE (not yet implemented)\n");
+ mu_stream_printf (str, "BODYSTRUCTURE:\nBEGIN\n");
+ print_bs (str, resp->bodystructure.bs, 0);
+ mu_stream_printf (str, "END\n");
break;
case MU_IMAP_FETCH_ENVELOPE:
{
+ struct mu_imapenvelope *env = resp->envelope.imapenvelope;
+
mu_stream_printf (str, "ENVELOPE:\n");
- format_date (str, "date", &resp->envelope.date, &resp->envelope.tz);
+ format_date (str, "date", &env->date, &env->tz);
mu_stream_printf (str, " subject = %s\n",
- resp->envelope.subject ?
- resp->envelope.subject : "NIL");
+ env->subject ?
+ env->subject : "NIL");
- format_email (str, "from", resp->envelope.from);
- format_email (str, "sender", resp->envelope.sender);
- format_email (str, "reply-to", resp->envelope.reply_to);
- format_email (str, "to", resp->envelope.to);
- format_email (str, "cc", resp->envelope.cc);
- format_email (str, "bcc", resp->envelope.bcc);
+ format_email (str, "from", env->from);
+ format_email (str, "sender", env->sender);
+ format_email (str, "reply-to", env->reply_to);
+ format_email (str, "to", env->to);
+ format_email (str, "cc", env->cc);
+ format_email (str, "bcc", env->bcc);
mu_stream_printf (str, " in-reply-to = %s\n",
- resp->envelope.in_reply_to ?
- resp->envelope.in_reply_to : "NIL");
+ env->in_reply_to ?
+ env->in_reply_to : "NIL");
mu_stream_printf (str, " message-id = %s\n",
- resp->envelope.message_id ?
- resp->envelope.message_id : "NIL");
+ env->message_id ?
+ env->message_id : "NIL");
}
break;
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index 219731def..2a9f4ea89 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -50,6 +50,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
INCLUDES = @MU_LIB_COMMON_INCLUDES@
noinst_PROGRAMS = \
+ bs\
fldel\
lstuid\
mbdel\
diff --git a/testsuite/bs.c b/testsuite/bs.c
new file mode 100644
index 000000000..8f74b2d86
--- /dev/null
+++ b/testsuite/bs.c
@@ -0,0 +1,169 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ GNU Mailutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GNU Mailutils 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.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <mailutils/mailutils.h>
+
+#define S(str) ((str) ? (str) : "")
+
+static void
+print_param (const char *prefix, mu_assoc_t assoc, int indent)
+{
+ mu_iterator_t itr;
+ int i;
+
+ mu_printf ("%*s%s:\n", indent, "", prefix);
+ if (!assoc)
+ return;
+ indent += 4;
+ MU_ASSERT (mu_assoc_get_iterator (assoc, &itr));
+
+ for (i = 0, mu_iterator_first (itr);
+ !mu_iterator_is_done (itr);
+ i++, mu_iterator_next (itr))
+ {
+ const char *name;
+ struct mu_mime_param *p;
+
+ mu_iterator_current_kv (itr, (const void **)&name, (void**)&p);
+ mu_printf ("%*s%d: %s=%s\n", indent, "", i, name, p->value);
+ }
+ mu_iterator_destroy (&itr);
+}
+
+struct print_data
+{
+ int num;
+ int level;
+};
+
+static void print_bs (struct mu_bodystructure *bs, int level);
+
+static int
+print_item (void *item, void *data)
+{
+ struct mu_bodystructure *bs = item;
+ struct print_data *pd = data;
+ mu_printf ("%*sPart #%d\n", (pd->level-1) << 2, "", pd->num);
+ print_bs (bs, pd->level);
+ ++pd->num;
+ return 0;
+}
+
+static void
+print_address (const char *title, mu_address_t addr, int indent)
+{
+ mu_printf ("%*s%s: ", indent, "", title);
+ mu_stream_format_address (mu_strout, addr);
+ mu_printf ("\n");
+}
+
+static void
+print_imapenvelope (struct mu_imapenvelope *env, int level)
+{
+ int indent = (level << 2);
+
+ mu_printf ("%*sEnvelope:\n", indent, "");
+ indent += 4;
+ mu_printf ("%*sTime: ", indent, "");
+ mu_c_streamftime (mu_strout, "%c%n", &env->date, &env->tz);
+ mu_printf ("%*sSubject: %s\n", indent, "", S(env->subject));
+ print_address ("From", env->from, indent);
+ print_address ("Sender", env->sender, indent);
+ print_address ("Reply-to", env->reply_to, indent);
+ print_address ("To", env->to, indent);
+ print_address ("Cc", env->cc, indent);
+ print_address ("Bcc", env->bcc, indent);
+ mu_printf ("%*sIn-Reply-To: %s\n", indent, "", S(env->in_reply_to));
+ mu_printf ("%*sMessage-ID: %s\n", indent, "", S(env->message_id));
+}
+
+static void
+print_bs (struct mu_bodystructure *bs, int level)
+{
+ int indent = level << 2;
+ mu_printf ("%*sbody_type=%s\n", indent, "", S(bs->body_type));
+ mu_printf ("%*sbody_subtype=%s\n", indent, "", S(bs->body_subtype));
+ print_param ("Parameters", bs->body_param, indent);
+ mu_printf ("%*sbody_id=%s\n", indent, "", S(bs->body_id));
+ mu_printf ("%*sbody_descr=%s\n", indent, "", S(bs->body_descr));
+ mu_printf ("%*sbody_encoding=%s\n", indent, "", S(bs->body_encoding));
+ mu_printf ("%*sbody_size=%lu\n", indent, "", (unsigned long) bs->body_size);
+ /* Optional */
+ mu_printf ("%*sbody_md5=%s\n", indent, "", S(bs->body_md5));
+ mu_printf ("%*sbody_disposition=%s\n", indent, "", S(bs->body_disposition));
+ print_param ("Disposition Parameters", bs->body_disp_param, indent);
+ mu_printf ("%*sbody_language=%s\n", indent, "", S(bs->body_language));
+ mu_printf ("%*sbody_location=%s\n", indent, "", S(bs->body_location));
+
+ mu_printf ("%*sType ", indent, "");
+ switch (bs->body_message_type)
+ {
+ case mu_message_other:
+ mu_printf ("mu_message_other\n");
+ break;
+
+ case mu_message_text:
+ mu_printf ("mu_message_text:\n%*sbody_lines=%lu\n", indent + 4, "",
+ (unsigned long) bs->v.text.body_lines);
+ break;
+
+ case mu_message_rfc822:
+ mu_printf ("mu_message_rfc822:\n%*sbody_lines=%lu\n", indent + 4, "",
+ (unsigned long) bs->v.rfc822.body_lines);
+ print_imapenvelope (bs->v.rfc822.body_env, level + 1);
+ print_bs (bs->v.rfc822.body_struct, level + 1);
+ break;
+
+ case mu_message_multipart:
+ {
+ struct print_data pd;
+ pd.num = 0;
+ pd.level = level + 1;
+ mu_printf ("mu_message_multipart:\n");
+ mu_list_foreach (bs->v.multipart.body_parts, print_item, &pd);
+ }
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ mu_mailbox_t mbox;
+ mu_message_t mesg;
+ struct mu_bodystructure *bs;
+
+ if (argc != 3)
+ {
+ fprintf (stderr, "usage: %s URL NUM\n", argv[0]);
+ return 1;
+ }
+
+ mu_register_all_mbox_formats ();
+ MU_ASSERT (mu_mailbox_create (&mbox, argv[1]));
+ MU_ASSERT (mu_mailbox_open (mbox, MU_STREAM_READ));
+ MU_ASSERT (mu_mailbox_get_message (mbox, atoi (argv[2]), &mesg));
+ MU_ASSERT (mu_message_get_bodystructure (mesg, &bs));
+ print_bs (bs, 0);
+ mu_bodystructure_free (bs);
+
+ return 0;
+}

Return to:

Send suggestions and report system problems to the System administrator.