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