/* 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 gboolean
update_cache (CamelGroupwiseJournal *groupwise_journal, CamelMimeMessage *message,
	      const CamelMessageInfo *mi, char **updated_uid, CamelException *ex)
{
	CamelOfflineJournal *journal = (CamelOfflineJournal *) groupwise_journal;
	CamelGroupwiseFolder *groupwise_folder = (CamelGroupwiseFolder *) journal->folder;
	CamelFolder *folder = (CamelFolder *) journal->folder;
	CamelMessageInfo *info;
	CamelStream *cache;
	guint32 nextuid;
	char *uid;

	if (groupwise_folder->cache == NULL) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
				     _("Cannot append message in offline mode: cache unavailable"));
		return FALSE;
	}

	nextuid = camel_folder_summary_next_uid (folder->summary);
	uid = g_strdup_printf ("-%u", nextuid);

	if (!(cache = camel_data_cache_add (groupwise_folder->cache, "cache", uid, ex))) {
		folder->summary->nextuid--;
		g_free (uid);
		return FALSE;
	}

	if (camel_data_wrapper_write_to_stream ((CamelDataWrapper *) message, cache) == -1
	    || camel_stream_flush (cache) == -1) {
		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
				      _("Cannot append message in offline mode: %s"),
				      g_strerror (errno));
		camel_data_cache_remove (groupwise_folder->cache, "cache", uid, NULL);
		folder->summary->nextuid--;
		camel_object_unref (cache);
		g_free (uid);
		return FALSE;
	}

	camel_object_unref (cache);

	info = camel_folder_summary_info_new_from_message (folder->summary, message);
	g_free(info->uid);
	info->uid = g_strdup (uid);

	gw_message_info_dup_to ((CamelMessageInfoBase *) info, (CamelMessageInfoBase *) mi);

	camel_folder_summary_add (folder->summary, info);

	if (updated_uid)
		*updated_uid = g_strdup (uid);

	g_free (uid);

	return TRUE;
}
/**
 * camel_imap_message_cache_insert_wrapper:
 * @cache: the cache
 * @uid: UID of the message data to cache
 * @part_spec: the IMAP part_spec of the data
 * @wrapper: the wrapper to cache
 *
 * Caches the provided data into @cache.
 **/
void
camel_imap_message_cache_insert_wrapper (CamelImapMessageCache *cache,
					 const char *uid, const char *part_spec,
					 CamelDataWrapper *wrapper, CamelException *ex)
{
	char *path, *key;
	CamelStream *stream;

	stream = insert_setup (cache, uid, part_spec, &path, &key, ex);
	if (!stream)
		return;

	if (camel_data_wrapper_write_to_stream (wrapper, stream) == -1) {
		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
				      _("Failed to cache message %s: %s"),
				      uid, g_strerror (errno));
		insert_abort (path, stream);
	} else {
		insert_finish (cache, uid, path, key, stream);
		camel_object_unref (CAMEL_OBJECT (stream));
	}
}
Beispiel #4
0
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;
}
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
nntp_folder_append_message_online (CamelFolder *folder, CamelMimeMessage *mime_message,
				   const CamelMessageInfo *info, char **appended_uid,
				   CamelException *ex)
{
	CamelNNTPStore *nntp_store = (CamelNNTPStore *) folder->parent_store;
	CamelStream *stream = (CamelStream*)nntp_store->stream;
	CamelStreamFilter *filtered_stream;
	CamelMimeFilter *crlffilter;
	int ret;
	unsigned int u;
	struct _camel_header_raw *header, *savedhdrs, *n, *tail;
	char *group, *line;

	CAMEL_SERVICE_REC_LOCK(nntp_store, connect_lock);

	/* send 'POST' command */
	ret = camel_nntp_command (nntp_store, ex, NULL, &line, "post");
	if (ret != 340) {
		if (ret == 440)
			camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
					      _("Posting failed: %s"), line);
		else if (ret != -1)
			camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
					      _("Posting failed: %s"), line);
		CAMEL_SERVICE_REC_UNLOCK(nntp_store, connect_lock);
		return;
	}

	/* the 'Newsgroups: ' header */
	group = g_strdup_printf ("Newsgroups: %s\r\n", folder->full_name);

	/* setup stream filtering */
	crlffilter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_ENCODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_DOTS);
	filtered_stream = camel_stream_filter_new_with_stream (stream);
	camel_stream_filter_add (filtered_stream, crlffilter);
	camel_object_unref (crlffilter);

	/* remove mail 'To', 'CC', and 'BCC' headers */
	savedhdrs = NULL;
	tail = (struct _camel_header_raw *) &savedhdrs;

	header = (struct _camel_header_raw *) &CAMEL_MIME_PART (mime_message)->headers;
	n = header->next;
	while (n != NULL) {
		if (!g_ascii_strcasecmp (n->name, "To") || !g_ascii_strcasecmp (n->name, "Cc") || !g_ascii_strcasecmp (n->name, "Bcc")) {
			header->next = n->next;
			tail->next = n;
			n->next = NULL;
			tail = n;
		} else {
			header = n;
		}

		n = header->next;
	}

	/* write the message */
	if (camel_stream_write(stream, group, strlen(group)) == -1
	    || camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (mime_message), CAMEL_STREAM (filtered_stream)) == -1
	    || camel_stream_flush (CAMEL_STREAM (filtered_stream)) == -1
	    || camel_stream_write (stream, "\r\n.\r\n", 5) == -1
	    || (ret = camel_nntp_stream_line (nntp_store->stream, (unsigned char **)&line, &u)) == -1) {
		if (errno == EINTR)
			camel_exception_setv (ex, CAMEL_EXCEPTION_USER_CANCEL, _("User canceled"));
		else
			camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Posting failed: %s"), g_strerror (errno));
	} else if (atoi(line) != 240) {
		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Posting failed: %s"), line);
	}

	camel_object_unref (filtered_stream);
	g_free(group);
	header->next = savedhdrs;

	CAMEL_SERVICE_REC_UNLOCK(nntp_store, connect_lock);

	return;
}
int main(int argc, char **argv)
{
    CamelSession *session;
    CamelStore *store;
    CamelException *ex;
    CamelFolder *folder;
    CamelMimeMessage *msg;
    int i, j;
    CamelStream *mbox;
    CamelFilterDriver *driver;

    camel_test_init(argc, argv);
    camel_test_provider_init(1, local_drivers);

    ex = camel_exception_new();

    /* clear out any camel-test data */
    system("/bin/rm -rf /tmp/camel-test");

    camel_test_start("Simple filtering of mbox");

    session = camel_test_session_new ("/tmp/camel-test");

    /* todo: cross-check everything with folder_info checks as well */
    /* todo: work out how to do imap/pop/nntp tests */

    push("getting store");
    store = camel_session_get_store(session, "mbox:///tmp/camel-test/mbox", ex);
    check_msg(!camel_exception_is_set(ex), "getting store: %s", camel_exception_get_description(ex));
    check(store != NULL);
    pull();

    push("Creating output folders");
    for (i=0; i<ARRAY_LEN(mailboxes); i++) {
        push("creating %s", mailboxes[i].name);
        mailboxes[i].folder = folder = camel_store_get_folder(store, mailboxes[i].name, CAMEL_STORE_FOLDER_CREATE, ex);
        check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
        check(folder != NULL);

        /* we need an empty folder for this to work */
        test_folder_counts(folder, 0, 0);
        pull();
    }
    pull();

    /* append a bunch of messages with specific content */
    push("creating 100 test message mbox");
    mbox = camel_stream_fs_new_with_name("/tmp/camel-test/inbox", O_WRONLY|O_CREAT|O_EXCL, 0600);
    for (j=0; j<100; j++) {
        char *content, *subject;

        push("creating test message");
        msg = test_message_create_simple();
        content = g_strdup_printf("data%d content\n", j);
        test_message_set_content_simple((CamelMimePart *)msg, 0, "text/plain",
                                        content, strlen(content));
        test_free(content);
        subject = g_strdup_printf("Test%d message%d subject", j, 100-j);
        camel_mime_message_set_subject(msg, subject);

        camel_mime_message_set_date(msg, j*60*24, 0);
        pull();

        camel_stream_printf(mbox, "From \n");
        check(camel_data_wrapper_write_to_stream((CamelDataWrapper *)msg, mbox) != -1);
#if 0
        push("appending simple message %d", j);
        camel_folder_append_message(folder, msg, NULL, ex);
        check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
        pull();
#endif
        test_free(subject);

        check_unref(msg, 1);
    }
    check(camel_stream_close(mbox) != -1);
    check_unref(mbox, 1);
    pull();

    push("Building filters");
    driver = camel_filter_driver_new(session);
    camel_filter_driver_set_folder_func(driver, get_folder, NULL);
    for (i=0; i<ARRAY_LEN(rules); i++) {
        camel_filter_driver_add_rule(driver, rules[i].name, rules[i].match, rules[i].action);
    }
    pull();

    push("Executing filters");
    camel_filter_driver_set_default_folder(driver, mailboxes[0].folder);
    camel_filter_driver_filter_mbox(driver, "/tmp/camel-test/inbox", NULL, ex);
    check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));

    /* now need to check the folder counts/etc */

    check_unref(driver, 1);
    pull();

    /* this tests that invalid rules are caught */
    push("Testing broken match rules");
    for (i=0; i<ARRAY_LEN(brokens); i++) {
        push("rule %s", brokens[i].match);
        driver = camel_filter_driver_new(session);
        camel_filter_driver_set_folder_func(driver, get_folder, NULL);
        camel_filter_driver_add_rule(driver, brokens[i].name, brokens[i].match, brokens[i].action);
        camel_filter_driver_filter_mbox(driver, "/tmp/camel-test/inbox", NULL, ex);
        check(camel_exception_is_set(ex));
        camel_exception_clear(ex);
        check_unref(driver, 1);
        pull();
    }
    pull();

    push("Testing broken action rules");
    for (i=0; i<ARRAY_LEN(brokena); i++) {
        push("rule %s", brokena[i].action);
        driver = camel_filter_driver_new(session);
        camel_filter_driver_set_folder_func(driver, get_folder, NULL);
        camel_filter_driver_add_rule(driver, brokena[i].name, brokena[i].match, brokena[i].action);
        camel_filter_driver_filter_mbox(driver, "/tmp/camel-test/inbox", NULL, ex);
        check(camel_exception_is_set(ex));
        camel_exception_clear(ex);
        check_unref(driver, 1);
        pull();
    }
    pull();


    for (i=0; i<ARRAY_LEN(mailboxes); i++) {
        check_unref(mailboxes[i].folder, 1);
    }

    check_unref(store, 1);

    check_unref(session, 1);
    camel_exception_free(ex);

    camel_test_end();

    return 0;
}
gboolean
e_composer_autosave_snapshot (EMsgComposer *composer)
{
	GtkhtmlEditor *editor;
	CamelMimeMessage *message;
	AutosaveState *state;
	CamelStream *stream;
	gint camelfd;
	const gchar *errmsg;

	g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), FALSE);

	editor = GTKHTML_EDITOR (composer);

	/* If the contents are unchanged, exit early. */
	if (!gtkhtml_editor_get_changed (editor))
		return TRUE;

	state = g_object_get_data (G_OBJECT (composer), "autosave");
	g_return_val_if_fail (state != NULL, FALSE);

	/* Open the autosave file on-demand. */
	if (!composer_autosave_state_open (state, NULL)) {
		errmsg = _("Could not open autosave file");
		goto fail;
	}

	/* Extract a MIME message from the composer. */
	message = e_msg_composer_get_message_draft (composer);
	if (message == NULL) {
		errmsg = _("Unable to retrieve message from editor");
		goto fail;
	}

	/* Move to the beginning of the autosave file. */
	if (lseek (state->fd, (off_t) 0, SEEK_SET) < 0) {
		camel_object_unref (message);
		errmsg = g_strerror (errno);
		goto fail;
	}

	/* Destroy the contents of the autosave file. */
	if (ftruncate (state->fd, (off_t) 0) < 0) {
		camel_object_unref (message);
		errmsg = g_strerror (errno);
		goto fail;
	}

	/* Duplicate the file descriptor for Camel. */
	if ((camelfd = dup (state->fd)) < 0) {
		camel_object_unref (message);
		errmsg = g_strerror (errno);
		goto fail;
	}

	/* Open a CamelStream to the autosave file. */
	stream = camel_stream_fs_new_with_fd (camelfd);

	/* Write the message to the CamelStream. */
	if (camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), stream) < 0) {
		camel_object_unref (message);
		camel_object_unref (stream);
		errmsg = g_strerror (errno);
		goto fail;
	}

	/* Close the CamelStream. */
	if (camel_stream_close (CAMEL_STREAM (stream)) < 0) {
		camel_object_unref (message);
		camel_object_unref (stream);
		errmsg = g_strerror (errno);
		goto fail;
	}

	/* Snapshot was successful; set various flags. */
	gtkhtml_editor_set_changed (editor, FALSE);
	e_composer_autosave_set_saved (composer, TRUE);

	camel_object_unref (message);
	camel_object_unref (stream);

	return TRUE;

fail:
	e_error_run (
		GTK_WINDOW (composer), "mail-composer:no-autosave",
		(state->filename != NULL) ? state->filename : "",
		errmsg, NULL);

	return FALSE;
}
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;
}