static GMimeStream* get_mime_stream (GMimeObject *obj, GError **err) { GMimeStream *mstream; GMimeDataWrapper *wrapper; if (!GMIME_IS_PART(obj)) { char *str; GByteArray *ar; str = g_mime_object_to_string (obj); ar = g_byte_array_new_take ((guchar*)str, strlen(str)); mstream = g_mime_stream_mem_new_with_byte_array (ar); g_mime_stream_mem_set_owner ( GMIME_STREAM_MEM(mstream), TRUE); return mstream; } wrapper = get_data_wrapper (obj, err); if (!wrapper) return NULL; mstream = g_mime_data_wrapper_get_stream (wrapper); if (!mstream || g_mime_stream_reset (mstream) != 0) { g_set_error (err, G_IO_ERROR, G_IO_ERROR_FAILED, "invalid mime-stream"); return NULL; } return mstream; }
/** * g_mime_header_list_write_to_stream: * @headers: a #GMimeHeaderList * @stream: output stream * * Write the headers to a stream. * * Returns: the number of bytes written or %-1 on fail. **/ ssize_t g_mime_header_list_write_to_stream (const GMimeHeaderList *headers, GMimeStream *stream) { ssize_t nwritten, total = 0; GMimeHeaderWriter writer; GHashTable *writers; GMimeHeader *header; g_return_val_if_fail (headers != NULL, -1); g_return_val_if_fail (stream != NULL, -1); if (headers->stream) { g_mime_stream_reset (headers->stream); return g_mime_stream_write_to_stream (headers->stream, stream); } header = (GMimeHeader *) headers->list.head; writers = headers->writers; while (header->next) { if (header->value) { if (!(writer = g_hash_table_lookup (writers, header->name))) writer = default_writer; if ((nwritten = writer (stream, header->name, header->value)) == -1) return -1; total += nwritten; } header = header->next; } return total; }
static void test_cat_read (GMimeStream *whole, struct _StreamPart *parts, int bounded) { struct _StreamPart *part = parts; GMimeStream *stream, *cat; Exception *ex; int fd; cat = g_mime_stream_cat_new (); while (part != NULL) { d(fprintf (stderr, "adding %s start=%lld, end=%lld...\n", part->filename, part->pstart, part->pend)); if ((fd = open (part->filename, O_RDONLY, 0)) == -1) { ex = exception_new ("could not open `%s': %s", part->filename, g_strerror (errno)); g_object_unref (cat); throw (ex); } stream = g_mime_stream_fs_new_with_bounds (fd, part->pstart, bounded ? part->pend : -1); g_mime_stream_cat_add_source ((GMimeStreamCat *) cat, stream); g_object_unref (stream); part = part->next; } g_mime_stream_reset (whole); if (check_streams_match (whole, cat, "stream.part*", TRUE) == -1) { ex = exception_new ("streams do not match"); g_object_unref (cat); throw (ex); } }
/** * g_mime_header_list_to_string: * @headers: a #GMimeHeaderList * * Allocates a string buffer containing the raw rfc822 headers * contained in @headers. * * Returns: a string containing the header block. **/ char * g_mime_header_list_to_string (const GMimeHeaderList *headers) { GMimeStream *stream; GByteArray *array; char *str; g_return_val_if_fail (headers != NULL, NULL); array = g_byte_array_new (); stream = g_mime_stream_mem_new (); g_mime_stream_mem_set_byte_array (GMIME_STREAM_MEM (stream), array); if (headers->stream) { g_mime_stream_reset (headers->stream); g_mime_stream_write_to_stream (headers->stream, stream); } else { g_mime_header_list_write_to_stream (headers, stream); } g_object_unref (stream); g_byte_array_append (array, (unsigned char *) "", 1); str = (char *) array->data; g_byte_array_free (array, FALSE); return str; }
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 test_stream_buffer_gets (const char *filename) { GMimeStream *stream, *buffered = NULL; int fd; if ((fd = open (filename, O_RDONLY, 0)) == -1) { v(fprintf (stderr, "failed to open %s", filename)); return; } stream = g_mime_stream_fs_new (fd); testsuite_check ("GMimeStreamBuffer::block gets"); try { g_mime_stream_reset (stream); buffered = g_mime_stream_buffer_new (stream, GMIME_STREAM_BUFFER_BLOCK_READ); test_stream_gets (buffered, filename); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("GMimeStreamBuffer::block gets() failed: %s", ex->message); } finally { g_object_unref (buffered); } testsuite_check ("GMimeStreamBuffer::cache gets"); try { g_mime_stream_reset (stream); buffered = g_mime_stream_buffer_new (stream, GMIME_STREAM_BUFFER_CACHE_READ); test_stream_gets (buffered, filename); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("GMimeStreamBuffer::block gets() failed: %s", ex->message); } finally { g_object_unref (buffered); } g_object_unref (stream); }
static GMimeStream * random_whole_stream (const char *datadir, char **filename) { size_t nwritten, buflen, total = 0, size, i; GMimeStream *stream; char buf[4096]; ssize_t n; int fd; /* read between 4k and 14k bytes */ size = 4096 + (size_t) (10240.0 * (rand () / (RAND_MAX + 1.0))); v(fprintf (stdout, "Generating %zu bytes of random data... ", size)); v(fflush (stdout)); g_mkdir_with_parents (datadir, 0755); g_snprintf (buf, sizeof (buf), "%s%cstream.%u", datadir, G_DIR_SEPARATOR, getpid ()); if ((fd = open (buf, O_CREAT | O_TRUNC | O_RDWR, 0666)) == -1) { fprintf (stderr, "Error: Cannot create `%s': %s\n", buf, g_strerror (errno)); exit (EXIT_FAILURE); } *filename = g_strdup (buf); stream = g_mime_stream_fs_new (fd); while (total < size) { buflen = size - total > sizeof (buf) ? sizeof (buf) : size - total; for (i = 0; i < buflen; i++) buf[i] = (char) (255 * (rand () / (RAND_MAX + 1.0))); nwritten = 0; do { if ((n = g_mime_stream_write (stream, buf + nwritten, buflen - nwritten)) <= 0) break; nwritten += n; total += n; } while (nwritten < buflen); if (nwritten < buflen) break; } g_mime_stream_flush (stream); g_mime_stream_reset (stream); v(fputs ("done\n", stdout)); return stream; }
static size_t gen_random_stream (GMimeStream *stream) { size_t nwritten, buflen, total = 0, size, i; char buf[4096]; ssize_t n; /* read between 4k and 14k bytes */ size = 4096 + (size_t) (10240.0 * (rand () / (RAND_MAX + 1.0))); v(fprintf (stdout, "Generating %" G_GSIZE_FORMAT " bytes of random data... ", size)); v(fflush (stdout)); while (total < size) { buflen = size - total > sizeof (buf) ? sizeof (buf) : size - total; for (i = 0; i < buflen; i++) buf[i] = (char) (255 * (rand () / (RAND_MAX + 1.0))); nwritten = 0; do { if ((n = g_mime_stream_write (stream, buf + nwritten, buflen - nwritten)) <= 0) break; nwritten += n; total += n; } while (nwritten < buflen); if (nwritten < buflen) break; } g_mime_stream_flush (stream); g_mime_stream_reset (stream); v(fputs ("done\n", stdout)); return size; }
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); }
static void test_cat_write (GMimeStream *whole, struct _StreamPart *parts, int bounded) { struct _StreamPart *part = parts; GMimeStream *stream, *sub, *cat; Exception *ex; int fd; cat = g_mime_stream_cat_new (); while (part != NULL) { d(fprintf (stderr, "adding %s start=%lld, end=%lld...\n", part->filename, part->pstart, part->pend)); if ((fd = open (part->filename, O_CREAT | O_TRUNC | O_WRONLY, 0666)) == -1) { ex = exception_new ("could not create `%s': %s", part->filename, g_strerror (errno)); throw (ex); } stream = g_mime_stream_fs_new_with_bounds (fd, part->pstart, part->pend); g_mime_stream_cat_add_source ((GMimeStreamCat *) cat, stream); g_object_unref (stream); part = part->next; } g_mime_stream_reset (whole); if (g_mime_stream_write_to_stream (whole, (GMimeStream *) cat) == -1) { ex = exception_new ("%s", g_strerror (errno)); g_object_unref (cat); throw (ex); } g_object_unref (cat); /* now lets check that the content matches */ d(fprintf (stderr, "checking all part streams have correct data...\n")); part = parts; while (part != NULL) { d(fprintf (stderr, "checking substream %s\n", part->filename)); if ((fd = open (part->filename, O_RDONLY, 0)) == -1) { ex = exception_new ("could not open `%s': %s", part->filename, g_strerror (errno)); throw (ex); } if (!(sub = g_mime_stream_substream (whole, part->wstart, part->wend))) { ex = exception_new ("could not substream original stream"); close (fd); throw (ex); } if (!(stream = g_mime_stream_fs_new_with_bounds (fd, part->pstart, -1))) { ex = exception_new ("could not instantiate stream for `%s'", part->filename); close (fd); throw (ex); } d(fprintf (stderr, "checking substream %s matches...\n", part->filename)); if (check_streams_match (sub, stream, part->filename, TRUE) == -1) { ex = exception_new ("streams did not match"); g_object_unref (stream); g_object_unref (sub); throw (ex); } g_object_unref (stream); g_object_unref (sub); part = part->next; } }
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; }
int main (int argc, char **argv) { #ifdef ENABLE_CRYPTO const char *datadir = "data/pgp"; GMimeStream *istream, *ostream; GMimeFilterOpenPGP *filter; GMimeCryptoContext *ctx; const char *what; char *gpg, *key; struct stat st; int i; g_mime_init (); testsuite_init (argc, argv); if (!(gpg = g_find_program_in_path ("gpg2"))) if (!(gpg = g_find_program_in_path ("gpg"))) return EXIT_FAILURE; if (testsuite_setup_gpghome (gpg) != 0) return EXIT_FAILURE; g_free (gpg); for (i = 1; i < argc; i++) { if (argv[i][0] != '-') { datadir = argv[i]; break; } } if (i < argc && (stat (datadir, &st) == -1 || !S_ISDIR (st.st_mode))) return 0; testsuite_start ("GnuPG crypto context"); ctx = g_mime_gpg_context_new (); g_mime_crypto_context_set_request_password (ctx, request_passwd); testsuite_check ("GMimeGpgContext::import"); try { key = g_build_filename (datadir, "gmime.gpg.pub", NULL); import_key (ctx, key); g_free (key); key = g_build_filename (datadir, "gmime.gpg.sec", NULL); import_key (ctx, key); g_free (key); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("GMimeGpgContext::import failed: %s", ex->message); return EXIT_FAILURE; } finally; key = g_build_filename (datadir, "gmime.gpg.pub", NULL); testsuite_check ("GMimeGpgContext::export"); try { test_export (ctx, key); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("GMimeGpgContext::export failed: %s", ex->message); } finally; g_free (key); istream = g_mime_stream_mem_new (); ostream = g_mime_stream_mem_new (); g_mime_stream_write_string (istream, "this is some cleartext\r\n"); g_mime_stream_reset (istream); what = "GMimeGpgContext::sign"; testsuite_check ("%s", what); try { test_sign (ctx, FALSE, istream, ostream); testsuite_check_passed (); what = "GMimeGpgContext::verify"; testsuite_check ("%s", what); g_mime_stream_reset (istream); g_mime_stream_reset (ostream); test_verify (ctx, istream, ostream); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("%s failed: %s", what, ex->message); } finally; g_object_unref (ostream); g_mime_stream_reset (istream); ostream = g_mime_stream_mem_new (); what = "GMimeGpgContext::sign (detached)"; testsuite_check ("%s", what); try { test_sign (ctx, TRUE, istream, ostream); testsuite_check_passed (); what = "GMimeGpgContext::verify (detached)"; testsuite_check ("%s", what); g_mime_stream_reset (istream); g_mime_stream_reset (ostream); test_verify_detached (ctx, istream, ostream); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("%s failed: %s", what, ex->message); } finally; g_object_unref (ostream); g_mime_stream_reset (istream); ostream = g_mime_stream_mem_new (); what = "GMimeGpgContext::encrypt"; testsuite_check ("%s", what); try { test_encrypt (ctx, FALSE, istream, ostream); testsuite_check_passed (); what = "GMimeGpgContext::decrypt"; testsuite_check ("%s", what); g_mime_stream_reset (istream); g_mime_stream_reset (ostream); test_decrypt (ctx, FALSE, istream, ostream); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("%s failed: %s", what, ex->message); } finally; g_object_unref (ostream); g_mime_stream_reset (istream); ostream = g_mime_stream_mem_new (); what = "GMimeGpgContext::encrypt+sign"; testsuite_check ("%s", what); try { test_encrypt (ctx, TRUE, istream, ostream); testsuite_check_passed (); what = "GMimeGpgContext::decrypt+verify"; testsuite_check ("%s", what); g_mime_stream_reset (istream); g_mime_stream_reset (ostream); test_decrypt (ctx, TRUE, istream, ostream); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("%s failed: %s", what, ex->message); } finally; g_object_unref (istream); g_object_unref (ostream); g_object_unref (ctx); filter = (GMimeFilterOpenPGP *) g_mime_filter_openpgp_new (); what = "GMimeFilterOpenPGP::public key block"; testsuite_check ("%s", what); try { key = g_build_filename (datadir, "gmime.gpg.pub", NULL); test_openpgp_filter (filter, key, GMIME_OPENPGP_DATA_PUBLIC_KEY, 0, 1720); g_free (key); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("%s failed: %s", what, ex->message); } finally; g_mime_filter_reset ((GMimeFilter *) filter); what = "GMimeFilterOpenPGP::private key block"; testsuite_check ("%s", what); try { key = g_build_filename (datadir, "gmime.gpg.sec", NULL); test_openpgp_filter (filter, key, GMIME_OPENPGP_DATA_PRIVATE_KEY, 0, 1928); g_free (key); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("%s failed: %s", what, ex->message); } finally; g_mime_filter_reset ((GMimeFilter *) filter); what = "GMimeFilterOpenPGP::signed message block"; testsuite_check ("%s", what); try { key = g_build_filename (datadir, "signed-message.txt", NULL); test_openpgp_filter (filter, key, GMIME_OPENPGP_DATA_SIGNED, 162, 440); g_free (key); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("%s failed: %s", what, ex->message); } finally; g_mime_filter_reset ((GMimeFilter *) filter); what = "GMimeFilterOpenPGP::encrypted message block"; testsuite_check ("%s", what); try { key = g_build_filename (datadir, "encrypted-message.txt", NULL); test_openpgp_filter (filter, key, GMIME_OPENPGP_DATA_ENCRYPTED, 165, 1084); g_free (key); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("%s failed: %s", what, ex->message); } finally; g_object_unref (filter); testsuite_end (); g_mime_shutdown (); if (testsuite_destroy_gpghome () != 0) return EXIT_FAILURE; return testsuite_exit (); #else fprintf (stderr, "PGP support not enabled in this build.\n"); return EXIT_SUCCESS; #endif }
static void test_export (GMimeCryptoContext *ctx, const char *path) { GMimeStream *istream, *ostream; register const char *inptr; const char *inbuf, *outbuf; size_t inlen, outlen; Exception *ex = NULL; const char *keys[2]; GError *err = NULL; int fd; if ((fd = open (path, O_RDONLY, 0)) == -1) throw (exception_new ("open() failed: %s", g_strerror (errno))); ostream = g_mime_stream_fs_new (fd); istream = g_mime_stream_mem_new (); g_mime_stream_write_to_stream (ostream, istream); g_mime_stream_reset (istream); g_object_unref (ostream); keys[0] = "*****@*****.**"; keys[1] = NULL; ostream = g_mime_stream_mem_new (); g_mime_crypto_context_export_keys (ctx, keys, ostream, &err); if (err != NULL) { ex = exception_new ("%s", err->message); g_object_unref (istream); g_object_unref (ostream); g_error_free (err); throw (ex); } inbuf = (const char *) GMIME_STREAM_MEM (istream)->buffer->data; inlen = GMIME_STREAM_MEM (istream)->buffer->len; if ((inptr = strstr (inbuf, "\n\n"))) { /* skip past the headers which may have different version numbers */ inptr += 2; inlen -= (inptr - inbuf); inbuf = inptr; } outbuf = (const char *) GMIME_STREAM_MEM (ostream)->buffer->data; outlen = GMIME_STREAM_MEM (ostream)->buffer->len; if ((inptr = strstr (outbuf, "\n\n"))) { /* skip past the headers which may have different version numbers */ inptr += 2; outlen -= (inptr - outbuf); outbuf = inptr; } if (outlen != inlen || memcmp (outbuf, inbuf, inlen) != 0) ex = exception_new ("exported key does not match original key"); g_object_unref (istream); g_object_unref (ostream); if (ex != NULL) throw (ex); }
int main (int argc, char **argv) { const char *datadir = "data/mbox"; char input[256], output[256], *tmp, *p, *q; GMimeStream *istream, *ostream, *mstream, *pstream; GMimeParser *parser; const char *dent; const char *path; struct stat st; GDir *dir; int i; #ifdef ENABLE_MBOX_MATCH int fd; if (mkdir ("./tmp", 0755) == -1 && errno != EEXIST) return 0; #endif g_mime_init (); testsuite_init (argc, argv); path = datadir; for (i = 1; i < argc; i++) { if (argv[i][0] != '-') { path = argv[i]; break; } } testsuite_start ("Mbox parser"); if (stat (path, &st) == -1) goto exit; if (S_ISDIR (st.st_mode)) { /* automated testsuite */ p = g_stpcpy (input, path); *p++ = G_DIR_SEPARATOR; p = g_stpcpy (p, "input"); if (!(dir = g_dir_open (input, 0, NULL))) goto exit; *p++ = G_DIR_SEPARATOR; *p = '\0'; q = g_stpcpy (output, path); *q++ = G_DIR_SEPARATOR; q = g_stpcpy (q, "output"); *q++ = G_DIR_SEPARATOR; *q = '\0'; while ((dent = g_dir_read_name (dir))) { if (!g_str_has_suffix (dent, ".mbox")) continue; strcpy (p, dent); strcpy (q, dent); tmp = NULL; parser = NULL; istream = NULL; ostream = NULL; mstream = NULL; pstream = NULL; testsuite_check ("%s", dent); try { if (!(istream = g_mime_stream_fs_open (input, O_RDONLY, 0, NULL))) { throw (exception_new ("could not open `%s': %s", input, g_strerror (errno))); } if (!(ostream = g_mime_stream_fs_open (output, O_RDONLY, 0, NULL))) { throw (exception_new ("could not open `%s': %s", output, g_strerror (errno))); } #ifdef ENABLE_MBOX_MATCH tmp = g_strdup_printf ("./tmp/%s", dent); if ((fd = open (tmp, O_CREAT | O_RDWR | O_TRUNC, 0644)) == -1) { throw (exception_new ("could not open `%s': %s", tmp, g_strerror (errno))); } mstream = g_mime_stream_fs_new (fd); #endif parser = g_mime_parser_new_with_stream (istream); g_mime_parser_set_persist_stream (parser, TRUE); g_mime_parser_set_format (parser, GMIME_FORMAT_MBOX); if (!g_mime_parser_get_persist_stream (parser)) throw (exception_new ("persist stream check failed")); if (g_mime_parser_get_format (parser) != GMIME_FORMAT_MBOX) throw (exception_new ("format check failed")); if (strstr (dent, "content-length") != NULL) { g_mime_parser_set_respect_content_length (parser, TRUE); if (!g_mime_parser_get_respect_content_length (parser)) throw (exception_new ("respect content-length check failed")); } else { g_mime_parser_set_respect_content_length (parser, FALSE); if (g_mime_parser_get_respect_content_length (parser)) throw (exception_new ("respect content-length check failed")); } g_mime_parser_set_header_regex (parser, "^X-Evolution", xevcb, NULL); pstream = g_mime_stream_mem_new (); test_parser (parser, mstream, pstream); #ifdef ENABLE_MBOX_MATCH g_mime_stream_flush (mstream); g_mime_stream_reset (istream); g_mime_stream_reset (mstream); if (!streams_match (istream, mstream)) throw (exception_new ("mboxes do not match for `%s'", dent)); #endif g_mime_stream_reset (ostream); g_mime_stream_reset (pstream); if (!streams_match (ostream, pstream)) throw (exception_new ("summaries do not match for `%s'", dent)); testsuite_check_passed (); #ifdef ENABLE_MBOX_MATCH unlink (tmp); #endif } catch (ex) { if (parser != NULL) testsuite_check_failed ("%s: %s", dent, ex->message); else testsuite_check_warn ("%s: %s", dent, ex->message); } finally; if (mstream != NULL) g_object_unref (mstream); if (pstream != NULL) g_object_unref (pstream); if (istream != NULL) g_object_unref (istream); if (ostream != NULL) g_object_unref (ostream); if (parser != NULL) g_object_unref (parser); g_free (tmp); } g_dir_close (dir); } else if (S_ISREG (st.st_mode)) { /* manually run test on a single file */ if (!(istream = g_mime_stream_fs_open (path, O_RDONLY, 0, NULL))) goto exit; parser = g_mime_parser_new_with_stream (istream); g_mime_parser_set_format (parser, GMIME_FORMAT_MBOX); #ifdef ENABLE_MBOX_MATCH tmp = g_strdup ("./tmp/mbox-test.XXXXXX"); if ((fd = g_mkstemp (tmp)) == -1) { g_object_unref (istream); g_object_unref (parser); g_free (tmp); goto exit; } mstream = g_mime_stream_fs_new (fd); #else mstream = NULL; #endif ostream = g_mime_stream_file_new (stdout); g_mime_stream_file_set_owner ((GMimeStreamFile *) ostream, FALSE); testsuite_check ("user-input mbox: `%s'", path); try { test_parser (parser, mstream, ostream); #ifdef ENABLE_MBOX_MATCH g_mime_stream_reset (istream); g_mime_stream_reset (mstream); if (!streams_match (istream, mstream)) throw (exception_new ("`%s' does not match `%s'", tmp, path)); unlink (tmp); #endif testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("user-input mbox `%s': %s", path, ex->message); } finally; g_object_unref (istream); g_object_unref (ostream); g_object_unref (parser); #ifdef ENABLE_MBOX_MATCH g_object_unref (mstream); g_free (tmp); #endif } else { goto exit; } exit: #ifdef ENABLE_MBOX_MATCH //if ((dir = g_dir_open ("./tmp", 0, NULL))) { // p = g_stpcpy (input, "./tmp"); // *p++ = G_DIR_SEPARATOR; // // while ((dent = g_dir_read_name (dir))) { // strcpy (p, dent); // unlink (input); // } // // g_dir_close (dir); //} //rmdir ("./tmp"); #endif testsuite_end (); g_mime_shutdown (); return testsuite_exit (); }
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; }
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_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; }
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; }