static char* mime_part_get_filename (GMimeObject *mobj, unsigned index, gboolean construct_if_needed) { gchar *fname; fname = 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) /* 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... */ cleanup_filename (fname); return fname; }
static gboolean handle_mime_object (MuMsg *msg, GMimeObject *mobj, GMimeObject *parent, MuMsgOptions opts, unsigned *index, gboolean decrypted, MuMsgPartForeachFunc func, gpointer user_data) { if (GMIME_IS_PART (mobj)) return handle_part (msg, GMIME_PART(mobj), parent, opts, index, decrypted, func, user_data); else if (GMIME_IS_MESSAGE_PART (mobj)) return handle_message_part (msg, GMIME_MESSAGE_PART(mobj), parent, opts, index, decrypted, func, user_data); else if ((opts & MU_MSG_OPTION_VERIFY) && GMIME_IS_MULTIPART_SIGNED (mobj)) { check_signature (msg, GMIME_MULTIPART_SIGNED (mobj), opts); return handle_multipart (msg, GMIME_MULTIPART (mobj), mobj, opts, index, decrypted, func, user_data); } else if ((opts & MU_MSG_OPTION_DECRYPT) && GMIME_IS_MULTIPART_ENCRYPTED (mobj)) return handle_encrypted_part (msg, GMIME_MULTIPART_ENCRYPTED (mobj), opts, index, func, user_data); else if (GMIME_IS_MULTIPART (mobj)) return handle_multipart (msg, GMIME_MULTIPART (mobj), parent, opts, index, decrypted, func, user_data); return TRUE; }
gboolean 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 (!((opts & MU_MSG_OPTION_OVERWRITE) && (opts & MU_MSG_OPTION_USE_EXISTING)), FALSE); if (!mu_msg_load_msg_file (msg, err)) return FALSE; part = get_mime_object_at_index (msg, opts, partidx); /* special case: convert a message-part into a message */ if (GMIME_IS_MESSAGE_PART (part)) part = (GMimeObject*)g_mime_message_part_get_message (GMIME_MESSAGE_PART (part)); if (!GMIME_IS_PART(part) && !GMIME_IS_MESSAGE(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; } return save_object (part, opts, fullpath, err); }
/** * sign_prepare: * @mime_part: MIME part * * Prepare a part (and all subparts) to be signed. To do this we need * to set the encoding of all parts (that are not already encoded to * either QP or Base64 or 7-bit) to QP. * * Ref: RFC 3156, sect. 3. **/ static void sign_prepare(GMimeObject * mime_part) { GMimeContentEncoding encoding; GMimeObject *subpart; if (GMIME_IS_MULTIPART(mime_part)) { GMimeMultipart *multipart; int i, n; multipart = (GMimeMultipart *) mime_part; if (GMIME_IS_MULTIPART_SIGNED(multipart) || GMIME_IS_MULTIPART_ENCRYPTED(multipart)) { /* must not modify these parts as they must be treated as opaque */ return; } n = g_mime_multipart_get_count(multipart); for (i = 0; i < n; i++) { subpart = g_mime_multipart_get_part(multipart, i); sign_prepare(subpart); } } else if (GMIME_IS_MESSAGE_PART(mime_part)) { subpart = GMIME_MESSAGE_PART(mime_part)->message->mime_part; sign_prepare(subpart); } else { encoding = g_mime_part_get_content_encoding(GMIME_PART(mime_part)); if ((encoding != GMIME_CONTENT_ENCODING_BASE64) && (encoding != GMIME_CONTENT_ENCODING_7BIT)) g_mime_part_set_content_encoding(GMIME_PART(mime_part), GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE); } }
static gboolean handle_mime_object (MuMsg *msg, GMimeObject *mobj, GMimeObject *parent, MuMsgOptions opts, unsigned index, MuMsgPartForeachFunc func, gpointer user_data) { 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; }
notmuch_status_t _notmuch_message_crypto_potential_payload (_notmuch_message_crypto_t *msg_crypto, GMimeObject *payload, GMimeObject *parent, int childnum) { const char *protected_headers = NULL; const char *forwarded = NULL; const char *subject = NULL; if (!msg_crypto || !payload) return NOTMUCH_STATUS_NULL_POINTER; /* only fire on the first payload part encountered */ if (msg_crypto->payload_encountered) return NOTMUCH_STATUS_SUCCESS; /* the first child of multipart/encrypted that matches the * encryption protocol should be "control information" metadata, * not payload. So we skip it. (see * https://tools.ietf.org/html/rfc1847#page-8) */ if (parent && GMIME_IS_MULTIPART_ENCRYPTED (parent) && childnum == GMIME_MULTIPART_ENCRYPTED_VERSION) { const char *enc_type = g_mime_object_get_content_type_parameter (parent, "protocol"); GMimeContentType *ct = g_mime_object_get_content_type (payload); if (ct && enc_type) { const char *part_type = g_mime_content_type_get_mime_type (ct); if (part_type && strcmp (part_type, enc_type) == 0) return NOTMUCH_STATUS_SUCCESS; } } msg_crypto->payload_encountered = true; /* don't bother recording anything if there is no cryptographic * envelope: */ if ((msg_crypto->decryption_status != NOTMUCH_MESSAGE_DECRYPTED_FULL) && (msg_crypto->sig_list == NULL)) return NOTMUCH_STATUS_SUCCESS; /* Verify that this payload has headers that are intended to be * exported to the larger message: */ /* Consider a payload that uses Alexei Melinkov's forwarded="no" for * message/global or message/rfc822: * https://tools.ietf.org/html/draft-melnikov-smime-header-signing-05#section-4 */ forwarded = g_mime_object_get_content_type_parameter (payload, "forwarded"); if (GMIME_IS_MESSAGE_PART (payload) && forwarded && strcmp (forwarded, "no") == 0) { GMimeMessage *message = g_mime_message_part_get_message (GMIME_MESSAGE_PART (payload)); subject = g_mime_message_get_subject (message); /* FIXME: handle more than just Subject: at some point */ } else { /* Consider "memoryhole"-style protected headers as practiced by Enigmail and K-9 */ protected_headers = g_mime_object_get_content_type_parameter (payload, "protected-headers"); if (protected_headers && strcasecmp("v1", protected_headers) == 0) subject = g_mime_object_get_header (payload, "Subject"); /* FIXME: handle more than just Subject: at some point */ } if (subject) { if (msg_crypto->payload_subject) talloc_free (msg_crypto->payload_subject); msg_crypto->payload_subject = talloc_strdup (msg_crypto, subject); } return NOTMUCH_STATUS_SUCCESS; }