summaryrefslogtreecommitdiff
path: root/libproto/imap/fetch.c
diff options
context:
space:
mode:
Diffstat (limited to 'libproto/imap/fetch.c')
-rw-r--r--libproto/imap/fetch.c498
1 files changed, 465 insertions, 33 deletions
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 },

Return to:

Send suggestions and report system problems to the System administrator.