void test_message_set_content_simple (CamelMimePart *part, gint how, const gchar *type, const gchar *text, gint len) { CamelStreamMem *content = NULL; CamelDataWrapper *dw; static GByteArray *ba; switch (how) { case 0: camel_mime_part_set_content (part, text, len, type); break; case 1: content = (CamelStreamMem *) camel_stream_mem_new_with_buffer (text, len); break; case 2: content = (CamelStreamMem *) camel_stream_mem_new (); camel_stream_mem_set_buffer (content, text, len); break; case 3: ba = g_byte_array_new (); g_byte_array_append (ba, (guint8 *) text, len); content = (CamelStreamMem *) camel_stream_mem_new_with_byte_array (ba); ba = NULL; break; case 4: ba = g_byte_array_new (); g_byte_array_append (ba, (guint8 *) text, len); content = (CamelStreamMem *) camel_stream_mem_new (); camel_stream_mem_set_byte_array (content, ba); g_object_weak_ref ( G_OBJECT (content), (GWeakNotify) content_weak_notify, ba); break; } if (content != 0) { dw = camel_data_wrapper_new (); camel_data_wrapper_set_mime_type (dw, type); camel_data_wrapper_construct_from_stream_sync ( dw, (CamelStream *) content, NULL, NULL); camel_medium_set_content ((CamelMedium *) part, dw); check_unref (content, 2); check_unref (dw, 2); } }
/** * mail_importer_add_line: * importer: A MailImporter structure. * str: Next line of the mbox. * finished: TRUE if @str is the last line of the message. * * Adds lines to the message until it is finished, and then adds * the complete message to the folder. */ void mail_importer_add_line (MailImporter *importer, const char *str, gboolean finished) { CamelMimeMessage *msg; CamelMessageInfo *info; CamelException *ex; if (importer->mstream == NULL) importer->mstream = CAMEL_STREAM_MEM (camel_stream_mem_new ()); camel_stream_write (CAMEL_STREAM (importer->mstream), str, strlen (str)); if (finished == FALSE) return; camel_stream_reset (CAMEL_STREAM (importer->mstream)); info = camel_message_info_new(NULL); camel_message_info_set_flags(info, CAMEL_MESSAGE_SEEN, ~0); msg = camel_mime_message_new (); camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (msg), CAMEL_STREAM (importer->mstream)); camel_object_unref (importer->mstream); importer->mstream = NULL; ex = camel_exception_new (); camel_folder_append_message (importer->folder, msg, info, NULL, ex); camel_object_unref (msg); camel_exception_free (ex); camel_message_info_free(info); }
/* there is also an identical copy of this in camel-filter-search.c */ gboolean camel_search_message_body_contains (CamelDataWrapper *object, regex_t *pattern) { CamelDataWrapper *containee; int truth = FALSE; int parts, i; containee = camel_medium_get_content_object (CAMEL_MEDIUM (object)); if (containee == NULL) return FALSE; /* using the object types is more accurate than using the mime/types */ if (CAMEL_IS_MULTIPART (containee)) { parts = camel_multipart_get_number (CAMEL_MULTIPART (containee)); for (i = 0; i < parts && truth == FALSE; i++) { CamelDataWrapper *part = (CamelDataWrapper *)camel_multipart_get_part (CAMEL_MULTIPART (containee), i); if (part) truth = camel_search_message_body_contains (part, pattern); } } else if (CAMEL_IS_MIME_MESSAGE (containee)) { /* for messages we only look at its contents */ truth = camel_search_message_body_contains ((CamelDataWrapper *)containee, pattern); } else if (camel_content_type_is(CAMEL_DATA_WRAPPER (containee)->mime_type, "text", "*")) { /* for all other text parts, we look inside, otherwise we dont care */ CamelStreamMem *mem = (CamelStreamMem *)camel_stream_mem_new (); camel_data_wrapper_write_to_stream (containee, CAMEL_STREAM (mem)); camel_stream_write (CAMEL_STREAM (mem), "", 1); truth = regexec (pattern, (char *) mem->buffer->data, 0, NULL, 0) == 0; camel_object_unref (mem); } return truth; }
static void save_snapshot_get_message_cb (EMsgComposer *composer, GAsyncResult *result, GSimpleAsyncResult *simple) { SaveContext *context; CamelMimeMessage *message; GInputStream *input_stream; CamelStream *camel_stream; GByteArray *buffer; GError *local_error = NULL; context = g_simple_async_result_get_op_res_gpointer (simple); message = e_msg_composer_get_message_draft_finish ( composer, result, &local_error); if (local_error != NULL) { g_warn_if_fail (message == NULL); g_simple_async_result_take_error (simple, local_error); g_simple_async_result_complete (simple); g_object_unref (simple); return; } g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); /* Decode the message to an in-memory buffer. We have to do this * because CamelStreams are synchronous-only, and using threads is * dangerous because CamelDataWrapper is not reentrant. */ buffer = g_byte_array_new (); camel_stream = camel_stream_mem_new (); camel_stream_mem_set_byte_array ( CAMEL_STREAM_MEM (camel_stream), buffer); camel_data_wrapper_decode_to_stream_sync ( CAMEL_DATA_WRAPPER (message), camel_stream, NULL, NULL); g_object_unref (camel_stream); g_object_unref (message); /* Load the buffer into a GMemoryInputStream. */ input_stream = g_memory_input_stream_new (); if (buffer->len > 0) g_memory_input_stream_add_data ( G_MEMORY_INPUT_STREAM (input_stream), buffer->data, (gssize) buffer->len, (GDestroyNotify) g_free); g_byte_array_free (buffer, FALSE); /* Splice the input and output streams. */ g_output_stream_splice_async ( context->output_stream, input_stream, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, G_PRIORITY_DEFAULT, context->cancellable, (GAsyncReadyCallback) save_snapshot_splice_cb, simple); g_object_unref (input_stream); }
/** * camel_mime_filter_save_new: * * Create a new #CamelMimeFilterSave filter object. * * Returns a new #CamelMimeFilterSave object **/ CamelMimeFilter * camel_mime_filter_save_new (void) { CamelMimeFilterSave *save = CAMEL_MIME_FILTER_SAVE (camel_object_new (CAMEL_MIME_FILTER_SAVE_TYPE)); save->stream = camel_stream_mem_new (); return (CamelMimeFilter *) save; }
/** * * "util_get_msg_body" is based on mail-to-task eplugin's get_description function. * which is GPL licensed. * */ static gchar * util_get_msg_body(CamelMimeMessage *message, gchar **text) { CamelDataWrapper *content; CamelStream *mem; CamelContentType *type; CamelMimePart *mime_part = CAMEL_MIME_PART(message); GSList sl; gchar *str, *convert_str = NULL; gsize bytes_read, bytes_written; gint count = 2; content = camel_medium_get_content_object((CamelMedium *) message); if (!content) return; /* * Get non-multipart content from multipart message. */ while (CAMEL_IS_MULTIPART(content) && count > 0) { mime_part = camel_multipart_get_part(CAMEL_MULTIPART(content), 0); content = camel_medium_get_content_object(CAMEL_MEDIUM(mime_part)); count--; } if (!mime_part) return; type = camel_mime_part_get_content_type(mime_part); if (!camel_content_type_is(type, "text", "plain")) return; mem = camel_stream_mem_new(); camel_data_wrapper_decode_to_stream(content, mem); str = g_strndup((const gchar *) ((CamelStreamMem *) mem)->buffer->data, ((CamelStreamMem *) mem)->buffer->len); camel_object_unref(mem); /* convert to UTF-8 string */ if (str && content->mime_type->params && content->mime_type->params->value) { convert_str = g_convert(str, strlen(str), "UTF-8", content->mime_type->params->value, &bytes_read, &bytes_written, NULL); } if (convert_str) *text = convert_str; else *text = str; /*g_free (str); if (convert_str) g_free (convert_str); */ }
static gboolean data_wrapper_construct_from_stream_sync (CamelDataWrapper *data_wrapper, CamelStream *stream, GCancellable *cancellable, GError **error) { CamelStream *memory_stream; gssize bytes_written; camel_data_wrapper_lock ( data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK); /* Check for cancellation after locking. */ if (g_cancellable_set_error_if_cancelled (cancellable, error)) { camel_data_wrapper_unlock ( data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK); return FALSE; } if (G_IS_SEEKABLE (stream)) { if (!g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, cancellable, error)) { camel_data_wrapper_unlock (data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK); return FALSE; } } /* Wipe any previous contents from our byte array. */ g_byte_array_set_size (data_wrapper->priv->byte_array, 0); memory_stream = camel_stream_mem_new (); /* We retain ownership of the byte array. */ camel_stream_mem_set_byte_array ( CAMEL_STREAM_MEM (memory_stream), data_wrapper->priv->byte_array); /* Transfer incoming contents to our byte array. */ bytes_written = camel_stream_write_to_stream ( stream, memory_stream, cancellable, error); g_object_unref (memory_stream); camel_data_wrapper_unlock ( data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK); return (bytes_written >= 0); }
static gssize data_wrapper_write_to_stream_sync (CamelDataWrapper *data_wrapper, CamelStream *stream, GCancellable *cancellable, GError **error) { CamelStream *memory_stream; gssize ret; camel_data_wrapper_lock ( data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK); /* Check for cancellation after locking. */ if (g_cancellable_set_error_if_cancelled (cancellable, error)) { camel_data_wrapper_unlock ( data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK); return -1; } memory_stream = camel_stream_mem_new (); /* We retain ownership of the byte array. */ camel_stream_mem_set_byte_array ( CAMEL_STREAM_MEM (memory_stream), data_wrapper->priv->byte_array); ret = camel_stream_write_to_stream ( memory_stream, stream, cancellable, error); g_object_unref (memory_stream); camel_data_wrapper_unlock ( data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK); return ret; }
static void test_filter(CamelMimeFilter *f, const char *inname, const char *outname) { CamelStreamMem *in, *out; CamelStream *indisk, *outdisk, *filter; int id; camel_test_push("Data file `%s'", inname); camel_test_push("setup"); indisk = camel_stream_fs_new_with_name(inname, O_RDONLY, 0); check(indisk); outdisk = camel_stream_fs_new_with_name(outname, O_RDONLY, 0); check(outdisk); out = (CamelStreamMem *)camel_stream_mem_new(); check(camel_stream_write_to_stream(outdisk, (CamelStream *)out) > 0); camel_test_pull(); camel_test_push("reading through filter stream"); in = (CamelStreamMem *)camel_stream_mem_new(); filter = (CamelStream *)camel_stream_filter_new_with_stream(indisk); check_count(indisk, 2); id = camel_stream_filter_add((CamelStreamFilter *)filter, f); check_count(f, 2); check(camel_stream_write_to_stream(filter, (CamelStream *)in) > 0); check_msg(in->buffer->len == out->buffer->len && memcmp(in->buffer->data, out->buffer->data, in->buffer->len) == 0, "Buffer content mismatch, %d != %d, in = '%.*s' != out = '%.*s'", in->buffer->len, out->buffer->len, in->buffer->len, in->buffer->data, out->buffer->len, out->buffer->data); camel_test_pull(); camel_stream_filter_remove((CamelStreamFilter *)filter, id); check_count(f, 1); camel_mime_filter_reset(f); check_unref(filter, 1); check_count(indisk, 1); check_count(f, 1); check_unref(in, 1); check(camel_stream_reset(indisk) == 0); camel_test_push("writing through filter stream"); in = (CamelStreamMem *)camel_stream_mem_new(); filter = (CamelStream *)camel_stream_filter_new_with_stream((CamelStream *)in); check_count(in, 2); id = camel_stream_filter_add((CamelStreamFilter *)filter, f); check_count(f, 2); check(camel_stream_write_to_stream(indisk, filter) > 0); check(camel_stream_flush(filter) == 0); check_msg(in->buffer->len == out->buffer->len && memcmp(in->buffer->data, out->buffer->data, in->buffer->len) == 0, "Buffer content mismatch, %d != %d, in = '%.*s' != out = '%.*s'", in->buffer->len, out->buffer->len, in->buffer->len, in->buffer->data, out->buffer->len, out->buffer->data); camel_stream_filter_remove((CamelStreamFilter *)filter, id); check_unref(filter, 1); check_unref(in, 1); check_unref(indisk, 1); check_unref(outdisk, 1); check_unref(out, 1); camel_test_pull(); camel_test_pull(); }
static CamelCipherValidity * sm_decrypt(CamelCipherContext *context, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex) { NSSCMSDecoderContext *dec; NSSCMSMessage *cmsg; CamelStreamMem *istream; CamelStream *ostream; CamelCipherValidity *valid = NULL; /* FIXME: This assumes the content is only encrypted. Perhaps its ok for this api to do this ... */ ostream = camel_stream_mem_new(); camel_stream_mem_set_secure((CamelStreamMem *)ostream); /* FIXME: stream this to the decoder incrementally */ istream = (CamelStreamMem *)camel_stream_mem_new(); camel_data_wrapper_decode_to_stream(camel_medium_get_content_object((CamelMedium *)ipart), (CamelStream *)istream); camel_stream_reset((CamelStream *)istream); dec = NSS_CMSDecoder_Start(NULL, sm_write_stream, ostream, /* content callback */ NULL, NULL, NULL, NULL); /* decrypt key callback */ if (NSS_CMSDecoder_Update(dec, (char *) istream->buffer->data, istream->buffer->len) != SECSuccess) { printf("decoder update failed\n"); } camel_object_unref(istream); cmsg = NSS_CMSDecoder_Finish(dec); if (cmsg == NULL) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Decoder failed, error %d"), PORT_GetError()); goto fail; } #if 0 /* not sure if we really care about this? */ if (!NSS_CMSMessage_IsEncrypted(cmsg)) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("S/MIME Decrypt: No encrypted content found")); NSS_CMSMessage_Destroy(cmsg); goto fail; } #endif camel_stream_reset(ostream); camel_data_wrapper_construct_from_stream((CamelDataWrapper *)opart, ostream); if (NSS_CMSMessage_IsSigned(cmsg)) { valid = sm_verify_cmsg(context, cmsg, NULL, ex); } else { valid = camel_cipher_validity_new(); valid->encrypt.description = g_strdup(_("Encrypted content")); valid->encrypt.status = CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED; } NSS_CMSMessage_Destroy(cmsg); fail: camel_object_unref(ostream); return valid; }
static CamelCipherValidity * sm_verify(CamelCipherContext *context, CamelMimePart *ipart, CamelException *ex) { NSSCMSDecoderContext *dec; NSSCMSMessage *cmsg; CamelStreamMem *mem; CamelStream *constream = NULL; CamelCipherValidity *valid = NULL; CamelContentType *ct; const char *tmp; CamelMimePart *sigpart; CamelDataWrapper *dw; dw = camel_medium_get_content_object((CamelMedium *)ipart); ct = dw->mime_type; /* FIXME: we should stream this to the decoder */ mem = (CamelStreamMem *)camel_stream_mem_new(); if (camel_content_type_is(ct, "multipart", "signed")) { CamelMultipart *mps = (CamelMultipart *)dw; tmp = camel_content_type_param(ct, "protocol"); if (!CAMEL_IS_MULTIPART_SIGNED(mps) || tmp == NULL || (g_ascii_strcasecmp(tmp, context->sign_protocol) != 0 && g_ascii_strcasecmp(tmp, "application/pkcs7-signature") != 0)) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot verify message signature: Incorrect message format")); goto fail; } constream = camel_multipart_signed_get_content_stream((CamelMultipartSigned *)mps, ex); if (constream == NULL) goto fail; sigpart = camel_multipart_get_part(mps, CAMEL_MULTIPART_SIGNED_SIGNATURE); if (sigpart == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot verify message signature: Incorrect message format")); goto fail; } } else if (camel_content_type_is(ct, "application", "x-pkcs7-mime")) { sigpart = ipart; } else { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot verify message signature: Incorrect message format")); goto fail; } dec = NSS_CMSDecoder_Start(NULL, NULL, NULL, /* content callback */ NULL, NULL, /* password callback */ NULL, NULL); /* decrypt key callback */ camel_data_wrapper_decode_to_stream(camel_medium_get_content_object((CamelMedium *)sigpart), (CamelStream *)mem); (void)NSS_CMSDecoder_Update(dec, (char *) mem->buffer->data, mem->buffer->len); cmsg = NSS_CMSDecoder_Finish(dec); if (cmsg == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Decoder failed")); goto fail; } valid = sm_verify_cmsg(context, cmsg, constream, ex); NSS_CMSMessage_Destroy(cmsg); fail: camel_object_unref(mem); if (constream) camel_object_unref(constream); return valid; }
static int sm_sign(CamelCipherContext *context, const char *userid, CamelCipherHash hash, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex) { int res = -1; NSSCMSMessage *cmsg; CamelStream *ostream, *istream; SECOidTag sechash; NSSCMSEncoderContext *enc; CamelDataWrapper *dw; CamelContentType *ct; switch (hash) { case CAMEL_CIPHER_HASH_SHA1: case CAMEL_CIPHER_HASH_DEFAULT: default: sechash = SEC_OID_SHA1; break; case CAMEL_CIPHER_HASH_MD5: sechash = SEC_OID_MD5; break; } cmsg = sm_signing_cmsmessage((CamelSMIMEContext *)context, userid, sechash, ((CamelSMIMEContext *)context)->priv->sign_mode == CAMEL_SMIME_SIGN_CLEARSIGN, ex); if (cmsg == NULL) return -1; ostream = camel_stream_mem_new(); /* FIXME: stream this, we stream output at least */ istream = camel_stream_mem_new(); if (camel_cipher_canonical_to_stream(ipart, CAMEL_MIME_FILTER_CANON_STRIP |CAMEL_MIME_FILTER_CANON_CRLF |CAMEL_MIME_FILTER_CANON_FROM, istream) == -1) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Could not generate signing data: %s"), g_strerror(errno)); goto fail; } enc = NSS_CMSEncoder_Start(cmsg, sm_write_stream, ostream, /* DER output callback */ NULL, NULL, /* destination storage */ NULL, NULL, /* password callback */ NULL, NULL, /* decrypt key callback */ NULL, NULL ); /* detached digests */ if (!enc) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create encoder context")); goto fail; } if (NSS_CMSEncoder_Update(enc, (char *) ((CamelStreamMem *)istream)->buffer->data, ((CamelStreamMem *)istream)->buffer->len) != SECSuccess) { NSS_CMSEncoder_Cancel(enc); camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to add data to CMS encoder")); goto fail; } if (NSS_CMSEncoder_Finish(enc) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to encode data")); goto fail; } res = 0; dw = camel_data_wrapper_new(); camel_stream_reset(ostream); camel_data_wrapper_construct_from_stream(dw, ostream); dw->encoding = CAMEL_TRANSFER_ENCODING_BINARY; if (((CamelSMIMEContext *)context)->priv->sign_mode == CAMEL_SMIME_SIGN_CLEARSIGN) { CamelMultipartSigned *mps; CamelMimePart *sigpart; sigpart = camel_mime_part_new(); ct = camel_content_type_new("application", "x-pkcs7-signature"); camel_content_type_set_param(ct, "name", "smime.p7s"); camel_data_wrapper_set_mime_type_field(dw, ct); camel_content_type_unref(ct); camel_medium_set_content_object((CamelMedium *)sigpart, dw); camel_mime_part_set_filename(sigpart, "smime.p7s"); camel_mime_part_set_disposition(sigpart, "attachment"); camel_mime_part_set_encoding(sigpart, CAMEL_TRANSFER_ENCODING_BASE64); mps = camel_multipart_signed_new(); ct = camel_content_type_new("multipart", "signed"); camel_content_type_set_param(ct, "micalg", camel_cipher_hash_to_id(context, hash)); camel_content_type_set_param(ct, "protocol", context->sign_protocol); camel_data_wrapper_set_mime_type_field((CamelDataWrapper *)mps, ct); camel_content_type_unref(ct); camel_multipart_set_boundary((CamelMultipart *)mps, NULL); mps->signature = sigpart; mps->contentraw = istream; camel_stream_reset(istream); camel_object_ref(istream); camel_medium_set_content_object((CamelMedium *)opart, (CamelDataWrapper *)mps); } else { ct = camel_content_type_new("application", "x-pkcs7-mime"); camel_content_type_set_param(ct, "name", "smime.p7m"); camel_content_type_set_param(ct, "smime-type", "signed-data"); camel_data_wrapper_set_mime_type_field(dw, ct); camel_content_type_unref(ct); camel_medium_set_content_object((CamelMedium *)opart, dw); camel_mime_part_set_filename(opart, "smime.p7m"); camel_mime_part_set_description(opart, "S/MIME Signed Message"); camel_mime_part_set_disposition(opart, "attachment"); camel_mime_part_set_encoding(opart, CAMEL_TRANSFER_ENCODING_BASE64); } camel_object_unref(dw); fail: camel_object_unref(ostream); camel_object_unref(istream); return res; }
static gint multipart_signed_parse_content (CamelMultipartSigned *mps) { CamelMimeParser *cmp; CamelMultipart *mp = (CamelMultipart *) mps; CamelDataWrapper *data_wrapper; GByteArray *byte_array; CamelStream *stream; const gchar *boundary; gchar *buf; gsize len; gint state; boundary = camel_multipart_get_boundary (mp); g_return_val_if_fail (boundary != NULL, -1); data_wrapper = CAMEL_DATA_WRAPPER (mps); byte_array = camel_data_wrapper_get_byte_array (data_wrapper); stream = camel_stream_mem_new (); /* Do not give the stream ownership of the byte array. */ camel_stream_mem_set_byte_array ( CAMEL_STREAM_MEM (stream), byte_array); /* This is all seriously complex. * This is so we can parse all cases properly, without altering the content. * All we are doing is finding part offsets. */ cmp = camel_mime_parser_new (); camel_mime_parser_init_with_stream (cmp, stream, NULL); camel_mime_parser_push_state (cmp, CAMEL_MIME_PARSER_STATE_MULTIPART, boundary); mps->start1 = -1; mps->end1 = -1; mps->start2 = -1; mps->end2 = -1; while ((state = camel_mime_parser_step (cmp, &buf, &len)) != CAMEL_MIME_PARSER_STATE_MULTIPART_END) { if (mps->start1 == -1) { mps->start1 = camel_mime_parser_tell_start_headers (cmp); } else if (mps->start2 == -1) { mps->start2 = camel_mime_parser_tell_start_headers (cmp); mps->end1 = camel_mime_parser_tell_start_boundary (cmp); if (mps->end1 > mps->start1 && byte_array->data[mps->end1 - 1] == '\n') mps->end1--; if (mps->end1 > mps->start1 && byte_array->data[mps->end1 - 1] == '\r') mps->end1--; } else { g_warning ("multipart/signed has more than 2 parts, remaining parts ignored"); state = CAMEL_MIME_PARSER_STATE_MULTIPART_END; break; } if (multipart_signed_skip_content (cmp) == -1) break; } if (state == CAMEL_MIME_PARSER_STATE_MULTIPART_END) { mps->end2 = camel_mime_parser_tell_start_boundary (cmp); camel_multipart_set_preface (mp, camel_mime_parser_preface (cmp)); camel_multipart_set_postface (mp, camel_mime_parser_postface (cmp)); } g_object_unref (cmp); g_object_unref (stream); if (mps->end2 == -1 || mps->start2 == -1) { if (mps->end1 == -1) mps->start1 = -1; return -1; } return 0; }
static gboolean empe_inlinepgp_signed_parse (EMailParserExtension *extension, EMailParser *parser, CamelMimePart *part, GString *part_id, GCancellable *cancellable, GQueue *out_mail_parts) { CamelStream *filtered_stream; CamelMimeFilterPgp *pgp_filter; CamelContentType *content_type; CamelCipherContext *cipher; CamelCipherValidity *valid; CamelDataWrapper *dw; CamelMimePart *opart; CamelStream *ostream; GQueue work_queue = G_QUEUE_INIT; GList *head, *link; gchar *type; gint len; GError *local_error = NULL; GByteArray *ba; if (g_cancellable_is_cancelled (cancellable) || /* avoid recursion */ (part_id->str && part_id->len > 17 && g_str_has_suffix (part_id->str, ".inlinepgp_signed"))) return FALSE; cipher = camel_gpg_context_new (e_mail_parser_get_session (parser)); /* Verify the signature of the message */ valid = camel_cipher_context_verify_sync ( cipher, part, cancellable, &local_error); if (local_error != NULL) { e_mail_parser_error ( parser, out_mail_parts, _("Error verifying signature: %s"), local_error->message); g_error_free (local_error); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.source", cancellable, out_mail_parts); g_object_unref (cipher); return TRUE; } /* Setup output stream */ ostream = camel_stream_mem_new (); filtered_stream = camel_stream_filter_new (ostream); /* Add PGP header / footer filter */ pgp_filter = (CamelMimeFilterPgp *) camel_mime_filter_pgp_new (); camel_stream_filter_add ( CAMEL_STREAM_FILTER (filtered_stream), CAMEL_MIME_FILTER (pgp_filter)); g_object_unref (pgp_filter); /* Pass through the filters that have been setup */ dw = camel_medium_get_content ((CamelMedium *) part); camel_data_wrapper_decode_to_stream_sync ( dw, (CamelStream *) filtered_stream, cancellable, NULL); camel_stream_flush ((CamelStream *) filtered_stream, cancellable, NULL); g_object_unref (filtered_stream); /* Create a new text/plain MIME part containing the signed * content preserving the original part's Content-Type params. */ content_type = camel_mime_part_get_content_type (part); type = camel_content_type_format (content_type); content_type = camel_content_type_decode (type); g_free (type); g_free (content_type->type); content_type->type = g_strdup ("text"); g_free (content_type->subtype); content_type->subtype = g_strdup ("plain"); type = camel_content_type_format (content_type); camel_content_type_unref (content_type); ba = camel_stream_mem_get_byte_array ((CamelStreamMem *) ostream); opart = camel_mime_part_new (); camel_mime_part_set_content (opart, (gchar *) ba->data, ba->len, type); g_free (type); len = part_id->len; g_string_append (part_id, ".inlinepgp_signed"); e_mail_parser_parse_part ( parser, opart, part_id, cancellable, &work_queue); head = g_queue_peek_head_link (&work_queue); for (link = head; link != NULL; link = g_list_next (link)) { EMailPart *mail_part = link->data; e_mail_part_update_validity ( mail_part, valid, E_MAIL_PART_VALIDITY_SIGNED | E_MAIL_PART_VALIDITY_PGP); } e_queue_transfer (&work_queue, out_mail_parts); g_string_truncate (part_id, len); /* Add a widget with details about the encryption, but only when * the encrypted isn't itself secured, in that case it has created * the button itself */ if (!e_mail_part_is_secured (opart)) { EMailPart *mail_part; g_string_append (part_id, ".inlinepgp_signed.button"); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.widget.secure-button", cancellable, &work_queue); mail_part = g_queue_peek_head (&work_queue); if (mail_part != NULL) e_mail_part_update_validity ( mail_part, valid, E_MAIL_PART_VALIDITY_SIGNED | E_MAIL_PART_VALIDITY_PGP); e_queue_transfer (&work_queue, out_mail_parts); g_string_truncate (part_id, len); } /* Clean Up */ camel_cipher_validity_free (valid); g_object_unref (opart); g_object_unref (ostream); g_object_unref (cipher); return TRUE; }
gint main (gint argc, gchar **argv) { CamelSession *session; CamelSMimeContext *ctx; GError **error; CamelCipherValidity *valid; CamelStream *stream1, *stream2, *stream3; GPtrArray *recipients; GByteArray *buf; gchar *before, *after; camel_test_init (argc, argv); ex = camel_exception_new (); /* clear out any camel-test data */ system ("/bin/rm -rf /tmp/camel-test"); session = camel_test_session_new ("/tmp/camel-test"); ctx = camel_smime_context_new (session); camel_test_start ("Test of S/MIME PKCS7 functions"); stream1 = camel_stream_mem_new (); camel_stream_write (stream1, "Hello, I am a test stream.", 25); g_seekable_seek (G_SEEKABLE (stream1), 0, G_SEEK_SET, NULL, NULL); stream2 = camel_stream_mem_new (); camel_test_push ("PKCS7 signing"); camel_smime_sign (ctx, "*****@*****.**", CAMEL_CIPHER_HASH_SHA1, stream1, stream2, ex); check_msg (!camel_exception_is_set (ex), "%s", camel_exception_get_description (ex)); camel_test_pull (); camel_exception_clear (ex); camel_test_push ("PKCS7 verify"); g_seekable_seek (G_SEEKABLE (stream1), 0, G_SEEK_SET, NULL, NULL); g_seekable_seek (G_SEEKABLE (stream2), 0, G_SEEK_SET, NULL, NULL); valid = camel_smime_verify (ctx, CAMEL_CIPHER_HASH_SHA1, stream1, stream2, ex); check_msg (!camel_exception_is_set (ex), "%s", camel_exception_get_description (ex)); check_msg (camel_cipher_validity_get_valid (valid), "%s", camel_cipher_validity_get_description (valid)); camel_cipher_validity_free (valid); camel_test_pull (); g_object_unref (stream1); g_object_unref (stream2); stream1 = camel_stream_mem_new (); stream2 = camel_stream_mem_new (); stream3 = camel_stream_mem_new (); camel_stream_write (stream1, "Hello, I am a test of encryption/decryption.", 44); g_seekable_seek (G_SEEKABLE (stream1), 0, G_SEEK_SET, NULL, NULL); camel_exception_clear (ex); camel_test_push ("PKCS7 encrypt"); recipients = g_ptr_array_new (); g_ptr_array_add (recipients, "*****@*****.**"); camel_smime_encrypt (ctx, FALSE, "*****@*****.**", recipients, stream1, stream2, ex); check_msg (!camel_exception_is_set (ex), "%s", camel_exception_get_description (ex)); g_ptr_array_free (recipients, TRUE); camel_test_pull (); g_seekable_seek (G_SEEKABLE (stream2), 0, G_SEEK_SET, NULL, NULL); camel_exception_clear (ex); camel_test_push ("PKCS7 decrypt"); camel_smime_decrypt (ctx, stream2, stream3, ex); check_msg (!camel_exception_is_set (ex), "%s", camel_exception_get_description (ex)); buf = CAMEL_STREAM_MEM (stream1)->buffer; before = g_strndup (buf->data, buf->len); buf = CAMEL_STREAM_MEM (stream3)->buffer; after = g_strndup (buf->data, buf->len); check_msg (string_equal (before, after), "before = '%s', after = '%s'", before, after); g_free (before); g_free (after); camel_test_pull (); g_object_unref (ctx); g_object_unref (session); camel_test_end (); return 0; }
static CamelMimePart * multipart_signed_get_part (CamelMultipart *multipart, guint index) { CamelMultipartSigned *mps = (CamelMultipartSigned *) multipart; CamelDataWrapper *data_wrapper; CamelStream *stream; GByteArray *byte_array; data_wrapper = CAMEL_DATA_WRAPPER (multipart); byte_array = camel_data_wrapper_get_byte_array (data_wrapper); switch (index) { case CAMEL_MULTIPART_SIGNED_CONTENT: if (mps->content) return mps->content; if (mps->contentraw) { g_return_val_if_fail ( G_IS_SEEKABLE (mps->contentraw), NULL); stream = g_object_ref (mps->contentraw); } else if (mps->start1 == -1 && multipart_signed_parse_content (mps) == -1 && byte_array->len == 0) { g_warning ("Trying to get content on an invalid multipart/signed"); return NULL; } else if (byte_array->len == 0) { return NULL; } else if (mps->start1 == -1) { stream = camel_stream_mem_new (); camel_stream_mem_set_byte_array ( CAMEL_STREAM_MEM (stream), byte_array); } else { stream = multipart_signed_clip_stream ( mps, mps->start1, mps->end1); } g_seekable_seek ( G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL); mps->content = camel_mime_part_new (); camel_data_wrapper_construct_from_stream_sync ( CAMEL_DATA_WRAPPER (mps->content), stream, NULL, NULL); g_object_unref (stream); return mps->content; case CAMEL_MULTIPART_SIGNED_SIGNATURE: if (mps->signature) return mps->signature; if (mps->start1 == -1 && multipart_signed_parse_content (mps) == -1) { g_warning ("Trying to get signature on invalid multipart/signed"); return NULL; } else if (byte_array->len == 0) { return NULL; } stream = multipart_signed_clip_stream ( mps, mps->start2, mps->end2); g_seekable_seek ( G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL); mps->signature = camel_mime_part_new (); camel_data_wrapper_construct_from_stream_sync ( CAMEL_DATA_WRAPPER (mps->signature), stream, NULL, NULL); g_object_unref (stream); return mps->signature; default: g_warning ("trying to get object out of bounds for multipart"); } return NULL; }
static void attachment_button_expand_drag_data_get_cb (EAttachmentButton *button, GdkDragContext *context, GtkSelectionData *selection, guint info, guint time) { EAttachmentView *view; EAttachment *attachment; gchar *mime_type = NULL; attachment = e_attachment_button_get_attachment (button); if (attachment != NULL) mime_type = e_attachment_dup_mime_type (attachment); if (mime_type != NULL) { gboolean processed = FALSE; GdkAtom atom; gchar *atom_name; atom = gtk_selection_data_get_target (selection); atom_name = gdk_atom_name (atom); if (g_strcmp0 (atom_name, mime_type) == 0) { CamelMimePart *mime_part; mime_part = e_attachment_ref_mime_part (attachment); if (mime_part != NULL) { CamelDataWrapper *wrapper; CamelStream *stream; GByteArray *buffer; buffer = g_byte_array_new (); stream = camel_stream_mem_new (); camel_stream_mem_set_byte_array ( CAMEL_STREAM_MEM (stream), buffer); wrapper = camel_medium_get_content ( CAMEL_MEDIUM (mime_part)); camel_data_wrapper_decode_to_stream_sync ( wrapper, stream, NULL, NULL); g_object_unref (stream); gtk_selection_data_set ( selection, atom, 8, buffer->data, buffer->len); processed = TRUE; g_byte_array_free (buffer, TRUE); g_object_unref (mime_part); } } g_free (atom_name); g_free (mime_type); if (processed) return; } view = e_attachment_button_get_view (button); e_attachment_view_drag_data_get ( view, context, selection, info, time); }
/* TODO: This is suboptimal, but the only other solution is to pass around NSSCMSMessages */ guint32 camel_smime_context_describe_part(CamelSMIMEContext *context, CamelMimePart *part) { guint32 flags = 0; CamelContentType *ct; const char *tmp; if (!part) return flags; ct = camel_mime_part_get_content_type(part); if (camel_content_type_is(ct, "multipart", "signed")) { tmp = camel_content_type_param(ct, "protocol"); if (tmp && (g_ascii_strcasecmp(tmp, ((CamelCipherContext *)context)->sign_protocol) == 0 || g_ascii_strcasecmp(tmp, "application/pkcs7-signature") == 0)) flags = CAMEL_SMIME_SIGNED; } else if (camel_content_type_is(ct, "application", "x-pkcs7-mime")) { CamelStreamMem *istream; NSSCMSMessage *cmsg; NSSCMSDecoderContext *dec; /* FIXME: stream this to the decoder incrementally */ istream = (CamelStreamMem *)camel_stream_mem_new(); camel_data_wrapper_decode_to_stream(camel_medium_get_content_object((CamelMedium *)part), (CamelStream *)istream); camel_stream_reset((CamelStream *)istream); dec = NSS_CMSDecoder_Start(NULL, NULL, NULL, NULL, NULL, /* password callback */ NULL, NULL); /* decrypt key callback */ NSS_CMSDecoder_Update(dec, (char *) istream->buffer->data, istream->buffer->len); camel_object_unref(istream); cmsg = NSS_CMSDecoder_Finish(dec); if (cmsg) { if (NSS_CMSMessage_IsSigned(cmsg)) { printf("message is signed\n"); flags |= CAMEL_SMIME_SIGNED; } if (NSS_CMSMessage_IsEncrypted(cmsg)) { printf("message is encrypted\n"); flags |= CAMEL_SMIME_ENCRYPTED; } #if 0 if (NSS_CMSMessage_ContainsCertsOrCrls(cmsg)) { printf("message contains certs or crls\n"); flags |= CAMEL_SMIME_CERTS; } #endif NSS_CMSMessage_Destroy(cmsg); } else { printf("Message could not be parsed\n"); } } return flags; }
static void mail_attachment_handler_message_rfc822 (EAttachmentView *view, GdkDragContext *drag_context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time, EAttachmentHandler *handler) { static GdkAtom atom = GDK_NONE; EAttachmentStore *store; EAttachment *attachment; CamelMimeMessage *message; CamelDataWrapper *wrapper; CamelStream *stream; const gchar *data; gboolean success = FALSE; gpointer parent; gint length; if (G_UNLIKELY (atom == GDK_NONE)) atom = gdk_atom_intern_static_string ("message/rfc822"); if (gtk_selection_data_get_target (selection_data) != atom) return; g_signal_stop_emission_by_name (view, "drag-data-received"); data = (const gchar *) gtk_selection_data_get_data (selection_data); length = gtk_selection_data_get_length (selection_data); stream = camel_stream_mem_new (); camel_stream_write (stream, data, length, NULL, NULL); g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL); message = camel_mime_message_new (); wrapper = CAMEL_DATA_WRAPPER (message); if (!camel_data_wrapper_construct_from_stream_sync ( wrapper, stream, NULL, NULL)) goto exit; store = e_attachment_view_get_store (view); parent = gtk_widget_get_toplevel (GTK_WIDGET (view)); parent = gtk_widget_is_toplevel (parent) ? parent : NULL; attachment = e_attachment_new_for_message (message); e_attachment_store_add_attachment (store, attachment); e_attachment_load_async ( attachment, (GAsyncReadyCallback) call_attachment_load_handle_error, parent ? g_object_ref (parent) : NULL); g_object_unref (attachment); success = TRUE; exit: g_object_unref (message); g_object_unref (stream); gtk_drag_finish (drag_context, success, FALSE, time); }
static CamelCipherValidity * sm_verify_cmsg(CamelCipherContext *context, NSSCMSMessage *cmsg, CamelStream *extstream, CamelException *ex) { struct _CamelSMIMEContextPrivate *p = ((CamelSMIMEContext *)context)->priv; NSSCMSSignedData *sigd = NULL; NSSCMSEnvelopedData *envd; NSSCMSEncryptedData *encd; SECAlgorithmID **digestalgs; NSSCMSDigestContext *digcx; int count, i, nsigners, j; SECItem **digests; PLArenaPool *poolp = NULL; CamelStreamMem *mem; NSSCMSVerificationStatus status; CamelCipherValidity *valid; GString *description; description = g_string_new(""); valid = camel_cipher_validity_new(); camel_cipher_validity_set_valid(valid, TRUE); status = NSSCMSVS_Unverified; /* NB: this probably needs to go into a decoding routine that can be used for processing enveloped data too */ count = NSS_CMSMessage_ContentLevelCount(cmsg); for (i = 0; i < count; i++) { NSSCMSContentInfo *cinfo = NSS_CMSMessage_ContentLevel(cmsg, i); SECOidTag typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo); switch (typetag) { case SEC_OID_PKCS7_SIGNED_DATA: sigd = (NSSCMSSignedData *)NSS_CMSContentInfo_GetContent(cinfo); if (sigd == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("No signed data in signature")); goto fail; } /* need to build digests of the content */ if (!NSS_CMSSignedData_HasDigests(sigd)) { if (extstream == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Digests missing from enveloped data")); goto fail; } if ((poolp = PORT_NewArena(1024)) == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, g_strerror (ENOMEM)); goto fail; } digestalgs = NSS_CMSSignedData_GetDigestAlgs(sigd); digcx = NSS_CMSDigestContext_StartMultiple(digestalgs); if (digcx == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot calculate digests")); goto fail; } mem = (CamelStreamMem *)camel_stream_mem_new(); camel_stream_write_to_stream(extstream, (CamelStream *)mem); NSS_CMSDigestContext_Update(digcx, mem->buffer->data, mem->buffer->len); camel_object_unref(mem); if (NSS_CMSDigestContext_FinishMultiple(digcx, poolp, &digests) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot calculate digests")); goto fail; } if (NSS_CMSSignedData_SetDigests(sigd, digestalgs, digests) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot set message digests")); goto fail; } PORT_FreeArena(poolp, PR_FALSE); poolp = NULL; } /* import all certificates present */ if (NSS_CMSSignedData_ImportCerts(sigd, p->certdb, certUsageEmailSigner, PR_TRUE) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Certificate import failed")); goto fail; } if (NSS_CMSSignedData_ImportCerts(sigd, p->certdb, certUsageEmailRecipient, PR_TRUE) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Certificate import failed")); goto fail; } /* check for certs-only message */ nsigners = NSS_CMSSignedData_SignerInfoCount(sigd); if (nsigners == 0) { /* already imported certs above, not sure what usage we should use here or if this isn't handled above */ if (NSS_CMSSignedData_VerifyCertsOnly(sigd, p->certdb, certUsageEmailSigner) != SECSuccess) { g_string_printf(description, _("Certificate is the only message, cannot verify certificates")); } else { status = NSSCMSVS_GoodSignature; g_string_printf(description, _("Certificate is the only message, certificates imported and verified")); } } else { if (!NSS_CMSSignedData_HasDigests(sigd)) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find signature digests")); goto fail; } for (j = 0; j < nsigners; j++) { NSSCMSSignerInfo *si; char *cn, *em; si = NSS_CMSSignedData_GetSignerInfo(sigd, j); NSS_CMSSignedData_VerifySignerInfo(sigd, j, p->certdb, certUsageEmailSigner); status = NSS_CMSSignerInfo_GetVerificationStatus(si); cn = NSS_CMSSignerInfo_GetSignerCommonName(si); em = NSS_CMSSignerInfo_GetSignerEmailAddress(si); g_string_append_printf(description, _("Signer: %s <%s>: %s\n"), cn?cn:"<unknown>", em?em:"<unknown>", sm_status_description(status)); camel_cipher_validity_add_certinfo(valid, CAMEL_CIPHER_VALIDITY_SIGN, cn, em); if (cn) PORT_Free(cn); if (em) PORT_Free(em); if (status != NSSCMSVS_GoodSignature) camel_cipher_validity_set_valid(valid, FALSE); } } break; case SEC_OID_PKCS7_ENVELOPED_DATA: envd = (NSSCMSEnvelopedData *)NSS_CMSContentInfo_GetContent(cinfo); break; case SEC_OID_PKCS7_ENCRYPTED_DATA: encd = (NSSCMSEncryptedData *)NSS_CMSContentInfo_GetContent(cinfo); break; case SEC_OID_PKCS7_DATA: break; default: break; } } camel_cipher_validity_set_valid(valid, status == NSSCMSVS_GoodSignature); camel_cipher_validity_set_description(valid, description->str); g_string_free(description, TRUE); return valid; fail: camel_cipher_validity_free(valid); g_string_free(description, TRUE); return NULL; }
static CamelMimeMessage * mail_attachment_handler_get_selected_message (EAttachmentHandler *handler) { EAttachment *attachment; EAttachmentView *view; CamelMimePart *mime_part; CamelMimeMessage *message = NULL; CamelDataWrapper *outer_wrapper; CamelContentType *outer_content_type; CamelDataWrapper *inner_wrapper; CamelContentType *inner_content_type; GList *selected; gboolean inner_and_outer_content_types_match; view = e_attachment_handler_get_view (handler); selected = e_attachment_view_get_selected_attachments (view); g_return_val_if_fail (g_list_length (selected) == 1, NULL); attachment = E_ATTACHMENT (selected->data); mime_part = e_attachment_ref_mime_part (attachment); outer_wrapper = camel_medium_get_content (CAMEL_MEDIUM (mime_part)); outer_content_type = camel_data_wrapper_get_mime_type_field (outer_wrapper); if (!camel_content_type_is (outer_content_type, "message", "rfc822")) goto exit; inner_wrapper = camel_medium_get_content (CAMEL_MEDIUM (outer_wrapper)); inner_content_type = camel_data_wrapper_get_mime_type_field (inner_wrapper); inner_and_outer_content_types_match = camel_content_type_is ( inner_content_type, outer_content_type->type, outer_content_type->subtype); if (!inner_and_outer_content_types_match) { CamelStream *mem; gboolean success; /* Create a message copy in case the inner content * type doesn't match the mime_part's content type, * which can happen for multipart/digest, where it * confuses the formatter on reply, which skips all * rfc822 subparts. */ mem = camel_stream_mem_new (); camel_data_wrapper_write_to_stream_sync ( CAMEL_DATA_WRAPPER (outer_wrapper), mem, NULL, NULL); g_seekable_seek ( G_SEEKABLE (mem), 0, G_SEEK_SET, NULL, NULL); message = camel_mime_message_new (); success = camel_data_wrapper_construct_from_stream_sync ( CAMEL_DATA_WRAPPER (message), mem, NULL, NULL); if (!success) g_clear_object (&message); g_object_unref (mem); } exit: if (message == NULL) message = g_object_ref (outer_wrapper); g_clear_object (&mime_part); g_list_free_full (selected, (GDestroyNotify) g_object_unref); return message; }
static int sm_encrypt(CamelCipherContext *context, const char *userid, GPtrArray *recipients, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex) { struct _CamelSMIMEContextPrivate *p = ((CamelSMIMEContext *)context)->priv; /*NSSCMSRecipientInfo **recipient_infos;*/ CERTCertificate **recipient_certs = NULL; NSSCMSContentInfo *cinfo; PK11SymKey *bulkkey = NULL; SECOidTag bulkalgtag; int bulkkeysize, i; CK_MECHANISM_TYPE type; PK11SlotInfo *slot; PLArenaPool *poolp; NSSCMSMessage *cmsg = NULL; NSSCMSEnvelopedData *envd; NSSCMSEncoderContext *enc = NULL; CamelStreamMem *mem; CamelStream *ostream = NULL; CamelDataWrapper *dw; CamelContentType *ct; poolp = PORT_NewArena(1024); if (poolp == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, g_strerror (ENOMEM)); return -1; } /* Lookup all recipients certs, for later working */ recipient_certs = (CERTCertificate **)PORT_ArenaZAlloc(poolp, sizeof(*recipient_certs[0])*(recipients->len + 1)); if (recipient_certs == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, g_strerror (ENOMEM)); goto fail; } for (i=0;i<recipients->len;i++) { recipient_certs[i] = CERT_FindCertByNicknameOrEmailAddr(p->certdb, recipients->pdata[i]); if (recipient_certs[i] == NULL) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find certificate for `%s'"), recipients->pdata[i]); goto fail; } } /* Find a common algorithm, probably 3DES anyway ... */ if (NSS_SMIMEUtil_FindBulkAlgForRecipients(recipient_certs, &bulkalgtag, &bulkkeysize) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find common bulk encryption algorithm")); goto fail; } /* Generate a new bulk key based on the common algorithm - expensive */ type = PK11_AlgtagToMechanism(bulkalgtag); slot = PK11_GetBestSlot(type, context); if (slot == NULL) { /* PORT_GetError(); ?? */ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot allocate slot for encryption bulk key")); goto fail; } bulkkey = PK11_KeyGen(slot, type, NULL, bulkkeysize/8, context); PK11_FreeSlot(slot); /* Now we can start building the message */ /* msg->envelopedData->data */ cmsg = NSS_CMSMessage_Create(NULL); if (cmsg == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS Message")); goto fail; } envd = NSS_CMSEnvelopedData_Create(cmsg, bulkalgtag, bulkkeysize); if (envd == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS Enveloped data")); goto fail; } cinfo = NSS_CMSMessage_GetContentInfo(cmsg); if (NSS_CMSContentInfo_SetContent_EnvelopedData(cmsg, cinfo, envd) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot attach CMS Enveloped data")); goto fail; } cinfo = NSS_CMSEnvelopedData_GetContentInfo(envd); if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot attach CMS data object")); goto fail; } /* add recipient certs */ for (i=0;recipient_certs[i];i++) { NSSCMSRecipientInfo *ri = NSS_CMSRecipientInfo_Create(cmsg, recipient_certs[i]); if (ri == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS Recipient information")); goto fail; } if (NSS_CMSEnvelopedData_AddRecipient(envd, ri) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add CMS Recipient information")); goto fail; } } /* dump it out */ ostream = camel_stream_mem_new(); enc = NSS_CMSEncoder_Start(cmsg, sm_write_stream, ostream, NULL, NULL, NULL, NULL, sm_decrypt_key, bulkkey, NULL, NULL); if (enc == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create encoder context")); goto fail; } /* FIXME: Stream the input */ /* FIXME: Canonicalise the input? */ mem = (CamelStreamMem *)camel_stream_mem_new(); camel_data_wrapper_write_to_stream((CamelDataWrapper *)ipart, (CamelStream *)mem); if (NSS_CMSEncoder_Update(enc, (char *) mem->buffer->data, mem->buffer->len) != SECSuccess) { NSS_CMSEncoder_Cancel(enc); camel_object_unref(mem); camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to add data to encoder")); goto fail; } camel_object_unref(mem); if (NSS_CMSEncoder_Finish(enc) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to encode data")); goto fail; } PK11_FreeSymKey(bulkkey); NSS_CMSMessage_Destroy(cmsg); for (i=0;recipient_certs[i];i++) CERT_DestroyCertificate(recipient_certs[i]); PORT_FreeArena(poolp, PR_FALSE); dw = camel_data_wrapper_new(); camel_data_wrapper_construct_from_stream(dw, ostream); camel_object_unref(ostream); dw->encoding = CAMEL_TRANSFER_ENCODING_BINARY; ct = camel_content_type_new("application", "x-pkcs7-mime"); camel_content_type_set_param(ct, "name", "smime.p7m"); camel_content_type_set_param(ct, "smime-type", "enveloped-data"); camel_data_wrapper_set_mime_type_field(dw, ct); camel_content_type_unref(ct); camel_medium_set_content_object((CamelMedium *)opart, dw); camel_object_unref(dw); camel_mime_part_set_disposition(opart, "attachment"); camel_mime_part_set_filename(opart, "smime.p7m"); camel_mime_part_set_description(opart, "S/MIME Encrypted Message"); camel_mime_part_set_encoding(opart, CAMEL_TRANSFER_ENCODING_BASE64); return 0; fail: if (ostream) camel_object_unref(ostream); if (cmsg) NSS_CMSMessage_Destroy(cmsg); if (bulkkey) PK11_FreeSymKey(bulkkey); if (recipient_certs) { for (i=0;recipient_certs[i];i++) CERT_DestroyCertificate(recipient_certs[i]); } PORT_FreeArena(poolp, PR_FALSE); return -1; }
static void create_mime_message_cb (ESoapMessage *msg, gpointer user_data) { struct _create_mime_msg_data *create_data = user_data; CamelStream *mem, *filtered; CamelMimeFilter *filter; CamelContentType *content_type; GByteArray *bytes; gchar *base64; gint msgflag; guint32 message_camel_flags = 0; if (create_data->info) message_camel_flags = camel_message_info_flags (create_data->info); e_soap_message_start_element (msg, "Message", NULL, NULL); e_soap_message_start_element (msg, "MimeContent", NULL, NULL); /* This is horrid. We really need to extend ESoapMessage to allow us * to stream this directly rather than storing it in RAM. Which right * now we are doing about four times: the GByteArray in the mem stream, * then the base64 version, then the xmlDoc, then the soup request. */ camel_mime_message_set_best_encoding ( create_data->message, CAMEL_BESTENC_GET_ENCODING, CAMEL_BESTENC_8BIT); mem = camel_stream_mem_new (); filtered = camel_stream_filter_new (mem); filter = camel_mime_filter_crlf_new ( CAMEL_MIME_FILTER_CRLF_ENCODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY); camel_stream_filter_add (CAMEL_STREAM_FILTER (filtered), filter); g_object_unref (filter); camel_data_wrapper_write_to_stream_sync ( CAMEL_DATA_WRAPPER (create_data->message), filtered, NULL, NULL); camel_stream_flush (filtered, NULL, NULL); camel_stream_flush (mem, NULL, NULL); bytes = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (mem)); base64 = g_base64_encode (bytes->data, bytes->len); g_object_unref (mem); g_object_unref (filtered); e_soap_message_write_string (msg, base64); g_free (base64); e_soap_message_end_element (msg); /* MimeContent */ content_type = camel_mime_part_get_content_type (CAMEL_MIME_PART (create_data->message)); if (content_type && camel_content_type_is (content_type, "multipart", "report") && camel_content_type_param (content_type, "report-type") && g_ascii_strcasecmp (camel_content_type_param (content_type, "report-type"), "disposition-notification") == 0) { /* it's a disposition notification reply, set ItemClass too */ e_soap_message_start_element (msg, "ItemClass", NULL, NULL); e_soap_message_write_string (msg, "REPORT.IPM.NOTE.IPNRN"); e_soap_message_end_element (msg); /* ItemClass */ } e_ews_message_write_string_parameter_with_attribute ( msg, "Importance", NULL, (message_camel_flags & CAMEL_MESSAGE_FLAGGED) != 0 ? "High" : "Normal", NULL, NULL); /* more MAPI crap. You can't just set the IsDraft property * here you have to use the MAPI MSGFLAG_UNSENT extended * property Further crap is that Exchange 2007 assumes when it * sees this property that you're setting the value to 0 * ... it never checks */ msgflag = MAPI_MSGFLAG_READ; /* draft or sent is always read */ if ((message_camel_flags & CAMEL_MESSAGE_DRAFT) != 0) msgflag |= MAPI_MSGFLAG_UNSENT; e_ews_message_add_extended_property_tag_int (msg, 0x0e07, msgflag); if ((message_camel_flags & (CAMEL_MESSAGE_FORWARDED | CAMEL_MESSAGE_ANSWERED)) != 0) { gint icon; icon = (message_camel_flags & CAMEL_MESSAGE_ANSWERED) != 0 ? 0x105 : 0x106; e_ews_message_add_extended_property_tag_int (msg, 0x1080, icon); } if (create_data->info) { const gchar *followup, *completed, *dueby; time_t completed_tt = (time_t) 0 , dueby_tt = (time_t) 0; /* follow-up flags */ followup = camel_message_info_user_tag (create_data->info, "follow-up"); completed = camel_message_info_user_tag (create_data->info, "completed-on"); dueby = camel_message_info_user_tag (create_data->info, "due-by"); if (followup && !*followup) followup = NULL; if (completed && *completed) completed_tt = camel_header_decode_date (completed, NULL); if (dueby && *dueby) dueby_tt = camel_header_decode_date (dueby, NULL); /* PidTagFlagStatus */ e_ews_message_add_extended_property_tag_int (msg, 0x1090, followup ? (completed_tt != (time_t) 0 ? 0x01 /* followupComplete */: 0x02 /* followupFlagged */) : 0x0); if (followup) { /* PidLidFlagRequest */ e_ews_message_add_extended_property_distinguished_tag_string (msg, "Common", 0x8530, followup); /* PidTagToDoItemFlags */ e_ews_message_add_extended_property_tag_int (msg, 0x0e2b, 1); } if (followup && completed_tt != (time_t) 0) { /* minute precision */ completed_tt = completed_tt - (completed_tt % 60); /* PidTagFlagCompleteTime */ e_ews_message_add_extended_property_tag_time (msg, 0x1091, completed_tt); /* PidLidTaskDateCompleted */ e_ews_message_add_extended_property_distinguished_tag_time (msg, "Task", 0x810f, completed_tt); /* PidLidTaskStatus */ e_ews_message_add_extended_property_distinguished_tag_int (msg, "Task", 0x8101, 2); /* PidLidPercentComplete */ e_ews_message_add_extended_property_distinguished_tag_double (msg, "Task", 0x8102, 1.0); /* PidLidTaskComplete */ e_ews_message_add_extended_property_distinguished_tag_boolean (msg, "Task", 0x811c, TRUE); } if (followup && dueby_tt != (time_t) 0 && completed_tt == (time_t) 0) { /* PidLidTaskStatus */ e_ews_message_add_extended_property_distinguished_tag_int (msg, "Task", 0x8101, 0); /* PidLidPercentComplete */ e_ews_message_add_extended_property_distinguished_tag_double (msg, "Task", 0x8102, 0.0); /* PidLidTaskDueDate */ e_ews_message_add_extended_property_distinguished_tag_time (msg, "Task", 0x8105, dueby_tt); /* PidLidTaskComplete */ e_ews_message_add_extended_property_distinguished_tag_boolean (msg, "Task", 0x811c, FALSE); } } if (create_data->recipients) { GHashTable *recip_to, *recip_cc, *recip_bcc; recip_to = g_hash_table_new (camel_strcase_hash, camel_strcase_equal); recip_cc = g_hash_table_new (camel_strcase_hash, camel_strcase_equal); recip_bcc = g_hash_table_new (camel_strcase_hash, camel_strcase_equal); filter_recipients (create_data->message, create_data->recipients, recip_to, recip_cc, recip_bcc); write_recipients (msg, "ToRecipients", recip_to); write_recipients (msg, "CcRecipients", recip_cc); write_recipients (msg, "BccRecipients", recip_bcc); g_hash_table_destroy (recip_to); g_hash_table_destroy (recip_cc); g_hash_table_destroy (recip_bcc); } e_ews_message_write_string_parameter_with_attribute ( msg, "IsRead", NULL, (message_camel_flags & CAMEL_MESSAGE_SEEN) != 0 ? "true" : "false", NULL, NULL); e_soap_message_end_element (msg); /* Message */ g_free (create_data); }
static int pipe_to_sa_full (CamelMimeMessage *msg, const char *in, char **argv, int rv_err, int wait_for_termination, GByteArray *output_buffer, GError **error) { int result, status, errnosav, fds[2], out_fds[2]; CamelStream *stream; char *program; pid_t pid; if (camel_debug_start ("junk")) { int i; printf ("pipe_to_sa "); for (i = 0; argv[i]; i++) printf ("%s ", argv[i]); printf ("\n"); camel_debug_end (); } program = g_find_program_in_path (argv [0]); if (program == NULL) { d(printf ("program not found, returning %d\n", rv_err)); g_set_error (error, EM_JUNK_ERROR, rv_err, _("SpamAssassin not found, code: %d"), rv_err); return rv_err; } g_free (program); if (pipe (fds) == -1) { errnosav = errno; d(printf ("failed to create a pipe (for use with spamassassin: %s\n", strerror (errno))); g_set_error (error, EM_JUNK_ERROR, errnosav, _("Failed to create pipe: %s"), strerror (errnosav)); errno = errnosav; return rv_err; } if (output_buffer && pipe (out_fds) == -1) { errnosav = errno; d(printf ("failed to create a pipe (for use with spamassassin: %s\n", strerror (errno))); g_set_error (error, EM_JUNK_ERROR, errnosav, _("Failed to create pipe: %s"), strerror (errnosav)); close (fds [0]); close (fds [1]); errno = errnosav; return rv_err; } if (!(pid = fork ())) { /* child process */ int maxfd, fd, nullfd; nullfd = open ("/dev/null", O_WRONLY); if (dup2 (fds[0], STDIN_FILENO) == -1 || dup2 (nullfd, STDERR_FILENO) == -1 || (output_buffer == NULL && dup2 (nullfd, STDOUT_FILENO) == -1) || (output_buffer != NULL && dup2 (out_fds[1], STDOUT_FILENO) == -1)) _exit (rv_err & 0377); close (fds [0]); if (output_buffer) close (out_fds [1]); setsid (); maxfd = sysconf (_SC_OPEN_MAX); for (fd = 3; fd < maxfd; fd++) fcntl (fd, F_SETFD, FD_CLOEXEC); execvp (argv[0], argv); _exit (rv_err & 0377); } else if (pid < 0) { errnosav = errno; close (fds[0]); close (fds[1]); if (output_buffer) { close (out_fds [0]); close (out_fds [1]); } if (errnosav != 0 && errnosav != -1) g_set_error (error, EM_JUNK_ERROR, errnosav, _("Error after fork: %s"), strerror (errnosav)); errno = errnosav; return rv_err; } /* parent process */ close (fds[0]); if (output_buffer) close (out_fds [1]); if (msg) { stream = camel_stream_fs_new_with_fd (fds[1]); camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (msg), stream); camel_stream_flush (stream); camel_stream_close (stream); camel_object_unref (stream); } else if (in) { camel_write (fds[1], in, strlen (in)); close (fds[1]); } if (output_buffer) { CamelStreamMem *memstream; stream = camel_stream_fs_new_with_fd (out_fds[0]); memstream = (CamelStreamMem *) camel_stream_mem_new (); camel_stream_mem_set_byte_array (memstream, output_buffer); camel_stream_write_to_stream (stream, (CamelStream *) memstream); camel_object_unref (stream); g_byte_array_append (output_buffer, (unsigned char *)"", 1); d(printf ("child process output: %s len: %d\n", output_buffer->data, output_buffer->len)); } if (wait_for_termination) { int res; d(printf ("wait for child %d termination\n", pid)); result = waitpid (pid, &status, 0); d(printf ("child %d terminated with result %d status %d exited %d exitstatus %d\n", pid, result, status, WIFEXITED (status), WEXITSTATUS (status))); if (result == -1 && errno == EINTR) { /* child process is hanging... */ kill (pid, SIGTERM); sleep (1); result = waitpid (pid, &status, WNOHANG); if (result == 0) { /* ...still hanging, set phasers to KILL */ kill (pid, SIGKILL); sleep (1); result = waitpid (pid, &status, WNOHANG); g_set_error (error, EM_JUNK_ERROR, -2, _("SpamAssassin child process does not respond, killing...")); } else g_set_error (error, EM_JUNK_ERROR, -3, _("Wait for Spamassassin child process interrupted, terminating...")); } if (result != -1 && WIFEXITED (status)) res = WEXITSTATUS (status); else res = rv_err; if (res != 0) g_set_error (error, EM_JUNK_ERROR, res, _("Pipe to SpamAssassin failed, error code: %d"), res); return res; } else return 0; }
int main (int argc, char **argv) { CamelSession *session; CamelCipherContext *ctx; CamelException *ex; CamelCipherValidity *valid; CamelStream *stream1, *stream2; struct _CamelMimePart *sigpart, *conpart, *encpart, *outpart; CamelDataWrapper *dw; GPtrArray *recipients; GByteArray *buf; char *before, *after; int ret; if (getenv("CAMEL_TEST_GPG") == NULL) return 77; camel_test_init (argc, argv); /* clear out any camel-test data */ system ("/bin/rm -rf /tmp/camel-test"); system ("/bin/mkdir /tmp/camel-test"); setenv ("GNUPGHOME", "/tmp/camel-test/.gnupg", 1); /* import the gpg keys */ if ((ret = system ("gpg < /dev/null > /dev/null 2>&1")) == -1) return 77; else if (WEXITSTATUS (ret) == 127) return 77; g_message ("gpg --import " TEST_DATA_DIR "/camel-test.gpg.pub > /dev/null 2>&1"); system ("gpg --import " TEST_DATA_DIR "/camel-test.gpg.pub > /dev/null 2>&1"); g_message ("gpg --import " TEST_DATA_DIR "/camel-test.gpg.sec > /dev/null 2>&1"); system ("gpg --import " TEST_DATA_DIR "/camel-test.gpg.sec > /dev/null 2>&1"); session = camel_pgp_session_new ("/tmp/camel-test"); ex = camel_exception_new (); ctx = camel_gpg_context_new (session); camel_gpg_context_set_always_trust (CAMEL_GPG_CONTEXT (ctx), TRUE); camel_test_start ("Test of PGP functions"); stream1 = camel_stream_mem_new (); camel_stream_write (stream1, "Hello, I am a test stream.\n", 27); camel_stream_reset (stream1); conpart = camel_mime_part_new(); dw = camel_data_wrapper_new(); camel_data_wrapper_construct_from_stream(dw, stream1); camel_medium_set_content_object((CamelMedium *)conpart, dw); camel_object_unref(stream1); camel_object_unref(dw); sigpart = camel_mime_part_new(); camel_test_push ("PGP signing"); camel_cipher_sign (ctx, "*****@*****.**", CAMEL_CIPHER_HASH_SHA1, conpart, sigpart, ex); if (camel_exception_is_set(ex)) { printf("PGP signing failed assuming non-functional environment\n%s", camel_exception_get_description (ex)); camel_test_pull(); return 77; } camel_test_pull (); camel_exception_clear (ex); camel_test_push ("PGP verify"); valid = camel_cipher_verify (ctx, sigpart, ex); check_msg (!camel_exception_is_set (ex), "%s", camel_exception_get_description (ex)); check_msg (camel_cipher_validity_get_valid (valid), "%s", camel_cipher_validity_get_description (valid)); camel_cipher_validity_free (valid); camel_test_pull (); camel_object_unref(conpart); camel_object_unref(sigpart); stream1 = camel_stream_mem_new (); camel_stream_write (stream1, "Hello, I am a test of encryption/decryption.", 44); camel_stream_reset (stream1); conpart = camel_mime_part_new(); dw = camel_data_wrapper_new(); camel_stream_reset(stream1); camel_data_wrapper_construct_from_stream(dw, stream1); camel_medium_set_content_object((CamelMedium *)conpart, dw); camel_object_unref(stream1); camel_object_unref(dw); encpart = camel_mime_part_new(); camel_exception_clear (ex); camel_test_push ("PGP encrypt"); recipients = g_ptr_array_new (); g_ptr_array_add (recipients, "*****@*****.**"); camel_cipher_encrypt (ctx, "*****@*****.**", recipients, conpart, encpart, ex); check_msg (!camel_exception_is_set (ex), "%s", camel_exception_get_description (ex)); g_ptr_array_free (recipients, TRUE); camel_test_pull (); camel_exception_clear (ex); camel_test_push ("PGP decrypt"); outpart = camel_mime_part_new(); valid = camel_cipher_decrypt (ctx, encpart, outpart, ex); check_msg (!camel_exception_is_set (ex), "%s", camel_exception_get_description (ex)); check_msg (valid->encrypt.status == CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED, "%s", valid->encrypt.description); stream1 = camel_stream_mem_new(); stream2 = camel_stream_mem_new(); camel_data_wrapper_write_to_stream((CamelDataWrapper *)conpart, stream1); camel_data_wrapper_write_to_stream((CamelDataWrapper *)outpart, stream2); buf = CAMEL_STREAM_MEM (stream1)->buffer; before = g_strndup (buf->data, buf->len); buf = CAMEL_STREAM_MEM (stream2)->buffer; after = g_strndup (buf->data, buf->len); check_msg (string_equal (before, after), "before = '%s', after = '%s'", before, after); g_free (before); g_free (after); camel_object_unref(stream1); camel_object_unref(stream2); camel_object_unref(conpart); camel_object_unref(encpart); camel_object_unref(outpart); camel_test_pull (); camel_object_unref (CAMEL_OBJECT (ctx)); camel_object_unref (CAMEL_OBJECT (session)); camel_test_end (); return 0; }