diff --git a/lib/mu-msg-part.c b/lib/mu-msg-part.c index c2a90645..00fe16ff 100644 --- a/lib/mu-msg-part.c +++ b/lib/mu-msg-part.c @@ -88,49 +88,94 @@ struct _PartData { MuMsgPartForeachFunc _func; gpointer _user_data; GMimePart *_body_part; - MuMsgOptions _opts; + MuMsgOptions _opts; }; typedef struct _PartData PartData; + +static gchar *mime_message_to_string (GMimeMessage *mimemsg); + +static void +each_mime_part_get_text (GMimeObject *parent, GMimeObject *part, + GString **gstr) +{ + char *txt; + txt = NULL; + + if (GMIME_IS_MESSAGE(part)) { + txt = mime_message_to_string (GMIME_MESSAGE(part)); + if (txt) + *gstr = g_string_append (*gstr, txt); + } + + if (GMIME_IS_PART (part)) { + GMimeContentType *ctype; + gboolean err; + ctype = g_mime_object_get_content_type (part); + if (!g_mime_content_type_is_type (ctype, "text", "plain")) + return; /* not plain text */ + txt = mu_msg_mime_part_to_string + ((GMimePart*)part, &err); + } + + if (txt) { + *gstr = g_string_append_c (*gstr, '\n'); + *gstr = g_string_append (*gstr, txt); + g_free (txt); + } +} + +static gchar * +mime_message_to_string (GMimeMessage *mimemsg) +{ + GString *data; + InternetAddressList *addresses; + gchar *adrs; + + data = g_string_sized_new (2048); /* just a guess */ + + g_string_append (data, g_mime_message_get_sender(mimemsg)); + g_string_append_c (data, '\n'); + g_string_append (data, g_mime_message_get_subject(mimemsg)); + g_string_append_c (data, '\n'); + + addresses = g_mime_message_get_all_recipients (mimemsg); + adrs = internet_address_list_to_string (addresses, FALSE); + g_object_unref(G_OBJECT(addresses)); + + g_string_append (data, adrs); + g_free (adrs); + + /* recurse through all text parts */ + g_mime_message_foreach + (mimemsg, + (GMimeObjectForeachFunc)each_mime_part_get_text, + &data); + + return g_string_free (data, FALSE); +} + char* mu_msg_part_get_text (MuMsgPart *self, gboolean *err) { GMimeObject *mobj; g_return_val_if_fail (self && self->data, NULL); - mobj = (GMimeObject*)self->data; - if (GMIME_IS_PART(mobj)) + if (GMIME_IS_PART(mobj)) { + /* ignore all but plain text */ + if ((strcasecmp (self->type, "text") == 0) && + (strcasecmp (self->subtype, "plain") == 0)) + return NULL; return mu_msg_mime_part_to_string ((GMimePart*)mobj, err); - else if (GMIME_IS_MESSAGE(mobj)) { - /* when it's an (embedded) message, the text is just - * of the message metadata, so we can index it. - */ - GString *data; - GMimeMessage *msg; - InternetAddressList *addresses; - gchar *adrs; + } - msg = (GMimeMessage*)mobj; - data = g_string_sized_new (512); /* just a guess */ - - g_string_append (data, g_mime_message_get_sender(msg)); - g_string_append_c (data, '\n'); - g_string_append (data, g_mime_message_get_subject(msg)); - g_string_append_c (data, '\n'); - - addresses = g_mime_message_get_all_recipients (msg); - adrs = internet_address_list_to_string (addresses, FALSE); - g_object_unref(G_OBJECT(addresses)); - - g_string_append (data, adrs); - g_free (adrs); - - return g_string_free (data, FALSE); - } else + if (GMIME_IS_MESSAGE(mobj)) + return mime_message_to_string ((GMimeMessage*)mobj); + g_return_val_if_reached (NULL); return NULL; } @@ -157,91 +202,6 @@ get_part_size (GMimePart *part) } - -static gboolean -init_msg_part_from_mime_part (GMimePart *part, MuMsgPart *pi) -{ - const gchar *fname, *descr; - GMimeContentType *ct; - - ct = g_mime_object_get_content_type ((GMimeObject*)part); - if (GMIME_IS_CONTENT_TYPE(ct)) { - pi->type = (char*)g_mime_content_type_get_media_type (ct); - pi->subtype = (char*)g_mime_content_type_get_media_subtype (ct); - } - - pi->disposition = (char*)g_mime_object_get_disposition - ((GMimeObject*)part); - - fname = g_mime_part_get_filename (part); - pi->file_name = fname ? mu_str_utf8ify (fname) : NULL; - - descr = g_mime_part_get_content_description (part); - pi->description = descr ? mu_str_utf8ify (descr) : NULL; - - pi->size = get_part_size (part); - pi->is_leaf = TRUE; - pi->is_msg = FALSE; - - return TRUE; -} - -static gchar* -get_filename_for_mime_message_part (GMimeMessage *mmsg) -{ - gchar *name, *cur; - - name = (char*)g_mime_message_get_subject (mmsg); - if (!name) - name = "message"; - - name = g_strconcat (name, ".eml", NULL); - - /* remove slashes... */ - for (cur = name ; *cur; ++cur) { - if (*cur == '/' || *cur == ' ' || *cur == ':') - *cur = '-'; - } - - return name; -} - - -static gboolean -init_msg_part_from_mime_message_part (GMimeMessage *mmsg, MuMsgPart *pi) -{ - pi->disposition = GMIME_DISPOSITION_ATTACHMENT; - - /* pseudo-file name... */ - pi->file_name = get_filename_for_mime_message_part (mmsg); - pi->description = g_strdup ("message"); - - pi->type = "message"; - pi->subtype = "rfc822"; - - pi->size = 0; - pi->is_leaf = TRUE; - pi->is_msg = TRUE; - - return TRUE; -} - - - -static void -msg_part_free (MuMsgPart *pi) -{ - if (!pi) - return; - - g_free (pi->file_name); - g_free (pi->description); - -#ifdef BUILD_CRYPTO - mu_msg_part_free_sig_infos (pi->sig_infos); -#endif /*BUILD_CRYPTO*/ -} - #ifdef BUILD_CRYPTO static void check_signature_maybe (GMimeObject *parent, GMimeObject *mobj, MuMsgPart *pi, @@ -274,9 +234,104 @@ check_signature_maybe (GMimeObject *parent, GMimeObject *mobj, MuMsgPart *pi, g_clear_error (&err); } } - #endif /*BUILD_CRYPTO*/ +static gboolean +init_msg_part_from_mime_part (MuMsgOptions opts, GMimeObject *parent, + GMimePart *part, MuMsgPart *pi) +{ + const gchar *fname, *descr; + GMimeContentType *ct; + + ct = g_mime_object_get_content_type ((GMimeObject*)part); + if (GMIME_IS_CONTENT_TYPE(ct)) { + pi->type = (char*)g_mime_content_type_get_media_type (ct); + pi->subtype = (char*)g_mime_content_type_get_media_subtype (ct); + } + + pi->disposition = (char*)g_mime_object_get_disposition + ((GMimeObject*)part); + + fname = g_mime_part_get_filename (part); + pi->file_name = fname ? mu_str_utf8ify (fname) : NULL; + + descr = g_mime_part_get_content_description (part); + pi->description = descr ? mu_str_utf8ify (descr) : NULL; + pi->size = get_part_size (part); + pi->part_type = MU_MSG_PART_TYPE_LEAF; + + if (!pi->disposition || + g_ascii_strcasecmp (pi->disposition, + GMIME_DISPOSITION_INLINE) == 0) + pi->part_type |= MU_MSG_PART_TYPE_INLINE; + + if (GMIME_IS_MULTIPART_SIGNED (parent)) + pi->part_type |= MU_MSG_PART_TYPE_SIGNED; + if (GMIME_IS_MULTIPART_ENCRYPTED (parent)) + pi->part_type |= MU_MSG_PART_TYPE_ENCRYPTED; + + /* if we have crypto support, check the signature if there is one */ +#ifdef BUILD_CRYPTO + if (opts & MU_MSG_OPTION_CHECK_SIGNATURES) + check_signature_maybe (parent, (GMimeObject*)part, + pi, opts); +#endif /*BUILD_CRYPTO*/ + + return TRUE; +} + +static gchar* +get_filename_for_mime_message_part (GMimeMessage *mmsg) +{ + gchar *name, *cur; + + name = (char*)g_mime_message_get_subject (mmsg); + if (!name) + name = "message"; + + name = g_strconcat (name, ".eml", NULL); + + /* remove slashes... */ + for (cur = name ; *cur; ++cur) { + if (*cur == '/' || *cur == ' ' || *cur == ':') + *cur = '-'; + } + + return name; +} + + +static gboolean +init_msg_part_from_mime_message_part (GMimeMessage *mmsg, MuMsgPart *pi) +{ + pi->disposition = GMIME_DISPOSITION_ATTACHMENT; + + /* pseudo-file name... */ + pi->file_name = get_filename_for_mime_message_part (mmsg); + pi->description = g_strdup ("message"); + pi->type = "message"; + pi->subtype = "rfc822"; + pi->size = 0; + pi->part_type = MU_MSG_PART_TYPE_MESSAGE; + + return TRUE; +} + + + +static void +msg_part_free (MuMsgPart *pi) +{ + if (!pi) + return; + + g_free (pi->file_name); + g_free (pi->description); + +#ifdef BUILD_CRYPTO + mu_msg_part_free_sig_infos (pi->sig_infos); +#endif /*BUILD_CRYPTO*/ +} static void @@ -292,34 +347,25 @@ part_foreach_cb (GMimeObject *parent, GMimeObject *mobj, PartData *pdata) memset (&pi, 0, sizeof(pi)); pi.index = pdata->_idx++; pi.content_id = (char*)g_mime_object_get_content_id (mobj); - pi.data = (gpointer)mobj; /* check if this is the body part */ - pi.is_body = ((void*)pdata->_body_part == (void*)mobj); + if ((void*)pdata->_body_part == (void*)mobj) + pi.part_type |= MU_MSG_PART_TYPE_BODY; - if (GMIME_IS_PART(mobj)) - rv = init_msg_part_from_mime_part ((GMimePart*)mobj, &pi); - else if (GMIME_IS_MESSAGE_PART(mobj)) { + if (GMIME_IS_PART(mobj)) { + pi.data = (gpointer)mobj; + rv = init_msg_part_from_mime_part + (pdata->_opts, parent, (GMimePart*)mobj, &pi); + } else if (GMIME_IS_MESSAGE_PART(mobj)) { GMimeMessage *mmsg; mmsg = g_mime_message_part_get_message ((GMimeMessagePart*)mobj); if (!mmsg) return; + /* use the message, not the message part */ + pi.data = (gpointer)mmsg; rv = init_msg_part_from_mime_message_part (mmsg, &pi); - if (rv && (pdata->_opts && MU_MSG_OPTION_RECURSE_RFC822)) - /* NOTE: this screws up the counting - * (pdata->_idx); happily, we only use it - * where we don't care about that */ - g_mime_message_foreach /* recurse */ - (mmsg, (GMimeObjectForeachFunc)part_foreach_cb, - pdata); } else rv = FALSE; /* ignore */ - /* if we have crypto support, check the signature if there is one */ -#ifdef BUILD_CRYPTO - if (pdata->_opts & MU_MSG_OPTION_CHECK_SIGNATURES) - check_signature_maybe (parent, mobj, &pi, pdata->_opts); -#endif /*BUILD_CRYPTO*/ - if (rv) pdata->_func(pdata->_msg, &pi, pdata->_user_data); @@ -710,17 +756,15 @@ mu_msg_part_find_files (MuMsg *msg, const GRegex *pattern) gboolean -mu_msg_part_looks_like_attachment (MuMsgPart *part, gboolean include_inline) +mu_msg_part_looks_like_attachment (MuMsgPart *part, + gboolean include_inline) { g_return_val_if_fail (part, FALSE); - if (part->is_body||!part->disposition||!part->type) + if (part->part_type & MU_MSG_PART_TYPE_BODY) + return FALSE; + if (!include_inline && (part->part_type & MU_MSG_PART_TYPE_INLINE)) return FALSE; - if (include_inline || - g_ascii_strcasecmp (part->disposition, - GMIME_DISPOSITION_ATTACHMENT) == 0) - return TRUE; - - return FALSE; + return TRUE; } diff --git a/lib/mu-msg-part.h b/lib/mu-msg-part.h index 9a912708..66f289c9 100644 --- a/lib/mu-msg-part.h +++ b/lib/mu-msg-part.h @@ -27,6 +27,25 @@ 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? */ + MU_MSG_PART_TYPE_MESSAGE = 1 << 2, + /* disposition inline? */ + MU_MSG_PART_TYPE_INLINE = 1 << 3, + /* a signed part? */ + MU_MSG_PART_TYPE_SIGNED = 1 << 5, + /* an encrypted part? */ + MU_MSG_PART_TYPE_ENCRYPTED = 1 << 6 +}; +typedef enum _MuMsgPartType MuMsgPartType; + + struct _MuMsgPart { /* index of this message part */ @@ -55,11 +74,7 @@ struct _MuMsgPart { gpointer data; /* opaque data */ - gboolean is_body; /* TRUE if this is probably the - * message body*/ - gboolean is_leaf; /* if the body is a leaf part (MIME - * Part), not eg. a multipart/ */ - gboolean is_msg; /* part is a message/rfc822 */ + MuMsgPartType part_type; /* crypto stuff */ GSList *sig_infos; /* list of MuMsgPartSig */ @@ -122,6 +137,7 @@ char* mu_msg_part_get_text (MuMsgPart *part, gboolean *err); gboolean mu_msg_part_looks_like_attachment (MuMsgPart *part, gboolean include_inline); + /** * save a specific attachment to some targetdir * diff --git a/lib/mu-msg.h b/lib/mu-msg.h index 66c22ead..f3d34cfd 100644 --- a/lib/mu-msg.h +++ b/lib/mu-msg.h @@ -35,19 +35,21 @@ typedef struct _MuMsg MuMsg; /* options for various functions */ enum _MuMsgOptions { MU_MSG_OPTION_NONE = 0, - MU_MSG_OPTION_RECURSE_RFC822 = 1 << 0, /* recurse into submessages */ +/* 1 << 0 is still free! */ /* for -> sexp conversion */ MU_MSG_OPTION_HEADERS_ONLY = 1 << 1, MU_MSG_OPTION_EXTRACT_IMAGES = 1 << 2, +/* 1 << 3 is still free! */ + /* below options are for checking signatures; only effective * if mu was built with crypto support */ - MU_MSG_OPTION_CHECK_SIGNATURES = 1 << 3, - MU_MSG_OPTION_AUTO_RETRIEVE_KEY = 1 << 4, - MU_MSG_OPTION_USE_AGENT = 1 << 5, - MU_MSG_OPTION_USE_PKCS7 = 1 << 6 /* gpg is the default */ + MU_MSG_OPTION_CHECK_SIGNATURES = 1 << 4, + MU_MSG_OPTION_AUTO_RETRIEVE_KEY = 1 << 5, + MU_MSG_OPTION_USE_AGENT = 1 << 6, + MU_MSG_OPTION_USE_PKCS7 = 1 << 7 /* gpg is the default */ }; typedef enum _MuMsgOptions MuMsgOptions;