示例#1
0
gint main (gint argc, gchar **argv)
{
	CamelService *service;
	CamelSession *session;
	CamelStore *store;
	CamelFolder *folder;
	CamelMimeMessage *msg;
	gint i, j;
	CamelStream *mbox;
	CamelFilterDriver *driver;
	GError *error = NULL;

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

	/* 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");
	service = camel_session_add_service (
		session, "test-uid", "mbox:///tmp/camel-test/mbox",
		CAMEL_PROVIDER_STORE, &error);
	check_msg (error == NULL, "getting store: %s", error->message);
	check (CAMEL_IS_STORE (service));
	store = CAMEL_STORE (service);
	g_clear_error (&error);
	pull ();

	push ("Creating output folders");
	for (i = 0; i < G_N_ELEMENTS (mailboxes); i++) {
		push ("creating %s", mailboxes[i].name);
		mailboxes[i].folder = folder = camel_store_get_folder_sync (
			store, mailboxes[i].name,
			CAMEL_STORE_FOLDER_CREATE, NULL, &error);
		check_msg (error == NULL, "%s", error->message);
		check (folder != NULL);

		/* we need an empty folder for this to work */
		test_folder_counts (folder, 0, 0);
		g_clear_error (&error);
		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, NULL);
	for (j = 0; j < 100; j++) {
		gchar *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_write_string (mbox, "From \n", NULL, NULL);
		check (camel_data_wrapper_write_to_stream_sync (
			CAMEL_DATA_WRAPPER (msg), mbox, NULL, NULL) != -1);
#if 0
		push ("appending simple message %d", j);
		camel_folder_append_message (folder, msg, NULL, ex);
		check_msg (error == NULL, "%s", error->message);
		g_clear_error (&error);
		pull ();
#endif
		test_free (subject);

		check_unref (msg, 1);
	}
	check (camel_stream_close (mbox, NULL, NULL) != -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 < G_N_ELEMENTS (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);
#if 0  /* FIXME We no longer filter mbox files. */
	camel_filter_driver_filter_mbox (
		driver, "/tmp/camel-test/inbox", NULL, NULL, &error);
#endif
	check_msg (error == NULL, "%s", error->message);

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

	check_unref (driver, 1);
	g_clear_error (&error);
	pull ();

	/* this tests that invalid rules are caught */
	push ("Testing broken match rules");
	for (i = 0; i < G_N_ELEMENTS (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);
#if 0  /* FIXME We no longer filter mbox files. */
		camel_filter_driver_filter_mbox (
			driver, "/tmp/camel-test/inbox", NULL, NULL, &error);
#endif
		check (error != NULL);
		check_unref (driver, 1);
		g_clear_error (&error);
		pull ();
	}
	pull ();

	push ("Testing broken action rules");
	for (i = 0; i < G_N_ELEMENTS (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);
#if 0  /* FIXME We no longer filter mbox files. */
		camel_filter_driver_filter_mbox (
			driver, "/tmp/camel-test/inbox", NULL, NULL, &error);
#endif
		check (error != NULL);
		check_unref (driver, 1);
		g_clear_error (&error);
		pull ();
	}
	pull ();

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

	check_unref (store, 1);

	check_unref (session, 1);

	camel_test_end ();

	return 0;
}
static gssize
multipart_signed_write_to_stream_sync (CamelDataWrapper *data_wrapper,
                                       CamelStream *stream,
                                       GCancellable *cancellable,
                                       GError **error)
{
	CamelMultipartSigned *mps = (CamelMultipartSigned *) data_wrapper;
	CamelMultipart *mp = (CamelMultipart *) mps;
	GByteArray *byte_array;
	const gchar *boundary;
	gssize total = 0;
	gssize count;
	gchar *content;

	byte_array = camel_data_wrapper_get_byte_array (data_wrapper);

	/* we have 3 basic cases:
	 * 1. constructed, we write out the data wrapper stream we got
	 * 2. signed content, we create and write out a new stream
	 * 3. invalid
	*/

	/* 1 */
	/* FIXME: locking? */
	if (byte_array->len > 0) {
		return camel_stream_write (
			stream, (gchar *) byte_array->data,
			byte_array->len, cancellable, error);
	}

	/* 3 */
	if (mps->contentraw == NULL) {
		g_set_error (
			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
			_("No content available"));
		return -1;
	}

	/* 3 */
	if (mps->signature == NULL) {
		g_set_error (
			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
			_("No signature available"));
		return -1;
	}

	/* 2 */
	boundary = camel_multipart_get_boundary (mp);
	if (mp->preface) {
		count = camel_stream_write_string (
			stream, mp->preface, cancellable, error);
		if (count == -1)
			return -1;
		total += count;
	}

	/* first boundary */
	content = g_strdup_printf ("\n--%s\n", boundary);
	count = camel_stream_write_string (
		stream, content, cancellable, error);
	g_free (content);
	if (count == -1)
		return -1;
	total += count;

	/* output content part */
	/* XXX Both CamelGpgContext and CamelSMIMEContext set this
	 *     to a memory stream, so assume it's always seekable. */
	g_seekable_seek (
		G_SEEKABLE (mps->contentraw), 0, G_SEEK_SET, NULL, NULL);
	count = camel_stream_write_to_stream (
		mps->contentraw, stream, cancellable, error);
	if (count == -1)
		return -1;
	total += count;

	/* boundary */
	content = g_strdup_printf ("\n--%s\n", boundary);
	count = camel_stream_write_string (
		stream, content, cancellable, error);
	g_free (content);
	if (count == -1)
		return -1;
	total += count;

	/* signature */
	count = camel_data_wrapper_write_to_stream_sync (
		CAMEL_DATA_WRAPPER (mps->signature),
		stream, cancellable, error);
	if (count == -1)
		return -1;
	total += count;

	/* write the terminating boudary delimiter */
	content = g_strdup_printf ("\n--%s--\n", boundary);
	count = camel_stream_write_string (
		stream, content, cancellable, error);
	g_free (content);
	if (count == -1)
		return -1;
	total += count;

	/* and finally the postface */
	if (mp->postface) {
		count = camel_stream_write_string (
			stream, mp->postface, cancellable, error);
		if (count == -1)
			return -1;
		total += count;
	}

	return total;
}
/* this is MIME specific, doesn't belong here really */
static gssize
multipart_write_to_stream_sync (CamelDataWrapper *data_wrapper,
                                CamelStream *stream,
                                GCancellable *cancellable,
                                GError **error)
{
	CamelMultipart *multipart = CAMEL_MULTIPART (data_wrapper);
	const gchar *boundary;
	GList *node;
	gchar *content;
	gssize total = 0;
	gssize count;

	/* get the bundary text */
	boundary = camel_multipart_get_boundary (multipart);

	/* we cannot write a multipart without a boundary string */
	g_return_val_if_fail (boundary, -1);

	/*
	 * write the preface text (usually something like
	 *   "This is a mime message, if you see this, then
	 *    your mail client probably doesn't support ...."
	 */
	if (multipart->preface) {
		count = camel_stream_write_string (
			stream, multipart->preface, cancellable, error);
		if (count == -1)
			return -1;
		total += count;
	}

	/*
	 * Now, write all the parts, separated by the boundary
	 * delimiter
	 */
	node = multipart->parts;
	while (node) {
		content = g_strdup_printf ("\n--%s\n", boundary);
		count = camel_stream_write_string (
			stream, content, cancellable, error);
		g_free (content);
		if (count == -1)
			return -1;
		total += count;

		count = camel_data_wrapper_write_to_stream_sync (
			CAMEL_DATA_WRAPPER (node->data),
			stream, cancellable, error);
		if (count == -1)
			return -1;
		total += count;
		node = node->next;
	}

	/* write the terminating boudary delimiter */
	content = g_strdup_printf ("\n--%s--\n", boundary);
	count = camel_stream_write_string (
		stream, content, cancellable, error);
	g_free (content);
	if (count == -1)
		return -1;
	total += count;

	/* and finally the postface */
	if (multipart->postface) {
		count = camel_stream_write_string (
			stream, multipart->postface, cancellable, error);
		if (count == -1)
			return -1;
		total += count;
	}

	return total;
}
示例#4
0
static CamelAuthenticationResult
try_sasl (CamelPOP3Store *store,
          const gchar *mechanism,
          GCancellable *cancellable,
          GError **error)
{
	CamelPOP3Engine *pop3_engine;
	CamelPOP3Stream *pop3_stream;
	CamelNetworkSettings *network_settings;
	CamelAuthenticationResult result;
	CamelSettings *settings;
	CamelService *service;
	guchar *line, *resp;
	CamelSasl *sasl = NULL;
	gchar *string;
	gchar *host;
	guint len;
	gint ret;

	service = CAMEL_SERVICE (store);

	settings = camel_service_ref_settings (service);

	network_settings = CAMEL_NETWORK_SETTINGS (settings);
	host = camel_network_settings_dup_host (network_settings);

	g_object_unref (settings);

	pop3_engine = camel_pop3_store_ref_engine (store);
	if (!pop3_engine) {
		g_set_error_literal (
			error, CAMEL_SERVICE_ERROR,
			CAMEL_SERVICE_ERROR_UNAVAILABLE,
			_("You must be working online to complete this operation"));
		result = CAMEL_AUTHENTICATION_ERROR;
		goto exit;
	}

	pop3_stream = pop3_engine->stream;

	sasl = camel_sasl_new ("pop", mechanism, service);
	if (sasl == NULL) {
		g_set_error (
			error, CAMEL_SERVICE_ERROR,
			CAMEL_SERVICE_ERROR_URL_INVALID,
			_("No support for %s authentication"), mechanism);
		result = CAMEL_AUTHENTICATION_ERROR;
		goto exit;
	}

	string = g_strdup_printf ("AUTH %s\r\n", mechanism);
	ret = camel_stream_write_string (
		CAMEL_STREAM (pop3_stream), string, cancellable, error);
	g_free (string);

	if (ret == -1)
		goto ioerror;

	while (1) {
		GError *local_error = NULL;

		if (camel_pop3_stream_line (pop3_stream, &line, &len, cancellable, error) == -1)
			goto ioerror;

		if (strncmp ((gchar *) line, "+OK", 3) == 0) {
			result = CAMEL_AUTHENTICATION_ACCEPTED;
			break;
		}

		if (strncmp ((gchar *) line, "-ERR", 4) == 0) {
			result = CAMEL_AUTHENTICATION_REJECTED;
			break;
		}

		/* If we dont get continuation, or the sasl object's run out
		 * of work, or we dont get a challenge, its a protocol error,
		 * so fail, and try reset the server. */
		if (strncmp ((gchar *) line, "+ ", 2) != 0
		    || camel_sasl_get_authenticated (sasl)
		    || (resp = (guchar *) camel_sasl_challenge_base64_sync (sasl, (const gchar *) line + 2, cancellable, &local_error)) == NULL) {
			camel_stream_write_string (
				CAMEL_STREAM (pop3_stream), "*\r\n", cancellable, NULL);
			camel_pop3_stream_line (pop3_stream, &line, &len, cancellable, NULL);

			if (local_error) {
				g_propagate_error (error, local_error);
				local_error = NULL;
				goto ioerror;
			}

			g_set_error (
				error, CAMEL_SERVICE_ERROR,
				CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
				_("Cannot login to POP server %s: "
				"SASL Protocol error"), host);
			result = CAMEL_AUTHENTICATION_ERROR;
			goto exit;
		}

		string = g_strdup_printf ("%s\r\n", resp);
		ret = camel_stream_write_string (
			CAMEL_STREAM (pop3_stream), string, cancellable, error);
		g_free (string);

		g_free (resp);

		if (ret == -1)
			goto ioerror;

	}

	goto exit;

ioerror:
	g_prefix_error (
		error, _("Failed to authenticate on POP server %s: "), host);
	result = CAMEL_AUTHENTICATION_ERROR;

exit:
	if (sasl != NULL)
		g_object_unref (sasl);

	g_free (host);

	g_clear_object (&pop3_engine);

	return result;
}
static CamelAuthenticationResult
smtp_transport_authenticate_sync (CamelService *service,
                                  const gchar *mechanism,
                                  GCancellable *cancellable,
                                  GError **error)
{
	CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
	CamelAuthenticationResult result;
	CamelSasl *sasl;
	gchar *cmdbuf, *respbuf = NULL, *challenge;
	gboolean auth_challenge = FALSE;
	GError *local_error = NULL;

	if (mechanism == NULL) {
		g_set_error (
			error, CAMEL_SERVICE_ERROR,
			CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
			_("No SASL mechanism was specified"));
		return CAMEL_AUTHENTICATION_ERROR;
	}

	sasl = camel_sasl_new ("smtp", mechanism, service);
	if (sasl == NULL) {
		g_set_error (
			error, CAMEL_SERVICE_ERROR,
			CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
			_("No support for %s authentication"), mechanism);
		return CAMEL_AUTHENTICATION_ERROR;
	}

	challenge = camel_sasl_challenge_base64_sync (
		sasl, NULL, cancellable, &local_error);
	if (challenge) {
		auth_challenge = TRUE;
		cmdbuf = g_strdup_printf (
			"AUTH %s %s\r\n", mechanism, challenge);
		g_free (challenge);
	} else if (local_error) {
		d (fprintf (stderr, "[SMTP] SASL challenge failed: %s", local_error->message));
		g_propagate_error (error, local_error);
		g_object_unref (sasl);
		return CAMEL_AUTHENTICATION_ERROR;
	} else {
		cmdbuf = g_strdup_printf (
			"AUTH %s\r\n", mechanism);
	}

	d (fprintf (stderr, "[SMTP] sending: %s", cmdbuf));
	if (camel_stream_write_string (
		transport->ostream, cmdbuf,
		cancellable, error) == -1) {
		g_free (cmdbuf);
		g_prefix_error (error, _("AUTH command failed: "));
		goto lose;
	}
	g_free (cmdbuf);

	respbuf = camel_stream_buffer_read_line (
		CAMEL_STREAM_BUFFER (transport->istream),
		cancellable, error);
	d (fprintf (stderr, "[SMTP] received: %s\n", respbuf ? respbuf : "(null)"));

	while (!camel_sasl_get_authenticated (sasl)) {
		if (!respbuf) {
			g_prefix_error (error, _("AUTH command failed: "));
			transport->connected = FALSE;
			goto lose;
		}

		/* the server may have accepted our initial response */
		if (strncmp (respbuf, "235", 3) == 0)
			break;

		/* the server challenge/response should follow a 334 code */
		if (strncmp (respbuf, "334", 3) != 0) {
			smtp_set_error (
				transport, respbuf, cancellable, error);
			g_prefix_error (error, _("AUTH command failed: "));
			goto lose;
		}

		if (FALSE) {
		broken_smtp_server:
			d (fprintf (
				stderr, "[SMTP] Your SMTP server's implementation "
				"of the %s SASL\nauthentication mechanism is "
				"broken. Please report this to the\n"
				"appropriate vendor and suggest that they "
				"re-read rfc2554 again\nfor the first time "
				"(specifically Section 4).\n",
				mechanism));
		}

		/* eat whtspc */
		for (challenge = respbuf + 4; isspace (*challenge); challenge++);

		challenge = camel_sasl_challenge_base64_sync (
			sasl, challenge, cancellable, error);
		if (challenge == NULL)
			goto break_and_lose;

		g_free (respbuf);

		/* send our challenge */
		cmdbuf = g_strdup_printf ("%s\r\n", challenge);
		g_free (challenge);
		d (fprintf (stderr, "[SMTP] sending: %s", cmdbuf));
		if (camel_stream_write_string (
			transport->ostream, cmdbuf,
			cancellable, error) == -1) {
			g_free (cmdbuf);
			goto lose;
		}
		g_free (cmdbuf);

		/* get the server's response */
		respbuf = camel_stream_buffer_read_line (
			CAMEL_STREAM_BUFFER (transport->istream),
			cancellable, error);
		d (fprintf (stderr, "[SMTP] received: %s\n", respbuf ? respbuf : "(null)"));
	}

	if (respbuf == NULL)
		goto lose;

	/* Work around broken SASL implementations. */
	if (auth_challenge && strncmp (respbuf, "334", 3) == 0)
		goto broken_smtp_server;

	/* If our authentication data was rejected, destroy the
	 * password so that the user gets prompted to try again. */
	if (strncmp (respbuf, "535", 3) == 0) {
		result = CAMEL_AUTHENTICATION_REJECTED;

		/* Read the continuation, if the server returned it. */
		while (respbuf && respbuf[3] == '-') {
			g_free (respbuf);
			respbuf = camel_stream_buffer_read_line (
				CAMEL_STREAM_BUFFER (transport->istream),
				cancellable, error);
			d (fprintf (stderr, "[SMTP] received: %s\n", respbuf ? respbuf : "(null)"));
		}
	} else if (strncmp (respbuf, "235", 3) == 0)
		result = CAMEL_AUTHENTICATION_ACCEPTED;
	/* Catch any other errors. */
	else {
		g_set_error (
			error, CAMEL_SERVICE_ERROR,
			CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
			_("Bad authentication response from server."));
		goto lose;
	}

	goto exit;

break_and_lose:
	/* Get the server out of "waiting for continuation data" mode. */
	d (fprintf (stderr, "[SMTP] sending: *\n"));
	camel_stream_write (transport->ostream, "*\r\n", 3, cancellable, NULL);
	respbuf = camel_stream_buffer_read_line (
		CAMEL_STREAM_BUFFER (transport->istream), cancellable, NULL);
	d (fprintf (stderr, "[SMTP] received: %s\n", respbuf ? respbuf : "(null)"));

lose:
	result = CAMEL_AUTHENTICATION_ERROR;

exit:
	g_object_unref (sasl);
	g_free (respbuf);

	return result;
}