diff --git a/lib/mu-msg-file.c b/lib/mu-msg-file.c index 061c4284..6e6083c4 100644 --- a/lib/mu-msg-file.c +++ b/lib/mu-msg-file.c @@ -659,21 +659,35 @@ get_references (MuMsgFile *self) return g_slist_reverse (msgids); } - +/* see: http://does-not-exist.org/mail-archives/mutt-dev/msg08249.html */ static GSList* get_tags (MuMsgFile *self) { - GSList *lst; + GSList *lst1, *lst2, *last; char *hdr; + /* X-Label are space-separated */ hdr = mu_msg_file_get_header (self, "X-Label"); - if (!hdr) - return NULL; + if (hdr) { + lst1 = mu_str_to_list (hdr, ' ', TRUE); + g_free (hdr); + } - lst = mu_str_to_list (hdr, ',', TRUE); - g_free (hdr); + /* X-Keywords are ','-separated */ + hdr = mu_msg_file_get_header (self, "X-Keywords"); + if (hdr) { + lst2 = mu_str_to_list (hdr, ',', TRUE); + g_free (hdr); + } - return lst; + if (!lst1) + return lst2; + + /* append lst2, if any */ + last = g_slist_last (lst1); + last->next = lst2; + + return last; } @@ -722,18 +736,15 @@ mu_msg_file_get_str_field (MuMsgFile *self, MuMsgFieldId mfid, switch (mfid) { - case MU_MSG_FIELD_ID_EMBEDDED_TEXT: *do_free = TRUE; - return NULL; /* FIXME */ - case MU_MSG_FIELD_ID_BCC: case MU_MSG_FIELD_ID_CC: case MU_MSG_FIELD_ID_TO: *do_free = TRUE; return get_recipient (self, recipient_type(mfid)); - case MU_MSG_FIELD_ID_BODY_TEXT: *do_free = TRUE; - return get_concatenated_text (self, TRUE); /* FIXME: decrypt ? */ - case MU_MSG_FIELD_ID_BODY_HTML: *do_free = TRUE; - return get_body (self, TRUE, TRUE); /* FIXME: decrypt ? */ + /* case MU_MSG_FIELD_ID_BODY_TEXT: *do_free = TRUE; */ + /* return get_concatenated_text (self, TRUE); /\* FIXME: decrypt ? *\/ */ + /* case MU_MSG_FIELD_ID_BODY_HTML: *do_free = TRUE; */ + /* return get_body (self, TRUE, TRUE); /\* FIXME: decrypt ? *\/ */ case MU_MSG_FIELD_ID_FROM: return (char*)maybe_cleanup @@ -752,6 +763,14 @@ mu_msg_file_get_str_field (MuMsgFile *self, MuMsgFieldId mfid, case MU_MSG_FIELD_ID_MAILDIR: return self->_maildir; + case MU_MSG_FIELD_ID_BODY_TEXT: + case MU_MSG_FIELD_ID_BODY_HTML: + case MU_MSG_FIELD_ID_EMBEDDED_TEXT: + g_warning ("not available here: %s", + mu_msg_field_name (mfid)); + g_return_val_if_reached (NULL); + return NULL; + default: g_return_val_if_reached (NULL); } } diff --git a/lib/mu-msg-part.c b/lib/mu-msg-part.c index 47426cf6..a93b21ca 100644 --- a/lib/mu-msg-part.c +++ b/lib/mu-msg-part.c @@ -34,8 +34,9 @@ #include "mu-msg-crypto.h" #endif /*BUILD_CRYPTO*/ -static gboolean handle_children (MuMsg *msg, GMimeObject *mobj, MuMsgOptions opts, - unsigned index, MuMsgPartForeachFunc func, +static gboolean handle_children (MuMsg *msg, GMimeObject *mobj, + MuMsgOptions opts, unsigned index, + MuMsgPartForeachFunc func, gpointer user_data); struct _DoData { @@ -386,26 +387,6 @@ handle_encrypted_part (MuMsg *msg, return TRUE; } -/* check if the current part might be a body part, and, if so, update - * the msgpart struct */ -static void -check_if_body_part (MuMsg *msg, GMimeObject *mobj, MuMsgPart *msgpart) -{ - /* is it an attachment? if so, this one is not the body */ - if (msgpart->part_type & MU_MSG_PART_TYPE_ATTACHMENT) - return; - - /* is it a text part? */ - if (g_ascii_strcasecmp (msgpart->type, "text") != 0) - return; - - /* we consider it a body part if it's an inline text/plain or - * text/html */ - if ((g_ascii_strcasecmp (msgpart->subtype, "plain") == 0) || - (g_ascii_strcasecmp (msgpart->subtype, "html") == 0)) - msgpart->part_type |= MU_MSG_PART_TYPE_BODY; -} - /* call 'func' with information about this MIME-part */ static gboolean @@ -418,17 +399,21 @@ handle_part (MuMsg *msg, GMimePart *part, GMimeObject *parent, memset (&msgpart, 0, sizeof(MuMsgPart)); - ct = g_mime_object_get_content_type ((GMimeObject*)part); - if (GMIME_IS_CONTENT_TYPE(ct)) { - msgpart.type = g_mime_content_type_get_media_type (ct); - msgpart.subtype = g_mime_content_type_get_media_subtype (ct); - } - msgpart.size = get_part_size (part); msgpart.part_type = MU_MSG_PART_TYPE_LEAF; msgpart.part_type |= get_disposition ((GMimeObject*)part); - check_if_body_part (msg, (GMimeObject*)part, &msgpart); + ct = g_mime_object_get_content_type ((GMimeObject*)part); + if (GMIME_IS_CONTENT_TYPE(ct)) { + msgpart.type = g_mime_content_type_get_media_type (ct); + msgpart.subtype = g_mime_content_type_get_media_subtype (ct); + /* store as in the part_type as well, for quick + * checking */ + if (g_mime_content_type_is_type (ct, "text", "plain")) + msgpart.part_type |= MU_MSG_PART_TYPE_TEXT_PLAIN; + else if (g_mime_content_type_is_type (ct, "text", "html")) + msgpart.part_type |= MU_MSG_PART_TYPE_TEXT_HTML; + } msgpart.data = (gpointer)part; msgpart.index = index; @@ -703,8 +688,8 @@ mu_msg_part_get_cache_path (MuMsg *msg, MuMsgOptions opts, guint partid, partid); if (!mu_util_create_dir_maybe (dirname, 0700, FALSE)) { - mu_util_g_set_error (err, MU_ERROR_FILE, "failed to create dir %s", - dirname); + mu_util_g_set_error (err, MU_ERROR_FILE, + "failed to create dir %s", dirname); g_free (dirname); return NULL; } @@ -840,8 +825,6 @@ mu_msg_part_looks_like_attachment (MuMsgPart *part, gboolean include_inline) { g_return_val_if_fail (part, FALSE); - if (part->part_type & MU_MSG_PART_TYPE_BODY) - return FALSE; if (!include_inline && (part->part_type & MU_MSG_PART_TYPE_INLINE)) return FALSE; diff --git a/lib/mu-msg-part.h b/lib/mu-msg-part.h index 630b6f0c..25532174 100644 --- a/lib/mu-msg-part.h +++ b/lib/mu-msg-part.h @@ -30,8 +30,6 @@ G_BEGIN_DECLS enum _MuMsgPartType { MU_MSG_PART_TYPE_NONE = 0, - /* look like the message body (heuristic) ? */ - MU_MSG_PART_TYPE_BODY = 1 << 0, /* MIME part without children */ MU_MSG_PART_TYPE_LEAF = 1 << 1, /* an RFC822 message part? */ @@ -45,7 +43,11 @@ enum _MuMsgPartType { /* an encrypted part? */ MU_MSG_PART_TYPE_ENCRYPTED = 1 << 6, /* a decrypted part? */ - MU_MSG_PART_TYPE_DECRYPTED = 1 << 7 + MU_MSG_PART_TYPE_DECRYPTED = 1 << 7, + /* a text/plain part? */ + MU_MSG_PART_TYPE_TEXT_PLAIN = 1 << 8, + /* a text/html part? */ + MU_MSG_PART_TYPE_TEXT_HTML = 1 << 9 }; typedef enum _MuMsgPartType MuMsgPartType; diff --git a/lib/mu-msg-sexp.c b/lib/mu-msg-sexp.c index 73fa4b74..4894fbd8 100644 --- a/lib/mu-msg-sexp.c +++ b/lib/mu-msg-sexp.c @@ -279,7 +279,6 @@ get_part_type_string (MuMsgPartType ptype) GString *gstr; unsigned u; MuMsgPartType ptypes[] = { - MU_MSG_PART_TYPE_BODY, MU_MSG_PART_TYPE_LEAF, MU_MSG_PART_TYPE_MESSAGE, MU_MSG_PART_TYPE_INLINE, @@ -294,7 +293,6 @@ get_part_type_string (MuMsgPartType ptype) const char* name; switch (ptype & ptypes[u]) { case MU_MSG_PART_TYPE_NONE : continue; - case MU_MSG_PART_TYPE_BODY :name = "body"; break; case MU_MSG_PART_TYPE_LEAF :name = "leaf"; break; case MU_MSG_PART_TYPE_MESSAGE :name = "message"; break; case MU_MSG_PART_TYPE_INLINE :name = "inline"; break; @@ -400,9 +398,9 @@ append_message_file_parts (GString *gstr, MuMsg *msg, MuMsgOptions opts) append_sexp_attr (gstr, "in-reply-to", mu_msg_get_header (msg, "In-Reply-To")); append_sexp_attr (gstr, "body-txt", - mu_msg_get_body_text(msg)); + mu_msg_get_body_text(msg, opts)); append_sexp_attr (gstr, "body-html", - mu_msg_get_body_html(msg)); + mu_msg_get_body_html(msg, opts)); } diff --git a/lib/mu-msg.c b/lib/mu-msg.c index 4e59a600..0b05f998 100644 --- a/lib/mu-msg.c +++ b/lib/mu-msg.c @@ -335,23 +335,19 @@ mu_msg_get_header (MuMsg *self, const char *header) time_t mu_msg_get_timestamp (MuMsg *self) { + const char *path; + struct stat statbuf; + g_return_val_if_fail (self, 0); if (self->_file) return self->_file->_timestamp; - else { - const char *path; - struct stat statbuf; - path = mu_msg_get_path (self); - if (!path) - return 0; + path = mu_msg_get_path (self); + if (!path || stat (path, &statbuf) < 0) + return 0; - if (stat (path, &statbuf) < 0) - return 0; - - return statbuf.st_mtime; - } + return statbuf.st_mtime; } @@ -424,7 +420,6 @@ mu_msg_get_date (MuMsg *self) } - MuFlags mu_msg_get_flags (MuMsg *self) { @@ -448,19 +443,70 @@ mu_msg_get_prio (MuMsg *self) } -const char* -mu_msg_get_body_html (MuMsg *self) + +struct _BodyData { + GString *gstr; + gboolean want_html; +}; +typedef struct _BodyData BodyData; + + +static void +accumulate_body (MuMsg *msg, MuMsgPart *mpart, BodyData *bdata) { - g_return_val_if_fail (self, NULL); - return get_str_field (self, MU_MSG_FIELD_ID_BODY_HTML); + char *txt; + gboolean err; + + /* if it looks like an attachment, skip it */ + if (mpart->part_type & MU_MSG_PART_TYPE_ATTACHMENT) + return; + + txt = NULL; + + if (!bdata->want_html && + (mpart->part_type & MU_MSG_PART_TYPE_TEXT_PLAIN)) + txt = mu_msg_mime_part_to_string ( + (GMimePart*)mpart->data, &err); + else if (bdata->want_html && + (mpart->part_type & MU_MSG_PART_TYPE_TEXT_HTML)) + txt = mu_msg_mime_part_to_string ( + (GMimePart*)mpart->data, &err); + if (!err && txt) + bdata->gstr = g_string_append (bdata->gstr, txt); + + g_free (txt); } +static char* +get_body (MuMsg *self, MuMsgOptions opts, gboolean want_html) +{ + BodyData bdata; + + bdata.want_html = want_html; + bdata.gstr = g_string_sized_new (4096); + + mu_msg_part_foreach (self, opts, + (MuMsgPartForeachFunc)accumulate_body, + &bdata); + + return g_string_free (bdata.gstr, FALSE); +} + const char* -mu_msg_get_body_text (MuMsg *self) +mu_msg_get_body_html (MuMsg *self, MuMsgOptions opts) { g_return_val_if_fail (self, NULL); - return get_str_field (self, MU_MSG_FIELD_ID_BODY_TEXT); + return free_later_str (self, get_body (self, opts, TRUE)); +} + + + +const char* +mu_msg_get_body_text (MuMsg *self, MuMsgOptions opts) +{ + g_return_val_if_fail (self, NULL); + return free_later_str (self, get_body (self, opts, FALSE)); } @@ -750,8 +796,7 @@ mu_msg_is_readable (MuMsg *self) { g_return_val_if_fail (self, FALSE); - return (access (get_str_field (self, MU_MSG_FIELD_ID_PATH), R_OK) - == 0) ? TRUE : FALSE; + return access (mu_msg_get_path (self), R_OK) == 0 ? TRUE : FALSE; } @@ -771,16 +816,19 @@ get_target_mdir (MuMsg *msg, const char *target_maildir, GError **err) /* maildir is the maildir stored in the message, e.g. '/foo' */ maildir = mu_msg_get_maildir(msg); if (!maildir) { - g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_GMIME, - "message without maildir"); + mu_util_g_set_error (err, MU_ERROR_GMIME, + "message without maildir"); return NULL; } /* the 'rootmaildir' is the filesystem path from root to * maildir, ie. /home/user/Maildir/foo */ rootmaildir = mu_maildir_get_maildir_from_path (mu_msg_get_path(msg)); - if (!rootmaildir) + if (!rootmaildir) { + mu_util_g_set_error (err, MU_ERROR_GMIME, + "cannot determinex maildir"); return NULL; + } /* we do a sanity check: verify that that maildir is a suffix of * rootmaildir;*/ @@ -825,6 +873,8 @@ mu_msg_move_to_maildir (MuMsg *self, const char *maildir, g_return_val_if_fail (self, FALSE); g_return_val_if_fail (maildir, FALSE); /* i.e. "/inbox" */ + /* targetmdir is the full path to maildir, i.e., + * /home/foo/Maildir/inbox */ targetmdir = get_target_mdir (self, maildir, err); if (!targetmdir) return FALSE; @@ -832,18 +882,22 @@ mu_msg_move_to_maildir (MuMsg *self, const char *maildir, newfullpath = mu_maildir_move_message (mu_msg_get_path (self), targetmdir, flags, ignore_dups, err); - g_free (targetmdir); - /* update the message path and the flags; they may have * changed */ - if (!newfullpath) + if (!newfullpath) { + g_free (targetmdir); return FALSE; + } /* clear the old backends */ mu_msg_doc_destroy (self->_doc); + self->_doc = NULL; + mu_msg_file_destroy (self->_file); /* and create a new one */ - self->_file = mu_msg_file_new (newfullpath, targetmdir, err); + self->_file = mu_msg_file_new (newfullpath, maildir, err); + g_free (targetmdir); + return self->_file ? TRUE : FALSE; } diff --git a/lib/mu-msg.h b/lib/mu-msg.h index 23298399..14b1478e 100644 --- a/lib/mu-msg.h +++ b/lib/mu-msg.h @@ -157,23 +157,25 @@ void mu_msg_cache_values (MuMsg *self); * get the plain text body of this message * * @param msg a valid MuMsg* instance + * @param opts options for getting the body * * @return the plain text body or NULL in case of error or if there is no * such body. the returned string should *not* be modified or freed. * The returned data is in UTF8 or NULL. */ -const char* mu_msg_get_body_text (MuMsg *msg); +const char* mu_msg_get_body_text (MuMsg *msg, MuMsgOptions opts); /** * get the html body of this message * * @param msg a valid MuMsg* instance + * @param opts options for getting the body * * @return the html body or NULL in case of error or if there is no * such body. the returned string should *not* be modified or freed. */ -const char* mu_msg_get_body_html (MuMsg *msg); +const char* mu_msg_get_body_html (MuMsg *msgMu, MuMsgOptions opts); /** * get the sender (From:) of this message