Exemple #1
0
static gchar *
pop3_store_get_name (CamelService *service,
                     gboolean brief)
{
	CamelNetworkSettings *network_settings;
	CamelSettings *settings;
	gchar *host;
	gchar *user;
	gchar *name;

	settings = camel_service_ref_settings (service);

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

	g_object_unref (settings);

	if (brief)
		name = g_strdup_printf (
			_("POP3 server %s"), host);
	else
		name = g_strdup_printf (
			_("POP3 server for %s on %s"), user, host);

	g_free (host);
	g_free (user);

	return name;
}
static gchar *
smtp_transport_get_name (CamelService *service,
                         gboolean brief)
{
	CamelNetworkSettings *network_settings;
	CamelSettings *settings;
	gchar *host;
	gchar *name;

	settings = camel_service_ref_settings (service);

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

	g_object_unref (settings);

	if (brief)
		name = g_strdup_printf (
			_("SMTP server %s"), host);
	else
		name = g_strdup_printf (
			_("SMTP mail delivery via %s"), host);

	g_free (host);

	return name;
}
Exemple #3
0
static gchar *
ews_transport_get_name (CamelService *service,
                        gboolean brief)
{
	CamelSettings *settings;
	gchar *host;
	gchar *name;

	settings = camel_service_ref_settings (service);

	host = camel_ews_utils_get_host_name (settings);

	g_object_unref (settings);

	if (brief)
		name = g_strdup_printf (
			_("Exchange server %s"), host);
	else
		name = g_strdup_printf (
			_("Exchange mail delivery via %s"), host);

	g_free (host);

	return name;
}
Exemple #4
0
static gboolean
ews_transport_connect_sync (CamelService *service,
			    GCancellable *cancellable,
			    GError **error)
{
	EEwsConnection *connection;
	CamelSession *session;
	CamelSettings *settings;
	gchar *auth_mech;
	gboolean success;

	/* Chain up to parent's method. */
	if (!CAMEL_SERVICE_CLASS (camel_ews_transport_parent_class)->connect_sync (service, cancellable, error))
		return FALSE;

	if (camel_service_get_connection_status (service) == CAMEL_SERVICE_DISCONNECTED)
		return FALSE;

	connection = ews_transport_ref_connection (CAMEL_EWS_TRANSPORT (service));
	if (connection) {
		g_object_unref (connection);
		return TRUE;
	}

	session = camel_service_ref_session (service);
	settings = camel_service_ref_settings (service);

	/* Try running an operation that requires authentication
	 * to make sure we have valid credentials available. */
	auth_mech = camel_network_settings_dup_auth_mechanism (CAMEL_NETWORK_SETTINGS (settings));

	success = camel_session_authenticate_sync (session, service,
			   auth_mech ? auth_mech : "NTLM", cancellable, error);

	g_free (auth_mech);

	g_object_unref (session);
	g_object_unref (settings);

	return success;
}
static void
smtp_debug_print_server_name (CamelService *service,
			      const gchar *what)
{
	CamelNetworkSettings *network_settings;
	CamelSettings *settings;
	gchar *host;
	gint port;

	if (d(1) + 0 == 0)
		return;

	settings = camel_service_ref_settings (service);

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

	g_object_unref (settings);

	fprintf (stderr, "[SMTP] %s server %s:%d from account %s\r\n", what, host, port, camel_service_get_uid (service));

	g_free (host);
}
Exemple #6
0
static CamelAuthenticationResult
pop3_store_authenticate_sync (CamelService *service,
                              const gchar *mechanism,
                              GCancellable *cancellable,
                              GError **error)
{
	CamelPOP3Store *store = CAMEL_POP3_STORE (service);
	CamelNetworkSettings *network_settings;
	CamelAuthenticationResult result;
	CamelSettings *settings;
	CamelPOP3Command *pcu = NULL;
	CamelPOP3Command *pcp = NULL;
	CamelPOP3Engine *pop3_engine;
	const gchar *password;
	gchar *host;
	gchar *user;
	gint status;

	password = camel_service_get_password (service);

	settings = camel_service_ref_settings (service);

	network_settings = CAMEL_NETWORK_SETTINGS (settings);
	host = camel_network_settings_dup_host (network_settings);
	user = camel_network_settings_dup_user (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;
	}

	if (mechanism == NULL) {
		if (password == NULL) {
			g_set_error_literal (
				error, CAMEL_SERVICE_ERROR,
				CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
				_("Authentication password not available"));
			result = CAMEL_AUTHENTICATION_ERROR;
			goto exit;
		}

		/* pop engine will take care of pipelining ability */
		pcu = camel_pop3_engine_command_new (
			pop3_engine, 0, NULL, NULL, cancellable, error,
			"USER %s\r\n", user);
		pcp = camel_pop3_engine_command_new (
			pop3_engine, 0, NULL, NULL, cancellable, error,
			"PASS %s\r\n", password);

	} else if (strcmp (mechanism, "+APOP") == 0 && pop3_engine->apop) {
		gchar *secret, *md5asc, *d;

		if (password == NULL) {
			g_set_error_literal (
				error, CAMEL_SERVICE_ERROR,
				CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
				_("Authentication password not available"));
			result = CAMEL_AUTHENTICATION_ERROR;
			goto exit;
		}

		d = pop3_engine->apop;

		while (*d != '\0') {
			if (!isascii ((gint) * d)) {

				/* Translators: Do not translate APOP. */
				g_set_error (
					error, CAMEL_SERVICE_ERROR,
					CAMEL_SERVICE_ERROR_URL_INVALID,
					_("Unable to connect to POP server %s:	"
					"Invalid APOP ID received. Impersonation "
					"attack suspected. Please contact your admin."),
					host);

				result = CAMEL_AUTHENTICATION_ERROR;
				goto exit;
			}
			d++;
		}

		secret = g_alloca (
			strlen (pop3_engine->apop) +
			strlen (password) + 1);
		sprintf (secret, "%s%s", pop3_engine->apop, password);
		md5asc = g_compute_checksum_for_string (
			G_CHECKSUM_MD5, secret, -1);
		pcp = camel_pop3_engine_command_new (
			pop3_engine, 0, NULL, NULL, cancellable, error,
			"APOP %s %s\r\n", user, md5asc);
		g_free (md5asc);

	} else {
		GList *link;

		link = pop3_engine->auth;
		while (link != NULL) {
			CamelServiceAuthType *auth = link->data;

			if (g_strcmp0 (auth->authproto, mechanism) == 0) {
				result = try_sasl (
					store, mechanism,
					cancellable, error);
				goto exit;
			}
			link = g_list_next (link);
		}

		g_set_error (
			error, CAMEL_SERVICE_ERROR,
			CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
			_("No support for %s authentication"), mechanism);
		result = CAMEL_AUTHENTICATION_ERROR;
		goto exit;
	}

	while ((status = camel_pop3_engine_iterate (pop3_engine, pcp, cancellable, error)) > 0)
		;

	if (status == -1) {
		g_prefix_error (
			error,
			_("Unable to connect to POP server %s.\n"
			"Error sending password: "******": " separator. */
			_("Unable to connect to POP server %s.\n"
			"Error sending username%s"),
			host, (tmp != NULL) ? tmp : "");
		g_free (tmp);
		result = CAMEL_AUTHENTICATION_ERROR;

	} else if (pcp->state != CAMEL_POP3_COMMAND_OK) {
		result = CAMEL_AUTHENTICATION_REJECTED;
	} else {
		result = CAMEL_AUTHENTICATION_ACCEPTED;
	}

	camel_pop3_engine_command_free (pop3_engine, pcp);

	if (pcu != NULL)
		camel_pop3_engine_command_free (pop3_engine, pcu);

exit:
	g_free (host);
	g_free (user);

	g_clear_object (&pop3_engine);

	return result;
}
Exemple #7
0
static gboolean
pop3_store_connect_sync (CamelService *service,
                         GCancellable *cancellable,
                         GError **error)
{
	CamelPOP3Store *store = (CamelPOP3Store *) service;
	CamelPOP3Engine *pop3_engine;
	CamelSettings *settings;
	CamelSession *session;
	const gchar *user_data_dir;
	gboolean success = TRUE;
	gchar *mechanism;

	session = camel_service_ref_session (service);
	user_data_dir = camel_service_get_user_data_dir (service);

	settings = camel_service_ref_settings (service);

	mechanism = camel_network_settings_dup_auth_mechanism (
		CAMEL_NETWORK_SETTINGS (settings));

	g_object_unref (settings);

	if (!camel_session_get_online (session)) {
		g_set_error (
			error, CAMEL_SERVICE_ERROR,
			CAMEL_SERVICE_ERROR_UNAVAILABLE,
			_("You must be working online to complete this operation"));
		success = FALSE;
		goto exit;
	}

	g_mutex_lock (&store->priv->property_lock);

	if (store->priv->cache == NULL) {
		CamelDataCache *cache;

		cache = camel_data_cache_new (user_data_dir, error);
		if (cache != NULL) {
			/* Ensure cache will never expire, otherwise
			 * it causes redownload of messages. */
			camel_data_cache_set_expire_age (cache, -1);
			camel_data_cache_set_expire_access (cache, -1);

			store->priv->cache = g_object_ref (cache);

			g_object_unref (cache);
		}
	}

	g_mutex_unlock (&store->priv->property_lock);

	success = connect_to_server (service, cancellable, error);

	if (!success)
		goto exit;

	success = camel_session_authenticate_sync (
		session, service, mechanism, cancellable, error);

	if (!success)
		goto exit;

	/* Now that we are in the TRANSACTION state,
	 * try regetting the capabilities */
	pop3_engine = camel_pop3_store_ref_engine (store);
	if (pop3_engine) {
		pop3_engine->state = CAMEL_POP3_ENGINE_TRANSACTION;
		if (!camel_pop3_engine_reget_capabilities (pop3_engine, cancellable, error))
			success = FALSE;
		g_clear_object (&pop3_engine);
	} else {
		g_set_error_literal (
			error, CAMEL_SERVICE_ERROR,
			CAMEL_SERVICE_ERROR_UNAVAILABLE,
			_("You must be working online to complete this operation"));
		success = FALSE;
	}

exit:
	g_free (mechanism);

	g_object_unref (session);

	if (!success) {
		/* to not leak possible connection to the server */
		g_mutex_lock (&store->priv->property_lock);
		g_clear_object (&store->priv->engine);
		g_mutex_unlock (&store->priv->property_lock);
	}

	return success;
}
Exemple #8
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;
}
Exemple #9
0
static gboolean
connect_to_server (CamelService *service,
                   GCancellable *cancellable,
                   GError **error)
{
	CamelPOP3Store *store = CAMEL_POP3_STORE (service);
	CamelNetworkSettings *network_settings;
	CamelNetworkSecurityMethod method;
	CamelSettings *settings;
	CamelStream *tcp_stream;
	CamelPOP3Engine *pop3_engine = NULL;
	CamelPOP3Command *pc;
	gboolean disable_extensions;
	gboolean success = TRUE;
	gchar *host;
	guint32 flags = 0;
	gint ret;
	GError *local_error = NULL;

	settings = camel_service_ref_settings (service);

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

	disable_extensions = camel_pop3_settings_get_disable_extensions (
		CAMEL_POP3_SETTINGS (settings));

	g_object_unref (settings);

	tcp_stream = camel_network_service_connect_sync (
		CAMEL_NETWORK_SERVICE (service), cancellable, error);

	if (tcp_stream == NULL) {
		success = FALSE;
		goto exit;
	}

	/* parent class connect initialization */
	if (CAMEL_SERVICE_CLASS (camel_pop3_store_parent_class)->
		connect_sync (service, cancellable, error) == FALSE) {
		g_object_unref (tcp_stream);
		success = FALSE;
		goto exit;
	}

	if (disable_extensions)
		flags |= CAMEL_POP3_ENGINE_DISABLE_EXTENSIONS;

	if (!(pop3_engine = camel_pop3_engine_new (tcp_stream, flags, cancellable, &local_error)) ||
	    local_error != NULL) {
		if (local_error)
			g_propagate_error (error, local_error);
		else
			g_set_error (
				error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
				_("Failed to read a valid greeting from POP server %s"),
				host);
		g_object_unref (tcp_stream);
		success = FALSE;
		goto exit;
	}

	if (method != CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT) {
		g_object_unref (tcp_stream);
		goto exit;
	}

	if (!(pop3_engine->capa & CAMEL_POP3_CAP_STLS)) {
		g_set_error (
			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
			_("Failed to connect to POP server %s in secure mode: %s"),
			host, _("STLS not supported by server"));
		goto stls_exception;
	}

	pc = camel_pop3_engine_command_new (
		pop3_engine, 0, NULL, NULL,
		cancellable, error, "STLS\r\n");
	while (camel_pop3_engine_iterate (pop3_engine, NULL, cancellable, NULL) > 0)
		;

	ret = pc->state == CAMEL_POP3_COMMAND_OK;
	camel_pop3_engine_command_free (pop3_engine, pc);

	if (ret == FALSE) {
		gchar *tmp;

		tmp = get_valid_utf8_error ((gchar *) pop3_engine->line);
		g_set_error (
			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
			/* Translators: Last %s is an optional
			 * explanation beginning with ": " separator. */
			_("Failed to connect to POP server %s in secure mode%s"),
			host, (tmp != NULL) ? tmp : "");
		g_free (tmp);
		goto stls_exception;
	}

	/* Okay, now toggle SSL/TLS mode */
	ret = camel_tcp_stream_ssl_enable_ssl (
		CAMEL_TCP_STREAM_SSL (tcp_stream), cancellable, error);

	if (ret == -1) {
		g_prefix_error (
			error,
			_("Failed to connect to POP server %s in secure mode: "),
			host);
		goto stls_exception;
	}

	g_object_unref (tcp_stream);

	/* rfc2595, section 4 states that after a successful STLS
	 * command, the client MUST discard prior CAPA responses */
	if (!camel_pop3_engine_reget_capabilities (pop3_engine, cancellable, error))
		goto exception;

	goto exit;

stls_exception:
	/* As soon as we send a STLS command, all hope
	 * is lost of a clean QUIT if problems arise. */
	/* if (clean_quit) {
		/ * try to disconnect cleanly * /
		pc = camel_pop3_engine_command_new (
			pop3_engine, 0, NULL, NULL,
			cancellable, NULL, "QUIT\r\n");
		while (camel_pop3_engine_iterate (pop3_engine, NULL, cancellable, NULL) > 0)
			;
		camel_pop3_engine_command_free (pop3_engine, pc);
	}*/

exception:
	g_object_unref (tcp_stream);

	g_clear_object (&pop3_engine);

	success = FALSE;

exit:
	g_free (host);

	g_mutex_lock (&store->priv->property_lock);
	if (pop3_engine != NULL)
		store->priv->engine = g_object_ref (pop3_engine);
	g_mutex_unlock (&store->priv->property_lock);

	g_clear_object (&pop3_engine);

	return success;
}
Exemple #10
0
static gboolean
ews_send_to_sync (CamelTransport *transport,
                  CamelMimeMessage *message,
                  CamelAddress *from,
                  CamelAddress *recipients,
		  gboolean *out_sent_message_saved,
                  GCancellable *cancellable,
                  GError **error)
{
	CamelNetworkSettings *network_settings;
	CamelEwsSettings *ews_settings;
	CamelInternetAddress *used_from;
	CamelSettings *settings;
	CamelService *service;
	EEwsConnection *cnc;
	EwsFolderId *folder_id = NULL;
	gchar *ews_email;
	gchar *host_url;
	gchar *user;
	gboolean success = FALSE;

	service = CAMEL_SERVICE (transport);

	settings = camel_service_ref_settings (service);

	ews_settings = CAMEL_EWS_SETTINGS (settings);
	ews_email = camel_ews_settings_dup_email (ews_settings);
	host_url = camel_ews_settings_dup_hosturl (ews_settings);

	network_settings = CAMEL_NETWORK_SETTINGS (settings);
	user = camel_network_settings_dup_user (network_settings);

	g_object_unref (settings);

	if (CAMEL_IS_INTERNET_ADDRESS (from))
		used_from = CAMEL_INTERNET_ADDRESS (from);
	else
		used_from = camel_mime_message_get_from (message);

	if (!used_from || camel_address_length (CAMEL_ADDRESS (used_from)) == 0) {
		g_set_error_literal (
			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
			_("Cannot send message with no From address"));
		goto exit;

	} else if (camel_address_length (CAMEL_ADDRESS (used_from)) > 1) {
		g_set_error_literal (
			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
			_("Exchange server cannot send message with "
			"multiple From addresses"));
		goto exit;

	} else {
		const gchar *used_email = NULL;

		if (!camel_internet_address_get (used_from, 0, NULL, &used_email)) {
			g_set_error_literal (
				error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
				_("Failed to read From address"));
			goto exit;
		}
	}

	cnc = ews_transport_ref_connection (CAMEL_EWS_TRANSPORT (service));
	if (!cnc) {
		g_set_error (
			error, CAMEL_SERVICE_ERROR,
			CAMEL_SERVICE_ERROR_NOT_CONNECTED,
			_("Service not connected"));
		goto exit;
	}

	if (ews_transport_can_server_side_sent_folder (service, &folder_id, cancellable)) {
		if (out_sent_message_saved)
			*out_sent_message_saved = TRUE;
	}

	success = camel_ews_utils_create_mime_message (
		cnc, folder_id ? "SendAndSaveCopy" : "SendOnly", folder_id, message, NULL,
		from, recipients, NULL, NULL, cancellable, error);

	g_object_unref (cnc);
	e_ews_folder_id_free (folder_id);

exit:
	g_free (ews_email);
	g_free (host_url);
	g_free (user);

	return success;
}
Exemple #11
0
static CamelAuthenticationResult
ews_transport_authenticate_sync (CamelService *service,
				 const gchar *mechanism,
				 GCancellable *cancellable,
				 GError **error)
{
	CamelAuthenticationResult result;
	CamelEwsTransport *ews_transport;
	CamelSettings *settings;
	CamelEwsSettings *ews_settings;
	EEwsConnection *connection;
	const gchar *password;
	gchar *hosturl, *new_sync_state = NULL;
	GSList *folders_created = NULL;
	GSList *folders_updated = NULL;
	GSList *folders_deleted = NULL;
	gboolean includes_last_folder = FALSE;
	GError *local_error = NULL;

	ews_transport = CAMEL_EWS_TRANSPORT (service);

	password = camel_service_get_password (service);

	settings = camel_service_ref_settings (service);

	ews_settings = CAMEL_EWS_SETTINGS (settings);
	hosturl = camel_ews_settings_dup_hosturl (ews_settings);

	connection = e_ews_connection_new (hosturl, ews_settings);
	e_ews_connection_set_password (connection, password);

	g_free (hosturl);

	g_object_unref (settings);

	e_binding_bind_property (
		service, "proxy-resolver",
		connection, "proxy-resolver",
		G_BINDING_SYNC_CREATE);

	/* XXX We need to run some operation that requires authentication
	 *     but does not change any server-side state, so we can check
	 *     the error status and determine if our password is valid.
	 *     David suggested e_ews_connection_sync_folder_hierarchy(),
	 *     since we have to do that eventually anyway. */

	e_ews_connection_sync_folder_hierarchy_sync (connection, EWS_PRIORITY_MEDIUM, NULL,
		&new_sync_state, &includes_last_folder, &folders_created, &folders_updated, &folders_deleted,
		cancellable, &local_error);

	g_slist_free_full (folders_created, g_object_unref);
	g_slist_free_full (folders_updated, g_object_unref);
	g_slist_free_full (folders_deleted, g_free);
	g_free (new_sync_state);

	if (g_error_matches (local_error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_UNAVAILABLE)) {
		local_error->domain = CAMEL_SERVICE_ERROR;
		local_error->code = CAMEL_SERVICE_ERROR_UNAVAILABLE;
	}

	if (!local_error) {
		g_mutex_lock (&ews_transport->priv->connection_lock);
		g_clear_object (&ews_transport->priv->connection);
		ews_transport->priv->connection = g_object_ref (connection);
		g_mutex_unlock (&ews_transport->priv->connection_lock);
	} else {
		g_mutex_lock (&ews_transport->priv->connection_lock);
		g_clear_object (&ews_transport->priv->connection);
		g_mutex_unlock (&ews_transport->priv->connection_lock);
	}

	if (!local_error) {
		result = CAMEL_AUTHENTICATION_ACCEPTED;
	} else if (g_error_matches (local_error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_AUTHENTICATION_FAILED)) {
		g_clear_error (&local_error);
		result = CAMEL_AUTHENTICATION_REJECTED;
	} else {
		g_propagate_error (error, local_error);
		result = CAMEL_AUTHENTICATION_ERROR;
	}

	g_object_unref (connection);

	return result;
}
Exemple #12
0
gchar *
mail_tool_do_movemail (CamelStore *store,
                       GError **error)
{
#ifndef G_OS_WIN32
	CamelService *service;
	CamelProvider *provider;
	CamelSettings *settings;
	gchar *src_path;
	gchar *dest_path;
	struct stat sb;
	gboolean success;

	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);

	service = CAMEL_SERVICE (store);
	provider = camel_service_get_provider (service);

	g_return_val_if_fail (provider != NULL, NULL);

	if (g_strcmp0 (provider->protocol, "mbox") != 0) {
		/* This is really only an internal error anyway */
		g_set_error (
			error, CAMEL_SERVICE_ERROR,
			CAMEL_SERVICE_ERROR_URL_INVALID,
			_("Trying to movemail a non-mbox source '%s'"),
			camel_service_get_uid (CAMEL_SERVICE (store)));
		return NULL;
	}

	settings = camel_service_ref_settings (service);

	src_path = camel_local_settings_dup_path (
		CAMEL_LOCAL_SETTINGS (settings));

	g_object_unref (settings);

	/* Set up our destination. */
	dest_path = mail_tool_get_local_movemail_path (store, error);
	if (dest_path == NULL)
		return NULL;

	/* Movemail from source to dest_path */
	success = camel_movemail (src_path, dest_path, error) != -1;

	g_free (src_path);

	if (g_stat (dest_path, &sb) < 0 || sb.st_size == 0) {
		g_unlink (dest_path); /* Clean up the movemail.foo file. */
		g_free (dest_path);
		return NULL;
	}

	if (!success) {
		g_free (dest_path);
		return NULL;
	}

	return dest_path;
#else
	/* Unclear yet whether camel-movemail etc makes any sense on
	 * Win32, at least it is not ported yet.
	 */
	g_warning ("%s: Not implemented", __FUNCTION__);
	return NULL;
#endif
}
Exemple #13
0
static gchar *
format_service_name (CamelService *service)
{
	CamelProvider *provider;
	CamelSettings *settings;
	gchar *service_name = NULL;
	const gchar *display_name;
	gchar *pretty_url = NULL;
	gchar *host = NULL;
	gchar *path = NULL;
	gchar *user = NULL;
	gchar *cp;
	gboolean have_host = FALSE;
	gboolean have_path = FALSE;
	gboolean have_user = FALSE;

	provider = camel_service_get_provider (service);
	display_name = camel_service_get_display_name (service);

	settings = camel_service_ref_settings (service);

	if (CAMEL_IS_NETWORK_SETTINGS (settings)) {
		host = camel_network_settings_dup_host (
			CAMEL_NETWORK_SETTINGS (settings));
		have_host = (host != NULL) && (*host != '\0');

		user = camel_network_settings_dup_user (
			CAMEL_NETWORK_SETTINGS (settings));
		have_user = (user != NULL) && (*user != '\0');
	}

	if (CAMEL_IS_LOCAL_SETTINGS (settings)) {
		path = camel_local_settings_dup_path (
			CAMEL_LOCAL_SETTINGS (settings));
		have_path = (path != NULL) && (*path != '\0');
	}

	g_object_unref (settings);

	/* Shorten user names with '@', since multiple '@' in a
	 * 'user@host' label look weird.  This is just supposed
	 * to be a hint anyway so it doesn't matter if it's not
	 * strictly correct. */
	if (have_user && (cp = strchr (user, '@')) != NULL)
		*cp = '\0';

	g_return_val_if_fail (provider != NULL, NULL);

	/* This should never happen, but if the service has no
	 * display name, fall back to the generic service name. */
	if (display_name == NULL || *display_name == '\0') {
		service_name = camel_service_get_name (service, TRUE);
		display_name = service_name;
	}

	if (have_host && have_user) {
		pretty_url = g_markup_printf_escaped (
			"<b>%s</b> <small>(%s@%s)</small>",
			display_name, user, host);
	} else if (have_host) {
		pretty_url = g_markup_printf_escaped (
			"<b>%s</b> <small>(%s)</small>",
			display_name, host);
	} else if (have_path) {
		pretty_url = g_markup_printf_escaped (
			"<b>%s</b> <small>(%s)</small>",
			display_name, path);
	} else {
		pretty_url = g_markup_printf_escaped (
			"<b>%s</b>", display_name);
	}

	g_free (service_name);
	g_free (host);
	g_free (path);
	g_free (user);

	return pretty_url;
}
Exemple #14
0
	}

	if (provider->object_types[CAMEL_PROVIDER_TRANSPORT])
		return SEND_SEND;

	return SEND_INVALID;
}

static gboolean
get_keep_on_server (CamelService *service)
{
	GObjectClass *class;
	CamelSettings *settings;
	gboolean keep_on_server = FALSE;

	settings = camel_service_ref_settings (service);
	class = G_OBJECT_GET_CLASS (settings);

	/* XXX This is a POP3-specific setting. */
	if (g_object_class_find_property (class, "keep-on-server") != NULL)
		g_object_get (
			settings, "keep-on-server",
			&keep_on_server, NULL);

	g_object_unref (settings);

	return keep_on_server;
}

static struct _send_data *
build_dialog (GtkWindow *parent,
static gboolean
smtp_transport_connect_sync (CamelService *service,
                             GCancellable *cancellable,
                             GError **error)
{
	CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
	CamelNetworkSettings *network_settings;
	CamelSettings *settings;
	gchar *host;
	gchar *mechanism;
	gboolean auth_required;
	gboolean success = TRUE;

	/* Chain up to parent's method. */
	if (!CAMEL_SERVICE_CLASS (camel_smtp_transport_parent_class)->connect_sync (service, cancellable, error))
		return FALSE;

	smtp_debug_print_server_name (service, "Connecting to");

	settings = camel_service_ref_settings (service);

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

	g_object_unref (settings);

	/* We (probably) need to check popb4smtp before we connect ... */
	if (g_strcmp0 (mechanism, "POPB4SMTP") == 0) {
		GByteArray *chal;
		CamelSasl *sasl;

		sasl = camel_sasl_new ("smtp", "POPB4SMTP", service);
		chal = camel_sasl_challenge_sync (sasl, NULL, cancellable, error);
		if (chal != NULL)
			g_byte_array_free (chal, TRUE);

		if (camel_sasl_get_authenticated (sasl))
			success = connect_to_server (
				service, cancellable, error);
		else
			success = FALSE;

		g_object_unref (sasl);

		goto exit;
	}

	success = connect_to_server (service, cancellable, error);

	if (!success)
		return FALSE;

	/* check to see if AUTH is required, if so...then AUTH ourselves */
	auth_required =
		(mechanism != NULL) &&
		(transport->authtypes != NULL) &&
		(g_hash_table_size (transport->authtypes) > 0) &&
		(transport->flags & CAMEL_SMTP_TRANSPORT_IS_ESMTP);

	if (auth_required) {
		CamelSession *session;

		session = camel_service_ref_session (service);

		if (g_hash_table_lookup (transport->authtypes, mechanism)) {
			success = camel_session_authenticate_sync (
				session, service, mechanism,
				cancellable, error);
		} else {
			g_set_error (
				error, CAMEL_SERVICE_ERROR,
				CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
				_("SMTP server %s does not support %s "
				"authentication"), host, mechanism);
			success = FALSE;
		}

		g_object_unref (session);

		if (!success)
			transport->connected = FALSE;
	}

exit:
	g_free (host);
	g_free (mechanism);

	return success;
}
static gboolean
migrate_mbox_to_maildir (EShell *shell,
                         CamelSession *session,
                         ESource *mbox_source)
{
	ESourceRegistry *registry;
	ESourceExtension *extension;
	const gchar *extension_name;
	CamelService *mbox_service = NULL;
	CamelService *maildir_service = NULL;
	CamelSettings *settings;
	const gchar *data_dir;
	const gchar *mbox_uid;
	gchar *path;
	struct MigrateStore ms;
	GThread *thread;
	GError *error = NULL;

	registry = e_shell_get_registry (shell);

	data_dir = camel_session_get_user_data_dir (session);

	mbox_uid = e_source_get_uid (mbox_source);
	e_source_set_display_name (mbox_source, "local_mbox");

	extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
	extension = e_source_get_extension (mbox_source, extension_name);

	e_source_backend_set_backend_name (
		E_SOURCE_BACKEND (extension), "mbox");

	extension_name = e_source_camel_get_extension_name ("mbox");
	extension = e_source_get_extension (mbox_source, extension_name);
	settings = e_source_camel_get_settings (E_SOURCE_CAMEL (extension));

	path = g_build_filename (data_dir, mbox_uid, NULL);
	g_object_set (settings, "path", path, NULL);
	g_free (path);

	e_source_registry_commit_source_sync (
		registry, mbox_source, NULL, &error);

	if (error == NULL)
		mbox_service = camel_session_add_service (
			session, mbox_uid, "mbox",
			CAMEL_PROVIDER_STORE, &error);

	if (error == NULL)
		maildir_service = camel_session_add_service (
			session, "local", "maildir",
			CAMEL_PROVIDER_STORE, &error);

	if (error != NULL) {
		if (mbox_service != NULL)
			g_object_unref (mbox_service);
		if (maildir_service != NULL)
			g_object_unref (maildir_service);
		g_warning ("%s: %s", G_STRFUNC, error->message);
		g_error_free (error);
		return FALSE;
	}

	g_return_val_if_fail (CAMEL_IS_STORE (mbox_service), FALSE);
	g_return_val_if_fail (CAMEL_IS_STORE (maildir_service), FALSE);

	camel_service_set_settings (mbox_service, settings);

	settings = camel_service_ref_settings (maildir_service);

	path = g_build_filename (data_dir, "local", NULL);
	g_object_set (settings, "path", path, NULL);
	if (g_mkdir (path, 0700) == -1)
		g_warning (
			"%s: Failed to make directory '%s': %s",
			G_STRFUNC, path, g_strerror (errno));
	g_free (path);

	g_object_unref (settings);

	ms.mail_store = CAMEL_STORE (mbox_service);
	ms.maildir_store = CAMEL_STORE (maildir_service);
	ms.session = session;
	ms.complete = FALSE;

	thread = g_thread_new (NULL, (GThreadFunc) migrate_stores, &ms);
	/* coverity[loop_condition] */
	while (!ms.complete)
		g_main_context_iteration (NULL, TRUE);

	g_object_unref (mbox_service);
	g_object_unref (maildir_service);
	g_thread_unref (thread);

	return TRUE;
}
static gboolean
sendmail_send_to_sync (CamelTransport *transport,
                       CamelMimeMessage *message,
                       CamelAddress *from,
                       CamelAddress *recipients,
		       gboolean *out_sent_message_saved,
                       GCancellable *cancellable,
                       GError **error)
{
	CamelHeaderRaw *header, *savedbcc, *n, *tail;
	const gchar *from_addr, *addr;
	GPtrArray *argv_arr;
	gint i, len, fd[2], nullfd, wstat;
	CamelStream *filter;
	CamelMimeFilter *crlf;
	sigset_t mask, omask;
	CamelStream *out;
	CamelSendmailSettings *settings;
	const gchar *binary = SENDMAIL_PATH;
	gchar *custom_binary = NULL, *custom_args = NULL;
	gboolean success;
	pid_t pid;

	success = camel_internet_address_get (
		CAMEL_INTERNET_ADDRESS (from), 0, NULL, &from_addr);

	if (!success) {
		g_set_error (
			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
			_("Failed to read From address"));
		return FALSE;
	}

	settings = CAMEL_SENDMAIL_SETTINGS (camel_service_ref_settings (CAMEL_SERVICE (transport)));

	if (!camel_sendmail_settings_get_send_in_offline (settings)) {
		CamelSession *session;
		gboolean is_online;

		session = camel_service_ref_session (CAMEL_SERVICE (transport));
		is_online = session && camel_session_get_online (session);
		g_clear_object (&session);

		if (!is_online) {
			g_set_error (
				error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
				_("Message send in offline mode is disabled"));
			return FALSE;
		}
	}

	if (camel_sendmail_settings_get_use_custom_binary (settings)) {
		custom_binary = camel_sendmail_settings_dup_custom_binary (settings);
		if (custom_binary && *custom_binary)
			binary = custom_binary;
	}

	if (camel_sendmail_settings_get_use_custom_args (settings)) {
		custom_args = camel_sendmail_settings_dup_custom_args (settings);
		/* means no arguments used */
		if (!custom_args)
			custom_args = g_strdup ("");
	}

	g_object_unref (settings);

	len = camel_address_length (recipients);
	for (i = 0; i < len; i++) {
		success = camel_internet_address_get (
			CAMEL_INTERNET_ADDRESS (recipients), i, NULL, &addr);

		if (!success) {
			g_set_error (
				error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
				_("Could not parse recipient list"));
			g_free (custom_binary);
			g_free (custom_args);

			return FALSE;
		}
	}

	argv_arr = parse_sendmail_args (
		binary,
		custom_args ? custom_args : "-i -f %F -- %R",
		from_addr,
		recipients);

	if (!argv_arr) {
		g_set_error (
			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
			_("Could not parse arguments"));

		g_free (custom_binary);
		g_free (custom_args);

		return FALSE;
	}

	/* unlink the bcc headers */
	savedbcc = NULL;
	tail = (CamelHeaderRaw *) &savedbcc;

	header = (CamelHeaderRaw *) &CAMEL_MIME_PART (message)->headers;
	n = header->next;
	while (n != NULL) {
		if (!g_ascii_strcasecmp (n->name, "Bcc")) {
			header->next = n->next;
			tail->next = n;
			n->next = NULL;
			tail = n;
		} else {
			header = n;
		}

		n = header->next;
	}

	if (pipe (fd) == -1) {
		g_set_error (
			error, G_IO_ERROR,
			g_io_error_from_errno (errno),
			_("Could not create pipe to '%s': %s: "
			"mail not sent"), binary, g_strerror (errno));

		/* restore the bcc headers */
		header->next = savedbcc;
		g_free (custom_binary);
		g_free (custom_args);
		g_ptr_array_free (argv_arr, TRUE);

		return FALSE;
	}

	/* Block SIGCHLD so the calling application doesn't notice
	 * sendmail exiting before we do.
	 */
	sigemptyset (&mask);
	sigaddset (&mask, SIGCHLD);
	sigprocmask (SIG_BLOCK, &mask, &omask);

	pid = fork ();
	switch (pid) {
	case -1:
		g_set_error (
			error, G_IO_ERROR,
			g_io_error_from_errno (errno),
			_("Could not fork '%s': %s: "
			"mail not sent"), binary, g_strerror (errno));
		close (fd[0]);
		close (fd[1]);
		sigprocmask (SIG_SETMASK, &omask, NULL);

		/* restore the bcc headers */
		header->next = savedbcc;
		g_free (custom_binary);
		g_free (custom_args);
		g_ptr_array_free (argv_arr, TRUE);

		return FALSE;
	case 0:
		/* Child process */
		nullfd = open ("/dev/null", O_RDWR);
		dup2 (fd[0], STDIN_FILENO);
		if (nullfd != -1) {
			/*dup2 (nullfd, STDOUT_FILENO);
			  dup2 (nullfd, STDERR_FILENO);*/
			close (nullfd);
		}
		close (fd[1]);

		execv (binary, (gchar **) argv_arr->pdata);
		_exit (255);
	}

	g_ptr_array_free (argv_arr, TRUE);

	/* Parent process. Write the message out. */
	close (fd[0]);
	out = camel_stream_fs_new_with_fd (fd[1]);

	/* XXX Workaround for lame sendmail implementations
	 *     that can't handle CRLF eoln sequences. */
	filter = camel_stream_filter_new (out);
	crlf = camel_mime_filter_crlf_new (
		CAMEL_MIME_FILTER_CRLF_DECODE,
		CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY);
	camel_stream_filter_add (CAMEL_STREAM_FILTER (filter), crlf);
	g_object_unref (crlf);
	g_object_unref (out);

	out = (CamelStream *) filter;
	if (camel_data_wrapper_write_to_stream_sync (
		CAMEL_DATA_WRAPPER (message), out, cancellable, error) == -1
	    || camel_stream_close (out, cancellable, error) == -1) {
		g_object_unref (out);
		g_prefix_error (error, _("Could not send message: "));

		/* Wait for sendmail to exit. */
		while (waitpid (pid, &wstat, 0) == -1 && errno == EINTR)
			;

		sigprocmask (SIG_SETMASK, &omask, NULL);

		/* restore the bcc headers */
		header->next = savedbcc;
		g_free (custom_binary);
		g_free (custom_args);

		return FALSE;
	}

	g_object_unref (out);

	/* Wait for sendmail to exit. */
	while (waitpid (pid, &wstat, 0) == -1 && errno == EINTR)
		;

	sigprocmask (SIG_SETMASK, &omask, NULL);

	/* restore the bcc headers */
	header->next = savedbcc;

	if (!WIFEXITED (wstat)) {
		g_set_error (
			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
			_("'%s' exited with signal %s: mail not sent."),
			binary, g_strsignal (WTERMSIG (wstat)));
		g_free (custom_binary);
		g_free (custom_args);

		return FALSE;
	} else if (WEXITSTATUS (wstat) != 0) {
		if (WEXITSTATUS (wstat) == 255) {
			g_set_error (
				error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
				_("Could not execute '%s': mail not sent."),
				binary);
		} else {
			g_set_error (
				error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
				_("'%s' exited with status %d: "
				"mail not sent."),
				binary, WEXITSTATUS (wstat));
		}
		g_free (custom_binary);
		g_free (custom_args);

		return FALSE;
	}

	g_free (custom_binary);
	g_free (custom_args);

	return TRUE;
}
static gboolean
connect_to_server (CamelService *service,
                   GCancellable *cancellable,
                   GError **error)
{
	CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
	CamelNetworkSettings *network_settings;
	CamelNetworkSecurityMethod method;
	CamelSettings *settings;
	CamelStream *stream;
	GIOStream *base_stream;
	GIOStream *tls_stream;
	gchar *respbuf = NULL;
	gboolean success = TRUE;
	gchar *host;

	if (!CAMEL_SERVICE_CLASS (camel_smtp_transport_parent_class)->
		connect_sync (service, cancellable, error))
		return FALSE;

	/* set some smtp transport defaults */
	transport->flags = 0;
	transport->authtypes = NULL;

	settings = camel_service_ref_settings (service);

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

	g_object_unref (settings);

	base_stream = camel_network_service_connect_sync (
		CAMEL_NETWORK_SERVICE (service), cancellable, error);

	if (base_stream != NULL) {
		/* get the localaddr - needed later by smtp_helo */
		transport->local_address =
			g_socket_connection_get_local_address (
			G_SOCKET_CONNECTION (base_stream), NULL);

		stream = camel_stream_new (base_stream);
		g_object_unref (base_stream);
	} else {
		success = FALSE;
		goto exit;
	}

	transport->connected = TRUE;

	transport->ostream = stream;
	transport->istream = camel_stream_buffer_new (
		stream, CAMEL_STREAM_BUFFER_READ);

	/* Read the greeting, note whether the server is ESMTP or not. */
	do {
		/* Check for "220" */
		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)"));
		if (respbuf == NULL) {
			g_prefix_error (error, _("Welcome response error: "));
			transport->connected = FALSE;
			success = FALSE;
			goto exit;
		}
		if (strncmp (respbuf, "220", 3)) {
			smtp_set_error (
				transport, respbuf, cancellable, error);
			g_prefix_error (error, _("Welcome response error: "));
			g_free (respbuf);
			success = FALSE;
			goto exit;
		}
	} while (*(respbuf+3) == '-'); /* if we got "220-" then loop again */
	g_free (respbuf);

	/* Try sending EHLO */
	transport->flags |= CAMEL_SMTP_TRANSPORT_IS_ESMTP;
	if (!smtp_helo (transport, cancellable, error)) {
		if (!transport->connected) {
			success = FALSE;
			goto exit;
		}

		/* Fall back to HELO */
		g_clear_error (error);
		transport->flags &= ~CAMEL_SMTP_TRANSPORT_IS_ESMTP;

		if (!smtp_helo (transport, cancellable, error)) {
			success = FALSE;
			goto exit;
		}
	}

	/* Clear any EHLO/HELO exception and assume that
	 * any SMTP errors encountered were non-fatal. */
	g_clear_error (error);

	if (method != CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT)
		goto exit;  /* we're done */

	if (!(transport->flags & CAMEL_SMTP_TRANSPORT_STARTTLS)) {
		g_set_error (
			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
			_("Failed to connect to SMTP server %s in secure mode: %s"),
			host, _("STARTTLS not supported"));

		success = FALSE;
		goto exit;
	}

	d (fprintf (stderr, "[SMTP] sending: STARTTLS\r\n"));
	if (camel_stream_write (
		stream, "STARTTLS\r\n", 10, cancellable, error) == -1) {
		g_prefix_error (error, _("STARTTLS command failed: "));
		success = FALSE;
		goto exit;
	}

	respbuf = NULL;

	do {
		/* Check for "220 Ready for TLS" */
		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)"));
		if (respbuf == NULL) {
			g_prefix_error (error, _("STARTTLS command failed: "));
			transport->connected = FALSE;
			success = FALSE;
			goto exit;
		}
		if (strncmp (respbuf, "220", 3) != 0) {
			smtp_set_error (
				transport, respbuf, cancellable, error);
			g_prefix_error (error, _("STARTTLS command failed: "));
			g_free (respbuf);
			success = FALSE;
			goto exit;
		}
	} while (*(respbuf+3) == '-'); /* if we got "220-" then loop again */

	/* Okay, now toggle SSL/TLS mode */
	base_stream = camel_stream_ref_base_stream (stream);
	tls_stream = camel_network_service_starttls (
		CAMEL_NETWORK_SERVICE (service), base_stream, error);
	g_object_unref (base_stream);

	if (tls_stream != NULL) {
		camel_stream_set_base_stream (stream, tls_stream);
		g_object_unref (tls_stream);
	} else {
		g_prefix_error (
			error,
			_("Failed to connect to SMTP server %s in secure mode: "),
			host);
		success = FALSE;
		goto exit;
	}

	/* We are supposed to re-EHLO after a successful STARTTLS to
	 * re-fetch any supported extensions. */
	if (!smtp_helo (transport, cancellable, error)) {
		success = FALSE;
	}

exit:
	g_free (host);

	if (!success) {
		transport->connected = FALSE;
		g_clear_object (&transport->istream);
		g_clear_object (&transport->ostream);
	}

	return success;
}