static void pump_data_through_filter (GMimeFilter *filter, const char *path, GMimeStream *ostream, gboolean is_text, gboolean inc) { GMimeStream *onebyte, *filtered, *stream; GMimeFilter *dos2unix; filtered = g_mime_stream_filter_new (ostream); if (is_text) { /* canonicalize text input */ dos2unix = g_mime_filter_dos2unix_new (FALSE); g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, dos2unix); g_object_unref (dos2unix); } g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter); if (inc) { onebyte = test_stream_onebyte_new (filtered); g_object_unref (filtered); } else { onebyte = filtered; } stream = g_mime_stream_fs_open (path, O_RDONLY, 0644, NULL); g_mime_stream_write_to_stream (stream, onebyte); g_mime_stream_flush (onebyte); g_object_unref (onebyte); g_object_unref (stream); }
static GMimeStream* create_stream(GMimeContentEncoding en, const gchar* fn) { GMimeStream* rv = NULL; FILE* f = fopen(fn, "r"); GMimeStream* fst = NULL; if ( f ) { fst = g_mime_stream_file_new(f); } if ( fst ) { switch (en) { case GMIME_CONTENT_ENCODING_DEFAULT: { rv = fst; } break; default: { GMimeFilter* flt = g_mime_filter_basic_new(en, TRUE); rv = g_mime_stream_filter_new(fst); g_mime_stream_filter_add(GMIME_STREAM_FILTER(rv), flt); g_object_unref(flt); g_object_unref(fst); } break; } } else { g_warning("failed to open '%s'", fn); } return rv; }
/** * g_mime_part_get_best_content_encoding: * @mime_part: a #GMimePart object * @constraint: a #GMimeEncodingConstraint * * Calculates the most efficient content encoding for the @mime_part * given the @constraint. * * Returns: the best content encoding for the specified mime part. **/ GMimeContentEncoding g_mime_part_get_best_content_encoding (GMimePart *mime_part, GMimeEncodingConstraint constraint) { GMimeStream *filtered, *stream; GMimeContentEncoding encoding; GMimeFilterBest *best; GMimeFilter *filter; g_return_val_if_fail (GMIME_IS_PART (mime_part), GMIME_CONTENT_ENCODING_DEFAULT); stream = g_mime_stream_null_new (); filtered = g_mime_stream_filter_new (stream); g_object_unref (stream); filter = g_mime_filter_best_new (GMIME_FILTER_BEST_ENCODING); g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter); best = (GMimeFilterBest *) filter; g_mime_data_wrapper_write_to_stream (mime_part->content, filtered); g_mime_stream_flush (filtered); g_object_unref (filtered); encoding = g_mime_filter_best_encoding (best, constraint); g_object_unref (best); return encoding; }
static GByteArray * read_all_bytes (const char *path, gboolean is_text) { GMimeStream *filtered, *stream, *mem; GMimeFilter *filter; GByteArray *buffer; buffer = g_byte_array_new (); stream = g_mime_stream_fs_open (path, O_RDONLY, 0644, NULL); mem = g_mime_stream_mem_new_with_byte_array (buffer); g_mime_stream_mem_set_owner ((GMimeStreamMem *) mem, FALSE); if (is_text) { filtered = g_mime_stream_filter_new (mem); filter = g_mime_filter_dos2unix_new (FALSE); g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter); g_object_unref (filter); g_object_unref (mem); } else { filtered = mem; } g_mime_stream_write_to_stream (stream, filtered); g_mime_stream_flush (filtered); g_object_unref (filtered); g_object_unref (stream); return buffer; }
static void pump_data_through_filter (GMimeFilter *filter, const char *path, GMimeStream *ostream) { GMimeStream *onebyte, *filtered, *stream; GMimeFilter *unix2dos, *dos2unix; filtered = g_mime_stream_filter_new (ostream); /* convert to DOS format before piping through the OpenPGP filter to maximize testing area */ unix2dos = g_mime_filter_unix2dos_new (FALSE); g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, unix2dos); g_object_unref (unix2dos); g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter); /* convert back to UNIX format after filtering */ dos2unix = g_mime_filter_dos2unix_new (FALSE); g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, dos2unix); g_object_unref (dos2unix); onebyte = test_stream_onebyte_new (filtered); g_object_unref (filtered); stream = g_mime_stream_fs_open (path, O_RDONLY, 0644, NULL); g_mime_stream_write_to_stream (stream, onebyte); g_mime_stream_flush (onebyte); g_object_unref (onebyte); g_object_unref (stream); }
static void format_part_content_raw (GMimeObject *part) { if (! GMIME_IS_PART (part)) return; GMimeStream *stream_stdout; GMimeStream *stream_filter = NULL; GMimeDataWrapper *wrapper; stream_stdout = g_mime_stream_file_new (stdout); g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE); stream_filter = g_mime_stream_filter_new (stream_stdout); 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); }
static GMimeStream * g_mime_data_wrapper_get_decoded_stream(GMimeDataWrapper * wrapper) { GMimeStream *decoded_stream; GMimeFilter *decoder; g_mime_stream_reset(wrapper->stream); switch (wrapper->encoding) { case GMIME_CONTENT_ENCODING_BASE64: case GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE: case GMIME_CONTENT_ENCODING_UUENCODE: decoder = g_mime_filter_basic_new(wrapper->encoding, FALSE); decoded_stream = g_mime_stream_filter_new(wrapper->stream); g_mime_stream_filter_add(GMIME_STREAM_FILTER(decoded_stream), decoder); g_object_unref(decoder); break; default: decoded_stream = wrapper->stream; g_object_ref(wrapper->stream); break; } return decoded_stream; }
static void write_result(GMimeMessage* m, const char* fn) { FILE* of = stdout; if ( fn ) { of = fopen(fn, "w"); } GMimeStream* fst = g_mime_stream_file_new(of); GMimeFilter* flt = g_mime_filter_crlf_new(TRUE, FALSE); GMimeStream* st = g_mime_stream_filter_new(fst); time_t dt; int tz_off = 0; if ( !g_mime_message_get_message_id(m) ) { char* mid = g_mime_utils_generate_message_id("MG"); g_mime_message_set_message_id(m, mid); g_free(mid); } g_mime_message_get_date(m, &dt, &tz_off); if ( !dt ) { g_mime_message_set_date(m, time(NULL), 0); } g_mime_stream_filter_add(GMIME_STREAM_FILTER(st), flt); g_mime_object_write_to_stream(GMIME_OBJECT(m), st); g_object_unref(st); g_object_unref(flt); g_object_unref(fst); }
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)); } } }
/** * 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); }
/* 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); }
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)); } } }
/** * 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 mime_part_encode (GMimeObject *object, GMimeEncodingConstraint constraint) { GMimePart *part = (GMimePart *) object; GMimeContentEncoding encoding; GMimeStream *stream, *null; GMimeFilter *filter; switch (part->encoding) { case GMIME_CONTENT_ENCODING_DEFAULT: /* Unspecified encoding, we need to figure out the * best encoding no matter what */ break; case GMIME_CONTENT_ENCODING_7BIT: /* This encoding is always safe. */ return; case GMIME_CONTENT_ENCODING_8BIT: /* This encoding is safe unless the constraint is 7bit. */ if (constraint != GMIME_ENCODING_CONSTRAINT_7BIT) return; break; case GMIME_CONTENT_ENCODING_BINARY: /* This encoding is only safe if the constraint is binary. */ if (constraint == GMIME_ENCODING_CONSTRAINT_BINARY) return; break; case GMIME_CONTENT_ENCODING_BASE64: case GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE: case GMIME_CONTENT_ENCODING_UUENCODE: /* These encodings are always safe. */ return; } filter = g_mime_filter_best_new (GMIME_FILTER_BEST_ENCODING); null = g_mime_stream_null_new (); stream = g_mime_stream_filter_new (null); g_mime_stream_filter_add ((GMimeStreamFilter *) stream, filter); g_object_unref (null); g_mime_object_write_to_stream (object, stream); g_object_unref (stream); encoding = g_mime_filter_best_encoding ((GMimeFilterBest *) filter, constraint); g_mime_part_set_content_encoding (part, encoding); g_object_unref (filter); }
static void show_reply_headers (GMimeMessage *message) { GMimeStream *stream_stdout = NULL, *stream_filter = NULL; 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 (stream_filter) { g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter), g_mime_filter_headers_new()); g_mime_object_write_to_stream(GMIME_OBJECT(message), stream_filter); g_object_unref(stream_filter); } g_object_unref(stream_stdout); } }
static notmuch_status_t format_part_raw (unused (const void *ctx), mime_node_t *node, unused (int indent), unused (const notmuch_show_params_t *params)) { if (node->envelope_file) { /* Special case the entire message to avoid MIME parsing. */ const char *filename; FILE *file; size_t size; char buf[4096]; filename = notmuch_message_get_filename (node->envelope_file); if (filename == NULL) { fprintf (stderr, "Error: Cannot get message filename.\n"); return NOTMUCH_STATUS_FILE_ERROR; } file = fopen (filename, "r"); if (file == NULL) { fprintf (stderr, "Error: Cannot open file %s: %s\n", filename, strerror (errno)); return NOTMUCH_STATUS_FILE_ERROR; } while (!feof (file)) { size = fread (buf, 1, sizeof (buf), file); if (ferror (file)) { fprintf (stderr, "Error: Read failed from %s\n", filename); fclose (file); return NOTMUCH_STATUS_FILE_ERROR; } if (fwrite (buf, size, 1, stdout) != 1) { fprintf (stderr, "Error: Write failed\n"); fclose (file); return NOTMUCH_STATUS_FILE_ERROR; } } fclose (file); return NOTMUCH_STATUS_SUCCESS; } GMimeStream *stream_stdout; GMimeStream *stream_filter = NULL; stream_stdout = g_mime_stream_file_new (stdout); g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE); stream_filter = g_mime_stream_filter_new (stream_stdout); if (GMIME_IS_PART (node->part)) { /* For leaf parts, we emit only the transfer-decoded * body. */ GMimeDataWrapper *wrapper; wrapper = g_mime_part_get_content_object (GMIME_PART (node->part)); if (wrapper && stream_filter) g_mime_data_wrapper_write_to_stream (wrapper, stream_filter); } else { /* Write out the whole part. For message parts (the root * part and embedded message parts), this will be the * message including its headers (but not the * encapsulating part's headers). For multipart parts, * this will include the headers. */ if (stream_filter) g_mime_object_write_to_stream (node->part, stream_filter); } if (stream_filter) g_object_unref (stream_filter); if (stream_stdout) g_object_unref(stream_stdout); return NOTMUCH_STATUS_SUCCESS; }
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; }
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; }
static int uuencode (const char *progname, int argc, char **argv) { GMimeStream *istream, *ostream, *fstream; GMimeContentEncoding encoding; const char *filename, *name; GMimeFilter *filter; gboolean base64; struct stat st; int fd, opt; base64 = FALSE; encoding = GMIME_CONTENT_ENCODING_UUENCODE; while ((opt = getopt_long (argc, argv, "hvm", longopts, NULL)) != -1) { switch (opt) { case 'h': usage (progname); return 0; case 'v': version (progname); return 0; case 'm': base64 = TRUE; encoding = GMIME_CONTENT_ENCODING_BASE64; break; default: printf ("Try `%s --help' for more information.\n", progname); return -1; } } if (optind >= argc) { printf ("Try `%s --help' for more information.\n", progname); return -1; } if (optind + 1 < argc) filename = argv[optind++]; else filename = NULL; name = argv[optind]; /* open our input file... */ if ((fd = filename ? open (filename, O_RDONLY, 0) : dup (0)) == -1) { fprintf (stderr, "%s: %s: %s\n", progname, filename ? filename : "stdin", g_strerror (errno)); return -1; } /* stat() our input file for file mode permissions */ if (fstat (fd, &st) == -1) { fprintf (stderr, "%s: %s: %s\n", progname, filename ? filename : "stdin", g_strerror (errno)); close (fd); return -1; } printf ("begin%s %.3o %s\n", base64 ? "-base64" : "", st.st_mode & 0777, name); fflush (stdout); istream = g_mime_stream_fs_new (fd); /* open our output stream */ ostream = g_mime_stream_fs_new (1); g_mime_stream_fs_set_owner ((GMimeStreamFs *) ostream, FALSE); fstream = g_mime_stream_filter_new (ostream); /* attach an encode filter */ filter = g_mime_filter_basic_new (encoding, TRUE); g_mime_stream_filter_add ((GMimeStreamFilter *) fstream, filter); g_object_unref (filter); if (g_mime_stream_write_to_stream (istream, fstream) == -1) { fprintf (stderr, "%s: %s\n", progname, g_strerror (errno)); g_object_unref (fstream); g_object_unref (istream); g_object_unref (ostream); return -1; } g_mime_stream_flush (fstream); g_object_unref (fstream); g_object_unref (istream); if (g_mime_stream_write_string (ostream, base64 ? "====\n" : "end\n") == -1) { fprintf (stderr, "%s: %s\n", progname, g_strerror (errno)); g_object_unref (ostream); return -1; } g_object_unref (ostream); return 0; }
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 ; }
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); } } }
static void test_openpgp_filter (GMimeFilterOpenPGP *filter, const char *path, GMimeOpenPGPData data_type, gint64 begin, gint64 end) { GMimeStream *filtered, *stream, *expected, *ostream; GMimeFilter *dos2unix; GMimeOpenPGPData type; Exception *ex = NULL; GByteArray *buf[2]; char *filename; struct stat st; gint64 offset; ostream = g_mime_stream_mem_new (); pump_data_through_filter ((GMimeFilter *) filter, path, ostream); if ((type = g_mime_filter_openpgp_get_data_type (filter)) != data_type) { g_object_unref (ostream); throw (exception_new ("Incorrect OpenPGP data type detected: %s", openpgp_data_types[type])); } if ((offset = g_mime_filter_openpgp_get_begin_offset (filter)) != begin) { g_object_unref (ostream); throw (exception_new ("Incorrect begin offset: %ld", (long) offset)); } if ((offset = g_mime_filter_openpgp_get_end_offset (filter)) != end) { g_object_unref (ostream); throw (exception_new ("Incorrect end offset: %ld", (long) offset)); } filename = g_strdup_printf ("%s.openpgp-block", path); if (stat (filename, &st) == -1) { stream = g_mime_stream_fs_open (filename, O_RDWR | O_CREAT, 0644, NULL); g_mime_stream_reset (ostream); g_mime_stream_write_to_stream (ostream, stream); g_mime_stream_flush (stream); g_mime_stream_reset (stream); } else { stream = g_mime_stream_fs_open (filename, O_RDONLY, 0644, NULL); } g_free (filename); /* make sure the data is in UNIX format before comparing (might be running tests on Windows) */ expected = g_mime_stream_mem_new (); filtered = g_mime_stream_filter_new (expected); dos2unix = g_mime_filter_dos2unix_new (FALSE); g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, dos2unix); g_object_unref (dos2unix); g_mime_stream_write_to_stream (stream, filtered); g_mime_stream_flush (filtered); g_object_unref (filtered); g_object_unref (stream); buf[0] = GMIME_STREAM_MEM (expected)->buffer; buf[1] = GMIME_STREAM_MEM (ostream)->buffer; if (buf[0]->len != buf[1]->len || memcmp (buf[0]->data, buf[1]->data, buf[0]->len) != 0) ex = exception_new ("filtered data does not match the expected result"); g_object_unref (expected); g_object_unref (ostream); if (ex != NULL) throw (ex); }
gboolean g_mime_gpgme_mpe_encrypt(GMimeMultipartEncrypted * mpe, GMimeObject * content, GPtrArray * recipients, gboolean trust_all, GtkWindow * parent, GError ** err) { GMimeStream *filtered_stream; GMimeStream *ciphertext; GMimeStream *stream; GMimePart *version_part; GMimePart *encrypted_part; GMimeDataWrapper *wrapper; GMimeFilter *crlf_filter; g_return_val_if_fail(GMIME_IS_MULTIPART_ENCRYPTED(mpe), FALSE); g_return_val_if_fail(GMIME_IS_OBJECT(content), FALSE); /* get the cleartext */ stream = g_mime_stream_mem_new(); filtered_stream = g_mime_stream_filter_new(stream); crlf_filter = g_mime_filter_crlf_new(TRUE, FALSE); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_stream), crlf_filter); g_object_unref(crlf_filter); g_mime_object_write_to_stream(content, filtered_stream); g_mime_stream_flush(filtered_stream); g_object_unref(filtered_stream); /* reset the content stream */ g_mime_stream_reset(stream); /* encrypt the content stream */ ciphertext = g_mime_stream_mem_new(); if (!libbalsa_gpgme_encrypt (recipients, NULL, stream, ciphertext, GPGME_PROTOCOL_OpenPGP, FALSE, trust_all, parent, err)) { g_object_unref(ciphertext); g_object_unref(stream); return FALSE; } g_object_unref(stream); g_mime_stream_reset(ciphertext); /* construct the version part */ version_part = g_mime_part_new_with_type("application", "pgp-encrypted"); g_mime_part_set_content_encoding(version_part, GMIME_CONTENT_ENCODING_7BIT); stream = g_mime_stream_mem_new_with_buffer("Version: 1\n", strlen("Version: 1\n")); wrapper = g_mime_data_wrapper_new_with_stream(stream, GMIME_CONTENT_ENCODING_7BIT); g_mime_part_set_content_object(version_part, wrapper); g_object_unref(wrapper); g_object_unref(stream); /* construct the encrypted mime part */ encrypted_part = g_mime_part_new_with_type("application", "octet-stream"); g_mime_part_set_content_encoding(encrypted_part, GMIME_CONTENT_ENCODING_7BIT); wrapper = g_mime_data_wrapper_new_with_stream(ciphertext, GMIME_CONTENT_ENCODING_7BIT); g_mime_part_set_content_object(encrypted_part, wrapper); g_object_unref(ciphertext); g_object_unref(wrapper); /* save the version and encrypted parts */ /* FIXME: make sure there aren't any other parts?? */ g_mime_multipart_add(GMIME_MULTIPART(mpe), GMIME_OBJECT(version_part)); g_mime_multipart_add(GMIME_MULTIPART(mpe), GMIME_OBJECT(encrypted_part)); g_object_unref(encrypted_part); g_object_unref(version_part); /* set the content-type params for this multipart/encrypted part */ g_mime_object_set_content_type_parameter(GMIME_OBJECT(mpe), "protocol", "application/pgp-encrypted"); g_mime_multipart_set_boundary(GMIME_MULTIPART(mpe), NULL); return TRUE; }
static ssize_t write_content (GMimePart *part, GMimeStream *stream) { ssize_t nwritten, total = 0; if (!part->content) return 0; /* Evil Genius's "slight" optimization: Since GMimeDataWrapper::write_to_stream() * decodes its content stream to the raw format, we can cheat by requesting its * content stream and not doing any encoding on the data if the source and * destination encodings are identical. */ if (part->encoding != g_mime_data_wrapper_get_encoding (part->content)) { GMimeStream *filtered_stream; const char *filename; GMimeFilter *filter; switch (part->encoding) { case GMIME_CONTENT_ENCODING_UUENCODE: filename = g_mime_part_get_filename (part); nwritten = g_mime_stream_printf (stream, "begin 0644 %s\n", filename ? filename : "unknown"); if (nwritten == -1) return -1; total += nwritten; /* fall thru... */ case GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE: case GMIME_CONTENT_ENCODING_BASE64: filtered_stream = g_mime_stream_filter_new (stream); filter = g_mime_filter_basic_new (part->encoding, TRUE); g_mime_stream_filter_add (GMIME_STREAM_FILTER (filtered_stream), filter); g_object_unref (filter); break; default: filtered_stream = stream; g_object_ref (stream); break; } nwritten = g_mime_data_wrapper_write_to_stream (part->content, filtered_stream); g_mime_stream_flush (filtered_stream); g_object_unref (filtered_stream); if (nwritten == -1) return -1; total += nwritten; if (part->encoding == GMIME_CONTENT_ENCODING_UUENCODE) { /* FIXME: get rid of this special-case x-uuencode crap */ nwritten = g_mime_stream_write (stream, "end\n", 4); if (nwritten == -1) return -1; total += nwritten; } } else { GMimeStream *content_stream; content_stream = g_mime_data_wrapper_get_stream (part->content); g_mime_stream_reset (content_stream); nwritten = g_mime_stream_write_to_stream (content_stream, stream); g_mime_stream_reset (content_stream); if (nwritten == -1) return -1; total += nwritten; } return total; }
GMimeGpgmeSigstat * g_mime_gpgme_mps_verify(GMimeMultipartSigned * mps, GError ** error) { const gchar *protocol; gpgme_protocol_t crypto_prot; gchar *content_type; GMimeObject *content; GMimeObject *signature; GMimeStream *stream; GMimeStream *filtered_stream; GMimeFilter *crlf_filter; GMimeDataWrapper *wrapper; GMimeStream *sigstream; GMimeGpgmeSigstat *result; g_return_val_if_fail(GMIME_IS_MULTIPART_SIGNED(mps), NULL); if (g_mime_multipart_get_count(GMIME_MULTIPART(mps)) < 2) { g_set_error(error, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR, "%s", _ ("Cannot verify multipart/signed part due to missing subparts.")); return NULL; } /* grab the protocol so we can configure the GpgME context */ protocol = g_mime_object_get_content_type_parameter(GMIME_OBJECT(mps), "protocol"); if (protocol) { if (g_ascii_strcasecmp("application/pgp-signature", protocol) == 0) crypto_prot = GPGME_PROTOCOL_OpenPGP; else if (g_ascii_strcasecmp ("application/pkcs7-signature", protocol) == 0 || g_ascii_strcasecmp("application/x-pkcs7-signature", protocol) == 0) crypto_prot = GPGME_PROTOCOL_CMS; else crypto_prot = GPGME_PROTOCOL_UNKNOWN; } else crypto_prot = GPGME_PROTOCOL_UNKNOWN; /* eject on unknown protocols */ if (crypto_prot == GPGME_PROTOCOL_UNKNOWN) { g_set_error(error, GPGME_ERROR_QUARK, GPG_ERR_INV_VALUE, _("unsupported protocol “%s”"), protocol); return NULL; } signature = g_mime_multipart_get_part(GMIME_MULTIPART(mps), GMIME_MULTIPART_SIGNED_SIGNATURE); /* make sure the protocol matches the signature content-type */ content_type = g_mime_content_type_to_string(signature->content_type); if (g_ascii_strcasecmp(content_type, protocol) != 0) { g_set_error(error, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR, "%s", _ ("Cannot verify multipart/signed part: signature content-type does not match protocol.")); g_free(content_type); return NULL; } g_free(content_type); content = g_mime_multipart_get_part(GMIME_MULTIPART(mps), GMIME_MULTIPART_SIGNED_CONTENT); /* get the content stream */ stream = g_mime_stream_mem_new(); filtered_stream = g_mime_stream_filter_new(stream); /* Note: see rfc2015 or rfc3156, section 5.1 */ crlf_filter = g_mime_filter_crlf_new(TRUE, FALSE); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_stream), crlf_filter); g_object_unref(crlf_filter); g_mime_object_write_to_stream(content, filtered_stream); g_mime_stream_flush(filtered_stream); g_object_unref(filtered_stream); g_mime_stream_reset(stream); /* get the signature stream */ wrapper = g_mime_part_get_content_object(GMIME_PART(signature)); /* a s/mime signature is always encoded, a pgp signature shouldn't, * but there exist implementations which encode it... */ sigstream = g_mime_stream_mem_new(); g_mime_data_wrapper_write_to_stream(wrapper, sigstream); g_mime_stream_reset(sigstream); /* verify the signature */ result = libbalsa_gpgme_verify(stream, sigstream, crypto_prot, FALSE, error); g_object_unref(stream); g_object_unref(sigstream); return result; }