QNetworkReply* MailNetworkManager::makeReply(const QNetworkRequest& req, GMimeObject* content) { auto ctype = g_mime_object_get_content_type(content); char *mtstr = g_mime_content_type_to_string(ctype); QString mediaType = QString::fromUtf8(mtstr); g_free(mtstr); const char *enc = g_mime_content_type_get_parameter(ctype, "charset"); if (enc != NULL) { mediaType += "; charset=\""; mediaType += QString::fromUtf8(enc); mediaType += "\""; } g_return_val_if_fail(GMIME_IS_PART(content), NULL); GMimeStream *stream = g_mime_stream_mem_new(); GMimeDataWrapper *wrapper = g_mime_part_get_content_object(GMIME_PART(content)); g_mime_data_wrapper_write_to_stream(wrapper, stream); GByteArray *bytes = g_mime_stream_mem_get_byte_array(GMIME_STREAM_MEM(stream)); QByteArray buffer((const char*) bytes->data, bytes->len); g_object_unref(stream); qDebug() <<"making reply of length" <<buffer.size() <<"and type" <<mediaType; return StaticHTTPReply::ok(req, buffer, mediaType); }
/* 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) { GMimeContentType *ct; MuMsgPart msgpart; memset (&msgpart, 0, sizeof(MuMsgPart)); msgpart.size = get_part_size (part); msgpart.part_type = MU_MSG_PART_TYPE_LEAF; msgpart.part_type |= get_disposition ((GMimeObject*)part); 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; func (msg, &msgpart, user_data); return TRUE; }
const gchar * libbalsa_message_body_charset(LibBalsaMessageBody * body) { const gchar *charset; if (!body) return NULL; if (body->charset) /* This overrides all! Important for non * us-ascii messages over IMAP. */ return body->charset; if (GMIME_IS_PART(body->mime_part)) { GMimeContentType *type; type = g_mime_object_get_content_type(body->mime_part); return g_mime_content_type_get_parameter(type, "charset"); } charset = libbalsa_message_body_charset(body->parts); if (charset) return charset; return libbalsa_message_body_charset(body->next); }
static void reply_part_content (GMimeObject *part) { GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part)); GMimeContentDisposition *disposition = g_mime_object_get_content_disposition (part); if (g_mime_content_type_is_type (content_type, "multipart", "*") || g_mime_content_type_is_type (content_type, "message", "rfc822")) { /* Output nothing, since multipart subparts will be handled individually. */ } else if (g_mime_content_type_is_type (content_type, "application", "pgp-encrypted") || g_mime_content_type_is_type (content_type, "application", "pgp-signature")) { /* Ignore PGP/MIME cruft parts */ } else if (g_mime_content_type_is_type (content_type, "text", "*") && !g_mime_content_type_is_type (content_type, "text", "html")) { GMimeStream *stream_stdout = NULL, *stream_filter = NULL; GMimeDataWrapper *wrapper; const char *charset; charset = g_mime_object_get_content_type_parameter (part, "charset"); stream_stdout = g_mime_stream_file_new (stdout); if (stream_stdout) { g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE); stream_filter = g_mime_stream_filter_new(stream_stdout); if (charset) { g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter), g_mime_filter_charset_new(charset, "UTF-8")); } } g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter), g_mime_filter_reply_new(TRUE)); wrapper = g_mime_part_get_content_object (GMIME_PART (part)); if (wrapper && stream_filter) g_mime_data_wrapper_write_to_stream (wrapper, stream_filter); if (stream_filter) g_object_unref(stream_filter); if (stream_stdout) g_object_unref(stream_stdout); } else { if (disposition && strcmp (disposition->disposition, GMIME_DISPOSITION_ATTACHMENT) == 0) { const char *filename = g_mime_part_get_filename (GMIME_PART (part)); printf ("Attachment: %s (%s)\n", filename, g_mime_content_type_to_string (content_type)); } else { printf ("Non-text part: %s\n", g_mime_content_type_to_string (content_type)); } } }
static void format_part_reply (mime_node_t *node) { int i; if (node->envelope_file) { printf ("On %s, %s wrote:\n", notmuch_message_get_header (node->envelope_file, "date"), notmuch_message_get_header (node->envelope_file, "from")); } else if (GMIME_IS_MESSAGE (node->part)) { GMimeMessage *message = GMIME_MESSAGE (node->part); InternetAddressList *recipients; const char *recipients_string; printf ("> From: %s\n", g_mime_message_get_sender (message)); recipients = g_mime_message_get_recipients (message, GMIME_RECIPIENT_TYPE_TO); recipients_string = internet_address_list_to_string (recipients, 0); if (recipients_string) printf ("> To: %s\n", recipients_string); recipients = g_mime_message_get_recipients (message, GMIME_RECIPIENT_TYPE_CC); recipients_string = internet_address_list_to_string (recipients, 0); if (recipients_string) printf ("> Cc: %s\n", recipients_string); printf ("> Subject: %s\n", g_mime_message_get_subject (message)); printf ("> Date: %s\n", g_mime_message_get_date_as_string (message)); printf (">\n"); } else if (GMIME_IS_PART (node->part)) { GMimeContentType *content_type = g_mime_object_get_content_type (node->part); GMimeContentDisposition *disposition = g_mime_object_get_content_disposition (node->part); if (g_mime_content_type_is_type (content_type, "application", "pgp-encrypted") || g_mime_content_type_is_type (content_type, "application", "pgp-signature")) { /* Ignore PGP/MIME cruft parts */ } else if (g_mime_content_type_is_type (content_type, "text", "*") && !g_mime_content_type_is_type (content_type, "text", "html")) { GMimeStream *stream_stdout = g_mime_stream_file_new (stdout); g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE); show_text_part_content (node->part, stream_stdout, NOTMUCH_SHOW_TEXT_PART_REPLY); g_object_unref(stream_stdout); } else if (disposition && strcasecmp (g_mime_content_disposition_get_disposition (disposition), GMIME_DISPOSITION_ATTACHMENT) == 0) { const char *filename = g_mime_part_get_filename (GMIME_PART (node->part)); printf ("Attachment: %s (%s)\n", filename, g_mime_content_type_to_string (content_type)); } else { printf ("Non-text part: %s\n", g_mime_content_type_to_string (content_type)); } } for (i = 0; i < node->nchildren; i++) format_part_reply (mime_node_child (node, i)); }
static gint find_part_of_type(GMimeObject *part, GMimeContentType *fct) { const GMimeContentType *ct; ct = g_mime_object_get_content_type(part); if (g_mime_content_type_is_type(ct, fct->type, fct->subtype)) { return 0; } return -1; }
/* call 'func' with information about this MIME-part */ static gboolean handle_part (MuMsg *msg, GMimePart *part, GMimeObject *parent, MuMsgOptions opts, unsigned *index, gboolean decrypted, MuMsgPartForeachFunc func, gpointer user_data) { GMimeContentType *ct; MuMsgPart msgpart; memset (&msgpart, 0, sizeof(MuMsgPart)); msgpart.size = get_part_size (part); msgpart.part_type = MU_MSG_PART_TYPE_LEAF; msgpart.part_type |= get_disposition ((GMimeObject*)part); if (decrypted) msgpart.part_type |= MU_MSG_PART_TYPE_DECRYPTED; else if ((opts & MU_MSG_OPTION_DECRYPT) && GMIME_IS_MULTIPART_ENCRYPTED (parent)) msgpart.part_type |= MU_MSG_PART_TYPE_ENCRYPTED; 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; } /* put the verification info in the pgp-signature and every * descendent of a pgp-encrypted part */ msgpart.sig_status_report = NULL; if (g_ascii_strcasecmp (msgpart.subtype, "pgp-signature") == 0 || decrypted) { msgpart.sig_status_report = (MuMsgPartSigStatusReport*) g_object_get_data (G_OBJECT(parent), SIG_STATUS_REPORT); if (msgpart.sig_status_report) msgpart.part_type |= MU_MSG_PART_TYPE_SIGNED; } msgpart.data = (gpointer)part; msgpart.index = (*index)++; func (msg, &msgpart, user_data); return TRUE; }
static void format_part_end_json (GMimeObject *part) { GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part)); if (g_mime_content_type_is_type (content_type, "multipart", "*")) printf ("]"); else if (g_mime_content_type_is_type (content_type, "message", "rfc822")) printf ("}]"); printf ("}"); }
/** * g_mime_part_set_content_md5: * @mime_part: a #GMimePart object * @content_md5: content md5 or %NULL to generate the md5 digest. * * Set the content md5 for the specified mime part. **/ void g_mime_part_set_content_md5 (GMimePart *mime_part, const char *content_md5) { unsigned char digest[16], b64digest[32]; GMimeStreamFilter *filtered_stream; GMimeContentType *content_type; GMimeFilter *md5_filter; GMimeStream *stream; guint32 save = 0; int state = 0; size_t len; g_return_if_fail (GMIME_IS_PART (mime_part)); g_free (mime_part->content_md5); if (!content_md5) { /* compute a md5sum */ stream = g_mime_stream_null_new (); filtered_stream = (GMimeStreamFilter *) g_mime_stream_filter_new (stream); g_object_unref (stream); content_type = g_mime_object_get_content_type ((GMimeObject *) mime_part); if (g_mime_content_type_is_type (content_type, "text", "*")) { GMimeFilter *crlf_filter; crlf_filter = g_mime_filter_crlf_new (TRUE, FALSE); g_mime_stream_filter_add (filtered_stream, crlf_filter); g_object_unref (crlf_filter); } md5_filter = g_mime_filter_md5_new (); g_mime_stream_filter_add (filtered_stream, md5_filter); stream = (GMimeStream *) filtered_stream; g_mime_data_wrapper_write_to_stream (mime_part->content, stream); g_object_unref (stream); memset (digest, 0, 16); g_mime_filter_md5_get_digest ((GMimeFilterMd5 *) md5_filter, digest); g_object_unref (md5_filter); len = g_mime_encoding_base64_encode_close (digest, 16, b64digest, &state, &save); b64digest[len] = '\0'; g_strstrip ((char *) b64digest); content_md5 = (const char *) b64digest; } mime_part->content_md5 = g_strdup (content_md5); g_mime_header_list_set (GMIME_OBJECT (mime_part)->headers, "Content-Md5", content_md5); }
static void mime_foreach_callback (GMimeObject * parent, GMimeObject * part, gpointer user_data) { GMimeContentType *type; if (GMIME_IS_MESSAGE_PART (part)) { /* message/rfc822 or message/news */ GMimeMessage *message; /* g_mime_message_foreach_part() won't descend into child message parts, so if we want to count any subparts of this child message, we'll have to call g_mime_message_foreach_part() again here. */ rspamd_printf ("got message part %p: parent: %p\n", part, parent); message = g_mime_message_part_get_message ((GMimeMessagePart *) part); g_mime_message_foreach (message, mime_foreach_callback, part); } else if (GMIME_IS_MULTIPART (part)) { type = (GMimeContentType *) g_mime_object_get_content_type (GMIME_OBJECT ( part)); rspamd_printf ("got multipart part %p, boundary: %s: parent: %p, type: %s/%s\n", part, g_mime_multipart_get_boundary (GMIME_MULTIPART(part)), parent, g_mime_content_type_get_media_type (type), g_mime_content_type_get_media_subtype (type)); } else { type = (GMimeContentType *) g_mime_object_get_content_type (GMIME_OBJECT ( part)); rspamd_printf ("got normal part %p, parent: %p, type: %s/%s\n", part, parent, g_mime_content_type_get_media_type (type), g_mime_content_type_get_media_subtype (type)); } }
/* Write a MIME text part out to the given stream. * * If (flags & NOTMUCH_SHOW_TEXT_PART_REPLY), this prepends "> " to * each output line. * * Both line-ending conversion (CRLF->LF) and charset conversion ( -> * UTF-8) will be performed, so it is inappropriate to call this * function with a non-text part. Doing so will trigger an internal * error. */ void show_text_part_content (GMimeObject *part, GMimeStream *stream_out, notmuch_show_text_part_flags flags) { GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part)); GMimeStream *stream_filter = NULL; GMimeDataWrapper *wrapper; const char *charset; if (! g_mime_content_type_is_type (content_type, "text", "*")) INTERNAL_ERROR ("Illegal request to format non-text part (%s) as text.", g_mime_content_type_to_string (content_type)); if (stream_out == NULL) return; stream_filter = g_mime_stream_filter_new (stream_out); g_mime_stream_filter_add(GMIME_STREAM_FILTER (stream_filter), g_mime_filter_crlf_new (FALSE, FALSE)); charset = g_mime_object_get_content_type_parameter (part, "charset"); if (charset) { GMimeFilter *charset_filter; charset_filter = g_mime_filter_charset_new (charset, "UTF-8"); /* This result can be NULL for things like "unknown-8bit". * Don't set a NULL filter as that makes GMime print * annoying assertion-failure messages on stderr. */ if (charset_filter) { g_mime_stream_filter_add (GMIME_STREAM_FILTER (stream_filter), charset_filter); g_object_unref (charset_filter); } } if (flags & NOTMUCH_SHOW_TEXT_PART_REPLY) { GMimeFilter *reply_filter; reply_filter = g_mime_filter_reply_new (TRUE); if (reply_filter) { g_mime_stream_filter_add (GMIME_STREAM_FILTER (stream_filter), reply_filter); g_object_unref (reply_filter); } } wrapper = g_mime_part_get_content_object (GMIME_PART (part)); if (wrapper && stream_filter) g_mime_data_wrapper_write_to_stream (wrapper, stream_filter); if (stream_filter) g_object_unref(stream_filter); }
/* * when a part doesn't have a filename, it can be useful to 'guess' one based on * its mime-type, which allows other tools to handle them correctly, e.g. from * mu4e. * * For now, we only handle calendar invitations in that way, but others may * follow. */ static char* guess_file_name (GMimeObject *mobj, unsigned index) { GMimeContentType *ctype; ctype = g_mime_object_get_content_type (mobj); /* special case for calendars; map to '.vcs' */ if (g_mime_content_type_is_type (ctype, "text", "calendar")) return g_strdup_printf ("vcal-%u.vcs", index); /* fallback */ return g_strdup_printf ("%u.msgpart", index); }
static void reply_part_content (GMimeObject *part) { GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part)); GMimeContentDisposition *disposition = g_mime_object_get_content_disposition (part); if (g_mime_content_type_is_type (content_type, "text", "*") && !g_mime_content_type_is_type (content_type, "text", "html")) { GMimeStream *stream_stdout = NULL, *stream_filter = NULL; GMimeDataWrapper *wrapper; const char *charset; charset = g_mime_object_get_content_type_parameter (part, "charset"); stream_stdout = g_mime_stream_file_new (stdout); if (stream_stdout) { g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE); stream_filter = g_mime_stream_filter_new(stream_stdout); if (charset) { g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter), g_mime_filter_charset_new(charset, "UTF-8")); } } g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter), g_mime_filter_reply_new(TRUE)); wrapper = g_mime_part_get_content_object (GMIME_PART (part)); if (wrapper && stream_filter) g_mime_data_wrapper_write_to_stream (wrapper, stream_filter); if (stream_filter) g_object_unref(stream_filter); if (stream_stdout) g_object_unref(stream_stdout); } else { if (disposition && strcmp (disposition->disposition, GMIME_DISPOSITION_ATTACHMENT) == 0) { const char *filename = g_mime_part_get_filename (GMIME_PART (part)); printf ("Attachment: %s (%s)\n", filename, g_mime_content_type_to_string (content_type)); } else { printf ("Non-text part: %s\n", g_mime_content_type_to_string (content_type)); } } }
static void accumulate_text_part (MuMsg *msg, MuMsgPart *part, GString **gstrp) { GMimeContentType *ctype; gboolean err; char *txt; ctype = g_mime_object_get_content_type ((GMimeObject*)part->data); if (!g_mime_content_type_is_type (ctype, "text", "plain")) return; /* not plain text */ txt = mu_msg_mime_part_to_string ((GMimePart*)part->data, &err); if (txt) g_string_append (*gstrp, txt); g_free (txt); }
/** * g_mime_part_verify_content_md5: * @mime_part: a #GMimePart object * * Verify the content md5 for the specified mime part. * * Returns: %TRUE if the md5 is valid or %FALSE otherwise. Note: will * return %FALSE if the mime part does not contain a Content-MD5. **/ gboolean g_mime_part_verify_content_md5 (GMimePart *mime_part) { unsigned char digest[16], b64digest[32]; GMimeStreamFilter *filtered_stream; GMimeContentType *content_type; GMimeFilter *md5_filter; GMimeStream *stream; guint32 save = 0; int state = 0; size_t len; g_return_val_if_fail (GMIME_IS_PART (mime_part), FALSE); g_return_val_if_fail (mime_part->content != NULL, FALSE); if (!mime_part->content_md5) return FALSE; stream = g_mime_stream_null_new (); filtered_stream = (GMimeStreamFilter *) g_mime_stream_filter_new (stream); g_object_unref (stream); content_type = g_mime_object_get_content_type ((GMimeObject *) mime_part); if (g_mime_content_type_is_type (content_type, "text", "*")) { GMimeFilter *crlf_filter; crlf_filter = g_mime_filter_crlf_new (TRUE, FALSE); g_mime_stream_filter_add (filtered_stream, crlf_filter); g_object_unref (crlf_filter); } md5_filter = g_mime_filter_md5_new (); g_mime_stream_filter_add (filtered_stream, md5_filter); stream = (GMimeStream *) filtered_stream; g_mime_data_wrapper_write_to_stream (mime_part->content, stream); g_object_unref (stream); memset (digest, 0, 16); g_mime_filter_md5_get_digest ((GMimeFilterMd5 *) md5_filter, digest); g_object_unref (md5_filter); len = g_mime_encoding_base64_encode_close (digest, 16, b64digest, &state, &save); b64digest[len] = '\0'; g_strstrip ((char *) b64digest); return !strcmp ((char *) b64digest, mime_part->content_md5); }
static void format_part_content_json (GMimeObject *part) { GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part)); GMimeStream *stream_memory = g_mime_stream_mem_new (); const char *cid = g_mime_object_get_content_id (part); void *ctx = talloc_new (NULL); GByteArray *part_content; printf (", \"content-type\": %s", json_quote_str (ctx, g_mime_content_type_to_string (content_type))); if (cid != NULL) printf(", \"content-id\": %s", json_quote_str (ctx, cid)); if (GMIME_IS_PART (part)) { const char *filename = g_mime_part_get_filename (GMIME_PART (part)); if (filename) printf (", \"filename\": %s", json_quote_str (ctx, filename)); } if (g_mime_content_type_is_type (content_type, "text", "*") && !g_mime_content_type_is_type (content_type, "text", "html")) { show_text_part_content (part, stream_memory); part_content = g_mime_stream_mem_get_byte_array (GMIME_STREAM_MEM (stream_memory)); printf (", \"content\": %s", json_quote_chararray (ctx, (char *) part_content->data, part_content->len)); } else if (g_mime_content_type_is_type (content_type, "multipart", "*")) { printf (", \"content\": ["); } else if (g_mime_content_type_is_type (content_type, "message", "rfc822")) { printf (", \"content\": [{"); } talloc_free (ctx); if (stream_memory) g_object_unref (stream_memory); }
MuxMessagePart* mux_message_part_new (const char *path, GMimeObject *mobj) { MuxMessagePart *self; g_return_val_if_fail (path, NULL); g_return_val_if_fail (GMIME_IS_OBJECT(mobj), NULL); self = MUX_MESSAGE_PART(g_object_new(MUX_TYPE_MESSAGE_PART, NULL)); self->path = ext_path (path); self->content_type = g_mime_object_get_content_type (mobj); self->content_id = g_mime_object_get_content_id (mobj); self->content_disposition = g_mime_object_get_content_disposition (mobj); if (GMIME_IS_PART (mobj)) self->file_name = g_mime_part_get_filename ((GMimePart*)mobj); self->mime_object = g_object_ref (mobj); return self; }
static void format_part_content_text (GMimeObject *part) { const char *cid = g_mime_object_get_content_id (part); GMimeContentType *content_type = g_mime_object_get_content_type (GMIME_OBJECT (part)); if (GMIME_IS_PART (part)) { const char *filename = g_mime_part_get_filename (GMIME_PART (part)); if (filename) printf (", Filename: %s", filename); } if (cid) printf (", Content-id: %s", cid); printf (", Content-type: %s\n", g_mime_content_type_to_string (content_type)); if (g_mime_content_type_is_type (content_type, "text", "*") && !g_mime_content_type_is_type (content_type, "text", "html")) { GMimeStream *stream_stdout = g_mime_stream_file_new (stdout); g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE); show_text_part_content (part, stream_stdout); g_object_unref(stream_stdout); } else if (g_mime_content_type_is_type (content_type, "multipart", "*") || g_mime_content_type_is_type (content_type, "message", "rfc822")) { /* Do nothing for multipart since its content will be printed * when recursing. */ } else { printf ("Non-text part: %s\n", g_mime_content_type_to_string (content_type)); } }
static void print_mime_struct (GMimeStream *stream, GMimeObject *part, int depth) { GMimeMultipart *multipart; GMimeMessagePart *mpart; GMimeContentType *type; GMimeObject *subpart; GMimeObject *body; GMimeMessage *msg; int i, n; print_depth (stream, depth); type = g_mime_object_get_content_type (part); g_mime_stream_printf (stream, "Content-Type: %s/%s\n", g_mime_content_type_get_media_type (type), g_mime_content_type_get_media_subtype (type)); if (GMIME_IS_MULTIPART (part)) { multipart = (GMimeMultipart *) part; n = g_mime_multipart_get_count (multipart); for (i = 0; i < n; i++) { subpart = g_mime_multipart_get_part (multipart, i); print_mime_struct (stream, subpart, depth + 1); } } else if (GMIME_IS_MESSAGE_PART (part)) { mpart = (GMimeMessagePart *) part; msg = g_mime_message_part_get_message (mpart); if (msg != NULL) { body = g_mime_message_get_mime_part (msg); print_mime_struct (stream, body, depth + 1); } } }
static void write_part(GMimeObject *part) { GList *l; const GMimeContentType *ct; ct = g_mime_object_get_content_type(GMIME_OBJECT(part)); if (GMIME_IS_MULTIPART(part)) { if (g_mime_content_type_is_type(ct, "multipart", "alternative")) { choose_alternative(part); level += g_list_length(GMIME_MULTIPART(part)->subparts); } else { l = GMIME_MULTIPART(part)->subparts; while (l != NULL) { write_part(l->data); l = l->next; level++; } } } else if (GMIME_IS_MESSAGE_PART(part)) { } else if (GMIME_IS_PART(part)) { display_part(part, ct); } }
void AnalyseMessageParse(GMimePart * mime_part) { int ichar=0,iencode =0; if( NULL==mime_part ) { printf("empty part\n"); return ; } GMimeContentEncoding ReEncoding = g_mime_part_get_content_encoding(mime_part); char* szCharset = (char*)g_mime_object_get_content_type_parameter((GMimeObject*)mime_part,"charset"); printf("charset %s\n",szCharset); { char* szCharset = (char*)g_mime_object_get_content_type_parameter((GMimeObject*)mime_part,"name"); printf("name %s\n",szCharset); GMimeContentType* pContentType = g_mime_object_get_content_type((GMimeObject*)mime_part) ; printf("The content type is: (%s/%s)\n",pContentType->type,pContentType->subtype); const char * ppp= g_mime_object_get_disposition((GMimeObject*)mime_part); if(!ppp) { goto exits; } const char * qqq=g_mime_object_get_content_disposition_parameter((GMimeObject*)mime_part,"filename"); printf("get disposition\t%s\n%s\n",ppp,qqq); if(qqq) { FILE * ps=fopen(qqq,"w+b"); printf("\n=======write to file================\n" ); GMimeStream *stream = g_mime_stream_file_new (ps); GMimeDataWrapper * content=g_mime_part_get_content_object(mime_part); g_mime_data_wrapper_write_to_stream(content,stream); fclose(ps); printf("finish writing\n"); getchar(); return ; } } exits:{} /*decode for text/plain or html*/ GMimeDataWrapper *dataWrap = g_mime_part_get_content_object(mime_part); if(!dataWrap) printf("error in dataWrap\n" ); GMimeStream * gmime_stream= g_mime_data_wrapper_get_stream(dataWrap); //encoding转码 GMimeFilter * pAttFilter = g_mime_filter_basic_new(ReEncoding,FALSE); GMimeStream* pFilterStream = g_mime_stream_filter_new(gmime_stream); iencode = g_mime_stream_filter_add (GMIME_STREAM_FILTER (pFilterStream), pAttFilter); /*create a filter convert the charset into local type*/ GMimeFilter * secondPtr = g_mime_filter_charset_new(szCharset,g_mime_charset_locale_name()); ichar = g_mime_stream_filter_add (GMIME_STREAM_FILTER (pFilterStream), secondPtr); /*convert stream into stdout*/ GMimeStream *stream = g_mime_stream_file_new (stdout); g_mime_stream_write_to_stream(pFilterStream,stream); #if 0 /*get data from stream load into char* */ char pp[10000]= {0}; int tt=g_mime_stream_read(pFilterStream,pp,10000); printf("%d\t%s\n",tt,pp); #endif g_object_unref ( pAttFilter ); g_object_unref ( secondPtr ); g_mime_stream_filter_remove((GMimeStreamFilter*)pFilterStream,ichar); g_mime_stream_filter_remove((GMimeStreamFilter*)pFilterStream,iencode); g_object_unref (pFilterStream); //g_object_unref (gmime_stream); //g_object_unref (stream); //if(NULL==szCharset) { printf("\n====>>>>====>>>>====>>>>Finish decoding this part<<<<====<<<<====<<<<====\n"); getchar(); //return ; } return ; }
/** * Output a list of the parts included in the current message. */ void dump_mail( char *filename ) { std::string result; GMimeMessage *m_message; GMimeParser *parser; GMimeStream *stream; int fd; std::cout << "File: " << filename << std::endl; if ((fd = open( filename, O_RDONLY, 0)) == -1) { std::cout << "Opening failed ..." << std::endl; return; } stream = g_mime_stream_fs_new (fd); parser = g_mime_parser_new_with_stream (stream); g_object_unref (stream); m_message = g_mime_parser_construct_message (parser); g_object_unref (parser); /** * Create an iterator */ GMimePartIter *iter = g_mime_part_iter_new ((GMimeObject *) m_message); int count = 1; /** * Iterate over the message. */ do { GMimeObject *part = g_mime_part_iter_get_current (iter); if ( ( GMIME_IS_OBJECT( part ) ) && ( GMIME_IS_PART(part) ) ) { /** * Get the content-type */ GMimeContentType *content_type = g_mime_object_get_content_type (part); const char *filename = g_mime_object_get_content_disposition_parameter(part, "filename"); gchar *type = g_mime_content_type_to_string ( content_type ); std::cout << count << " " << type << std::endl; if ( filename ) std::cout << "\t[This is an attachment with file-name " << filename << "]" << std::endl; } /** * Highlight inline parts - which are not attachments. */ GMimeContentDisposition *disp = g_mime_object_get_content_disposition(part); if ( disp != NULL ) { const char *str = g_mime_content_disposition_get_disposition (disp); std::cout << "\tNOTE: Content-Disposition: " << str << std::endl; } count += 1; } while (g_mime_part_iter_next (iter)); g_mime_part_iter_free (iter); g_object_unref(m_message); }
GMimeObject * g_mime_gpgme_mpe_decrypt(GMimeMultipartEncrypted * mpe, GMimeGpgmeSigstat ** signature, GtkWindow * parent, GError ** err) { GMimeObject *decrypted, *version, *encrypted; GMimeStream *stream, *ciphertext; GMimeStream *filtered_stream; GMimeContentType *mime_type; GMimeGpgmeSigstat *sigstat; GMimeDataWrapper *wrapper; GMimeFilter *crlf_filter; GMimeParser *parser; const char *protocol; char *content_type; g_return_val_if_fail(GMIME_IS_MULTIPART_ENCRYPTED(mpe), NULL); if (signature && *signature) { g_object_unref(G_OBJECT(*signature)); *signature = NULL; } protocol = g_mime_object_get_content_type_parameter(GMIME_OBJECT(mpe), "protocol"); /* make sure the protocol is present and matches the cipher encrypt protocol */ if (!protocol || g_ascii_strcasecmp("application/pgp-encrypted", protocol) != 0) { g_set_error(err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR, _ ("Cannot decrypt multipart/encrypted part: unsupported encryption protocol “%s”."), protocol ? protocol : _("(none)")); return NULL; } version = g_mime_multipart_get_part(GMIME_MULTIPART(mpe), GMIME_MULTIPART_ENCRYPTED_VERSION); /* make sure the protocol matches the version part's content-type */ content_type = g_mime_content_type_to_string(version->content_type); if (g_ascii_strcasecmp(content_type, protocol) != 0) { g_set_error(err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR, "%s", _ ("Cannot decrypt multipart/encrypted part: content-type does not match protocol.")); g_free(content_type); return NULL; } g_free(content_type); /* get the encrypted part and check that it is of type application/octet-stream */ encrypted = g_mime_multipart_get_part(GMIME_MULTIPART(mpe), GMIME_MULTIPART_ENCRYPTED_CONTENT); mime_type = g_mime_object_get_content_type(encrypted); if (!g_mime_content_type_is_type (mime_type, "application", "octet-stream")) { g_set_error(err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR, "%s", _ ("Cannot decrypt multipart/encrypted part: unexpected content type")); return NULL; } /* get the ciphertext stream */ wrapper = g_mime_part_get_content_object(GMIME_PART(encrypted)); ciphertext = g_mime_data_wrapper_get_decoded_stream(wrapper); g_mime_stream_reset(ciphertext); stream = g_mime_stream_mem_new(); filtered_stream = g_mime_stream_filter_new(stream); crlf_filter = g_mime_filter_crlf_new(FALSE, FALSE); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_stream), crlf_filter); g_object_unref(crlf_filter); /* get the cleartext */ sigstat = libbalsa_gpgme_decrypt(ciphertext, filtered_stream, GPGME_PROTOCOL_OpenPGP, parent, err); if (!sigstat) { g_object_unref(filtered_stream); g_object_unref(ciphertext); g_object_unref(stream); return NULL; } g_mime_stream_flush(filtered_stream); g_object_unref(filtered_stream); g_object_unref(ciphertext); g_mime_stream_reset(stream); parser = g_mime_parser_new(); g_mime_parser_init_with_stream(parser, stream); g_object_unref(stream); decrypted = g_mime_parser_construct_part(parser); g_object_unref(parser); if (!decrypted) { g_set_error(err, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR, "%s", _ ("Cannot decrypt multipart/encrypted part: failed to parse decrypted content")); g_object_unref(G_OBJECT(sigstat)); return NULL; } /* cache the decrypted part */ if (signature) { if (sigstat->status != GPG_ERR_NOT_SIGNED) *signature = sigstat; else g_object_unref(G_OBJECT(sigstat)); } return decrypted; }
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; }
static void test_content_type_sync (void) { const char *raw_value, *value; GMimeHeaderList *headers; GMimeContentType *type; GMimeParamList *params; GMimeObject *object; GMimeHeader *header; GMimePart *part; object = (GMimeObject *) (part = g_mime_part_new ()); headers = g_mime_object_get_header_list (object); testsuite_check ("content-type synchronization"); try { /* first, check that the current Content-Type header * value is "application/octet-stream" as expected */ if (!(value = g_mime_object_get_header (object, "Content-Type"))) throw (exception_new ("initial content-type header was unexpectedly null")); if (strcmp ("application/octet-stream", value) != 0) throw (exception_new ("initial content-type header had unexpected value: %s", value)); /* now change the content-type's media type... */ type = g_mime_object_get_content_type (object); g_mime_content_type_set_media_type (type, "text"); if (!(value = g_mime_object_get_header (object, "Content-Type"))) throw (exception_new ("content-type header was unexpectedly null after changing type")); if (strcmp ("text/octet-stream", value) != 0) throw (exception_new ("content-type header had unexpected value after changing type")); header = g_mime_header_list_get_header (headers, "Content-Type"); if (!(raw_value = g_mime_header_get_raw_value (header))) throw (exception_new ("content-type raw_value was unexpectedly null after changing type")); if (strcmp (" text/octet-stream\n", raw_value) != 0) throw (exception_new ("content-type raw_value had unexpected value after changing type")); /* now change the content-type's media subtype... */ g_mime_content_type_set_media_subtype (type, "plain"); if (!(value = g_mime_object_get_header (object, "Content-Type"))) throw (exception_new ("content-type header was unexpectedly null after changing subtype")); if (strcmp ("text/plain", value) != 0) throw (exception_new ("content-type header had unexpected value after changing subtype")); header = g_mime_header_list_get_header (headers, "Content-Type"); if (!(raw_value = g_mime_header_get_raw_value (header))) throw (exception_new ("content-type raw_value was unexpectedly null after changing subtype")); if (strcmp (" text/plain\n", raw_value) != 0) throw (exception_new ("content-type raw_value had unexpected value after changing subtype")); /* now change the content-type's parameters by setting a param */ g_mime_content_type_set_parameter (type, "format", "flowed"); if (!(value = g_mime_object_get_header (object, "Content-Type"))) throw (exception_new ("content-type header was unexpectedly null after setting a param")); if (strcmp ("text/plain; format=flowed", value) != 0) throw (exception_new ("content-type header had unexpected value after setting a param")); header = g_mime_header_list_get_header (headers, "Content-Type"); if (!(raw_value = g_mime_header_get_raw_value (header))) throw (exception_new ("content-type raw_value was unexpectedly null after setting a param")); if (strcmp (" text/plain; format=flowed\n", raw_value) != 0) throw (exception_new ("content-type raw_value had unexpected value after setting a param")); /* now change the content-type's parameters by clearing the params */ params = g_mime_content_type_get_parameters (type); g_mime_param_list_clear (params); if (!(value = g_mime_object_get_header (object, "Content-Type"))) throw (exception_new ("content-type header was unexpectedly null after clearing params")); if (strcmp ("text/plain", value) != 0) throw (exception_new ("content-type header had unexpected value after clearing params")); header = g_mime_header_list_get_header (headers, "Content-Type"); if (!(raw_value = g_mime_header_get_raw_value (header))) throw (exception_new ("content-type raw_value was unexpectedly null after clearing params")); if (strcmp (" text/plain\n", raw_value) != 0) throw (exception_new ("content-type raw_value had unexpected value after clearing params")); /* let's try this in reverse... set the header value and make sure GMimeContentType gets updated */ header = g_mime_header_list_get_header_at (headers, 0); g_mime_header_set_value (header, NULL, "text/html; charset=utf-8", NULL); type = g_mime_object_get_content_type (object); if (!g_mime_content_type_is_type (type, "text", "html")) throw (exception_new ("GMimeContentType object was not updated")); header = g_mime_header_list_get_header (headers, "Content-Type"); if (!(raw_value = g_mime_header_get_raw_value (header))) throw (exception_new ("content-type raw_value was unexpectedly null after setting value")); if (strcmp (" text/html; charset=utf-8\n", raw_value) != 0) throw (exception_new ("content-type raw_value had unexpected value after setting value")); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("content-type header not synchronized: %s", ex->message); } finally; g_object_unref (part); }
gboolean g_mime_gpgme_mps_sign(GMimeMultipartSigned * mps, GMimeObject * content, const gchar * userid, gpgme_protocol_t protocol, GtkWindow * parent, GError ** err) { GMimeStream *stream; GMimeStream *filtered; GMimeStream *sigstream; GMimeFilter *filter; GMimeContentType *content_type; GMimeDataWrapper *wrapper; GMimeParser *parser; GMimePart *signature; gchar *micalg; const gchar *proto_type; const gchar *sig_subtype; gpgme_hash_algo_t hash_algo; g_return_val_if_fail(GMIME_IS_MULTIPART_SIGNED(mps), FALSE); g_return_val_if_fail(GMIME_IS_OBJECT(content), FALSE); /* Prepare all the parts for signing... */ sign_prepare(content); /* get the cleartext */ stream = g_mime_stream_mem_new(); filtered = g_mime_stream_filter_new(stream); /* Note: see rfc3156, section 3 - second note */ filter = g_mime_filter_from_new(GMIME_FILTER_FROM_MODE_ARMOR); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered), filter); g_object_unref(filter); /* Note: see rfc3156, section 5.4 (this is the main difference between rfc2015 and rfc3156) */ filter = g_mime_filter_strip_new(); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered), filter); g_object_unref(filter); g_mime_object_write_to_stream(content, filtered); g_mime_stream_flush(filtered); g_object_unref(filtered); g_mime_stream_reset(stream); /* Note: see rfc2015 or rfc3156, section 5.1 */ filtered = g_mime_stream_filter_new(stream); filter = g_mime_filter_crlf_new(TRUE, FALSE); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered), filter); g_object_unref(filter); /* construct the signature stream */ sigstream = g_mime_stream_mem_new(); /* sign the content stream */ hash_algo = libbalsa_gpgme_sign(userid, filtered, sigstream, protocol, FALSE, parent, err); g_object_unref(filtered); if (hash_algo == GPGME_MD_NONE) { g_object_unref(sigstream); g_object_unref(stream); return FALSE; } g_mime_stream_reset(sigstream); g_mime_stream_reset(stream); /* set the multipart/signed protocol and micalg */ content_type = g_mime_object_get_content_type(GMIME_OBJECT(mps)); if (protocol == GPGME_PROTOCOL_OpenPGP) { micalg = g_strdup_printf("PGP-%s", gpgme_hash_algo_name(hash_algo)); proto_type = "application/pgp-signature"; sig_subtype = "pgp-signature"; } else { micalg = g_strdup(gpgme_hash_algo_name(hash_algo)); proto_type = "application/pkcs7-signature"; sig_subtype = "pkcs7-signature"; } g_mime_content_type_set_parameter(content_type, "micalg", micalg); g_free(micalg); g_mime_content_type_set_parameter(content_type, "protocol", proto_type); g_mime_multipart_set_boundary(GMIME_MULTIPART(mps), NULL); /* construct the content part */ parser = g_mime_parser_new_with_stream(stream); content = g_mime_parser_construct_part(parser); g_object_unref(stream); g_object_unref(parser); /* construct the signature part */ signature = g_mime_part_new_with_type("application", sig_subtype); wrapper = g_mime_data_wrapper_new(); g_mime_data_wrapper_set_stream(wrapper, sigstream); g_mime_part_set_content_object(signature, wrapper); g_object_unref(sigstream); g_object_unref(wrapper); /* FIXME: temporary hack, this info should probably be set in * the CipherContext class - maybe ::sign can take/output a * GMimePart instead. */ if (protocol == GPGME_PROTOCOL_CMS) { g_mime_part_set_content_encoding(signature, GMIME_CONTENT_ENCODING_BASE64); g_mime_part_set_filename(signature, "smime.p7m"); } /* save the content and signature parts */ /* FIXME: make sure there aren't any other parts?? */ g_mime_multipart_add(GMIME_MULTIPART(mps), content); g_mime_multipart_add(GMIME_MULTIPART(mps), (GMimeObject *) signature); g_object_unref(signature); g_object_unref(content); return TRUE; }
void format_part_json (const void *ctx, mime_node_t *node, notmuch_bool_t first) { /* Any changes to the JSON format should be reflected in the file * devel/schemata. */ if (node->envelope_file) { printf ("{"); format_message_json (ctx, node->envelope_file); printf ("\"headers\": "); format_headers_json (ctx, GMIME_MESSAGE (node->part), FALSE); printf (", \"body\": ["); format_part_json (ctx, mime_node_child (node, 0), first); printf ("]}"); return; } void *local = talloc_new (ctx); /* The disposition and content-type metadata are associated with * the envelope for message parts */ GMimeObject *meta = node->envelope_part ? GMIME_OBJECT (node->envelope_part) : node->part; GMimeContentType *content_type = g_mime_object_get_content_type (meta); const char *cid = g_mime_object_get_content_id (meta); const char *filename = GMIME_IS_PART (node->part) ? g_mime_part_get_filename (GMIME_PART (node->part)) : NULL; const char *terminator = ""; int i; if (!first) printf (", "); printf ("{\"id\": %d", node->part_num); if (node->decrypt_attempted) printf (", \"encstatus\": [{\"status\": \"%s\"}]", node->decrypt_success ? "good" : "bad"); if (node->verify_attempted) { printf (", \"sigstatus\": "); format_part_sigstatus_json (node); } printf (", \"content-type\": %s", json_quote_str (local, g_mime_content_type_to_string (content_type))); if (cid) printf (", \"content-id\": %s", json_quote_str (local, cid)); if (filename) printf (", \"filename\": %s", json_quote_str (local, filename)); if (GMIME_IS_PART (node->part)) { /* For non-HTML text parts, we include the content in the * JSON. Since JSON must be Unicode, we handle charset * decoding here and do not report a charset to the caller. * For text/html parts, we do not include the content. If a * caller is interested in text/html parts, it should retrieve * them separately and they will not be decoded. Since this * makes charset decoding the responsibility on the caller, we * report the charset for text/html parts. */ if (g_mime_content_type_is_type (content_type, "text", "html")) { const char *content_charset = g_mime_object_get_content_type_parameter (meta, "charset"); if (content_charset != NULL) printf (", \"content-charset\": %s", json_quote_str (local, content_charset)); } else if (g_mime_content_type_is_type (content_type, "text", "*")) { GMimeStream *stream_memory = g_mime_stream_mem_new (); GByteArray *part_content; show_text_part_content (node->part, stream_memory, 0); part_content = g_mime_stream_mem_get_byte_array (GMIME_STREAM_MEM (stream_memory)); printf (", \"content\": %s", json_quote_chararray (local, (char *) part_content->data, part_content->len)); g_object_unref (stream_memory); } } else if (GMIME_IS_MULTIPART (node->part)) { printf (", \"content\": ["); terminator = "]"; } else if (GMIME_IS_MESSAGE (node->part)) { printf (", \"content\": [{"); printf ("\"headers\": "); format_headers_json (local, GMIME_MESSAGE (node->part), FALSE); printf (", \"body\": ["); terminator = "]}]"; } talloc_free (local); for (i = 0; i < node->nchildren; i++) format_part_json (ctx, mime_node_child (node, i), i == 0); printf ("%s}", terminator); }
static notmuch_status_t format_part_text (const void *ctx, mime_node_t *node, int indent, const notmuch_show_params_t *params) { /* The disposition and content-type metadata are associated with * the envelope for message parts */ GMimeObject *meta = node->envelope_part ? GMIME_OBJECT (node->envelope_part) : node->part; GMimeContentType *content_type = g_mime_object_get_content_type (meta); const notmuch_bool_t leaf = GMIME_IS_PART (node->part); const char *part_type; int i; if (node->envelope_file) { notmuch_message_t *message = node->envelope_file; part_type = "message"; printf ("\f%s{ id:%s depth:%d match:%d excluded:%d filename:%s\n", part_type, notmuch_message_get_message_id (message), indent, notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH) ? 1 : 0, notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_EXCLUDED) ? 1 : 0, notmuch_message_get_filename (message)); } else { GMimeContentDisposition *disposition = g_mime_object_get_content_disposition (meta); const char *cid = g_mime_object_get_content_id (meta); const char *filename = leaf ? g_mime_part_get_filename (GMIME_PART (node->part)) : NULL; if (disposition && strcmp (disposition->disposition, GMIME_DISPOSITION_ATTACHMENT) == 0) part_type = "attachment"; else part_type = "part"; printf ("\f%s{ ID: %d", part_type, node->part_num); if (filename) printf (", Filename: %s", filename); if (cid) printf (", Content-id: %s", cid); printf (", Content-type: %s\n", g_mime_content_type_to_string (content_type)); } if (GMIME_IS_MESSAGE (node->part)) { GMimeMessage *message = GMIME_MESSAGE (node->part); InternetAddressList *recipients; const char *recipients_string; printf ("\fheader{\n"); if (node->envelope_file) printf ("%s\n", _get_one_line_summary (ctx, node->envelope_file)); printf ("Subject: %s\n", g_mime_message_get_subject (message)); printf ("From: %s\n", g_mime_message_get_sender (message)); recipients = g_mime_message_get_recipients (message, GMIME_RECIPIENT_TYPE_TO); recipients_string = internet_address_list_to_string (recipients, 0); if (recipients_string) printf ("To: %s\n", recipients_string); recipients = g_mime_message_get_recipients (message, GMIME_RECIPIENT_TYPE_CC); recipients_string = internet_address_list_to_string (recipients, 0); if (recipients_string) printf ("Cc: %s\n", recipients_string); printf ("Date: %s\n", g_mime_message_get_date_as_string (message)); printf ("\fheader}\n"); printf ("\fbody{\n"); } if (leaf) { if (g_mime_content_type_is_type (content_type, "text", "*") && !g_mime_content_type_is_type (content_type, "text", "html")) { GMimeStream *stream_stdout = g_mime_stream_file_new (stdout); g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE); show_text_part_content (node->part, stream_stdout, 0); g_object_unref(stream_stdout); } else { printf ("Non-text part: %s\n", g_mime_content_type_to_string (content_type)); } } for (i = 0; i < node->nchildren; i++) format_part_text (ctx, mime_node_child (node, i), indent, params); if (GMIME_IS_MESSAGE (node->part)) printf ("\fbody}\n"); printf ("\f%s}\n", part_type); return NOTMUCH_STATUS_SUCCESS; }
static void collect_part(GMimeObject *part, PartCollectorData *fdata, gboolean multipart_parent) { GMimeContentType *content_type = g_mime_object_get_content_type(part); GMimeContentDisposition *disposition = g_mime_object_get_content_disposition(part); if (!content_type) return; GMimeDataWrapper *wrapper = g_mime_part_get_content_object(GMIME_PART(part)); if (!wrapper) return; // All the information will be collected in the CollectedPart CollectedPart *c_part = new_collected_part(fdata->part_id); gboolean is_attachment = FALSE; if (disposition) { c_part->disposition = g_ascii_strdown(disposition->disposition, -1); is_attachment = !g_ascii_strcasecmp(disposition->disposition, GMIME_DISPOSITION_ATTACHMENT); } // If a filename is given, collect it always const gchar *filename = g_mime_part_get_filename(GMIME_PART(part)); if (filename) c_part->filename = g_strdup(filename); // If a contentID is given, collect it always const char* content_id = g_mime_part_get_content_id (GMIME_PART(part)); if (content_id) c_part->content_id = g_strdup(content_id); // Get the contentType in lowercase gchar *content_type_str = g_mime_content_type_to_string(content_type); c_part->content_type = g_ascii_strdown(content_type_str, -1); g_free(content_type_str); // To qualify as a message body, a MIME entity MUST NOT have a Content-Disposition header with the value "attachment". if (!is_attachment && g_mime_content_type_is_type(content_type, "text", "*")) { gboolean is_text_plain = g_mime_content_type_is_type(content_type, "text", "plain"); gboolean is_text_html = g_mime_content_type_is_type(content_type, "text", "html"); gboolean is_text_rtf = g_mime_content_type_is_type(content_type, "text", "rtf"); gboolean is_text_enriched = g_mime_content_type_is_type(content_type, "text", "enriched"); gboolean is_new_text = !fdata->text_part && is_text_plain; gboolean is_new_html = !fdata->html_part && (is_text_html || is_text_enriched || is_text_rtf); GMimeStream *mem_stream = g_mime_stream_mem_new(); g_mime_stream_mem_set_owner(GMIME_STREAM_MEM(mem_stream), FALSE); GMimeStream *filtered_mem_stream = g_mime_stream_filter_new(mem_stream); const gchar *charset = g_mime_object_get_content_type_parameter(part, "charset"); if (charset && g_ascii_strcasecmp(charset, UTF8_CHARSET)) { GMimeFilter *utf8_charset_filter = g_mime_filter_charset_new(charset, UTF8_CHARSET); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_mem_stream), utf8_charset_filter); g_object_unref(utf8_charset_filter); } if (!fdata->raw && is_new_text) { GMimeFilter *strip_filter = g_mime_filter_strip_new(); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_mem_stream), strip_filter); g_object_unref(strip_filter); GMimeFilter *crlf_filter = g_mime_filter_crlf_new(FALSE, FALSE); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_mem_stream), crlf_filter); g_object_unref(crlf_filter); GMimeFilter *html_filter = g_mime_filter_html_new( GMIME_FILTER_HTML_CONVERT_NL | GMIME_FILTER_HTML_CONVERT_SPACES | GMIME_FILTER_HTML_CONVERT_URLS | GMIME_FILTER_HTML_MARK_CITATION | GMIME_FILTER_HTML_CONVERT_ADDRESSES | GMIME_FILTER_HTML_CITE, CITATION_COLOUR); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_mem_stream), html_filter); g_object_unref(html_filter); } if (!fdata->raw && (is_new_text || is_new_html)) { GMimeFilter *from_filter = g_mime_filter_from_new(GMIME_FILTER_FROM_MODE_ESCAPE); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_mem_stream), from_filter); g_object_unref(from_filter); } // Add Enriched/RTF filter for this content if (!fdata->raw && (is_new_html && (is_text_enriched || is_text_rtf))) { guint flags = 0; if (is_text_rtf) flags = GMIME_FILTER_ENRICHED_IS_RICHTEXT; GMimeFilter *enriched_filter = g_mime_filter_enriched_new(flags); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_mem_stream), enriched_filter); g_object_unref(enriched_filter); } g_mime_data_wrapper_write_to_stream(wrapper, filtered_mem_stream); // Very important! Flush the the stream and get all content through. g_mime_stream_flush(filtered_mem_stream); // Freed by the mem_stream on its own (owner) [transfer none] c_part->content = g_mime_stream_mem_get_byte_array(GMIME_STREAM_MEM(mem_stream)); // After we unref the mem_stream, part_content is NOT available anymore g_object_unref(filtered_mem_stream); g_object_unref(mem_stream); // Without content, the collected body part is of no use, so we ignore it. if (c_part->content->len == 0) { free_collected_part(c_part); return; } // We accept only the first text and first html content, everything // else is considered an alternative body if (is_new_text) { fdata->text_part = c_part; } else if (is_new_html) { fdata->html_part = c_part; } else { g_ptr_array_add(fdata->alternative_bodies, c_part); } } else { GMimeStream *attachment_mem_stream = g_mime_stream_mem_new(); g_mime_stream_mem_set_owner (GMIME_STREAM_MEM(attachment_mem_stream), FALSE); g_mime_data_wrapper_write_to_stream(wrapper, attachment_mem_stream); g_mime_stream_flush(attachment_mem_stream); c_part->content = g_mime_stream_mem_get_byte_array(GMIME_STREAM_MEM(attachment_mem_stream)); g_object_unref(attachment_mem_stream); // Some content may not have disposition defined so we need to determine better what it is if ((disposition && !g_ascii_strcasecmp(disposition->disposition, GMIME_DISPOSITION_INLINE)) || g_mime_part_get_content_id(GMIME_PART(part))) { g_ptr_array_add(fdata->inlines, c_part); } else { // All other disposition should be kept within attachments g_ptr_array_add(fdata->attachments, c_part); } } }
void format_part_sprinter (const void *ctx, sprinter_t *sp, mime_node_t *node, notmuch_bool_t first, notmuch_bool_t output_body, notmuch_bool_t include_html) { /* Any changes to the JSON or S-Expression format should be * reflected in the file devel/schemata. */ if (node->envelope_file) { sp->begin_map (sp); format_message_sprinter (sp, node->envelope_file); sp->map_key (sp, "headers"); format_headers_sprinter (sp, GMIME_MESSAGE (node->part), FALSE); if (output_body) { sp->map_key (sp, "body"); sp->begin_list (sp); format_part_sprinter (ctx, sp, mime_node_child (node, 0), first, TRUE, include_html); sp->end (sp); } sp->end (sp); return; } /* The disposition and content-type metadata are associated with * the envelope for message parts */ GMimeObject *meta = node->envelope_part ? GMIME_OBJECT (node->envelope_part) : node->part; GMimeContentType *content_type = g_mime_object_get_content_type (meta); const char *cid = g_mime_object_get_content_id (meta); const char *filename = GMIME_IS_PART (node->part) ? g_mime_part_get_filename (GMIME_PART (node->part)) : NULL; int nclose = 0; int i; sp->begin_map (sp); sp->map_key (sp, "id"); sp->integer (sp, node->part_num); if (node->decrypt_attempted) { sp->map_key (sp, "encstatus"); sp->begin_list (sp); sp->begin_map (sp); sp->map_key (sp, "status"); sp->string (sp, node->decrypt_success ? "good" : "bad"); sp->end (sp); sp->end (sp); } if (node->verify_attempted) { sp->map_key (sp, "sigstatus"); format_part_sigstatus_sprinter (sp, node); } sp->map_key (sp, "content-type"); sp->string (sp, g_mime_content_type_to_string (content_type)); if (cid) { sp->map_key (sp, "content-id"); sp->string (sp, cid); } if (filename) { sp->map_key (sp, "filename"); sp->string (sp, filename); } if (GMIME_IS_PART (node->part)) { /* For non-HTML text parts, we include the content in the * JSON. Since JSON must be Unicode, we handle charset * decoding here and do not report a charset to the caller. * For text/html parts, we do not include the content unless * the --include-html option has been passed. If a html part * is not included, it can be requested directly. This makes * charset decoding the responsibility on the caller so we * report the charset for text/html parts. */ if (g_mime_content_type_is_type (content_type, "text", "*") && (include_html || ! g_mime_content_type_is_type (content_type, "text", "html"))) { GMimeStream *stream_memory = g_mime_stream_mem_new (); GByteArray *part_content; show_text_part_content (node->part, stream_memory, 0); part_content = g_mime_stream_mem_get_byte_array (GMIME_STREAM_MEM (stream_memory)); sp->map_key (sp, "content"); sp->string_len (sp, (char *) part_content->data, part_content->len); g_object_unref (stream_memory); } else { format_omitted_part_meta_sprinter (sp, meta, GMIME_PART (node->part)); } } else if (GMIME_IS_MULTIPART (node->part)) { sp->map_key (sp, "content"); sp->begin_list (sp); nclose = 1; } else if (GMIME_IS_MESSAGE (node->part)) { sp->map_key (sp, "content"); sp->begin_list (sp); sp->begin_map (sp); sp->map_key (sp, "headers"); format_headers_sprinter (sp, GMIME_MESSAGE (node->part), FALSE); sp->map_key (sp, "body"); sp->begin_list (sp); nclose = 3; } for (i = 0; i < node->nchildren; i++) format_part_sprinter (ctx, sp, mime_node_child (node, i), i == 0, TRUE, include_html); /* Close content structures */ for (i = 0; i < nclose; i++) sp->end (sp); /* Close part map */ sp->end (sp); }