diff --git a/lib/mu-msg-file.c b/lib/mu-msg-file.c index 46e81162..5ce23492 100644 --- a/lib/mu-msg-file.c +++ b/lib/mu-msg-file.c @@ -518,9 +518,12 @@ gchar* mu_msg_mime_part_to_string (GMimePart *part, gboolean *err) { GMimeDataWrapper *wrapper; - GMimeStream *stream = NULL; + GMimeStream *stream; ssize_t buflen; - char *buffer = NULL; + char *buffer; + + buffer = NULL; + stream = NULL; *err = TRUE; /* guilty until proven innocent */ g_return_val_if_fail (GMIME_IS_PART(part), NULL); @@ -548,13 +551,10 @@ mu_msg_mime_part_to_string (GMimePart *part, gboolean *err) /* convert_to_utf8 will free the old 'buffer' if needed */ buffer = convert_to_utf8 (part, buffer); - *err = FALSE; cleanup: - if (stream) - g_object_unref (G_OBJECT(stream)); - + g_clear_object (&stream); return buffer; } @@ -583,33 +583,30 @@ mu_msg_mime_get_body_part (GMimeMessage *msg, gboolean decrypt, static char* -get_body (MuMsgFile *self, gboolean want_html) +get_body (MuMsgFile *self, gboolean decrypt, gboolean want_html) { GMimePart *part; + gboolean err; + gchar *str; g_return_val_if_fail (self, NULL); g_return_val_if_fail (GMIME_IS_MESSAGE(self->_mime_msg), NULL); part = mu_msg_mime_get_body_part (self->_mime_msg, - self->_auto_decrypt, - want_html); - if (GMIME_IS_PART(part)) { - gboolean err; - gchar *str; + decrypt, want_html); + if (!GMIME_IS_PART(part)) + return NULL; - err = FALSE; - str = mu_msg_mime_part_to_string (part, &err); + err = FALSE; + str = mu_msg_mime_part_to_string (part, &err); - /* note, str may be NULL (no body), but that's not necessarily - * an error; we only warn when an actual error occured */ - if (err) - g_warning ("error occured while retrieving %s body " - "for message %s", - want_html ? "html" : "text", self->_path); - return str; - } - - return NULL; + /* note, str may be NULL (no body), but that's not necessarily + * an error; we only warn when an actual error occured */ + if (err) + g_warning ("error occured while retrieving %s body " + "for message %s", + want_html ? "html" : "text", self->_path); + return str; } @@ -657,7 +654,7 @@ append_text (GMimeObject *parent, GMimeObject *part, gchar **txt) * all text/plain parts with inline disposition */ static char* -get_concatenated_text (MuMsgFile *self) +get_concatenated_text (MuMsgFile *self, gboolean decrypt) { char *txt; @@ -665,9 +662,9 @@ get_concatenated_text (MuMsgFile *self) g_return_val_if_fail (GMIME_IS_MESSAGE(self->_mime_msg), NULL); txt = NULL; - mu_mime_message_foreach (self->_mime_msg, self->_auto_decrypt, + mu_mime_message_foreach (self->_mime_msg, decrypt, (GMimeObjectForeachFunc)append_text, - &txt); + &txt); return txt; } @@ -766,8 +763,7 @@ recipient_type (MuMsgFieldId mfid) char* -mu_msg_file_get_str_field (MuMsgFile *self, MuMsgFieldId mfid, - gboolean *do_free) +mu_msg_file_get_str_field (MuMsgFile *self, MuMsgFieldId mfid, gboolean *do_free) { g_return_val_if_fail (self, NULL); g_return_val_if_fail (mu_msg_field_is_string(mfid), NULL); @@ -785,9 +781,9 @@ mu_msg_file_get_str_field (MuMsgFile *self, MuMsgFieldId mfid, return get_recipient (self, recipient_type(mfid)); case MU_MSG_FIELD_ID_BODY_TEXT: *do_free = TRUE; - return get_concatenated_text (self); + return get_concatenated_text (self, TRUE); /* FIXME: decrypt ? */ case MU_MSG_FIELD_ID_BODY_HTML: *do_free = TRUE; - return get_body (self, TRUE); + return get_body (self, TRUE, TRUE); /* FIXME: decrypt ? */ case MU_MSG_FIELD_ID_FROM: return (char*)maybe_cleanup @@ -889,27 +885,19 @@ typedef struct _ForeachData ForeachData; static void foreach_cb (GMimeObject *parent, GMimeObject *part, ForeachData *fdata) { + /* invoke the callback function */ fdata->user_func (parent, part, fdata->user_data); #ifdef BUILD_CRYPTO /* maybe iterate over decrypted parts */ if (fdata->decrypt && GMIME_IS_MULTIPART_ENCRYPTED (part)) { - - GError *err; GMimeObject *dec; - - err = NULL; dec = mu_msg_crypto_decrypt_part (GMIME_MULTIPART_ENCRYPTED(part), - MU_MSG_OPTION_NONE, &err); - if (!dec||err) { - g_printerr ("crypto error: %s\n", - err ? err->message : "something went wrong"); - g_clear_error(&err); - g_clear_object(&dec); + MU_MSG_OPTION_NONE, NULL, NULL, NULL); + if (!dec) return; - } if (GMIME_IS_MULTIPART (dec)) g_mime_multipart_foreach ( @@ -936,7 +924,6 @@ mu_mime_message_foreach (GMimeMessage *msg, gboolean decrypt, fdata.user_func = func; fdata.user_data = user_data; - fdata.decrypt = decrypt; g_mime_message_foreach (msg, diff --git a/lib/mu-msg-file.h b/lib/mu-msg-file.h index 0a800ce5..512ed530 100644 --- a/lib/mu-msg-file.h +++ b/lib/mu-msg-file.h @@ -27,11 +27,11 @@ typedef struct _MuMsgFile MuMsgFile; /** * create a new message from a file - * + * * @param path full path to the message * @param mdir * @param err error to receive (when function returns NULL), or NULL - * + * * @return a new MuMsg, or NULL in case of error */ MuMsgFile *mu_msg_file_new (const char *path, @@ -49,10 +49,10 @@ void mu_msg_file_destroy (MuMsgFile *self); /** * get a specific header - * + * * @param self a MuMsgFile instance * @param header a header (e.g. 'X-Mailer' or 'List-Id') - * + * * @return the value of the header or NULL if not found. Note, only * valid as long as this MuMsgFile is valid -- before * mu_msg_file_destroy @@ -62,7 +62,7 @@ const char* mu_msg_file_get_header (MuMsgFile *self, const char *header); /** * get a string value for this message - * + * * @param self a valid MuMsgFile * @param msfid the message field id to get (must be of type string) * @param do_free receives TRUE or FALSE, conveying if this string @@ -70,7 +70,7 @@ const char* mu_msg_file_get_header (MuMsgFile *self, const char *header); * this function should be treated as if it were returning a const * char*, and note that in that case the string is only valid as long * as the MuMsgFile is alive, ie. before mu_msg_file_destroy - * + * * @return a string, or NULL */ char* mu_msg_file_get_str_field (MuMsgFile *self, @@ -81,7 +81,7 @@ char* mu_msg_file_get_str_field (MuMsgFile *self, /** * get a string-list value for this message - * + * * @param self a valid MuMsgFile * @param msfid the message field id to get (must be of type string-list) * @param do_free receives TRUE or FALSE, conveying if this string @@ -89,7 +89,7 @@ char* mu_msg_file_get_str_field (MuMsgFile *self, * this function should be treated as if it were returning a const * GSList*, and note that in that case the string is only valid as long * as the MuMsgFile is alive, ie. before mu_msg_file_destroy - * + * * @return a GSList*, or NULL */ GSList* mu_msg_file_get_str_list_field (MuMsgFile *self, @@ -102,10 +102,10 @@ GSList* mu_msg_file_get_str_list_field (MuMsgFile *self, /** * get a numeric value for this message -- the return value should be * cast into the actual type, e.g., time_t, MuMsgPrio etc. - * + * * @param self a valid MuMsgFile * @param msfid the message field id to get (must be string-based one) - * + * * @return the numeric value, or -1 in case of error */ gint64 mu_msg_file_get_num_field (MuMsgFile *self, MuMsgFieldId mfid); diff --git a/lib/mu-msg-part.c b/lib/mu-msg-part.c index 8931ac94..b0cbd351 100644 --- a/lib/mu-msg-part.c +++ b/lib/mu-msg-part.c @@ -1,5 +1,4 @@ /* -*-mode: c; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-*/ - /* ** Copyright (C) 2008-2012 Dirk-Jan C. Binnema ** @@ -36,63 +35,71 @@ #endif /*BUILD_CRYPTO*/ -struct _FindPartData { - guint idx, wanted_idx; - GMimeObject *part; +struct _DoData { + GMimeObject *mime_obj; + unsigned index; }; -typedef struct _FindPartData FindPartData; - - -/* is this either a leaf part or an embedded message? */ -static gboolean -is_part_or_message_part (GMimeObject *part) -{ - return GMIME_IS_PART(part) || GMIME_IS_MESSAGE_PART (part); -} - +typedef struct _DoData DoData; static void -find_part_cb (GMimeObject *parent, GMimeObject *part, FindPartData *fpdata) +do_it_with_index (MuMsg *msg, MuMsgPart *part, DoData *ddata) { - /* ignore other parts */ - if (!is_part_or_message_part (part)) + if (ddata->mime_obj) return; - /* g_printerr ("%u Type-name: %s\n", */ - /* fpdata->idx, G_OBJECT_TYPE_NAME((GObject*)part)); */ - - if (fpdata->part || fpdata->wanted_idx != fpdata->idx++) - return; /* not yet found */ - - fpdata->part = part; + if (part->index == ddata->index) + ddata->mime_obj = (GMimeObject*)part->data; } static GMimeObject* -find_part (MuMsg* msg, guint partidx) +get_mime_object_at_index (MuMsg *msg, MuMsgOptions opts, unsigned index) { - FindPartData fpdata; + DoData ddata; - fpdata.wanted_idx = partidx; - fpdata.idx = 0; - fpdata.part = NULL; + ddata.mime_obj = NULL; + ddata.index = index; - mu_mime_message_foreach (msg->_file->_mime_msg, - mu_msg_get_auto_decrypt(msg), - (GMimeObjectForeachFunc)find_part_cb, - &fpdata); - return fpdata.part; + mu_msg_part_foreach (msg, opts, + (MuMsgPartForeachFunc)do_it_with_index, + &ddata); + + return ddata.mime_obj; } -struct _PartData { - MuMsg *_msg; - unsigned _idx; - MuMsgPartForeachFunc _func; - gpointer _user_data; - GMimePart *_body_part; - MuMsgOptions _opts; -}; -typedef struct _PartData PartData; +typedef gboolean (*MuMsgPartMatchFunc) (MuMsgPart *, gpointer); +struct _MatchData { + MuMsgPartMatchFunc match_func; + gpointer user_data; + int index; +}; +typedef struct _MatchData MatchData; + +static void +check_match (MuMsg *msg, MuMsgPart *part, MatchData *mdata) +{ + if (mdata->index != -1) + return; + + if (mdata->match_func (part, mdata->user_data)) + mdata->index = part->index; +} + +int +get_matching_part_index (MuMsg *msg, MuMsgOptions opts, + MuMsgPartMatchFunc func, gpointer user_data) +{ + MatchData mdata; + + mdata.match_func = func; + mdata.user_data = user_data; + mdata.index = -1; + + mu_msg_part_foreach (msg, opts, + (MuMsgPartForeachFunc)check_match, + &mdata); + return mdata.index; +} struct _TxtData { @@ -101,12 +108,10 @@ struct _TxtData { }; typedef struct _TxtData TxtData; -static gchar *mime_message_to_string (GMimeMessage *mimemsg, - gboolean decrypt); +static gchar *mime_message_to_string (GMimeMessage *mimemsg, gboolean decrypt); static void -each_mime_part_get_text (GMimeObject *parent, GMimeObject *part, - TxtData *tdata) +each_mime_part_get_text (GMimeObject *parent, GMimeObject *part, TxtData *tdata) { char *txt; txt = NULL; @@ -186,16 +191,15 @@ mu_msg_part_get_text (MuMsg *msg, MuMsgPart *self, gboolean *err) if (GMIME_IS_PART(mobj)) { /* ignore all but plain text */ - if ((strcasecmp (self->type, "text") == 0) && - (strcasecmp (self->subtype, "plain") == 0)) + if ((strcasecmp (self->type, "text") != 0) || + (strcasecmp (self->subtype, "plain") != 0)) return NULL; return mu_msg_mime_part_to_string ((GMimePart*)mobj, err); } if (GMIME_IS_MESSAGE(mobj)) - return mime_message_to_string ((GMimeMessage*)mobj, - mu_msg_get_auto_decrypt(msg)); - g_return_val_if_reached (NULL); + return mime_message_to_string ((GMimeMessage*)mobj,TRUE); + return NULL; } @@ -209,7 +213,7 @@ get_part_size (GMimePart *part) GMimeStream *stream; wrapper = g_mime_part_get_content_object (part); - if (!wrapper) + if (!GMIME_IS_DATA_WRAPPER(wrapper)) return -1; stream = g_mime_data_wrapper_get_stream (wrapper); @@ -218,212 +222,324 @@ get_part_size (GMimePart *part) else return g_mime_stream_length (stream); - /* NOTE: it seems we shouldn't unref stream/wrapper */ + /* NOTE: stream/wrapper are owned by gmime, no unreffing */ } -#ifdef BUILD_CRYPTO -static void -check_signature_maybe (GMimeObject *parent, GMimeObject *mobj, MuMsgPart *pi, - MuMsgOptions opts) +/* #ifdef BUILD_CRYPTO */ +/* static void */ +/* check_signature_maybe (GMimeObject *parent, GMimeObject *mobj, MuMsgPart *pi, */ +/* MuMsgOptions opts) */ +/* { */ +/* GMimeContentType *ctype; */ +/* GError *err; */ +/* gboolean pkcs7; */ + +/* if (!GMIME_IS_MULTIPART_SIGNED (parent)) */ +/* return; */ + +/* ctype = g_mime_object_get_content_type (mobj); */ +/* if (g_mime_content_type_is_type */ +/* (ctype, "application", "pgp-signature")) */ +/* pkcs7 = FALSE; */ +/* else if (g_mime_content_type_is_type */ +/* (ctype, "application", "x-pkcs7-signature")) */ +/* pkcs7 = TRUE; */ +/* else return; /\* don't know how to handle other kinds *\/ */ + +/* if (pkcs7) */ +/* opts |= MU_MSG_OPTION_USE_PKCS7; /\* gpg is the default *\/ */ + +/* err = NULL; */ +/* pi->sig_infos = mu_msg_mime_sig_infos */ +/* (GMIME_MULTIPART_SIGNED (parent), opts, &err); */ +/* if (err) { */ +/* g_warning ("error verifying signature: %s", err->message); */ +/* 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 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 char* +mime_part_get_filename (GMimeObject *mobj, unsigned index, + gboolean construct_if_needed) { - GMimeContentType *ctype; - GError *err; - gboolean pkcs7; + gchar *fname, *cur; - if (!GMIME_IS_MULTIPART_SIGNED (parent)) - return; - - ctype = g_mime_object_get_content_type (mobj); - if (g_mime_content_type_is_type - (ctype, "application", "pgp-signature")) - pkcs7 = FALSE; - else if (g_mime_content_type_is_type - (ctype, "application", "x-pkcs7-signature")) - pkcs7 = TRUE; - else return; /* don't know how to handle other kinds */ - - if (pkcs7) - opts |= MU_MSG_OPTION_USE_PKCS7; /* gpg is the default */ - - err = NULL; - pi->sig_infos = mu_msg_mime_sig_infos - (GMIME_MULTIPART_SIGNED (parent), opts, &err); - if (err) { - g_warning ("error verifying signature: %s", err->message); - g_clear_error (&err); + if (GMIME_IS_PART (mobj)) { + /* the easy case: the part has a filename */ + fname = (gchar*)g_mime_part_get_filename (GMIME_PART(mobj)); + if (fname) /* don't include directory components */ + fname = g_path_get_basename (fname); } + + if (!fname && !construct_if_needed) + return NULL; + + if (GMIME_IS_MESSAGE_PART(mobj)) { + GMimeMessage *msg; + const char *subj; + msg = g_mime_message_part_get_message + (GMIME_MESSAGE_PART(mobj)); + subj = g_mime_message_get_subject (msg); + fname = g_strdup_printf ("%s.eml", subj ? subj : "message"); + } + + if (!fname) + fname = g_strdup_printf ("%u.part", index); + + /* remove slashes, spaces, colons... */ + for (cur = fname; *cur; ++cur) + if (*cur == '/' || *cur == ' ' || *cur == ':') + *cur = '-'; + return fname; } +char* +mu_msg_part_get_filename (MuMsgPart *mpart, gboolean construct_if_needed) +{ + g_return_val_if_fail (mpart, NULL); + g_return_val_if_fail (GMIME_IS_OBJECT(mpart->data), NULL); -#endif /*BUILD_CRYPTO*/ + return mime_part_get_filename ((GMimeObject*)mpart->data, + mpart->index, construct_if_needed); +} + + +static MuMsgPartType +get_disposition (GMimeObject *mobj) +{ + const char *disp; + + disp = g_mime_object_get_disposition (mobj); + if (!disp) + return MU_MSG_PART_TYPE_NONE; + + if (strcasecmp (disp, GMIME_DISPOSITION_ATTACHMENT) == 0) + return MU_MSG_PART_TYPE_ATTACHMENT; + + if (strcasecmp (disp, GMIME_DISPOSITION_INLINE) == 0) + return MU_MSG_PART_TYPE_INLINE; + + return MU_MSG_PART_TYPE_NONE; +} static gboolean -init_msg_part_from_mime_part (MuMsgOptions opts, GMimeObject *parent, - GMimePart *part, MuMsgPart *pi) +handle_children (MuMsg *msg, + GMimeObject *mobj, MuMsgOptions opts, + unsigned index, MuMsgPartForeachFunc func, + gpointer user_data); + +/* call 'func' with information about this MIME-part */ +static gboolean +handle_signed_part (MuMsg *msg, + GMimeMultipartSigned *part, GMimeObject *parent, + MuMsgOptions opts, unsigned index, + MuMsgPartForeachFunc func, gpointer user_data) +{ + return TRUE; +} + +/* call 'func' with information about this MIME-part */ +static gboolean +handle_encrypted_part (MuMsg *msg, + GMimeMultipartEncrypted *part, GMimeObject *parent, + MuMsgOptions opts, unsigned index, + MuMsgPartForeachFunc func, gpointer user_data) +{ + return TRUE; +} + +/* call 'func' with information about this MIME-part */ +static gboolean +handle_part (MuMsg *msg, GMimePart *part, GMimeObject *parent, + MuMsgOptions opts, unsigned index, + MuMsgPartForeachFunc func, gpointer user_data) { - const gchar *fname, *descr; GMimeContentType *ct; + MuMsgPart msgpart; + + memset (&msgpart, 0, sizeof(MuMsgPart)); 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); + msgpart.type = g_mime_content_type_get_media_type (ct); + msgpart.subtype = g_mime_content_type_get_media_subtype (ct); } - pi->disposition = (char*)g_mime_object_get_disposition - ((GMimeObject*)part); + msgpart.size = get_part_size (part); - fname = g_mime_part_get_filename (part); - pi->file_name = fname ? mu_str_utf8ify (fname) : NULL; + msgpart.part_type = MU_MSG_PART_TYPE_LEAF; + msgpart.part_type |= get_disposition ((GMimeObject*)part); - 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; + /* a top-level non-attachment text part is probably a body */ + if ((!parent || GMIME_IS_MESSAGE(parent)) && + ((msgpart.part_type & MU_MSG_PART_TYPE_ATTACHMENT) == 0) && + g_strcmp0 (msgpart.type, "text") == 0) + msgpart.part_type |= MU_MSG_PART_TYPE_BODY; - if (!pi->disposition || - g_ascii_strcasecmp (pi->disposition, - GMIME_DISPOSITION_INLINE) == 0) - pi->part_type |= MU_MSG_PART_TYPE_INLINE; + msgpart.data = (gpointer)part; + msgpart.index = index; - 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*/ + func (msg, &msgpart, user_data); return TRUE; } -static gchar* -get_filename_for_mime_message_part (GMimeMessage *mmsg) + +/* call 'func' with information about this MIME-part */ +static gboolean +handle_message_part (MuMsg *msg, GMimeMessagePart *mmsg, GMimeObject *parent, + MuMsgOptions opts, unsigned index, + MuMsgPartForeachFunc func, gpointer user_data) { - gchar *name, *cur; + MuMsgPart msgpart; + memset (&msgpart, 0, sizeof(MuMsgPart)); - name = (char*)g_mime_message_get_subject (mmsg); - if (!name) - name = "message"; + msgpart.type = "message"; + msgpart.subtype = "rfc822"; + msgpart.index = index; - name = g_strconcat (name, ".eml", NULL); + /* msgpart.size = 0; /\* maybe calculate this? *\/ */ - /* remove slashes... */ - for (cur = name ; *cur; ++cur) { - if (*cur == '/' || *cur == ' ' || *cur == ':') - *cur = '-'; + msgpart.part_type = MU_MSG_PART_TYPE_MESSAGE; + msgpart.part_type |= get_disposition ((GMimeObject*)mmsg); + + msgpart.data = (gpointer)mmsg; + + func (msg, &msgpart, user_data); + + if (opts & MU_MSG_OPTION_RECURSE_RFC822) { + GMimeMessage *mime_msg; + mime_msg = g_mime_message_part_get_message (mmsg); + return handle_children + (msg, + (GMimeObject*)mime_msg, + opts, index, func, user_data); } - - return name; + return TRUE; } static gboolean -init_msg_part_from_mime_message_part (GMimeMessage *mmsg, MuMsgPart *pi) +handle_mime_object (MuMsg *msg, + GMimeObject *mobj, GMimeObject *parent, MuMsgOptions opts, + unsigned index, MuMsgPartForeachFunc func, gpointer user_data) { - 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; + if (GMIME_IS_PART (mobj)) + return handle_part + (msg, GMIME_PART(mobj), parent, + opts, index, func, user_data); + else if (GMIME_IS_MESSAGE_PART (mobj)) + return handle_message_part + (msg, GMIME_MESSAGE_PART(mobj), + parent, opts, index, func, user_data); + else if (GMIME_IS_MULTIPART_SIGNED (mobj)) + return handle_signed_part + (msg, GMIME_MULTIPART_SIGNED (mobj), + parent, opts, index, func, user_data); + else if (GMIME_IS_MULTIPART_ENCRYPTED (mobj)) + return handle_encrypted_part + (msg, GMIME_MULTIPART_ENCRYPTED (mobj), + parent, opts, index, func, user_data); return TRUE; } -static void -msg_part_free (MuMsgPart *pi) +static gboolean +handle_children (MuMsg *msg, + GMimeObject *mobj, MuMsgOptions opts, + unsigned index, MuMsgPartForeachFunc func, + gpointer user_data) { - 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 -part_foreach_cb (GMimeObject *parent, GMimeObject *mobj, PartData *pdata) -{ - MuMsgPart pi; gboolean rv; + GMimePartIter *iter; - /* ignore other non-leaf / message parts */ - if (!is_part_or_message_part (mobj)) - return; + /* the children */ + iter = g_mime_part_iter_new (mobj); - memset (&pi, 0, sizeof(pi)); - pi.index = pdata->_idx++; - pi.content_id = (char*)g_mime_object_get_content_id (mobj); + if (!iter) + return FALSE; + for (rv = TRUE; rv && g_mime_part_iter_is_valid (iter); + g_mime_part_iter_next (iter), index++) + rv = handle_mime_object ( + msg, g_mime_part_iter_get_current (iter), + g_mime_part_iter_get_parent (iter), + opts, index, func, user_data); - if (GMIME_IS_PART(mobj)) { - pi.data = (gpointer)mobj; - rv = init_msg_part_from_mime_part - (pdata->_opts, parent, (GMimePart*)mobj, &pi); + g_mime_part_iter_free (iter); - /* check if this is the body part */ - if (rv && (void*)pdata->_body_part == (void*)mobj) - pi.part_type |= MU_MSG_PART_TYPE_BODY; - - } 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); - - } else - rv = FALSE; /* ignore */ - - if (rv) - pdata->_func(pdata->_msg, &pi, pdata->_user_data); - - msg_part_free (&pi); + return rv; } - -void -mu_msg_part_foreach (MuMsg *msg, MuMsgPartForeachFunc func, gpointer user_data, - MuMsgOptions opts) +gboolean +mu_msg_part_foreach (MuMsg *msg, MuMsgOptions opts, + MuMsgPartForeachFunc func, gpointer user_data) { - PartData pdata; - GMimeMessage *mime_msg; + GMimeObject *toplevel; + unsigned idx; - g_return_if_fail (msg); + g_return_val_if_fail (msg, FALSE); if (!mu_msg_load_msg_file (msg, NULL)) - return; + return FALSE; - mime_msg = msg->_file->_mime_msg; + idx = 0; + toplevel = g_mime_message_get_mime_part + (GMIME_MESSAGE(msg->_file->_mime_msg)); + if (!toplevel || !handle_mime_object + (msg, toplevel, NULL, opts, idx++, func, user_data)) + return FALSE; - pdata._msg = msg; - pdata._idx = 0; - pdata._body_part = mu_msg_mime_get_body_part - (mime_msg, mu_msg_get_auto_decrypt(msg), FALSE); - pdata._func = func; - pdata._user_data = user_data; - pdata._opts = opts; - - mu_mime_message_foreach (msg->_file->_mime_msg, - mu_msg_get_auto_decrypt(msg), - (GMimeObjectForeachFunc)part_foreach_cb, - &pdata); + return handle_children (msg, toplevel, opts, idx, func, + user_data); } @@ -490,13 +606,16 @@ write_object_to_fd (GMimeObject *obj, int fd, GError **err) } - -gboolean -mu_msg_part_mime_save_object (GMimeObject *obj, const char *fullpath, - gboolean overwrite, gboolean use_existing, GError **err) +static gboolean +save_object (GMimeObject *obj, MuMsgOptions opts, const char *fullpath, + GError **err) { int fd; gboolean rv; + gboolean use_existing, overwrite; + + use_existing = opts & MU_MSG_OPTION_USE_EXISTING; + overwrite = opts & MU_MSG_OPTION_OVERWRITE; /* don't try to overwrite when we already have it; useful when * you're sure it's not a different file with the same name */ @@ -529,41 +648,25 @@ mu_msg_part_mime_save_object (GMimeObject *obj, const char *fullpath, gchar* -mu_msg_part_filepath (MuMsg *msg, const char* targetdir, guint partidx, - GError **err) +mu_msg_part_get_path (MuMsg *msg, MuMsgOptions opts, + const char* targetdir, unsigned index, GError **err) { char *fname, *filepath; GMimeObject* mobj; + g_return_val_if_fail (msg, NULL); + if (!mu_msg_load_msg_file (msg, NULL)) return NULL; - if (!(mobj = find_part (msg, partidx))) { - mu_util_g_set_error (err,MU_ERROR_GMIME, - "cannot find part %u", partidx); - return NULL; - } - - if (GMIME_IS_PART (mobj)) { - /* the easy case: the part has a filename */ - fname = (gchar*)g_mime_part_get_filename (GMIME_PART(mobj)); - if (fname) /* security: don't includ directory - * components */ - fname = g_path_get_basename (fname); - else - fname = g_strdup_printf ("%x-part-%u", - g_str_hash (mu_msg_get_path (msg)), - partidx); - } else if (GMIME_IS_MESSAGE_PART(mobj)) - fname = get_filename_for_mime_message_part - (g_mime_message_part_get_message - ((GMimeMessagePart*)mobj)); - else { + mobj = get_mime_object_at_index (msg, opts, index); + if (!mobj){ mu_util_g_set_error (err, MU_ERROR_GMIME, - "part %u cannot be saved", partidx); + "cannot find part %u", index); return NULL; } + fname = mime_part_get_filename (mobj, index, TRUE); filepath = g_build_path (G_DIR_SEPARATOR_S, targetdir ? targetdir : "", fname, NULL); g_free (fname); @@ -574,7 +677,8 @@ mu_msg_part_filepath (MuMsg *msg, const char* targetdir, guint partidx, gchar* -mu_msg_part_filepath_cache (MuMsg *msg, guint partid) +mu_msg_part_get_cache_path (MuMsg *msg, MuMsgOptions opts, guint partid, + GError **err) { char *dirname, *filepath; const char* path; @@ -585,8 +689,6 @@ mu_msg_part_filepath_cache (MuMsg *msg, guint partid) return NULL; path = mu_msg_get_path (msg); - if (!path) - return NULL; /* g_compute_checksum_for_string may be better, but requires * rel. new glib (2.16) */ @@ -596,61 +698,56 @@ mu_msg_part_filepath_cache (MuMsg *msg, 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); g_free (dirname); return NULL; } - filepath = mu_msg_part_filepath (msg, dirname, partid, NULL); + filepath = mu_msg_part_get_path (msg, opts, dirname, partid, err); g_free (dirname); - if (!filepath) - g_warning ("%s: could not get filename", __FUNCTION__); return filepath; } gboolean -mu_msg_part_save (MuMsg *msg, const char *fullpath, guint partidx, - gboolean overwrite, gboolean use_cached, GError **err) +mu_msg_part_save (MuMsg *msg, MuMsgOptions opts, + const char *fullpath, guint partidx, GError **err) { GMimeObject *part; g_return_val_if_fail (msg, FALSE); g_return_val_if_fail (fullpath, FALSE); - g_return_val_if_fail (!overwrite||!use_cached, FALSE); + g_return_val_if_fail (!((opts & MU_MSG_OPTION_OVERWRITE) && + (opts & MU_MSG_OPTION_USE_EXISTING)), FALSE); if (!mu_msg_load_msg_file (msg, err)) return FALSE; - part = find_part (msg, partidx); - if (!is_part_or_message_part (part)) { + part = get_mime_object_at_index (msg, opts, partidx); + if (!GMIME_IS_PART(part) || GMIME_IS_MESSAGE_PART(part)) { g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_GMIME, "unexpected type %s for part %u", G_OBJECT_TYPE_NAME((GObject*)part), partidx); return FALSE; - } else - return mu_msg_part_mime_save_object (part, fullpath, overwrite, - use_cached, err); + } + return save_object (part, opts, fullpath, err); } gchar* -mu_msg_part_save_temp (MuMsg *msg, guint partidx, GError **err) +mu_msg_part_save_temp (MuMsg *msg, MuMsgOptions opts, guint partidx, GError **err) { gchar *filepath; - gboolean rv; - filepath = mu_msg_part_filepath_cache (msg, partidx); - if (!filepath) { - g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_FILE, - "Could not get temp filepath"); + filepath = mu_msg_part_get_cache_path (msg, opts, partidx, err); + if (!filepath) return NULL; - } - rv = mu_msg_part_save (msg, filepath, partidx, FALSE, TRUE, err); - if (!rv) { + if (!mu_msg_part_save (msg, opts, filepath, partidx, err)) { g_free (filepath); return NULL; } @@ -658,59 +755,18 @@ mu_msg_part_save_temp (MuMsg *msg, guint partidx, GError **err) return filepath; } - - -typedef gboolean (*MatchFunc) (GMimeObject *part, gpointer data); - -struct _MatchData { - MatchFunc _matcher; - gpointer _user_data; - gint _idx, _found_idx; -}; -typedef struct _MatchData MatchData; - -static void -part_match_foreach_cb (GMimeObject *parent, GMimeObject *part, - MatchData *mdata) -{ - if (mdata->_found_idx < 0) - if (mdata->_matcher (part, mdata->_user_data)) - mdata->_found_idx = mdata->_idx; - - ++mdata->_idx; -} - -static int -msg_part_find_idx (GMimeMessage *mimemsg, gboolean auto_decrypt, - MatchFunc func, gpointer user_data) -{ - MatchData mdata; - - g_return_val_if_fail (mimemsg, -1); - g_return_val_if_fail (GMIME_IS_MESSAGE(mimemsg), -1); - - mdata._idx = 0; - mdata._found_idx = -1; - mdata._matcher = func; - mdata._user_data = user_data; - - mu_mime_message_foreach (mimemsg, auto_decrypt, - (GMimeObjectForeachFunc)part_match_foreach_cb, - &mdata); - - return mdata._found_idx; -} - - static gboolean -match_content_id (GMimeObject *part, const char *cid) +match_cid (MuMsgPart *mpart, const char *cid) { - return g_strcmp0 (g_mime_object_get_content_id (part), - cid) == 0 ? TRUE : FALSE; + const char *this_cid; + + this_cid = g_mime_object_get_content_id ((GMimeObject*)mpart->data); + + return g_strcmp0 (this_cid, cid) ? TRUE : FALSE; } int -mu_msg_part_find_cid (MuMsg *msg, const char* sought_cid) +mu_msg_find_index_for_cid (MuMsg *msg, MuMsgOptions opts, const char *sought_cid) { const char* cid; @@ -723,53 +779,43 @@ mu_msg_part_find_cid (MuMsg *msg, const char* sought_cid) cid = g_str_has_prefix (sought_cid, "cid:") ? sought_cid + 4 : sought_cid; - return msg_part_find_idx (msg->_file->_mime_msg, - mu_msg_get_auto_decrypt(msg), - (MatchFunc)match_content_id, - (gpointer)(char*)cid); + return get_matching_part_index (msg, opts, + (MuMsgPartMatchFunc)match_cid, + (gpointer)(char*)cid); } -struct _MatchData2 { - GSList *_lst; +struct _RxMatchData { + GSList *_lst; const GRegex *_rx; guint _idx; }; -typedef struct _MatchData2 MatchData2; +typedef struct _RxMatchData RxMatchData; static void -match_filename_rx (GMimeObject *parent, GMimeObject *part, MatchData2 *mdata) +match_filename_rx (MuMsg *msg, MuMsgPart *mpart, RxMatchData *mdata) { - const char *fname; + char *fname; - /* ignore other parts -- we need this guard so the counting of - * parts is the same as in other functions for dealing with - * msg parts (this is needed since we expose the numbers to - * the user) */ - if (!is_part_or_message_part (part)) + fname = mu_msg_part_get_filename (mpart, FALSE); + if (!fname) return; - fname = g_mime_part_get_filename (GMIME_PART(part)); - if (!fname) { - ++mdata->_idx; - return; - } - if (g_regex_match (mdata->_rx, fname, 0, NULL)) mdata->_lst = g_slist_prepend (mdata->_lst, - GUINT_TO_POINTER(mdata->_idx++)); + GUINT_TO_POINTER(mpart->index)); + g_free (fname); } GSList* -mu_msg_part_find_files (MuMsg *msg, const GRegex *pattern) +mu_msg_find_files (MuMsg *msg, MuMsgOptions opts, const GRegex *pattern) { - MatchData2 mdata; + RxMatchData mdata; g_return_val_if_fail (msg, NULL); g_return_val_if_fail (pattern, NULL); - if (!mu_msg_load_msg_file (msg, NULL)) return NULL; @@ -777,17 +823,15 @@ mu_msg_part_find_files (MuMsg *msg, const GRegex *pattern) mdata._rx = pattern; mdata._idx = 0; - mu_mime_message_foreach (msg->_file->_mime_msg, - mu_msg_get_auto_decrypt(msg), - (GMimeObjectForeachFunc)match_filename_rx, - &mdata); + mu_msg_part_foreach (msg, opts, + (MuMsgPartForeachFunc)match_filename_rx, + &mdata); return mdata._lst; } 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); diff --git a/lib/mu-msg-part.h b/lib/mu-msg-part.h index d1657e48..3cbb0869 100644 --- a/lib/mu-msg-part.h +++ b/lib/mu-msg-part.h @@ -38,10 +38,14 @@ enum _MuMsgPartType { MU_MSG_PART_TYPE_MESSAGE = 1 << 2, /* disposition inline? */ MU_MSG_PART_TYPE_INLINE = 1 << 3, + /* disposition attachment? */ + MU_MSG_PART_TYPE_ATTACHMENT = 1 << 4, /* a signed part? */ MU_MSG_PART_TYPE_SIGNED = 1 << 5, /* an encrypted part? */ - MU_MSG_PART_TYPE_ENCRYPTED = 1 << 6 + MU_MSG_PART_TYPE_ENCRYPTED = 1 << 6, + /* a decrypted part? */ + MU_MSG_PART_TYPE_DECRYPTED = 1 << 7 }; typedef enum _MuMsgPartType MuMsgPartType; @@ -52,22 +56,11 @@ struct _MuMsgPart { unsigned index; /* cid */ - char *content_id; + /* const char *content_id; */ /* content-type: type/subtype, ie. text/plain */ - char *type; - char *subtype; - /* full content-type, e.g. image/jpeg */ - /* char *content_type; */ - - /* the file name (if any) */ - char *file_name; - - /* description (if any) */ - char *description; - - /* usually, "attachment" or "inline" */ - char *disposition; + const char *type; + const char *subtype; /* size of the part; or < 0 if unknown */ ssize_t size; @@ -78,41 +71,20 @@ struct _MuMsgPart { /* crypto stuff */ GSList *sig_infos; /* list of MuMsgPartSig */ - - /* if TRUE, mu_msg_part_destroy will free the member vars - * as well*/ - gboolean own_members; -}; + }; typedef struct _MuMsgPart MuMsgPart; /** - * macro to get the file name for this mime-part + * get some appropriate file name for the mime-part * - * @param pi a MuMsgPart instance + * @param mpart a MuMsgPart + * @param construct_if_needed if there is no + * real filename, construct one. * - * @return the file name + * @return the file name (free with g_free) */ -#define mu_msg_part_file_name(pi) ((pi)->file_name) - - -/** - * macro to get the description for this mime-part - * - * @param pi a MuMsgPart instance - * - * @return the description - */ -#define mu_msg_part_description(pi) ((pi)->description) - - -/** - * macro to get the content-id (cid) for this mime-part - * - * @param pi a MuMsgPart instance - * - * @return the file name - */ -#define mu_msg_part_content_id(pi) ((pi)->content_id) +char *mu_msg_part_get_filename (MuMsgPart *mpart, gboolean construct_if_needed) + G_GNUC_WARN_UNUSED_RESULT; /** @@ -123,7 +95,8 @@ typedef struct _MuMsgPart MuMsgPart; * * @return utf8 string for this MIME part, to be freed by caller */ -char* mu_msg_part_get_text (MuMsg *msg, MuMsgPart *part, gboolean *err); +char* mu_msg_part_get_text (MuMsg *msg, MuMsgPart *part, gboolean *err) + G_GNUC_WARN_UNUSED_RESULT; /** @@ -142,16 +115,17 @@ gboolean mu_msg_part_looks_like_attachment (MuMsgPart *part, * save a specific attachment to some targetdir * * @param msg a valid MuMsg instance + * @param opts mu-message options (OVERWRITE/USE_EXISTING) * @gchar filepath the filepath to save * @param partidx index of the attachment you want to save - * @param overwrite overwrite existing files? - * @param don't raise error when the file already exists * @param err receives error information (when function returns NULL) * - * @return full path to the message part saved or NULL in case or error; free with g_free + * @return full path to the message part saved or NULL in case or + * error; free with g_free */ -gboolean mu_msg_part_save (MuMsg *msg, const char *filepath, guint partidx, - gboolean overwrite, gboolean use_cached, GError **err); +gboolean mu_msg_part_save (MuMsg *msg, MuMsgOptions opts, + const char *filepath, guint partidx, + GError **err); /** @@ -159,13 +133,15 @@ gboolean mu_msg_part_save (MuMsg *msg, const char *filepath, guint partidx, * this file * * @param msg a MuMsg message + * @param opts mu-message options (OVERWRITE/USE_EXISTING) * @param partidx index of the part to save * @param err receives error information if any * * @return the full path to the temp file, or NULL in case of error */ -gchar* mu_msg_part_save_temp (MuMsg *msg, guint partidx, GError **err); - +gchar* mu_msg_part_save_temp (MuMsg *msg, MuMsgOptions opts, + guint partidx, GError **err) + G_GNUC_WARN_UNUSED_RESULT; @@ -175,14 +151,17 @@ gchar* mu_msg_part_save_temp (MuMsg *msg, guint partidx, GError **err); * name based on the partidx and the message path * * @param msg a msg + * @param opts mu-message options * @param targetdir where to store the part * @param partidx the part for which to determine a filename * @param err receives error information (when function returns NULL) * * @return a filepath (g_free when done with it) or NULL in case of error */ -gchar* mu_msg_part_filepath (MuMsg *msg, const char* targetdir, - guint partidx, GError **err) G_GNUC_WARN_UNUSED_RESULT; +gchar* mu_msg_part_get_path (MuMsg *msg, MuMsgOptions opts, + const char* targetdir, + guint partidx, GError **err) + G_GNUC_WARN_UNUSED_RESULT; /** @@ -193,11 +172,14 @@ gchar* mu_msg_part_filepath (MuMsg *msg, const char* targetdir, * Will create the directory if needed. * * @param msg a msg + * @param opts mu-message options * @param partidx the part for which to determine a filename + * @param err receives error information (when function returns NULL) * * @return a filepath (g_free when done with it) or NULL in case of error */ -gchar* mu_msg_part_filepath_cache (MuMsg *msg, guint partid) +gchar* mu_msg_part_get_cache_path (MuMsg *msg, MuMsgOptions opts, + guint partidx, GError **err) G_GNUC_WARN_UNUSED_RESULT; @@ -209,7 +191,7 @@ gchar* mu_msg_part_filepath_cache (MuMsg *msg, guint partid) * * @return the part index number of the found part, or -1 if it was not found */ -int mu_msg_part_find_cid (MuMsg *msg, const char* content_id); +int mu_msg_find_index_for_cid (MuMsg *msg, MuMsgOptions opts, const char* content_id); @@ -217,16 +199,17 @@ int mu_msg_part_find_cid (MuMsg *msg, const char* content_id); * retrieve a list of indices for mime-parts with filenames matching a regex * * @param msg a message + * @param opts * @param a regular expression to match the filename with * * @return a list with indices for the files matching the pattern; the * indices are the GPOINTER_TO_UINT(lst->data) of the list. They must * be freed with g_slist_free */ -GSList* mu_msg_part_find_files (MuMsg *msg, const GRegex *pattern); +GSList* mu_msg_find_files (MuMsg *msg, MuMsgOptions opts, const GRegex *pattern); -typedef void (*MuMsgPartForeachFunc) (MuMsg*, MuMsgPart*, gpointer); +typedef void (*MuMsgPartForeachFunc) (MuMsg *msg, MuMsgPart*, gpointer); /** @@ -239,8 +222,8 @@ typedef void (*MuMsgPartForeachFunc) (MuMsg*, MuMsgPart*, gpointer); * @param options, bit-wise OR'ed * */ -void mu_msg_part_foreach (MuMsg *msg, MuMsgPartForeachFunc func, gpointer user_data, - MuMsgOptions opts); +gboolean mu_msg_part_foreach (MuMsg *msg, MuMsgOptions opts, + MuMsgPartForeachFunc func, gpointer user_data); G_END_DECLS diff --git a/lib/mu-msg-priv.h b/lib/mu-msg-priv.h index 732b7b7e..b5496279 100644 --- a/lib/mu-msg-priv.h +++ b/lib/mu-msg-priv.h @@ -44,9 +44,6 @@ struct _MuMsgFile { char _path [PATH_MAX + 1]; char _maildir [PATH_MAX + 1]; - /* whether to attemp to automagically decrypt encrypted parts */ - gboolean _auto_decrypt; - /* list where we push allocated strings so we can * free them when the struct gets destroyed */ @@ -79,20 +76,20 @@ struct _MuMsg { gchar* mu_msg_mime_part_to_string (GMimePart *part, gboolean *err); -/** - * write a GMimeObject to a file - * - * @param obj a GMimeObject - * @param fullpath full file path - * @param overwrite allow overwriting existing file - * @param if file already exist, don't bother to write - * @param err receives error information - * - * @return TRUE if writing succeeded, FALSE otherwise. - */ -gboolean mu_msg_part_mime_save_object (GMimeObject *obj, const char *fullpath, - gboolean overwrite, gboolean use_existing, - GError **err); +/* /\** */ +/* * write a GMimeObject to a file */ +/* * */ +/* * @param obj a GMimeObject */ +/* * @param fullpath full file path */ +/* * @param overwrite allow overwriting existing file */ +/* * @param if file already exist, don't bother to write */ +/* * @param err receives error information */ +/* * */ +/* * @return TRUE if writing succeeded, FALSE otherwise. */ +/* *\/ */ +/* gboolean mu_msg_part_mime_save_object (GMimeObject *obj, const char *fullpath, */ +/* gboolean overwrite, gboolean use_existing, */ +/* GError **err); */ @@ -111,14 +108,18 @@ GMimePart* mu_msg_mime_get_body_part (GMimeMessage *msg, gboolean decrypt, /** * Like g_mime_message_foreach, but will recurse into encrypted parts + * if @param decrypt is TRUE and mu was built with crypto support * - * @param msg + * @param msg a GMimeMessage * @param decrypt whether to try to automatically decrypt - * @param func - * @param user_data + * @param func user callback function for each part + * @param user_data user point passed to callback function + * @param err receives error information + * */ void mu_mime_message_foreach (GMimeMessage *msg, gboolean decrypt, - GMimeObjectForeachFunc func, gpointer user_data); + GMimeObjectForeachFunc func, + gpointer user_data); #ifdef BUILD_CRYPTO /** @@ -134,32 +135,32 @@ void mu_mime_message_foreach (GMimeMessage *msg, gboolean decrypt, GSList* mu_msg_mime_sig_infos (GMimeMultipartSigned *sigmpart, MuMsgOptions opts, GError **err); - - /** - * decrypt the given mime part + * callback function to retrieve a password from the user * - * @param encpart - * @param opts - * @param err + * @param user_id the user name / id to get the password for + * @param prompt_ctx a string containing some helpful context for the prompt + * @param reprompt whether this is a reprompt after an earlier, incorrect password + * @param user_data the user_data pointer passed to mu_msg_part_decrypt_foreach * - * @return + * @return a newly allocated (g_free'able) string */ -char* mu_msg_mime_decrypt (GMimeMultipartEncrypted *encpart, - MuMsgOptions opts, GError **err); - - +typedef char* (*MuMsgPartPasswordFunc) (const char *user_id, const char *prompt_ctx, + gboolean reprompt, gpointer user_data); /** * decrypt the given encrypted mime multipart * * @param enc encrypted part * @param opts options + * @param password_func callback function to retrieve as password (or NULL) + * @param user_data pointer passed to the password func * @param err receives error data * * @return the decrypted part, or NULL in case of error */ GMimeObject* mu_msg_crypto_decrypt_part (GMimeMultipartEncrypted *enc, MuMsgOptions opts, + MuMsgPartPasswordFunc func, gpointer user_data, GError **err); #endif /*BUILD_CRYPTO*/