[evolution-data-server] Add CamelNetworkService interface.



commit 2a9ad2ca5b9d2a423362ec5b0d81dd51af5e4480
Author: Matthew Barnes <mbarnes redhat com>
Date:   Tue Jul 19 16:58:23 2011 -0500

    Add CamelNetworkService interface.
    
    For now this interface is optional for network-based providers.
    Eventually I'd like to move the connect() and disconnect() methods
    from CamelService to CamelNetworkService entirely, but for now this
    interface just collects duplicate code from the imap, imapx, nntp,
    pop3 and smtp providers.  The connect_sync() method creates a TCP
    stream and configures it to use a SOCKS proxy if available.

 camel/Makefile.am                                  |    2 +
 camel/camel-enums.h                                |   25 ++-
 camel/camel-network-service.c                      |  311 +++++++++++++++++++
 camel/camel-network-service.h                      |   84 +++++
 camel/camel.h                                      |    1 +
 camel/providers/imap/camel-imap-store.c            |  275 +++++++++++-------
 camel/providers/imapx/camel-imapx-server.c         |   60 +----
 camel/providers/imapx/camel-imapx-store.c          |  164 ++++++++++-
 camel/providers/local/camel-spool-store.c          |    7 +-
 camel/providers/nntp/camel-nntp-store.c            |  266 ++++++++++------
 camel/providers/pop3/camel-pop3-store.c            |  270 +++++++++++-------
 camel/providers/smtp/camel-smtp-transport.c        |  317 ++++++++++++--------
 docs/reference/camel/camel-docs.sgml               |    1 +
 docs/reference/camel/camel-sections.txt            |   21 ++
 .../camel/tmpl/camel-network-service.sgml          |   84 +++++
 po/POTFILES.in                                     |    1 +
 16 files changed, 1403 insertions(+), 486 deletions(-)
---
diff --git a/camel/Makefile.am b/camel/Makefile.am
index 53b602e..0490cfe 100644
--- a/camel/Makefile.am
+++ b/camel/Makefile.am
@@ -64,6 +64,7 @@ libcamel_provider_1_2_la_SOURCES = 		\
 	camel-folder.c				\
 	camel-gpg-context.c			\
 	camel-http-stream.c			\
+	camel-network-service.c			\
 	camel-offline-folder.c			\
 	camel-offline-journal.c			\
 	camel-offline-store.c			\
@@ -112,6 +113,7 @@ libcamel_providerinclude_HEADERS =		\
 	camel-html-parser.h			\
 	camel-lock-helper.h			\
 	camel-movemail.h			\
+	camel-network-service.h			\
 	camel-offline-folder.h			\
 	camel-offline-journal.h			\
 	camel-offline-store.h			\
diff --git a/camel/camel-enums.h b/camel/camel-enums.h
index b082fe8..e9eb1e6 100644
--- a/camel/camel-enums.h
+++ b/camel/camel-enums.h
@@ -134,6 +134,26 @@ typedef enum {
 	CAMEL_MIME_FILTER_YENC_DIRECTION_DECODE
 } CamelMimeFilterYencDirection;
 
+/**
+ * CamelNetworkSecurityMethod:
+ * @CAMEL_NETWORK_SECURITY_METHOD_NONE:
+ *   Use an unencrypted network connection.
+ * @CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
+ *   Use SSL by connecting to an alternate port number.
+ * @CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT:
+ *   Use SSL or TLS by connecting to the standard port and invoking
+ *   STARTTLS before authenticating.  This is the recommended method.
+ *
+ * Methods for establishing an encrypted (or unencrypted) network connection.
+ *
+ * Since: 3.2
+ **/
+typedef enum {
+	CAMEL_NETWORK_SECURITY_METHOD_NONE,
+	CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT,
+	CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT
+} CamelNetworkSecurityMethod;
+
 typedef enum {
 	CAMEL_PROVIDER_CONF_END,
 	CAMEL_PROVIDER_CONF_SECTION_START,
@@ -146,7 +166,8 @@ typedef enum {
 	CAMEL_PROVIDER_CONF_OPTIONS
 } CamelProviderConfType;
 
-/* CamelProviderFlags;
+/**
+ * CamelProviderFlags;
  * @CAMEL_PROVIDER_IS_REMOTE:
  *   Provider works with remote data.
  * @CAMEL_PROVIDER_IS_LOCAL:
@@ -167,7 +188,7 @@ typedef enum {
  *   Provider may use a real trash folder instead of a virtual folder.
  * @CAMEL_PROVIDER_ALLOW_REAL_JUNK_FOLDER:
  *   Provider may use a real junk folder instead of a virtual folder.
- */
+ **/
 typedef enum { /*< flags >*/
 	CAMEL_PROVIDER_IS_REMOTE               = 1 << 0,
 	CAMEL_PROVIDER_IS_LOCAL                = 1 << 1,
diff --git a/camel/camel-network-service.c b/camel/camel-network-service.c
new file mode 100644
index 0000000..ee7d1b6
--- /dev/null
+++ b/camel/camel-network-service.c
@@ -0,0 +1,311 @@
+/*
+ * camel-network-service.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "camel-network-service.h"
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+
+#include <camel/camel-enumtypes.h>
+#include <camel/camel-service.h>
+#include <camel/camel-session.h>
+#include <camel/camel-tcp-stream-raw.h>
+
+#if CAMEL_HAVE_SSL
+#include <camel/camel-tcp-stream-ssl.h>
+#endif
+
+G_DEFINE_INTERFACE (
+	CamelNetworkService,
+	camel_network_service,
+	CAMEL_TYPE_SERVICE)
+
+static CamelStream *
+network_service_connect_sync (CamelNetworkService *service,
+                              GCancellable *cancellable,
+                              GError **error)
+{
+	CamelNetworkSecurityMethod method;
+	CamelSession *session;
+	CamelStream *stream;
+	CamelURL *url;
+	const gchar *service_name;
+	guint16 default_port;
+	gchar *socks_host;
+	gint socks_port;
+	gint status;
+
+	url = camel_service_get_camel_url (CAMEL_SERVICE (service));
+	session = camel_service_get_session (CAMEL_SERVICE (service));
+
+	method = camel_network_service_get_security_method (service);
+	service_name = camel_network_service_get_service_name (service);
+	default_port = camel_network_service_get_default_port (service);
+
+	/* If the URL explicitly gives a port number, make
+	 * it override the service name and default port. */
+	if (url->port > 0) {
+		service_name = g_alloca (16);
+		sprintf ((gchar *) service_name, "%d", url->port);
+		default_port = 0;
+	}
+
+	switch (method) {
+		case CAMEL_NETWORK_SECURITY_METHOD_NONE:
+			stream = camel_tcp_stream_raw_new ();
+			break;
+
+#ifdef CAMEL_HAVE_SSL
+		case CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT:
+			stream = camel_tcp_stream_ssl_new_raw (
+				session, url->host,
+				CAMEL_TCP_STREAM_SSL_ENABLE_TLS);
+			break;
+
+		case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
+			stream = camel_tcp_stream_ssl_new (
+				session, url->host,
+				CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 |
+				CAMEL_TCP_STREAM_SSL_ENABLE_SSL3);
+			break;
+#else
+		case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
+		case CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT:
+			g_set_error (
+				error, CAMEL_SERVICE_ERROR,
+				CAMEL_SERVICE_ERROR_UNAVAILABLE,
+				_("Could not connect to %s: %s"),
+				url->host, _("SSL unavailable"));
+			return NULL;
+#endif
+
+		default:
+			g_return_val_if_reached (NULL);
+	}
+
+	camel_session_get_socks_proxy (session, &socks_host, &socks_port);
+
+	if (socks_host != NULL) {
+		camel_tcp_stream_set_socks_proxy (
+			CAMEL_TCP_STREAM (stream),
+			socks_host, socks_port);
+		g_free (socks_host);
+	}
+
+	status = camel_tcp_stream_connect (
+		CAMEL_TCP_STREAM (stream), url->host,
+		service_name, default_port, cancellable, error);
+
+	if (status == -1) {
+		g_prefix_error (
+			error, _("Could not connect to %s: "), url->host);
+		g_object_unref (stream);
+		stream = NULL;
+	}
+
+	return stream;
+}
+
+static void
+camel_network_service_default_init (CamelNetworkServiceInterface *interface)
+{
+	interface->connect_sync = network_service_connect_sync;
+
+	g_object_interface_install_property (
+		interface,
+		g_param_spec_uint (
+			"default-port",
+			"Default Port",
+			"Default IP port",
+			0,
+			G_MAXUINT16,
+			0,
+			G_PARAM_READABLE |
+			G_PARAM_STATIC_STRINGS));
+
+	g_object_interface_install_property (
+		interface,
+		g_param_spec_enum (
+			"security-method",
+			"Security Method",
+			"Method used to establish a network connection",
+			CAMEL_TYPE_NETWORK_SECURITY_METHOD,
+			CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS));
+
+	g_object_interface_install_property (
+		interface,
+		g_param_spec_string (
+			"service-name",
+			"Service Name",
+			"Network service name",
+			NULL,
+			G_PARAM_READABLE |
+			G_PARAM_STATIC_STRINGS));
+}
+
+/**
+ * camel_network_service_get_service_name:
+ * @service: a #CamelNetworkService
+ *
+ * Returns the standard network service name for @service as defined
+ * in /etc/services.  The service name may depend on the value of the
+ * #CamelNetworkService:security-method property.  For example, the
+ * service name for unencrypted IMAP or encrypted IMAP using STARTTLS
+ * is "imap", but the service name for IMAP over SSL is "imaps".
+ *
+ * Returns: the network service name for @service, or %NULL
+ *
+ * Since: 3.2
+ **/
+const gchar *
+camel_network_service_get_service_name (CamelNetworkService *service)
+{
+	CamelNetworkServiceInterface *interface;
+	const gchar *service_name = NULL;
+
+	g_return_val_if_fail (CAMEL_IS_NETWORK_SERVICE (service), NULL);
+
+	interface = CAMEL_NETWORK_SERVICE_GET_INTERFACE (service);
+
+	if (interface->get_service_name != NULL)
+		service_name = interface->get_service_name (service);
+
+	return service_name;
+}
+
+/**
+ * camel_network_service_get_default_port:
+ * @service: a #CamelNetworkService
+ *
+ * Returns the default network port number of @service as defined
+ * in /etc/services.  The default port may depend on the value of the
+ * #CamelNetworkService:security-method property.  For example, the
+ * default port for unencrypted IMAP or encrypted IMAP using STARTTLS
+ * is 143, but the default port for IMAP over SSL is 993.
+ *
+ * Returns: the default port number for @service
+ *
+ * Since: 3.2
+ **/
+guint16
+camel_network_service_get_default_port (CamelNetworkService *service)
+{
+	CamelNetworkServiceInterface *interface;
+	guint16 default_port = 0;
+
+	g_return_val_if_fail (CAMEL_IS_NETWORK_SERVICE (service), 0);
+
+	interface = CAMEL_NETWORK_SERVICE_GET_INTERFACE (service);
+
+	if (interface->get_default_port != NULL)
+		default_port = interface->get_default_port (service);
+
+	return default_port;
+}
+
+/**
+ * camel_network_service_get_security_method:
+ * @service: a #CamelNetworkService
+ *
+ * Return the method used to establish a secure (or unsecure) network
+ * connection.
+ *
+ * Returns: the security method
+ *
+ * Since: 3.2
+ **/
+CamelNetworkSecurityMethod
+camel_network_service_get_security_method (CamelNetworkService *service)
+{
+	gpointer data;
+
+	g_return_val_if_fail (
+		CAMEL_IS_NETWORK_SERVICE (service),
+		CAMEL_NETWORK_SECURITY_METHOD_NONE);
+
+	data = g_object_get_data (
+		G_OBJECT (service), "CamelNetworkService:security-method");
+
+	return (CamelNetworkSecurityMethod) GPOINTER_TO_INT (data);
+}
+
+/**
+ * camel_network_service_set_security_method:
+ * @service: a #CamelNetworkService
+ * @method: the security method
+ *
+ * Sets the method used to establish a secure (or unsecure) network
+ * connection.  Note that changing this setting has no effect on an
+ * already-established network connection.
+ *
+ * Since: 3.2
+ **/
+void
+camel_network_service_set_security_method (CamelNetworkService *service,
+                                           CamelNetworkSecurityMethod method)
+{
+	GObject *object;
+
+	g_return_if_fail (CAMEL_IS_NETWORK_SERVICE (service));
+
+	object = G_OBJECT (service);
+
+	g_object_set_data (
+		object, "CamelNetworkService:security-method",
+		GINT_TO_POINTER (method));
+
+	g_object_freeze_notify (object);
+	g_object_notify (object, "default-port");
+	g_object_notify (object, "security-method");
+	g_object_notify (object, "service-name");
+	g_object_thaw_notify (object);
+}
+
+/**
+ * camel_network_service_connect_sync:
+ * @service: a #CamelNetworkService
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Attempts to establish a network connection to the server described by
+ * @service, using the preferred #CamelNetworkService:security-method to
+ * secure the connection.  If a connection cannot be established, or the
+ * connection attempt is cancelled, the function sets @error and returns
+ * %NULL.
+ *
+ * Returns: a #CamelStream, or %NULL
+ *
+ * Since: 3.2
+ **/
+CamelStream *
+camel_network_service_connect_sync (CamelNetworkService *service,
+                                    GCancellable *cancellable,
+                                    GError **error)
+{
+	CamelNetworkServiceInterface *interface;
+
+	g_return_val_if_fail (CAMEL_IS_NETWORK_SERVICE (service), NULL);
+
+	interface = CAMEL_NETWORK_SERVICE_GET_INTERFACE (service);
+	g_return_val_if_fail (interface->connect_sync != NULL, NULL);
+
+	return interface->connect_sync (service, cancellable, error);
+}
diff --git a/camel/camel-network-service.h b/camel/camel-network-service.h
new file mode 100644
index 0000000..4eaa26f
--- /dev/null
+++ b/camel/camel-network-service.h
@@ -0,0 +1,84 @@
+/*
+ * camel-network-service.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#if !defined (__CAMEL_H_INSIDE__) && !defined (CAMEL_COMPILATION)
+#error "Only <camel/camel.h> can be included directly."
+#endif
+
+#ifndef CAMEL_NETWORK_SERVICE_H
+#define CAMEL_NETWORK_SERVICE_H
+
+#include <camel/camel-enums.h>
+#include <camel/camel-stream.h>
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_NETWORK_SERVICE \
+	(camel_network_service_get_type ())
+#define CAMEL_NETWORK_SERVICE(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), CAMEL_TYPE_NETWORK_SERVICE, CamelNetworkService))
+#define CAMEL_NETWORK_SERVICE_INTERFACE(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), CAMEL_TYPE_NETWORK_SERVICE, CamelNetworkServiceInterface))
+#define CAMEL_IS_NETWORK_SERVICE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), CAMEL_TYPE_NETWORK_SERVICE))
+#define CAMEL_IS_NETWORK_SERVICE_INTERFACE(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), CAMEL_TYPE_NETWORK_SERVICE))
+#define CAMEL_NETWORK_SERVICE_GET_INTERFACE(obj) \
+	(G_TYPE_INSTANCE_GET_INTERFACE \
+	((obj), CAMEL_TYPE_NETWORK_SERVICE, CamelNetworkServiceInterface))
+
+G_BEGIN_DECLS
+
+typedef struct _CamelNetworkService CamelNetworkService;
+typedef struct _CamelNetworkServiceInterface CamelNetworkServiceInterface;
+
+struct _CamelNetworkServiceInterface {
+	GTypeInterface parent_interface;
+
+	const gchar *	(*get_service_name)	(CamelNetworkService *service);
+	guint16		(*get_default_port)	(CamelNetworkService *service);
+
+	CamelStream *	(*connect_sync)		(CamelNetworkService *service,
+						 GCancellable *cancellable,
+						 GError **error);
+
+	gpointer reserved[16];
+};
+
+GType		camel_network_service_get_type	(void) G_GNUC_CONST;
+const gchar *	camel_network_service_get_service_name
+						(CamelNetworkService *service);
+guint16		camel_network_service_get_default_port
+						(CamelNetworkService *service);
+CamelNetworkSecurityMethod
+		camel_network_service_get_security_method
+						(CamelNetworkService *service);
+void		camel_network_service_set_security_method
+						(CamelNetworkService *service,
+						 CamelNetworkSecurityMethod method);
+CamelStream *	camel_network_service_connect_sync
+						(CamelNetworkService *service,
+						 GCancellable *cancellable,
+						 GError **error);
+
+G_END_DECLS
+
+#endif /* CAMEL_NETWORK_SERVICE_H */
diff --git a/camel/camel.h b/camel/camel.h
index c0395bb..f758781 100644
--- a/camel/camel.h
+++ b/camel/camel.h
@@ -89,6 +89,7 @@
 #include <camel/camel-multipart-encrypted.h>
 #include <camel/camel-multipart-signed.h>
 #include <camel/camel-net-utils.h>
+#include <camel/camel-network-service.h>
 #include <camel/camel-nntp-address.h>
 #include <camel/camel-object.h>
 #include <camel/camel-object-bag.h>
diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c
index 2b9beef..471b758 100644
--- a/camel/providers/imap/camel-imap-store.c
+++ b/camel/providers/imap/camel-imap-store.c
@@ -92,30 +92,6 @@ static CamelFolderInfo * imap_store_get_folder_info_sync (CamelStore *store, con
 static CamelFolder * get_folder_offline (CamelStore *store, const gchar *folder_name, guint32 flags, GError **error);
 static CamelFolderInfo * get_folder_info_offline (CamelStore *store, const gchar *top, guint32 flags, GError **error);
 
-enum {
-	MODE_CLEAR,
-	MODE_SSL,
-	MODE_TLS
-};
-
-#ifdef HAVE_SSL
-#define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3)
-#define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS)
-#endif
-
-static struct {
-	const gchar *value;
-	const gchar *serv;
-	gint fallback_port;
-	gint mode;
-} ssl_options[] = {
-	{ "",              "imaps", IMAPS_PORT, MODE_SSL   },  /* really old (1.x) */
-	{ "always",        "imaps", IMAPS_PORT, MODE_SSL   },
-	{ "when-possible", "imap",  IMAP_PORT,  MODE_TLS   },
-	{ "never",         "imap",  IMAP_PORT,  MODE_CLEAR },
-	{ NULL,            "imap",  IMAP_PORT,  MODE_CLEAR },
-};
-
 static struct {
 	const gchar *name;
 	guint32 flag;
@@ -134,17 +110,31 @@ static struct {
 	{ NULL, 0 }
 };
 
+enum {
+	PROP_0,
+	PROP_DEFAULT_PORT,
+	PROP_SECURITY_METHOD,
+	PROP_SERVICE_NAME
+};
+
 extern CamelServiceAuthType camel_imap_password_authtype;
 
 static GInitableIface *parent_initable_interface;
 
 /* Forward Declarations */
 static void camel_imap_store_initable_init (GInitableIface *interface);
+static void camel_network_service_init (CamelNetworkServiceInterface *interface);
 
 G_DEFINE_TYPE_WITH_CODE (
-	CamelImapStore, camel_imap_store, CAMEL_TYPE_OFFLINE_STORE,
+	CamelImapStore,
+	camel_imap_store,
+	CAMEL_TYPE_OFFLINE_STORE,
 	G_IMPLEMENT_INTERFACE (
-		G_TYPE_INITABLE, camel_imap_store_initable_init))
+		G_TYPE_INITABLE,
+		camel_imap_store_initable_init)
+	G_IMPLEMENT_INTERFACE (
+		CAMEL_TYPE_NETWORK_SERVICE,
+		camel_network_service_init))
 
 static void
 parse_capability (CamelImapStore *store, gchar *capa)
@@ -213,70 +203,28 @@ imap_get_capability (CamelService *service,
 	return TRUE;
 }
 
-#ifdef CAMEL_HAVE_SSL
-#define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3)
-#define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS)
-#endif
-
 static gboolean
 connect_to_server (CamelService *service,
-                   const gchar *host,
-                   const gchar *serv,
-                   gint fallback_port,
-                   gint ssl_mode,
                    GCancellable *cancellable,
                    GError **error)
 {
 	CamelImapStore *store = (CamelImapStore *) service;
-	CamelSession *session;
 	CamelURL *url;
-	gchar *socks_host;
-	gint socks_port;
 	CamelImapResponse *response;
 	CamelStream *tcp_stream;
 	CamelSockOptData sockopt;
+	CamelNetworkSecurityMethod method;
 	gboolean force_imap4 = FALSE;
 	gboolean clean_quit = TRUE;
 	gchar *buf;
 
-	url = camel_service_get_camel_url (service);
-	session = camel_service_get_session (service);
-
-	if (ssl_mode != MODE_CLEAR) {
-#ifdef CAMEL_HAVE_SSL
-		if (ssl_mode == MODE_TLS)
-			tcp_stream = camel_tcp_stream_ssl_new_raw (session, url->host, STARTTLS_FLAGS);
-		else
-			tcp_stream = camel_tcp_stream_ssl_new (session, url->host, SSL_PORT_FLAGS);
-#else
-		g_set_error (
-			error, CAMEL_SERVICE_ERROR,
-			CAMEL_SERVICE_ERROR_UNAVAILABLE,
-			_("Could not connect to %s: %s"),
-			url->host, _("SSL unavailable"));
+	tcp_stream = camel_network_service_connect_sync (
+		CAMEL_NETWORK_SERVICE (service), cancellable, error);
 
+	if (tcp_stream == NULL)
 		return FALSE;
 
-#endif /* CAMEL_HAVE_SSL */
-	} else
-		tcp_stream = camel_tcp_stream_raw_new ();
-
-	camel_session_get_socks_proxy (session, &socks_host, &socks_port);
-
-	if (socks_host) {
-		camel_tcp_stream_set_socks_proxy ((CamelTcpStream *) tcp_stream, socks_host, socks_port);
-		g_free (socks_host);
-	}
-
-	if (camel_tcp_stream_connect (
-		CAMEL_TCP_STREAM (tcp_stream), host, serv,
-		fallback_port, cancellable, error) == -1) {
-		g_prefix_error (
-			error, _("Could not connect to %s: "),
-			url->host);
-		g_object_unref (tcp_stream);
-		return FALSE;
-	}
+	url = camel_service_get_camel_url (service);
 
 	store->ostream = tcp_stream;
 	store->istream = camel_stream_buffer_new (tcp_stream, CAMEL_STREAM_BUFFER_READ);
@@ -366,10 +314,11 @@ connect_to_server (CamelService *service,
 		store->server_level = IMAP_LEVEL_IMAP4;
 	}
 
-	if (ssl_mode != MODE_TLS) {
-		/* we're done */
-		return TRUE;
-	}
+	method = camel_network_service_get_security_method (
+		CAMEL_NETWORK_SERVICE (service));
+
+	if (method != CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT)
+		return TRUE;  /* we're done */
 
 #ifdef CAMEL_HAVE_SSL
 	/* as soon as we send a STARTTLS command, all hope is lost of a clean QUIT if problems arise */
@@ -619,10 +568,6 @@ connect_to_server_wrapper (CamelService *service,
                            GError **error)
 {
 	CamelURL *url;
-	const gchar *ssl_mode;
-	gint mode, i;
-	const gchar *serv;
-	gint fallback_port;
 
 #ifndef G_OS_WIN32
 	const gchar *command;
@@ -636,28 +581,7 @@ connect_to_server_wrapper (CamelService *service,
 		return connect_to_server_process (service, command, cancellable, error);
 #endif
 
-	if ((ssl_mode = camel_url_get_param (url, "use_ssl"))) {
-		for (i = 0; ssl_options[i].value; i++)
-			if (!strcmp (ssl_options[i].value, ssl_mode))
-				break;
-		mode = ssl_options[i].mode;
-		serv = (gchar *) ssl_options[i].serv;
-		fallback_port = ssl_options[i].fallback_port;
-	} else {
-		mode = MODE_CLEAR;
-		serv = (gchar *) "imap";
-		fallback_port = IMAP_PORT;
-	}
-
-	if (url->port) {
-		serv = g_alloca (16);
-		sprintf ((gchar *)serv, "%d", url->port);
-		fallback_port = 0;
-	}
-
-	return connect_to_server (
-		service, url->host, serv,
-		fallback_port, mode, cancellable, error);
+	return connect_to_server (service, cancellable, error);
 }
 
 static gboolean
@@ -882,6 +806,55 @@ free_key (gpointer key, gpointer value, gpointer user_data)
 }
 
 static void
+imap_store_set_property (GObject *object,
+                         guint property_id,
+                         const GValue *value,
+                         GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_SECURITY_METHOD:
+			camel_network_service_set_security_method (
+				CAMEL_NETWORK_SERVICE (object),
+				g_value_get_enum (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+imap_store_get_property (GObject *object,
+                         guint property_id,
+                         GValue *value,
+                         GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_DEFAULT_PORT:
+			g_value_set_uint (
+				value,
+				camel_network_service_get_default_port (
+				CAMEL_NETWORK_SERVICE (object)));
+			return;
+
+		case PROP_SECURITY_METHOD:
+			g_value_set_enum (
+				value,
+				camel_network_service_get_security_method (
+				CAMEL_NETWORK_SERVICE (object)));
+			return;
+
+		case PROP_SERVICE_NAME:
+			g_value_set_string (
+				value,
+				camel_network_service_get_service_name (
+				CAMEL_NETWORK_SERVICE (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
 imap_store_dispose (GObject *object)
 {
 	CamelImapStore *imap_store = CAMEL_IMAP_STORE (object);
@@ -915,6 +888,32 @@ imap_store_finalize (GObject *object)
 	G_OBJECT_CLASS (camel_imap_store_parent_class)->finalize (object);
 }
 
+static void
+imap_store_constructed (GObject *object)
+{
+	CamelURL *url;
+	const gchar *use_ssl;
+
+	/* Chain up to parent's constructed() method. */
+	G_OBJECT_CLASS (camel_imap_store_parent_class)->constructed (object);
+
+	url = camel_service_get_camel_url (CAMEL_SERVICE (object));
+	use_ssl = camel_url_get_param (url, "use_ssl");
+
+	if (g_strcmp0 (use_ssl, "never") == 0)
+		camel_network_service_set_security_method (
+			CAMEL_NETWORK_SERVICE (object),
+			CAMEL_NETWORK_SECURITY_METHOD_NONE);
+	else if (g_strcmp0 (use_ssl, "always") == 0)
+		camel_network_service_set_security_method (
+			CAMEL_NETWORK_SERVICE (object),
+			CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT);
+	else if (g_strcmp0 (use_ssl, "when-possible") == 0)
+		camel_network_service_set_security_method (
+			CAMEL_NETWORK_SERVICE (object),
+			CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT);
+}
+
 static gchar *
 imap_store_get_name (CamelService *service,
                      gboolean brief)
@@ -1308,6 +1307,48 @@ imap_store_initable_init (GInitable *initable,
 	return TRUE;
 }
 
+static const gchar *
+imap_store_get_service_name (CamelNetworkService *service)
+{
+	CamelNetworkSecurityMethod method;
+	const gchar *service_name;
+
+	method = camel_network_service_get_security_method (service);
+
+	switch (method) {
+		case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
+			service_name = "imaps";
+			break;
+
+		default:
+			service_name = "imap";
+			break;
+	}
+
+	return service_name;
+}
+
+static guint16
+imap_store_get_default_port (CamelNetworkService *service)
+{
+	CamelNetworkSecurityMethod method;
+	guint16 default_port;
+
+	method = camel_network_service_get_security_method (service);
+
+	switch (method) {
+		case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
+			default_port = IMAPS_PORT;
+			break;
+
+		default:
+			default_port = IMAP_PORT;
+			break;
+	}
+
+	return default_port;
+}
+
 static void
 camel_imap_store_class_init (CamelImapStoreClass *class)
 {
@@ -1316,8 +1357,11 @@ camel_imap_store_class_init (CamelImapStoreClass *class)
 	CamelStoreClass *store_class;
 
 	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = imap_store_set_property;
+	object_class->get_property = imap_store_get_property;
 	object_class->dispose = imap_store_dispose;
 	object_class->finalize = imap_store_finalize;
+	object_class->constructed = imap_store_constructed;
 
 	service_class = CAMEL_SERVICE_CLASS (class);
 	service_class->get_name = imap_store_get_name;
@@ -1341,6 +1385,24 @@ camel_imap_store_class_init (CamelImapStoreClass *class)
 	store_class->subscribe_folder_sync = imap_store_subscribe_folder_sync;
 	store_class->unsubscribe_folder_sync = imap_store_unsubscribe_folder_sync;
 	store_class->noop_sync = imap_store_noop_sync;
+
+	/* Inherited from CamelNetworkService. */
+	g_object_class_override_property (
+		object_class,
+		PROP_DEFAULT_PORT,
+		"default-port");
+
+	/* Inherited from CamelNetworkService. */
+	g_object_class_override_property (
+		object_class,
+		PROP_SECURITY_METHOD,
+		"security-method");
+
+	/* Inherited from CamelNetworkService. */
+	g_object_class_override_property (
+		object_class,
+		PROP_SERVICE_NAME,
+		"service-name");
 }
 
 static void
@@ -1352,6 +1414,13 @@ camel_imap_store_initable_init (GInitableIface *interface)
 }
 
 static void
+camel_network_service_init (CamelNetworkServiceInterface *interface)
+{
+	interface->get_service_name = imap_store_get_service_name;
+	interface->get_default_port = imap_store_get_default_port;
+}
+
+static void
 camel_imap_store_init (CamelImapStore *imap_store)
 {
 	imap_store->istream = NULL;
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index 04a441e..ae6f983 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -2860,20 +2860,13 @@ imapx_connect_to_server (CamelIMAPXServer *is,
                          GCancellable *cancellable,
                          GError **error)
 {
+	CamelNetworkService *network_service;
+	CamelNetworkSecurityMethod method;
 	CamelStream * tcp_stream = NULL;
-	gchar *socks_host;
-	gint socks_port;
 	CamelSockOptData sockopt;
-	gint ret, ssl_mode = 0;
-
-#ifdef CAMEL_HAVE_SSL
-	const gchar *mode;
-#endif
 	guint len;
 	guchar *token;
 	gint tok;
-	const gchar *serv;
-	gint fallback_port;
 	CamelIMAPXCommand *ic;
 	GError *local_error = NULL;
 
@@ -2888,51 +2881,15 @@ imapx_connect_to_server (CamelIMAPXServer *is,
 			goto connected;
 	}
 #endif
-	if (is->url->port) {
-		serv = g_alloca (16);
-		sprintf((gchar *) serv, "%d", is->url->port);
-		fallback_port = 0;
-	} else {
-		serv = "imap";
-		fallback_port = 143;
-	}
-#ifdef CAMEL_HAVE_SSL
-	mode = camel_url_get_param(is->url, "use_ssl");
-	if (mode && strcmp(mode, "never") != 0) {
-		if (!strcmp(mode, "when-possible")) {
-			tcp_stream = camel_tcp_stream_ssl_new_raw (is->session, is->url->host, STARTTLS_FLAGS);
-			ssl_mode = 2;
-		} else {
-			if (is->url->port == 0) {
-				serv = "imaps";
-				fallback_port = 993;
-			}
-			tcp_stream = camel_tcp_stream_ssl_new (is->session, is->url->host, SSL_PORT_FLAGS);
-		}
-	} else {
-		tcp_stream = camel_tcp_stream_raw_new ();
-	}
-#else
-	tcp_stream = camel_tcp_stream_raw_new ();
-#endif /* CAMEL_HAVE_SSL */
 
-	camel_session_get_socks_proxy (is->session, &socks_host, &socks_port);
+	network_service = CAMEL_NETWORK_SERVICE (is->store);
+	method = camel_network_service_get_security_method (network_service);
 
-	if (socks_host) {
-		camel_tcp_stream_set_socks_proxy ((CamelTcpStream *) tcp_stream, socks_host, socks_port);
-		g_free (socks_host);
-	}
+	tcp_stream = camel_network_service_connect_sync (
+		CAMEL_NETWORK_SERVICE (is->store), cancellable, error);
 
-	ret = camel_tcp_stream_connect (
-		CAMEL_TCP_STREAM (tcp_stream), is->url->host, serv,
-		fallback_port, cancellable, error);
-	if (ret == -1) {
-		g_prefix_error (
-			error, _("Could not connect to %s (port %s): "),
-			is->url->host, serv);
-		g_object_unref (tcp_stream);
+	if (tcp_stream == NULL)
 		return FALSE;
-	}
 
 	is->stream = (CamelIMAPXStream *) camel_imapx_stream_new (tcp_stream);
 	g_object_unref (tcp_stream);
@@ -2998,8 +2955,7 @@ imapx_connect_to_server (CamelIMAPXServer *is,
 	}
 
 #ifdef CAMEL_HAVE_SSL
-	if (ssl_mode == 2)
-	{
+	if (method == CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT) {
 
 		if (!(is->cinfo->capa & IMAPX_CAPABILITY_STARTTLS)) {
 			g_set_error (
diff --git a/camel/providers/imapx/camel-imapx-store.c b/camel/providers/imapx/camel-imapx-store.c
index 1e2b290..a76a6eb 100644
--- a/camel/providers/imapx/camel-imapx-store.c
+++ b/camel/providers/imapx/camel-imapx-store.c
@@ -47,6 +47,7 @@
 
 /* Specified in RFC 2060 section 2.1 */
 #define IMAP_PORT 143
+#define IMAPS_PORT 993
 
 #define FINFO_REFRESH_INTERVAL 60
 
@@ -54,11 +55,25 @@ static GInitableIface *parent_initable_interface;
 
 /* Forward Declarations */
 static void camel_imapx_store_initable_init (GInitableIface *interface);
+static void camel_network_service_init (CamelNetworkServiceInterface *interface);
 
 G_DEFINE_TYPE_WITH_CODE (
-	CamelIMAPXStore, camel_imapx_store, CAMEL_TYPE_OFFLINE_STORE,
+	CamelIMAPXStore,
+	camel_imapx_store,
+	CAMEL_TYPE_OFFLINE_STORE,
 	G_IMPLEMENT_INTERFACE (
-		G_TYPE_INITABLE, camel_imapx_store_initable_init))
+		G_TYPE_INITABLE,
+		camel_imapx_store_initable_init)
+	G_IMPLEMENT_INTERFACE (
+		CAMEL_TYPE_NETWORK_SERVICE,
+		camel_network_service_init))
+
+enum {
+	PROP_0,
+	PROP_DEFAULT_PORT,
+	PROP_SECURITY_METHOD,
+	PROP_SERVICE_NAME
+};
 
 static guint
 imapx_name_hash (gconstpointer key)
@@ -126,6 +141,55 @@ imapx_parse_receiving_options (CamelIMAPXStore *istore, CamelURL *url)
 }
 
 static void
+imapx_store_set_property (GObject *object,
+                          guint property_id,
+                          const GValue *value,
+                          GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_SECURITY_METHOD:
+			camel_network_service_set_security_method (
+				CAMEL_NETWORK_SERVICE (object),
+				g_value_get_enum (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+imapx_store_get_property (GObject *object,
+                          guint property_id,
+                          GValue *value,
+                          GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_DEFAULT_PORT:
+			g_value_set_uint (
+				value,
+				camel_network_service_get_default_port (
+				CAMEL_NETWORK_SERVICE (object)));
+			return;
+
+		case PROP_SECURITY_METHOD:
+			g_value_set_enum (
+				value,
+				camel_network_service_get_security_method (
+				CAMEL_NETWORK_SERVICE (object)));
+			return;
+
+		case PROP_SERVICE_NAME:
+			g_value_set_string (
+				value,
+				camel_network_service_get_service_name (
+				CAMEL_NETWORK_SERVICE (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
 imapx_store_finalize (GObject *object)
 {
 	CamelIMAPXStore *imapx_store = CAMEL_IMAPX_STORE (object);
@@ -150,6 +214,32 @@ imapx_store_finalize (GObject *object)
 	G_OBJECT_CLASS (camel_imapx_store_parent_class)->finalize (object);
 }
 
+static void
+imapx_store_constructed (GObject *object)
+{
+	CamelURL *url;
+	const gchar *use_ssl;
+
+	/* Chain up to parent's constructed() method. */
+	G_OBJECT_CLASS (camel_imapx_store_parent_class)->constructed (object);
+
+	url = camel_service_get_camel_url (CAMEL_SERVICE (object));
+	use_ssl = camel_url_get_param (url, "use_ssl");
+
+	if (g_strcmp0 (use_ssl, "never") == 0)
+		camel_network_service_set_security_method (
+			CAMEL_NETWORK_SERVICE (object),
+			CAMEL_NETWORK_SECURITY_METHOD_NONE);
+	else if (g_strcmp0 (use_ssl, "always") == 0)
+		camel_network_service_set_security_method (
+			CAMEL_NETWORK_SERVICE (object),
+			CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT);
+	else if (g_strcmp0 (use_ssl, "when-possible") == 0)
+		camel_network_service_set_security_method (
+			CAMEL_NETWORK_SERVICE (object),
+			CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT);
+}
+
 static gchar *
 imapx_get_name (CamelService *service, gboolean brief)
 {
@@ -1533,6 +1623,48 @@ imapx_store_initable_init (GInitable *initable,
 	return TRUE;
 }
 
+static const gchar *
+imapx_store_get_service_name (CamelNetworkService *service)
+{
+	CamelNetworkSecurityMethod method;
+	const gchar *service_name;
+
+	method = camel_network_service_get_security_method (service);
+
+	switch (method) {
+		case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
+			service_name = "imaps";
+			break;
+
+		default:
+			service_name = "imap";
+			break;
+	}
+
+	return service_name;
+}
+
+static guint16
+imapx_store_get_default_port (CamelNetworkService *service)
+{
+	CamelNetworkSecurityMethod method;
+	guint16 default_port;
+
+	method = camel_network_service_get_security_method (service);
+
+	switch (method) {
+		case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
+			default_port = IMAPS_PORT;
+			break;
+
+		default:
+			default_port = IMAP_PORT;
+			break;
+	}
+
+	return default_port;
+}
+
 static void
 camel_imapx_store_class_init (CamelIMAPXStoreClass *class)
 {
@@ -1541,7 +1673,10 @@ camel_imapx_store_class_init (CamelIMAPXStoreClass *class)
 	CamelStoreClass *store_class;
 
 	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = imapx_store_set_property;
+	object_class->get_property = imapx_store_get_property;
 	object_class->finalize = imapx_store_finalize;
+	object_class->constructed = imapx_store_constructed;
 
 	service_class = CAMEL_SERVICE_CLASS (class);
 	service_class->get_name = imapx_get_name;
@@ -1565,6 +1700,24 @@ camel_imapx_store_class_init (CamelIMAPXStoreClass *class)
 	store_class->subscribe_folder_sync = imapx_store_subscribe_folder_sync;
 	store_class->unsubscribe_folder_sync = imapx_store_unsubscribe_folder_sync;
 	store_class->noop_sync = imapx_store_noop_sync;
+
+	/* Inherited from CamelNetworkService. */
+	g_object_class_override_property (
+		object_class,
+		PROP_DEFAULT_PORT,
+		"default-port");
+
+	/* Inherited from CamelNetworkService. */
+	g_object_class_override_property (
+		object_class,
+		PROP_SECURITY_METHOD,
+		"security-method");
+
+	/* Inherited from CamelNetworkService. */
+	g_object_class_override_property (
+		object_class,
+		PROP_SERVICE_NAME,
+		"service-name");
 }
 
 static void
@@ -1576,6 +1729,13 @@ camel_imapx_store_initable_init (GInitableIface *interface)
 }
 
 static void
+camel_network_service_init (CamelNetworkServiceInterface *interface)
+{
+	interface->get_service_name = imapx_store_get_service_name;
+	interface->get_default_port = imapx_store_get_default_port;
+}
+
+static void
 camel_imapx_store_init (CamelIMAPXStore *istore)
 {
 	CamelStore *store = CAMEL_STORE (istore);
diff --git a/camel/providers/local/camel-spool-store.c b/camel/providers/local/camel-spool-store.c
index 16afb5c..5d89392 100644
--- a/camel/providers/local/camel-spool-store.c
+++ b/camel/providers/local/camel-spool-store.c
@@ -59,9 +59,12 @@ static GInitableIface *parent_initable_interface;
 static void camel_spool_store_initable_init (GInitableIface *interface);
 
 G_DEFINE_TYPE_WITH_CODE (
-	CamelSpoolStore, camel_spool_store, CAMEL_TYPE_MBOX_STORE,
+	CamelSpoolStore,
+	camel_spool_store,
+	CAMEL_TYPE_MBOX_STORE,
 	G_IMPLEMENT_INTERFACE (
-		G_TYPE_INITABLE, camel_spool_store_initable_init))
+		G_TYPE_INITABLE,
+		camel_spool_store_initable_init))
 
 /* partially copied from mbox */
 static void
diff --git a/camel/providers/nntp/camel-nntp-store.c b/camel/providers/nntp/camel-nntp-store.c
index 1d5e37a..e31955f 100644
--- a/camel/providers/nntp/camel-nntp-store.c
+++ b/camel/providers/nntp/camel-nntp-store.c
@@ -61,15 +61,29 @@ struct _CamelNNTPStorePrivate {
 	gint placeholder;
 };
 
+enum {
+	PROP_0,
+	PROP_DEFAULT_PORT,
+	PROP_SECURITY_METHOD,
+	PROP_SERVICE_NAME
+};
+
 static GInitableIface *parent_initable_interface;
 
 /* Forward Declarations */
 static void camel_nntp_store_initable_init (GInitableIface *interface);
+static void camel_network_service_init (CamelNetworkServiceInterface *interface);
 
 G_DEFINE_TYPE_WITH_CODE (
-	CamelNNTPStore, camel_nntp_store, CAMEL_TYPE_DISCO_STORE,
+	CamelNNTPStore,
+	camel_nntp_store,
+	CAMEL_TYPE_DISCO_STORE,
 	G_IMPLEMENT_INTERFACE (
-		G_TYPE_INITABLE, camel_nntp_store_initable_init))
+		G_TYPE_INITABLE,
+		camel_nntp_store_initable_init)
+	G_IMPLEMENT_INTERFACE (
+		CAMEL_TYPE_NETWORK_SERVICE,
+		camel_network_service_init))
 
 static gint
 camel_nntp_try_authenticate (CamelNNTPStore *store,
@@ -153,6 +167,55 @@ camel_nntp_try_authenticate (CamelNNTPStore *store,
 }
 
 static void
+nntp_store_set_property (GObject *object,
+                         guint property_id,
+                         const GValue *value,
+                         GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_SECURITY_METHOD:
+			camel_network_service_set_security_method (
+				CAMEL_NETWORK_SERVICE (object),
+				g_value_get_enum (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+nntp_store_get_property (GObject *object,
+                         guint property_id,
+                         GValue *value,
+                         GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_DEFAULT_PORT:
+			g_value_set_uint (
+				value,
+				camel_network_service_get_default_port (
+				CAMEL_NETWORK_SERVICE (object)));
+			return;
+
+		case PROP_SECURITY_METHOD:
+			g_value_set_enum (
+				value,
+				camel_network_service_get_security_method (
+				CAMEL_NETWORK_SERVICE (object)));
+			return;
+
+		case PROP_SERVICE_NAME:
+			g_value_set_string (
+				value,
+				camel_network_service_get_service_name (
+				CAMEL_NETWORK_SERVICE (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
 nntp_store_dispose (GObject *object)
 {
 	CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE (object);
@@ -213,6 +276,32 @@ nntp_store_finalize (GObject *object)
 	G_OBJECT_CLASS (camel_nntp_store_parent_class)->finalize (object);
 }
 
+static void
+nntp_store_constructed (GObject *object)
+{
+	CamelURL *url;
+	const gchar *use_ssl;
+
+	/* Chain up to parent's constructed() method. */
+	G_OBJECT_CLASS (camel_nntp_store_parent_class)->constructed (object);
+
+	url = camel_service_get_camel_url (CAMEL_SERVICE (object));
+	use_ssl = camel_url_get_param (url, "use_ssl");
+
+	if (g_strcmp0 (use_ssl, "never") == 0)
+		camel_network_service_set_security_method (
+			CAMEL_NETWORK_SERVICE (object),
+			CAMEL_NETWORK_SECURITY_METHOD_NONE);
+	else if (g_strcmp0 (use_ssl, "always") == 0)
+		camel_network_service_set_security_method (
+			CAMEL_NETWORK_SERVICE (object),
+			CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT);
+	else if (g_strcmp0 (use_ssl, "when-possible") == 0)
+		camel_network_service_set_security_method (
+			CAMEL_NETWORK_SERVICE (object),
+			CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT);
+}
+
 static gboolean
 nntp_can_work_offline (CamelDiscoStore *store)
 {
@@ -318,32 +407,14 @@ xover_setup (CamelNNTPStore *store,
 	return ret;
 }
 
-enum {
-	MODE_CLEAR,
-	MODE_SSL,
-	MODE_TLS
-};
-
-#ifdef CAMEL_HAVE_SSL
-#define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3)
-#define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS)
-#endif
-
 static gboolean
 connect_to_server (CamelService *service,
-                   const gchar *host,
-                   const gchar *serv,
-                   gint fallback_port,
-                   gint ssl_mode,
                    GCancellable *cancellable,
                    GError **error)
 {
 	CamelNNTPStore *store = (CamelNNTPStore *) service;
 	CamelDiscoStore *disco_store = (CamelDiscoStore*) service;
-	CamelSession *session;
 	CamelURL *url;
-	gchar *socks_host;
-	gint socks_port;
 	CamelStream *tcp_stream;
 	const gchar *user_data_dir;
 	gboolean retval = FALSE;
@@ -352,47 +423,15 @@ connect_to_server (CamelService *service,
 	gchar *path;
 
 	url = camel_service_get_camel_url (service);
-	session = camel_service_get_session (service);
 	user_data_dir = camel_service_get_user_data_dir (service);
 
 	camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
 
-	if (ssl_mode != MODE_CLEAR) {
-#ifdef CAMEL_HAVE_SSL
-		if (ssl_mode == MODE_TLS) {
-			tcp_stream = camel_tcp_stream_ssl_new_raw (session, url->host, STARTTLS_FLAGS);
-		} else {
-			tcp_stream = camel_tcp_stream_ssl_new (session, url->host, SSL_PORT_FLAGS);
-		}
-#else
-		g_set_error (
-			error, CAMEL_SERVICE_ERROR,
-			CAMEL_SERVICE_ERROR_UNAVAILABLE,
-			_("Could not connect to %s: %s"),
-			url->host, _("SSL unavailable"));
-		goto fail;
-#endif /* CAMEL_HAVE_SSL */
-	} else {
-		tcp_stream = camel_tcp_stream_raw_new ();
-	}
-
-	camel_session_get_socks_proxy (session, &socks_host, &socks_port);
-
-	if (socks_host) {
-		camel_tcp_stream_set_socks_proxy ((CamelTcpStream *) tcp_stream, socks_host, socks_port);
-		g_free (socks_host);
-	}
-
-	if (camel_tcp_stream_connect (
-		CAMEL_TCP_STREAM (tcp_stream), host, serv,
-		fallback_port, cancellable, error) == -1) {
-		g_prefix_error (
-			error, _("Could not connect to %s: "),
-			url->host);
-		g_object_unref (tcp_stream);
+	tcp_stream = camel_network_service_connect_sync (
+		CAMEL_NETWORK_SERVICE (service), cancellable, error);
 
+	if (tcp_stream == NULL)
 		goto fail;
-	}
 
 	store->stream = (CamelNNTPStream *) camel_nntp_stream_new (tcp_stream);
 	g_object_unref (tcp_stream);
@@ -451,56 +490,15 @@ connect_to_server (CamelService *service,
 	return retval;
 }
 
-static struct {
-	const gchar *value;
-	const gchar *serv;
-	gint fallback_port;
-	gint mode;
-} ssl_options[] = {
-	{ "",              "nntps", NNTPS_PORT, MODE_SSL   },  /* really old (1.x) */
-	{ "always",        "nntps", NNTPS_PORT, MODE_SSL   },
-	{ "when-possible", "nntp",  NNTP_PORT, MODE_TLS   },
-	{ "never",         "nntp",  NNTP_PORT, MODE_CLEAR },
-	{ NULL,            "nntp",  NNTP_PORT, MODE_CLEAR },
-};
-
 static gboolean
 nntp_connect_online (CamelService *service,
                      GCancellable *cancellable,
                      GError **error)
 {
 	CamelNNTPStore *store = CAMEL_NNTP_STORE (service);
-	CamelURL *url;
-	const gchar *ssl_mode;
-	gint mode, i;
-	gchar *serv;
-	gint fallback_port;
 	GError *local_error = NULL;
 
-	url = camel_service_get_camel_url (service);
-
-	if ((ssl_mode = camel_url_get_param (url, "use_ssl"))) {
-		for (i = 0; ssl_options[i].value; i++)
-			if (!strcmp (ssl_options[i].value, ssl_mode))
-				break;
-		mode = ssl_options[i].mode;
-		serv = (gchar *) ssl_options[i].serv;
-		fallback_port = ssl_options[i].fallback_port;
-	} else {
-		mode = MODE_CLEAR;
-		serv = (gchar *) "nntp";
-		fallback_port = NNTP_PORT;
-	}
-
-	if (url->port) {
-		serv = g_alloca (16);
-		sprintf (serv, "%d", url->port);
-		fallback_port = 0;
-	}
-
-	if (!connect_to_server (
-		service, url->host, serv,
-		fallback_port, mode, cancellable, error))
+	if (!connect_to_server (service, cancellable, error))
 		return FALSE;
 
 	if (check_capabilities (store, cancellable, &local_error) != -1)
@@ -522,9 +520,7 @@ nntp_connect_online (CamelService *service,
 
 	camel_service_unlock (CAMEL_SERVICE (store), CAMEL_SERVICE_REC_CONNECT_LOCK);
 
-	return connect_to_server (
-		service, url->host, serv,
-		fallback_port, mode, cancellable, error);
+	return connect_to_server (service, cancellable, error);
 }
 
 static gboolean
@@ -1415,6 +1411,48 @@ nntp_store_initable_init (GInitable *initable,
 	return TRUE;
 }
 
+static const gchar *
+nntp_store_get_service_name (CamelNetworkService *service)
+{
+	CamelNetworkSecurityMethod method;
+	const gchar *service_name;
+
+	method = camel_network_service_get_security_method (service);
+
+	switch (method) {
+		case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
+			service_name = "nntps";
+			break;
+
+		default:
+			service_name = "nntp";
+			break;
+	}
+
+	return service_name;
+}
+
+static guint16
+nntp_store_get_default_port (CamelNetworkService *service)
+{
+	CamelNetworkSecurityMethod method;
+	guint16 default_port;
+
+	method = camel_network_service_get_security_method (service);
+
+	switch (method) {
+		case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
+			default_port = NNTPS_PORT;
+			break;
+
+		default:
+			default_port = NNTP_PORT;
+			break;
+	}
+
+	return default_port;
+}
+
 static void
 camel_nntp_store_class_init (CamelNNTPStoreClass *class)
 {
@@ -1426,8 +1464,11 @@ camel_nntp_store_class_init (CamelNNTPStoreClass *class)
 	g_type_class_add_private (class, sizeof (CamelNNTPStorePrivate));
 
 	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = nntp_store_set_property;
+	object_class->get_property = nntp_store_get_property;
 	object_class->dispose = nntp_store_dispose;
 	object_class->finalize = nntp_store_finalize;
+	object_class->constructed = nntp_store_constructed;
 
 	service_class = CAMEL_SERVICE_CLASS (class);
 	service_class->get_name = nntp_store_get_name;
@@ -1455,6 +1496,24 @@ camel_nntp_store_class_init (CamelNNTPStoreClass *class)
 	disco_store_class->get_folder_info_online = nntp_get_folder_info_online;
 	disco_store_class->get_folder_info_resyncing = nntp_get_folder_info_online;
 	disco_store_class->get_folder_info_offline = nntp_get_folder_info_offline;
+
+	/* Inherited from CamelNetworkService. */
+	g_object_class_override_property (
+		object_class,
+		PROP_DEFAULT_PORT,
+		"default-port");
+
+	/* Inherited from CamelNetworkService. */
+	g_object_class_override_property (
+		object_class,
+		PROP_SECURITY_METHOD,
+		"security-method");
+
+	/* Inherited from CamelNetworkService. */
+	g_object_class_override_property (
+		object_class,
+		PROP_SERVICE_NAME,
+		"service-name");
 }
 
 static void
@@ -1466,6 +1525,13 @@ camel_nntp_store_initable_init (GInitableIface *interface)
 }
 
 static void
+camel_network_service_init (CamelNetworkServiceInterface *interface)
+{
+	interface->get_service_name = nntp_store_get_service_name;
+	interface->get_default_port = nntp_store_get_default_port;
+}
+
+static void
 camel_nntp_store_init (CamelNNTPStore *nntp_store)
 {
 	CamelStore *store = CAMEL_STORE (nntp_store);
diff --git a/camel/providers/pop3/camel-pop3-store.c b/camel/providers/pop3/camel-pop3-store.c
index 6298bb6..a2a0ca8 100644
--- a/camel/providers/pop3/camel-pop3-store.c
+++ b/camel/providers/pop3/camel-pop3-store.c
@@ -52,33 +52,25 @@
 #define POP3_ERROR_SIZE_LIMIT 60
 
 enum {
-	MODE_CLEAR,
-	MODE_SSL,
-	MODE_TLS
-};
-
-#ifdef CAMEL_HAVE_SSL
-#define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3)
-#define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS)
-#endif
-
-static struct {
-	const gchar *value;
-	const gchar *serv;
-	gint fallback_port;
-	gint mode;
-} ssl_options[] = {
-	{ "",              "pop3s", POP3S_PORT, MODE_SSL   },  /* really old (1.x) */
-	{ "always",        "pop3s", POP3S_PORT, MODE_SSL   },
-	{ "when-possible", "pop3",  POP3_PORT,  MODE_TLS   },
-	{ "never",         "pop3",  POP3_PORT,  MODE_CLEAR },
-	{ NULL,            "pop3",  POP3_PORT,  MODE_CLEAR },
+	PROP_0,
+	PROP_DEFAULT_PORT,
+	PROP_SECURITY_METHOD,
+	PROP_SERVICE_NAME
 };
 
 extern CamelServiceAuthType camel_pop3_password_authtype;
 extern CamelServiceAuthType camel_pop3_apop_authtype;
 
-G_DEFINE_TYPE (CamelPOP3Store, camel_pop3_store, CAMEL_TYPE_STORE)
+/* Forward Declarations */
+static void camel_network_service_init (CamelNetworkServiceInterface *interface);
+
+G_DEFINE_TYPE_WITH_CODE (
+	CamelPOP3Store,
+	camel_pop3_store,
+	CAMEL_TYPE_STORE,
+	G_IMPLEMENT_INTERFACE (
+		CAMEL_TYPE_NETWORK_SERVICE,
+		camel_network_service_init))
 
 /* returns error message with ': ' as prefix */
 static gchar *
@@ -102,18 +94,13 @@ get_valid_utf8_error (const gchar *text)
 
 static gboolean
 connect_to_server (CamelService *service,
-                   const gchar *host,
-                   const gchar *serv,
-                   gint fallback_port,
-                   gint ssl_mode,
                    GCancellable *cancellable,
                    GError **error)
 {
 	CamelPOP3Store *store = CAMEL_POP3_STORE (service);
-	CamelSession *session;
+	CamelNetworkService *network_service;
+	CamelNetworkSecurityMethod method;
 	CamelURL *url;
-	gchar *socks_host;
-	gint socks_port;
 	CamelStream *tcp_stream;
 	CamelPOP3Command *pc;
 	guint32 flags = 0;
@@ -122,42 +109,15 @@ connect_to_server (CamelService *service,
 	const gchar *param;
 
 	url = camel_service_get_camel_url (service);
-	session = camel_service_get_session (service);
 
-	if (ssl_mode != MODE_CLEAR) {
-#ifdef CAMEL_HAVE_SSL
-		if (ssl_mode == MODE_TLS) {
-			tcp_stream = camel_tcp_stream_ssl_new_raw (session, url->host, STARTTLS_FLAGS);
-		} else {
-			tcp_stream = camel_tcp_stream_ssl_new (session, url->host, SSL_PORT_FLAGS);
-		}
-#else
-		g_set_error (
-			error, CAMEL_SERVICE_ERROR,
-			CAMEL_SERVICE_ERROR_UNAVAILABLE,
-			_("Could not connect to %s: %s"),
-			url->host, _("SSL unavailable"));
+	tcp_stream = camel_network_service_connect_sync (
+		CAMEL_NETWORK_SERVICE (service), cancellable, error);
 
+	if (tcp_stream == NULL)
 		return FALSE;
-#endif /* CAMEL_HAVE_SSL */
-	} else
-		tcp_stream = camel_tcp_stream_raw_new ();
 
-	camel_session_get_socks_proxy (session, &socks_host, &socks_port);
-
-	if (socks_host) {
-		camel_tcp_stream_set_socks_proxy (
-			CAMEL_TCP_STREAM (tcp_stream),
-			socks_host, socks_port);
-		g_free (socks_host);
-	}
-
-	if (camel_tcp_stream_connect (
-		CAMEL_TCP_STREAM (tcp_stream), host, serv,
-		fallback_port, cancellable, error) == -1) {
-		g_object_unref (tcp_stream);
-		return FALSE;
-	}
+	network_service = CAMEL_NETWORK_SERVICE (service);
+	method = camel_network_service_get_security_method (network_service);
 
 	/* parent class connect initialization */
 	if (CAMEL_SERVICE_CLASS (camel_pop3_store_parent_class)->
@@ -186,7 +146,7 @@ connect_to_server (CamelService *service,
 		return FALSE;
 	}
 
-	if (ssl_mode != MODE_TLS) {
+	if (method != CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT) {
 		g_object_unref (tcp_stream);
 		return TRUE;
 	}
@@ -266,43 +226,6 @@ connect_to_server (CamelService *service,
 	return FALSE;
 }
 
-static gboolean
-connect_to_server_wrapper (CamelService *service,
-                           GCancellable *cancellable,
-                           GError **error)
-{
-	CamelURL *url;
-	const gchar *ssl_mode;
-	gint mode, i;
-	gchar *serv;
-	gint fallback_port;
-
-	url = camel_service_get_camel_url (service);
-
-	if ((ssl_mode = camel_url_get_param (url, "use_ssl"))) {
-		for (i = 0; ssl_options[i].value; i++)
-			if (!strcmp (ssl_options[i].value, ssl_mode))
-				break;
-		mode = ssl_options[i].mode;
-		serv = (gchar *) ssl_options[i].serv;
-		fallback_port = ssl_options[i].fallback_port;
-	} else {
-		mode = MODE_CLEAR;
-		serv = (gchar *) "pop3";
-		fallback_port = POP3S_PORT;
-	}
-
-	if (url->port) {
-		serv = g_alloca (16);
-		sprintf (serv, "%d", url->port);
-		fallback_port = 0;
-	}
-
-	return connect_to_server (
-		service, url->host, serv,
-		fallback_port, mode, cancellable, error);
-}
-
 static gint
 try_sasl (CamelPOP3Store *store,
           const gchar *mech,
@@ -549,6 +472,55 @@ pop3_try_authenticate (CamelService *service,
 }
 
 static void
+pop3_store_set_property (GObject *object,
+                         guint property_id,
+                         const GValue *value,
+                         GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_SECURITY_METHOD:
+			camel_network_service_set_security_method (
+				CAMEL_NETWORK_SERVICE (object),
+				g_value_get_enum (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+pop3_store_get_property (GObject *object,
+                         guint property_id,
+                         GValue *value,
+                         GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_DEFAULT_PORT:
+			g_value_set_uint (
+				value,
+				camel_network_service_get_default_port (
+				CAMEL_NETWORK_SERVICE (object)));
+			return;
+
+		case PROP_SECURITY_METHOD:
+			g_value_set_enum (
+				value,
+				camel_network_service_get_security_method (
+				CAMEL_NETWORK_SERVICE (object)));
+			return;
+
+		case PROP_SERVICE_NAME:
+			g_value_set_string (
+				value,
+				camel_network_service_get_service_name (
+				CAMEL_NETWORK_SERVICE (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
 pop3_store_finalize (GObject *object)
 {
 	CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (object);
@@ -567,6 +539,32 @@ pop3_store_finalize (GObject *object)
 	G_OBJECT_CLASS (camel_pop3_store_parent_class)->finalize (object);
 }
 
+static void
+pop3_store_constructed (GObject *object)
+{
+	CamelURL *url;
+	const gchar *use_ssl;
+
+	/* Chain up to parent's constructed() method. */
+	G_OBJECT_CLASS (camel_pop3_store_parent_class)->constructed (object);
+
+	url = camel_service_get_camel_url (CAMEL_SERVICE (object));
+	use_ssl = camel_url_get_param (url, "use_ssl");
+
+	if (g_strcmp0 (use_ssl, "never") == 0)
+		camel_network_service_set_security_method (
+			CAMEL_NETWORK_SERVICE (object),
+			CAMEL_NETWORK_SECURITY_METHOD_NONE);
+	else if (g_strcmp0 (use_ssl, "always") == 0)
+		camel_network_service_set_security_method (
+			CAMEL_NETWORK_SERVICE (object),
+			CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT);
+	else if (g_strcmp0 (use_ssl, "when-possible") == 0)
+		camel_network_service_set_security_method (
+			CAMEL_NETWORK_SERVICE (object),
+			CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT);
+}
+
 static gchar *
 pop3_store_get_name (CamelService *service,
                      gboolean brief)
@@ -609,7 +607,7 @@ pop3_store_connect_sync (CamelService *service,
 		}
 	}
 
-	if (!connect_to_server_wrapper (service, cancellable, error))
+	if (!connect_to_server (service, cancellable, error))
 		return FALSE;
 
 	while (1) {
@@ -704,7 +702,7 @@ pop3_store_query_auth_types_sync (CamelService *service,
 
 	url = camel_service_get_camel_url (service);
 
-	if (connect_to_server_wrapper (service, cancellable, NULL)) {
+	if (connect_to_server (service, cancellable, NULL)) {
 		types = g_list_concat (types, g_list_copy (store->engine->auth));
 		pop3_store_disconnect_sync (service, TRUE, cancellable, NULL);
 	} else {
@@ -769,6 +767,48 @@ pop3_store_get_trash_folder_sync (CamelStore *store,
 	return NULL;
 }
 
+static const gchar *
+pop3_store_get_service_name (CamelNetworkService *service)
+{
+	CamelNetworkSecurityMethod method;
+	const gchar *service_name;
+
+	method = camel_network_service_get_security_method (service);
+
+	switch (method) {
+		case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
+			service_name = "pop3s";
+			break;
+
+		default:
+			service_name = "pop3";
+			break;
+	}
+
+	return service_name;
+}
+
+static guint16
+pop3_store_get_default_port (CamelNetworkService *service)
+{
+	CamelNetworkSecurityMethod method;
+	guint16 default_port;
+
+	method = camel_network_service_get_security_method (service);
+
+	switch (method) {
+		case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
+			default_port = POP3S_PORT;
+			break;
+
+		default:
+			default_port = POP3_PORT;
+			break;
+	}
+
+	return default_port;
+}
+
 static void
 camel_pop3_store_class_init (CamelPOP3StoreClass *class)
 {
@@ -777,7 +817,10 @@ camel_pop3_store_class_init (CamelPOP3StoreClass *class)
 	CamelStoreClass *store_class;
 
 	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = pop3_store_set_property;
+	object_class->get_property = pop3_store_get_property;
 	object_class->finalize = pop3_store_finalize;
+	object_class->constructed = pop3_store_constructed;
 
 	service_class = CAMEL_SERVICE_CLASS (class);
 	service_class->get_name = pop3_store_get_name;
@@ -790,6 +833,31 @@ camel_pop3_store_class_init (CamelPOP3StoreClass *class)
 	store_class->get_folder_sync = pop3_store_get_folder_sync;
 	store_class->get_folder_info_sync = pop3_store_get_folder_info_sync;
 	store_class->get_trash_folder_sync = pop3_store_get_trash_folder_sync;
+
+	/* Inherited from CamelNetworkService. */
+	g_object_class_override_property (
+		object_class,
+		PROP_DEFAULT_PORT,
+		"default-port");
+
+	/* Inherited from CamelNetworkService. */
+	g_object_class_override_property (
+		object_class,
+		PROP_SECURITY_METHOD,
+		"security-method");
+
+	/* Inherited from CamelNetworkService. */
+	g_object_class_override_property (
+		object_class,
+		PROP_SERVICE_NAME,
+		"service-name");
+}
+
+static void
+camel_network_service_init (CamelNetworkServiceInterface *interface)
+{
+	interface->get_service_name = pop3_store_get_service_name;
+	interface->get_default_port = pop3_store_get_default_port;
 }
 
 static void
diff --git a/camel/providers/smtp/camel-smtp-transport.c b/camel/providers/smtp/camel-smtp-transport.c
index 0da8e8d..44bffc5 100644
--- a/camel/providers/smtp/camel-smtp-transport.c
+++ b/camel/providers/smtp/camel-smtp-transport.c
@@ -88,45 +88,32 @@ static void		smtp_set_error		(CamelSmtpTransport *transport,
 						 GError **error);
 
 enum {
-	MODE_CLEAR,
-	MODE_SSL,
-	MODE_TLS
+	PROP_0,
+	PROP_DEFAULT_PORT,
+	PROP_SECURITY_METHOD,
+	PROP_SERVICE_NAME
 };
 
-#ifdef CAMEL_HAVE_SSL
-#define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3)
-#define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS)
-#endif
+/* Forward Declarations */
+static void camel_network_service_init (CamelNetworkServiceInterface *interface);
 
-static struct {
-	const gchar *value;
-	const gchar *serv;
-	gint fallback_port;
-	gint mode;
-} ssl_options[] = {
-	{ "",              "smtps", SMTPS_PORT, MODE_SSL  },  /* really old (1.x) */
-	{ "always",        "smtps", SMTPS_PORT, MODE_SSL  },
-	{ "when-possible", "smtp",  SMTP_PORT, MODE_TLS   },
-	{ "never",         "smtp",  SMTP_PORT, MODE_CLEAR },
-	{ NULL,            "smtp",  SMTP_PORT, MODE_CLEAR }
-};
-
-G_DEFINE_TYPE (CamelSmtpTransport, camel_smtp_transport, CAMEL_TYPE_TRANSPORT)
+G_DEFINE_TYPE_WITH_CODE (
+	CamelSmtpTransport,
+	camel_smtp_transport,
+	CAMEL_TYPE_TRANSPORT,
+	G_IMPLEMENT_INTERFACE (
+		CAMEL_TYPE_NETWORK_SERVICE,
+		camel_network_service_init))
 
 static gboolean
 connect_to_server (CamelService *service,
-                   const gchar *host,
-                   const gchar *serv,
-                   gint fallback_port,
-                   gint ssl_mode,
                    GCancellable *cancellable,
                    GError **error)
 {
 	CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
-	CamelSession *session;
+	CamelNetworkService *network_service;
+	CamelNetworkSecurityMethod method;
 	CamelURL *url;
-	gchar *socks_host;
-	gint socks_port;
 	CamelStream *tcp_stream;
 	gchar *respbuf = NULL;
 
@@ -139,43 +126,15 @@ connect_to_server (CamelService *service,
 	transport->authtypes = NULL;
 
 	url = camel_service_get_camel_url (service);
-	session = camel_service_get_session (service);
-
-	if (ssl_mode != MODE_CLEAR) {
-#ifdef CAMEL_HAVE_SSL
-		if (ssl_mode == MODE_TLS) {
-			tcp_stream = camel_tcp_stream_ssl_new_raw (session, url->host, STARTTLS_FLAGS);
-		} else {
-			tcp_stream = camel_tcp_stream_ssl_new (session, url->host, SSL_PORT_FLAGS);
-		}
-#else
-		g_set_error (
-			error, CAMEL_SERVICE_ERROR,
-			CAMEL_SERVICE_ERROR_UNAVAILABLE,
-			_("Could not connect to %s: %s"),
-			url->host, _("SSL unavailable"));
 
-		return FALSE;
-#endif /* CAMEL_HAVE_SSL */
-	} else {
-		tcp_stream = camel_tcp_stream_raw_new ();
-	}
-
-	camel_session_get_socks_proxy (session, &socks_host, &socks_port);
+	network_service = CAMEL_NETWORK_SERVICE (service);
+	method = camel_network_service_get_security_method (network_service);
 
-	if (socks_host) {
-		camel_tcp_stream_set_socks_proxy (
-			CAMEL_TCP_STREAM (tcp_stream),
-			socks_host, socks_port);
-		g_free (socks_host);
-	}
+	tcp_stream = camel_network_service_connect_sync (
+		CAMEL_NETWORK_SERVICE (service), cancellable, error);
 
-	if (camel_tcp_stream_connect (
-		CAMEL_TCP_STREAM (tcp_stream), host, serv,
-		fallback_port, cancellable, error) == -1) {
-		g_object_unref (tcp_stream);
+	if (tcp_stream == NULL)
 		return FALSE;
-	}
 
 	transport->connected = TRUE;
 
@@ -228,10 +187,8 @@ connect_to_server (CamelService *service,
 	/* clear any EHLO/HELO exception and assume that any SMTP errors encountered were non-fatal */
 	g_clear_error (error);
 
-	if (ssl_mode != MODE_TLS) {
-		/* we're done */
-		return TRUE;
-	}
+	if (method != CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT)
+		return TRUE;  /* we're done */
 
 #ifdef CAMEL_HAVE_SSL
 	if (!(transport->flags & CAMEL_SMTP_TRANSPORT_STARTTLS)) {
@@ -311,51 +268,89 @@ connect_to_server (CamelService *service,
 	return FALSE;
 }
 
-static gboolean
-connect_to_server_wrapper (CamelService *service,
-                           GCancellable *cancellable,
-                           GError **error)
+static void
+authtypes_free (gpointer key, gpointer value, gpointer data)
 {
-	CamelURL *url;
-	const gchar *ssl_mode;
-	gint mode, i;
-	gchar *serv;
-	gint fallback_port;
-
-	url = camel_service_get_camel_url (service);
+	g_free (value);
+}
 
-	if ((ssl_mode = camel_url_get_param (url, "use_ssl"))) {
-		for (i = 0; ssl_options[i].value; i++)
-			if (!strcmp (ssl_options[i].value, ssl_mode))
-				break;
-		mode = ssl_options[i].mode;
-		serv = (gchar *) ssl_options[i].serv;
-		fallback_port = ssl_options[i].fallback_port;
-	} else {
-		mode = MODE_CLEAR;
-		serv = (gchar *) "smtp";
-		fallback_port = SMTP_PORT;
+static void
+smtp_transport_set_property (GObject *object,
+                             guint property_id,
+                             const GValue *value,
+                             GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_SECURITY_METHOD:
+			camel_network_service_set_security_method (
+				CAMEL_NETWORK_SERVICE (object),
+				g_value_get_enum (value));
+			return;
 	}
 
-	if (url->port) {
-		serv = g_alloca (16);
-		sprintf (serv, "%d", url->port);
-		fallback_port = 0;
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+smtp_transport_get_property (GObject *object,
+                             guint property_id,
+                             GValue *value,
+                             GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_DEFAULT_PORT:
+			g_value_set_uint (
+				value,
+				camel_network_service_get_default_port (
+				CAMEL_NETWORK_SERVICE (object)));
+			return;
+
+		case PROP_SECURITY_METHOD:
+			g_value_set_enum (
+				value,
+				camel_network_service_get_security_method (
+				CAMEL_NETWORK_SERVICE (object)));
+			return;
+
+		case PROP_SERVICE_NAME:
+			g_value_set_string (
+				value,
+				camel_network_service_get_service_name (
+				CAMEL_NETWORK_SERVICE (object)));
+			return;
 	}
 
-	return connect_to_server (
-		service, url->host, serv,
-		fallback_port, mode, cancellable, error);
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 }
 
 static void
-authtypes_free (gpointer key, gpointer value, gpointer data)
+smtp_transport_constructed (GObject *object)
 {
-	g_free (value);
+	CamelURL *url;
+	const gchar *use_ssl;
+
+	/* Chain up to parent's constructed() method. */
+	G_OBJECT_CLASS (camel_smtp_transport_parent_class)->constructed (object);
+
+	url = camel_service_get_camel_url (CAMEL_SERVICE (object));
+	use_ssl = camel_url_get_param (url, "use_ssl");
+
+	if (g_strcmp0 (use_ssl, "never") == 0)
+		camel_network_service_set_security_method (
+			CAMEL_NETWORK_SERVICE (object),
+			CAMEL_NETWORK_SECURITY_METHOD_NONE);
+	else if (g_strcmp0 (use_ssl, "always") == 0)
+		camel_network_service_set_security_method (
+			CAMEL_NETWORK_SERVICE (object),
+			CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT);
+	else if (g_strcmp0 (use_ssl, "when-possible") == 0)
+		camel_network_service_set_security_method (
+			CAMEL_NETWORK_SERVICE (object),
+			CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT);
 }
 
 static gchar *
-smtp_get_name (CamelService *service, gboolean brief)
+smtp_transport_get_name (CamelService *service, gboolean brief)
 {
 	CamelURL *url;
 
@@ -372,9 +367,9 @@ smtp_get_name (CamelService *service, gboolean brief)
 }
 
 static gboolean
-smtp_connect_sync (CamelService *service,
-                   GCancellable *cancellable,
-                   GError **error)
+smtp_transport_connect_sync (CamelService *service,
+                             GCancellable *cancellable,
+                             GError **error)
 {
 	CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
 	CamelSasl *sasl = NULL;
@@ -399,10 +394,10 @@ smtp_connect_sync (CamelService *service,
 		if (!truth)
 			return FALSE;
 
-		return connect_to_server_wrapper (service, cancellable, error);
+		return connect_to_server (service, cancellable, error);
 	}
 
-	if (!connect_to_server_wrapper (service, cancellable, error))
+	if (!connect_to_server (service, cancellable, error))
 		return FALSE;
 
 	/* check to see if AUTH is required, if so...then AUTH ourselves */
@@ -536,10 +531,10 @@ smtp_connect_sync (CamelService *service,
 }
 
 static gboolean
-smtp_disconnect_sync (CamelService *service,
-                      gboolean clean,
-                      GCancellable *cancellable,
-                      GError **error)
+smtp_transport_disconnect_sync (CamelService *service,
+                                gboolean clean,
+                                GCancellable *cancellable,
+                                GError **error)
 {
 	CamelServiceClass *service_class;
 	CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
@@ -583,20 +578,21 @@ smtp_disconnect_sync (CamelService *service,
 }
 
 static GList *
-smtp_query_auth_types_sync (CamelService *service,
-                            GCancellable *cancellable,
-                            GError **error)
+smtp_transport_query_auth_types_sync (CamelService *service,
+                                      GCancellable *cancellable,
+                                      GError **error)
 {
 	CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
 	CamelServiceAuthType *authtype;
 	CamelProvider *provider;
 	GList *types, *t, *next;
 
-	if (!connect_to_server_wrapper (service, cancellable, error))
+	if (!connect_to_server (service, cancellable, error))
 		return NULL;
 
 	if (!transport->authtypes) {
-		smtp_disconnect_sync (service, TRUE, cancellable, NULL);
+		smtp_transport_disconnect_sync (
+			service, TRUE, cancellable, NULL);
 		return NULL;
 	}
 
@@ -613,18 +609,18 @@ smtp_query_auth_types_sync (CamelService *service,
 		}
 	}
 
-	smtp_disconnect_sync (service, TRUE, cancellable, NULL);
+	smtp_transport_disconnect_sync (service, TRUE, cancellable, NULL);
 
 	return types;
 }
 
 static gboolean
-smtp_send_to_sync (CamelTransport *transport,
-                   CamelMimeMessage *message,
-                   CamelAddress *from,
-                   CamelAddress *recipients,
-                   GCancellable *cancellable,
-                   GError **error)
+smtp_transport_send_to_sync (CamelTransport *transport,
+                             CamelMimeMessage *message,
+                             CamelAddress *from,
+                             CamelAddress *recipients,
+                             GCancellable *cancellable,
+                             GError **error)
 {
 	CamelSmtpTransport *smtp_transport = CAMEL_SMTP_TRANSPORT (transport);
 	CamelInternetAddress *cia;
@@ -713,20 +709,93 @@ smtp_send_to_sync (CamelTransport *transport,
 	return TRUE;
 }
 
+static const gchar *
+smtp_transport_get_service_name (CamelNetworkService *service)
+{
+	CamelNetworkSecurityMethod method;
+	const gchar *service_name;
+
+	method = camel_network_service_get_security_method (service);
+
+	switch (method) {
+		case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
+			service_name = "smtps";
+			break;
+
+		default:
+			service_name = "smtp";
+			break;
+	}
+
+	return service_name;
+}
+
+static guint16
+smtp_transport_get_default_port (CamelNetworkService *service)
+{
+	CamelNetworkSecurityMethod method;
+	guint16 default_port;
+
+	method = camel_network_service_get_security_method (service);
+
+	switch (method) {
+		case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
+			default_port = SMTPS_PORT;
+			break;
+
+		default:
+			default_port = SMTP_PORT;
+			break;
+	}
+
+	return default_port;
+}
+
 static void
 camel_smtp_transport_class_init (CamelSmtpTransportClass *class)
 {
-	CamelTransportClass *transport_class;
+	GObjectClass *object_class;
 	CamelServiceClass *service_class;
+	CamelTransportClass *transport_class;
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = smtp_transport_set_property;
+	object_class->get_property = smtp_transport_get_property;
+	object_class->constructed = smtp_transport_constructed;
 
 	service_class = CAMEL_SERVICE_CLASS (class);
-	service_class->get_name = smtp_get_name;
-	service_class->connect_sync = smtp_connect_sync;
-	service_class->disconnect_sync = smtp_disconnect_sync;
-	service_class->query_auth_types_sync = smtp_query_auth_types_sync;
+	service_class->get_name = smtp_transport_get_name;
+	service_class->connect_sync = smtp_transport_connect_sync;
+	service_class->disconnect_sync = smtp_transport_disconnect_sync;
+	service_class->query_auth_types_sync = smtp_transport_query_auth_types_sync;
 
 	transport_class = CAMEL_TRANSPORT_CLASS (class);
-	transport_class->send_to_sync = smtp_send_to_sync;
+	transport_class->send_to_sync = smtp_transport_send_to_sync;
+
+	/* Inherited from CamelNetworkService. */
+	g_object_class_override_property (
+		object_class,
+		PROP_DEFAULT_PORT,
+		"default-port");
+
+	/* Inherited from CamelNetworkService. */
+	g_object_class_override_property (
+		object_class,
+		PROP_SECURITY_METHOD,
+		"security-method");
+
+	/* Inherited from CamelNetworkService. */
+	g_object_class_override_property (
+		object_class,
+		PROP_SERVICE_NAME,
+		"service-name");
+}
+
+static void
+camel_network_service_init (CamelNetworkServiceInterface *interface)
+{
+	interface->get_service_name = smtp_transport_get_service_name;
+	interface->get_default_port = smtp_transport_get_default_port;
 }
 
 static void
diff --git a/docs/reference/camel/camel-docs.sgml b/docs/reference/camel/camel-docs.sgml
index e42ab83..73e2397 100644
--- a/docs/reference/camel/camel-docs.sgml
+++ b/docs/reference/camel/camel-docs.sgml
@@ -90,6 +90,7 @@
       <xi:include href="xml/camel-session.xml"/>
       <xi:include href="xml/camel-provider.xml"/>
       <xi:include href="xml/camel-service.xml"/>
+      <xi:include href="xml/camel-network-service.xml"/>
       <xi:include href="xml/camel-store.xml"/>
       <xi:include href="xml/camel-store-summary.xml"/>
       <xi:include href="xml/camel-offline-store.xml"/>
diff --git a/docs/reference/camel/camel-sections.txt b/docs/reference/camel/camel-sections.txt
index 1e25685..7d4e369 100644
--- a/docs/reference/camel/camel-sections.txt
+++ b/docs/reference/camel/camel-sections.txt
@@ -1474,6 +1474,27 @@ camel_multipart_get_type
 </SECTION>
 
 <SECTION>
+<FILE>camel-network-service</FILE>
+<TITLE>CamelNetworkService</TITLE>
+CamelNetworkService
+camel_network_service_get_default_port
+camel_network_service_get_service_name
+CamelNetworkSecurityMethod
+camel_network_service_get_security_method
+camel_network_service_set_security_method
+camel_network_service_connect_sync
+<SUBSECTION Standard>
+CAMEL_NETWORK_SERVICE
+CAMEL_IS_NETWORK_SERVICE
+CAMEL_TYPE_NETWORK_SERVICE
+CAMEL_NETWORK_SERVICE_INTERFACE
+CAMEL_IS_NETWORK_SERVICE_INTERFACE
+CAMEL_NETWORK_SERVICE_GET_INTERFACE
+CamelNetworkServiceInterface
+camel_network_service_get_type
+</SECTION>
+
+<SECTION>
 <FILE>camel-nntp-address</FILE>
 <TITLE>CamelNNTPAddress</TITLE>
 CamelNNTPAddress
diff --git a/docs/reference/camel/tmpl/camel-network-service.sgml b/docs/reference/camel/tmpl/camel-network-service.sgml
new file mode 100644
index 0000000..7c2fadd
--- /dev/null
+++ b/docs/reference/camel/tmpl/camel-network-service.sgml
@@ -0,0 +1,84 @@
+<!-- ##### SECTION Title ##### -->
+CamelNetworkService
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT CamelNetworkService ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### FUNCTION camel_network_service_get_default_port ##### -->
+<para>
+
+</para>
+
+ service: 
+ Returns: 
+
+
+<!-- ##### FUNCTION camel_network_service_get_service_name ##### -->
+<para>
+
+</para>
+
+ service: 
+ Returns: 
+
+
+<!-- ##### ENUM CamelNetworkSecurityMethod ##### -->
+<para>
+
+</para>
+
+ CAMEL_NETWORK_SECURITY_METHOD_NONE: 
+ CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT: 
+ CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT: 
+
+<!-- ##### FUNCTION camel_network_service_get_security_method ##### -->
+<para>
+
+</para>
+
+ service: 
+ Returns: 
+
+
+<!-- ##### FUNCTION camel_network_service_set_security_method ##### -->
+<para>
+
+</para>
+
+ service: 
+ method: 
+
+
+<!-- ##### FUNCTION camel_network_service_connect_sync ##### -->
+<para>
+
+</para>
+
+ service: 
+ cancellable: 
+ error: 
+ Returns: 
+
+
diff --git a/po/POTFILES.in b/po/POTFILES.in
index a350f09..4a7bd35 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -88,6 +88,7 @@ camel/camel-movemail.c
 camel/camel-multipart.c
 camel/camel-multipart-encrypted.c
 camel/camel-multipart-signed.c
+camel/camel-network-service.c
 camel/camel-net-utils.c
 camel/camel-object.c
 camel/camel-offline-folder.c



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]