[gnome-online-accounts/wip/mail: 6/6] Add IMAP/SMTP
- From: Debarshi Ray <debarshir src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-online-accounts/wip/mail: 6/6] Add IMAP/SMTP
- Date: Tue, 12 Feb 2013 23:31:01 +0000 (UTC)
commit 6c4340d91e92e198e63843728fe38c03cc3545c8
Author: Debarshi Ray <debarshir gnome org>
Date: Mon Jan 28 21:45:54 2013 +0100
Add IMAP/SMTP
Fixes: https://bugzilla.gnome.org/692736
configure.ac | 11 +
src/goabackend/Makefile.am | 5 +
src/goabackend/goabackendenums-priv.h | 16 +
src/goabackend/goabackendtypes.h | 7 +-
src/goabackend/goaimapauthlogin.c | 374 ++++++++++++
src/goabackend/goaimapauthlogin.h | 55 ++
src/goabackend/goaimapsmtpprovider.c | 1019 +++++++++++++++++++++++++++++++++
src/goabackend/goaimapsmtpprovider.h | 45 ++
src/goabackend/goamailauth.c | 175 ++++++
src/goabackend/goamailauth.h | 83 +++
src/goabackend/goamailclient.c | 330 +++++++++++
src/goabackend/goamailclient.h | 71 +++
src/goabackend/goaprovider.c | 6 +-
src/goabackend/goasmtpauthplain.c | 520 +++++++++++++++++
src/goabackend/goasmtpauthplain.h | 56 ++
15 files changed, 2768 insertions(+), 5 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 1e1fa95..0a316dd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -172,6 +172,16 @@ if test "$enable_google" != "no"; then
AC_DEFINE(GOA_GOOGLE_ENABLED, 1, [Enable Google data provider])
fi
+# IMAP/SMTP
+AC_ARG_ENABLE([imap-smtp],
+ [AS_HELP_STRING([--enable-imap-smtp],
+ [Enable IMAP/SMTP provider])],
+ [],
+ [enable_imap_smtp=no])
+if test "$enable_imap_smtp" != "no"; then
+ AC_DEFINE(GOA_IMAP_SMTP_ENABLED, 1, [Enable IMAP/SMTP data provider])
+fi
+
# ownCloud
AC_ARG_ENABLE([owncloud],
[AS_HELP_STRING([--enable-owncloud],
@@ -450,6 +460,7 @@ echo "
Flickr provider: ${enable_flickr} (OAuth 1.0, key:${with_flickr_consumer_key} secret:${with_flickr_consumer_secret})
Google provider: ${enable_google} (OAuth 2.0, id:${with_google_client_id} secret:${with_google_client_secret})
+ IMAP/SMTP provider: ${enable_imap_smtp}
Microsoft Exchange provider: ${enable_exchange}
ownCloud provider: ${enable_owncloud}
Kerberos provider: ${enable_kerberos}
diff --git a/src/goabackend/Makefile.am b/src/goabackend/Makefile.am
index 666e175..93185c0 100644
--- a/src/goabackend/Makefile.am
+++ b/src/goabackend/Makefile.am
@@ -60,12 +60,17 @@ libgoa_backend_1_0_la_SOURCES = \
goaewsclient.h goaewsclient.c \
goahttpclient.h goahttpclient.c \
goaprovider-priv.h goaprovider.c \
+ goamailauth.h goamailauth.c \
+ goaimapauthlogin.h goaimapauthlogin.c \
+ goasmtpauthplain.h goasmtpauthplain.c \
+ goamailclient.h goamailclient.c \
goaexchangeprovider.h goaexchangeprovider.c \
goalogging.h goalogging.c \
goaoauthprovider.h goaoauthprovider.c \
goaoauth2provider.h goaoauth2provider.c \
goagoogleprovider.h goagoogleprovider.c \
goafacebookprovider.h goafacebookprovider.c \
+ goaimapsmtpprovider.h goaimapsmtpprovider.c \
goaowncloudprovider.h goaowncloudprovider.c \
goayahooprovider.h goayahooprovider.c \
goatwitterprovider.h goatwitterprovider.c \
diff --git a/src/goabackend/goabackendenums-priv.h b/src/goabackend/goabackendenums-priv.h
index 5c8eab3..9d87fbd 100644
--- a/src/goabackend/goabackendenums-priv.h
+++ b/src/goabackend/goabackendenums-priv.h
@@ -49,6 +49,22 @@ typedef enum
GOA_LOG_LEVEL_ERROR
} GoaLogLevel;
+/**
+ * GoaTlsType:
+ * @GOA_TLS_TYPE_NONE: No encryption.
+ * @GOA_TLS_TYPE_STARTTLS: STARTTLS should be used on a standard port
+ * after the connection has been established to obtain a secure channel.
+ * @GOA_TLS_TYPE_SSL: SSL should be used on a dedicated port.
+ *
+ * Type of SSL/TLS used to connect to a server.
+ */
+typedef enum
+{
+ GOA_TLS_TYPE_NONE,
+ GOA_TLS_TYPE_STARTTLS,
+ GOA_TLS_TYPE_SSL
+} GoaTlsType;
+
G_END_DECLS
#endif /* __GOA_BACKEND_ENUMS_PRIV_H__ */
diff --git a/src/goabackend/goabackendtypes.h b/src/goabackend/goabackendtypes.h
index 94a2fea..2187625 100644
--- a/src/goabackend/goabackendtypes.h
+++ b/src/goabackend/goabackendtypes.h
@@ -1,6 +1,6 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
- * Copyright (C) 2011, 2012 Red Hat, Inc.
+ * Copyright (C) 2011, 2012, 2013 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,7 +17,8 @@
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
- * Author: David Zeuthen <davidz redhat com>
+ * Authors: David Zeuthen <davidz redhat com>
+ * Debarshi Ray <debarshir gnome org>
*/
#if !defined (__GOA_BACKEND_INSIDE_GOA_BACKEND_H__) && !defined (GOA_BACKEND_COMPILATION)
@@ -30,8 +31,6 @@
#include <goa/goa.h>
#include <goabackend/goabackendenums.h>
-G_BEGIN_DECLS
-
struct _GoaProvider;
typedef struct _GoaProvider GoaProvider;
diff --git a/src/goabackend/goaimapauthlogin.c b/src/goabackend/goaimapauthlogin.c
new file mode 100644
index 0000000..ad46340
--- /dev/null
+++ b/src/goabackend/goaimapauthlogin.c
@@ -0,0 +1,374 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2011, 2013 Red Hat, Inc.
+ *
+ * This library 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) any later version.
+ *
+ * This library 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: David Zeuthen <davidz redhat com>
+ * Debarshi Ray <debarshir gnome org>
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+#include <stdlib.h>
+
+#include "goaimapauthlogin.h"
+#include "goaprovider.h"
+#include "goautils.h"
+
+/**
+ * SECTION:goaimapauthlogin
+ * @title: GoaImapAuthLogin
+ * @short_description: LOGIN authentication method for IMAP
+ *
+ * #GoaImapAuthLogin implements the standard <ulink
+ * url="http://tools.ietf.org/html/rfc3501#section-6.2.3">LOGIN</ulink>
+ * authentication method (e.g. using usernames / passwords) for IMAP.
+ */
+
+/**
+ * GoaImapAuthLogin:
+ *
+ * The #GoaImapAuthLogin structure contains only private data
+ * and should only be accessed using the provided API.
+ */
+struct _GoaImapAuthLogin
+{
+ GoaMailAuth parent_instance;
+
+ GoaProvider *provider;
+ GoaObject *object;
+ gchar *username;
+ gchar *password;
+};
+
+typedef struct
+{
+ GoaMailAuthClass parent_class;
+
+} GoaImapAuthLoginClass;
+
+enum
+{
+ PROP_0,
+ PROP_PROVIDER,
+ PROP_OBJECT,
+ PROP_USERNAME,
+ PROP_PASSWORD
+};
+
+static gboolean goa_imap_auth_login_run_sync (GoaMailAuth *_auth,
+ GDataInputStream *input,
+ GDataOutputStream *output,
+ GCancellable *cancellable,
+ GError **error);
+
+G_DEFINE_TYPE (GoaImapAuthLogin, goa_imap_auth_login, GOA_TYPE_MAIL_AUTH);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+goa_imap_auth_login_finalize (GObject *object)
+{
+ GoaImapAuthLogin *auth = GOA_IMAP_AUTH_LOGIN (object);
+
+ g_clear_object (&auth->provider);
+ g_clear_object (&auth->object);
+ g_free (auth->username);
+ g_free (auth->password);
+
+ G_OBJECT_CLASS (goa_imap_auth_login_parent_class)->finalize (object);
+}
+
+static void
+goa_imap_auth_login_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GoaImapAuthLogin *auth = GOA_IMAP_AUTH_LOGIN (object);
+
+ switch (prop_id)
+ {
+ case PROP_PROVIDER:
+ g_value_set_object (value, auth->provider);
+ break;
+
+ case PROP_OBJECT:
+ g_value_set_object (value, auth->object);
+ break;
+
+ case PROP_USERNAME:
+ g_value_set_string (value, auth->username);
+ break;
+
+ case PROP_PASSWORD:
+ g_value_set_string (value, auth->password);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+goa_imap_auth_login_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GoaImapAuthLogin *auth = GOA_IMAP_AUTH_LOGIN (object);
+
+ switch (prop_id)
+ {
+ case PROP_PROVIDER:
+ auth->provider = g_value_dup_object (value);
+ break;
+
+ case PROP_OBJECT:
+ auth->object = g_value_dup_object (value);
+ break;
+
+ case PROP_USERNAME:
+ auth->username = g_value_dup_string (value);
+ break;
+
+ case PROP_PASSWORD:
+ auth->password = g_value_dup_string (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+
+static void
+goa_imap_auth_login_init (GoaImapAuthLogin *client)
+{
+}
+
+static void
+goa_imap_auth_login_class_init (GoaImapAuthLoginClass *klass)
+{
+ GObjectClass *gobject_class;
+ GoaMailAuthClass *auth_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = goa_imap_auth_login_finalize;
+ gobject_class->get_property = goa_imap_auth_login_get_property;
+ gobject_class->set_property = goa_imap_auth_login_set_property;
+
+ auth_class = GOA_MAIL_AUTH_CLASS (klass);
+ auth_class->run_sync = goa_imap_auth_login_run_sync;
+
+ /**
+ * GoaImapAuthLogin:provider:
+ *
+ * The #GoaProvider object for the account or %NULL.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_PROVIDER,
+ g_param_spec_object ("provider",
+ "provider",
+ "provider",
+ GOA_TYPE_PROVIDER,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GoaImapAuthLogin:object:
+ *
+ * The #GoaObject object for the account.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_OBJECT,
+ g_param_spec_object ("object",
+ "object",
+ "object",
+ GOA_TYPE_OBJECT,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GoaImapAuthLogin:user-name:
+ *
+ * The user name.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_USERNAME,
+ g_param_spec_string ("user-name",
+ "user-name",
+ "user-name",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GoaImapAuthLogin:password:
+ *
+ * The password or %NULL.
+ *
+ * If this is %NULL, the credentials are looked up using
+ * goa_utils_lookup_credentials_sync() using the
+ * #GoaImapAuthLogin:provider and #GoaImapAuthLogin:object for
+ * @provider and @object. The credentials are expected to be a
+ * %G_VARIANT_VARDICT and the key <literal>imap-password</literal>
+ * is used to look up the password.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_PASSWORD,
+ g_param_spec_string ("password",
+ "password",
+ "password",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * goa_imap_auth_login_new:
+ * @provider: (allow-none): A #GoaLoginProvider or %NULL.
+ * @object: (allow-none): An account object or %NULL.
+ * @username: The user name to use.
+ * @password: (allow-none): The password to use or %NULL to look it up
+ * (see the #GoaImapAuthLogin:password property).
+ *
+ * Creates a new #GoaMailAuth to be used for username/password
+ * authentication using LOGIN over IMAP.
+ *
+ * Returns: (type GoaImapAuthLogin): A #GoaImapAuthLogin. Free with
+ * g_object_unref().
+ */
+GoaMailAuth *
+goa_imap_auth_login_new (GoaProvider *provider,
+ GoaObject *object,
+ const gchar *username,
+ const gchar *password)
+{
+ g_return_val_if_fail (provider == NULL || GOA_IS_PROVIDER (provider), NULL);
+ g_return_val_if_fail (object == NULL || GOA_IS_OBJECT (object), NULL);
+ g_return_val_if_fail (username != NULL, NULL);
+ return GOA_MAIL_AUTH (g_object_new (GOA_TYPE_IMAP_AUTH_LOGIN,
+ "provider", provider,
+ "object", object,
+ "user-name", username,
+ "password", password,
+ NULL));
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+goa_imap_auth_login_run_sync (GoaMailAuth *_auth,
+ GDataInputStream *input,
+ GDataOutputStream *output,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GoaImapAuthLogin *auth = GOA_IMAP_AUTH_LOGIN (_auth);
+ gchar *request;
+ gchar *response;
+ gboolean ret;
+ gchar *password;
+
+ request = NULL;
+ response = NULL;
+ password = NULL;
+ ret = FALSE;
+
+ if (auth->password != NULL)
+ {
+ password = g_strdup (auth->password);
+ }
+ else if (auth->provider != NULL && auth->object != NULL)
+ {
+ GVariant *credentials;
+ credentials = goa_utils_lookup_credentials_sync (auth->provider,
+ auth->object,
+ cancellable,
+ error);
+ if (credentials == NULL)
+ {
+ g_prefix_error (error, "Error looking up credentials for IMAP LOGIN in keyring: ");
+ goto out;
+ }
+ if (!g_variant_lookup (credentials, "imap-password", "s", &password))
+ {
+ g_set_error (error,
+ GOA_ERROR,
+ GOA_ERROR_FAILED,
+ "Did not find imap-password in credentials");
+ g_variant_unref (credentials);
+ goto out;
+ }
+ g_variant_unref (credentials);
+ }
+ else
+ {
+ g_set_error (error,
+ GOA_ERROR,
+ GOA_ERROR_FAILED,
+ "Cannot do IMAP LOGIN without a password");
+ goto out;
+ }
+
+ request = g_strdup_printf ("A001 LOGIN \"%s\" \"%s\"\r\n", auth->username, password);
+ if (!g_data_output_stream_put_string (output, request, cancellable, error))
+ goto out;
+
+ again:
+ response = g_data_input_stream_read_line (input, NULL, cancellable, error);
+ if (response == NULL)
+ goto out;
+ /* ignore untagged responses */
+ if (g_str_has_prefix (response, "*"))
+ {
+ g_free (response);
+ goto again;
+ }
+ if (!g_str_has_prefix (response, "A001 OK"))
+ {
+ g_set_error (error,
+ GOA_ERROR,
+ GOA_ERROR_FAILED,
+ "Unexpected response `%s' while doing LOGIN authentication",
+ response);
+ goto out;
+ }
+
+ ret = TRUE;
+
+ out:
+ g_free (response);
+ g_free (request);
+ g_free (password);
+ return ret;
+}
diff --git a/src/goabackend/goaimapauthlogin.h b/src/goabackend/goaimapauthlogin.h
new file mode 100644
index 0000000..6c66e48
--- /dev/null
+++ b/src/goabackend/goaimapauthlogin.h
@@ -0,0 +1,55 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2011, 2013 Red Hat, Inc.
+ *
+ * This library 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) any later version.
+ *
+ * This library 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: David Zeuthen <davidz redhat com>
+ * Debarshi Ray <debarshir gnome org>
+ */
+
+#if !defined (__GOA_BACKEND_INSIDE_GOA_BACKEND_H__) && !defined (GOA_BACKEND_COMPILATION)
+#error "Only <goabackend/goabackend.h> can be included directly."
+#endif
+
+#ifndef __GOA_IMAP_AUTH_LOGIN_H__
+#define __GOA_IMAP_AUTH_LOGIN_H__
+
+#include <gio/gio.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include <goabackend/goabackendtypes.h>
+
+#include "goamailauth.h"
+
+G_BEGIN_DECLS
+
+#define GOA_TYPE_IMAP_AUTH_LOGIN (goa_imap_auth_login_get_type ())
+#define GOA_IMAP_AUTH_LOGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOA_TYPE_IMAP_AUTH_LOGIN, GoaImapAuthLogin))
+#define GOA_IS_IMAP_AUTH_LOGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOA_TYPE_IMAP_AUTH_LOGIN))
+
+typedef struct _GoaImapAuthLogin GoaImapAuthLogin;
+
+GType goa_imap_auth_login_get_type (void) G_GNUC_CONST;
+GoaMailAuth *goa_imap_auth_login_new (GoaProvider *provider,
+ GoaObject *object,
+ const gchar *user_name,
+ const gchar *password);
+
+G_END_DECLS
+
+#endif /* __GOA_IMAP_AUTH_LOGIN_H__ */
diff --git a/src/goabackend/goaimapsmtpprovider.c b/src/goabackend/goaimapsmtpprovider.c
new file mode 100644
index 0000000..1c2427b
--- /dev/null
+++ b/src/goabackend/goaimapsmtpprovider.c
@@ -0,0 +1,1019 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2011, 2013 Red Hat, Inc.
+ *
+ * This library 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) any later version.
+ *
+ * This library 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: David Zeuthen <davidz redhat com>
+ * Debarshi Ray <debarshir gnome org>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+
+#include "goaimapauthlogin.h"
+#include "goamailclient.h"
+#include "goaimapsmtpprovider.h"
+#include "goalogging.h"
+#include "goaprovider.h"
+#include "goaprovider-priv.h"
+#include "goasmtpauthplain.h"
+#include "goautils.h"
+
+/**
+ * GoaImapSmtpProvider:
+ *
+ * The #GoaImapSmtpProvider structure contains only private data and should
+ * only be accessed using the provided API.
+ */
+struct _GoaImapSmtpProvider
+{
+ /*< private >*/
+ GoaProvider parent_instance;
+};
+
+typedef struct _GoaImapSmtpProviderClass GoaImapSmtpProviderClass;
+
+struct _GoaImapSmtpProviderClass
+{
+ GoaProviderClass parent_class;
+};
+
+/**
+ * SECTION:goaimapsmtpprovider
+ * @title: GoaImapSmtpProvider
+ * @short_description: A provider for IMAP and SMTP servers
+ *
+ * #GoaImapSmtpProvider is used to access IMAP and SMTP mail servers.
+ */
+
+G_DEFINE_TYPE_WITH_CODE (GoaImapSmtpProvider, goa_imap_smtp_provider, GOA_TYPE_PROVIDER,
+ goa_provider_ensure_extension_points_registered ();
+ g_io_extension_point_implement (GOA_PROVIDER_EXTENSION_POINT_NAME,
+ g_define_type_id,
+ "imap_smtp",
+ 0));
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static const gchar *
+get_provider_type (GoaProvider *provider)
+{
+ return "imap_smtp";
+}
+
+static gchar *
+get_provider_name (GoaProvider *provider, GoaObject *object)
+{
+ return g_strdup (_("IMAP and SMTP"));
+}
+
+static GoaProviderGroup
+get_provider_group (GoaProvider *provider)
+{
+ return GOA_PROVIDER_GROUP_MAIL;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean on_handle_get_password (GoaPasswordBased *interface,
+ GDBusMethodInvocation *invocation,
+ const gchar *id,
+ gpointer user_data);
+
+static gboolean
+build_object (GoaProvider *provider,
+ GoaObjectSkeleton *object,
+ GKeyFile *key_file,
+ const gchar *group,
+ GDBusConnection *connection,
+ gboolean just_added,
+ GError **error)
+{
+ GoaAccount *account;
+ GoaMail *mail;
+ GoaPasswordBased *password_based;
+ gboolean enabled;
+ gboolean imap_accept_ssl_errors;
+ gboolean imap_use_ssl;
+ gboolean imap_use_tls;
+ gboolean ret;
+ gboolean smtp_accept_ssl_errors;
+ gboolean smtp_use_ssl;
+ gboolean smtp_use_tls;
+ gchar *email_address;
+ gchar *imap_host;
+ gchar *imap_username;
+ gchar *smtp_host;
+ gchar *smtp_username;
+
+ account = NULL;
+ mail = NULL;
+ password_based = NULL;
+ email_address = NULL;
+ imap_host = NULL;
+ imap_username = NULL;
+ smtp_host = NULL;
+ smtp_username = NULL;
+
+ ret = FALSE;
+
+ /* Chain up */
+ if (!GOA_PROVIDER_CLASS (goa_imap_smtp_provider_parent_class)->build_object (provider,
+ object,
+ key_file,
+ group,
+ connection,
+ just_added,
+ error))
+ goto out;
+
+ password_based = goa_object_get_password_based (GOA_OBJECT (object));
+ if (password_based == NULL)
+ {
+ password_based = goa_password_based_skeleton_new ();
+ /* Ensure D-Bus method invocations run in their own thread */
+ g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (password_based),
+ G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
+ goa_object_skeleton_set_password_based (object, password_based);
+ g_signal_connect (password_based,
+ "handle-get-password",
+ G_CALLBACK (on_handle_get_password),
+ NULL);
+ }
+
+ account = goa_object_get_account (GOA_OBJECT (object));
+
+ /* Email */
+ mail = goa_object_get_mail (GOA_OBJECT (object));
+ enabled = g_key_file_get_boolean (key_file, group, "Enabled", NULL);
+ if (enabled)
+ {
+ if (mail == NULL)
+ {
+ email_address = g_key_file_get_string (key_file, group, "EmailAddress", NULL);
+
+ imap_host = g_key_file_get_string (key_file, group, "ImapHost", NULL);
+ imap_username = g_key_file_get_string (key_file, group, "ImapUserName", NULL);
+ if (imap_username == NULL)
+ imap_username = g_strdup (g_get_user_name ());
+ imap_use_ssl = g_key_file_get_boolean (key_file, group, "ImapUseSsl", NULL);
+ imap_use_tls = g_key_file_get_boolean (key_file, group, "ImapUseTls", NULL);
+ imap_accept_ssl_errors = g_key_file_get_boolean (key_file, group, "ImapAcceptSslErrors", NULL);
+
+ smtp_host = g_key_file_get_string (key_file, group, "SmtpHost", NULL);
+ smtp_username = g_key_file_get_string (key_file, group, "SmtpUserName", NULL);
+ if (smtp_username == NULL)
+ smtp_username = g_strdup (g_get_user_name ());
+ smtp_use_ssl = g_key_file_get_boolean (key_file, group, "SmtpUseSsl", NULL);
+ smtp_use_tls = g_key_file_get_boolean (key_file, group, "SmtpUseTls", NULL);
+ smtp_accept_ssl_errors = g_key_file_get_boolean (key_file, group, "SmtpAcceptSslErrors", NULL);
+
+ mail = goa_mail_skeleton_new ();
+ g_object_set (G_OBJECT (mail),
+ "email-address", email_address,
+ "imap-supported", TRUE,
+ "imap-host", imap_host,
+ "imap-user-name", imap_username,
+ "imap-use-ssl", imap_use_ssl,
+ "imap-use-tls", imap_use_tls,
+ "imap-accept-ssl-errors", imap_accept_ssl_errors,
+ "smtp-supported", TRUE,
+ "smtp-host", smtp_host,
+ "smtp-user-name", smtp_username,
+ "smtp-use-ssl", smtp_use_ssl,
+ "smtp-use-tls", smtp_use_tls,
+ "smtp-accept-ssl-errors", smtp_accept_ssl_errors,
+ NULL);
+ goa_object_skeleton_set_mail (object, mail);
+ }
+ }
+ else
+ {
+ if (mail != NULL)
+ goa_object_skeleton_set_mail (object, NULL);
+ }
+
+ if (just_added)
+ {
+ goa_account_set_mail_disabled (account, !enabled);
+ g_signal_connect (account,
+ "notify::mail-disabled",
+ G_CALLBACK (goa_util_account_notify_property_cb),
+ "Enabled");
+ }
+
+ ret = TRUE;
+
+ out:
+ g_clear_object (&account);
+ g_clear_object (&mail);
+ g_clear_object (&password_based);
+ g_free (email_address);
+ g_free (imap_host);
+ g_free (imap_username);
+ g_free (smtp_host);
+ g_free (smtp_username);
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+ensure_credentials_sync (GoaProvider *provider,
+ GoaObject *object,
+ gint *out_expires_in,
+ GCancellable *cancellable,
+ GError **error)
+{
+ /* TODO: we could try and log into the mail server etc. but for now we don't */
+ if (out_expires_in != NULL)
+ *out_expires_in = 0;
+ return TRUE;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+add_combo_box (GtkWidget *grid,
+ gint row,
+ const gchar *text,
+ GtkWidget **out_combo_box)
+{
+ GtkStyleContext *context;
+ GtkWidget *label;
+ GtkWidget *combo_box;
+
+ label = gtk_label_new_with_mnemonic (text);
+ context = gtk_widget_get_style_context (label);
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_DIM_LABEL);
+ gtk_widget_set_halign (label, GTK_ALIGN_END);
+ gtk_widget_set_hexpand (label, TRUE);
+ gtk_grid_attach (GTK_GRID (grid), label, 0, row, 1, 1);
+
+ combo_box = gtk_combo_box_text_new ();
+ gtk_widget_set_hexpand (combo_box, TRUE);
+ gtk_grid_attach (GTK_GRID (grid), combo_box, 1, row, 3, 1);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo_box);
+ if (out_combo_box != NULL)
+ *out_combo_box = combo_box;
+}
+
+static void
+add_entry (GtkWidget *grid,
+ gint row,
+ const gchar *text,
+ GtkWidget **out_entry)
+{
+ GtkStyleContext *context;
+ GtkWidget *label;
+ GtkWidget *entry;
+
+ label = gtk_label_new_with_mnemonic (text);
+ context = gtk_widget_get_style_context (label);
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_DIM_LABEL);
+ gtk_widget_set_halign (label, GTK_ALIGN_END);
+ gtk_widget_set_hexpand (label, TRUE);
+ gtk_grid_attach (GTK_GRID (grid), label, 0, row, 1, 1);
+
+ entry = gtk_entry_new ();
+ gtk_widget_set_hexpand (entry, TRUE);
+ gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
+ gtk_grid_attach (GTK_GRID (grid), entry, 1, row, 3, 1);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
+ if (out_entry != NULL)
+ *out_entry = entry;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+ GCancellable *cancellable;
+
+ GtkDialog *dialog;
+ GMainLoop *loop;
+
+ GtkWidget *cluebar;
+ GtkWidget *cluebar_label;
+ GtkWidget *notebook;
+ GtkWidget *forward_button;
+ GtkWidget *progress_grid;
+
+ GtkWidget *email_address;
+ GtkWidget *name;
+
+ GtkWidget *imap_server;
+ GtkWidget *imap_username;
+ GtkWidget *imap_password;
+ GtkWidget *imap_encryption;
+
+ GtkWidget *smtp_server;
+ GtkWidget *smtp_username;
+ GtkWidget *smtp_password;
+ GtkWidget *smtp_encryption;
+
+ gchar *account_object_path;
+
+ GError *error;
+} AddAccountData;
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_email_address_changed (GtkEditable *editable, gpointer user_data)
+{
+ AddAccountData *data = user_data;
+ gboolean can_add;
+ const gchar *email;
+
+ email = gtk_entry_get_text (GTK_ENTRY (data->email_address));
+ can_add = goa_utils_parse_email_address (email, NULL, NULL);
+ gtk_dialog_set_response_sensitive (data->dialog, GTK_RESPONSE_OK, can_add);
+}
+
+static void
+on_imap_changed (GtkEditable *editable, gpointer user_data)
+{
+ AddAccountData *data = user_data;
+ gboolean can_add;
+
+ can_add = gtk_entry_get_text_length (GTK_ENTRY (data->imap_password)) != 0
+ && gtk_entry_get_text_length (GTK_ENTRY (data->imap_server)) != 0
+ && gtk_entry_get_text_length (GTK_ENTRY (data->imap_username)) != 0;
+ gtk_dialog_set_response_sensitive (data->dialog, GTK_RESPONSE_OK, can_add);
+}
+
+static void
+on_smtp_changed (GtkEditable *editable, gpointer user_data)
+{
+ AddAccountData *data = user_data;
+ gboolean can_add;
+
+ can_add = gtk_entry_get_text_length (GTK_ENTRY (data->smtp_password)) != 0
+ && gtk_entry_get_text_length (GTK_ENTRY (data->smtp_server)) != 0
+ && gtk_entry_get_text_length (GTK_ENTRY (data->smtp_username)) != 0;
+ gtk_dialog_set_response_sensitive (data->dialog, GTK_RESPONSE_OK, can_add);
+}
+
+static void
+create_account_details_ui (GoaProvider *provider,
+ GtkDialog *dialog,
+ GtkBox *vbox,
+ gboolean new_account,
+ AddAccountData *data)
+{
+ GtkWidget *action_area;
+ GtkWidget *grid0;
+ GtkWidget *grid1;
+ GtkWidget *label;
+ GtkWidget *spinner;
+ gint row;
+ gint width;
+
+ goa_utils_set_dialog_title (provider, dialog, new_account);
+
+ grid0 = gtk_grid_new ();
+ gtk_container_set_border_width (GTK_CONTAINER (grid0), 5);
+ gtk_widget_set_margin_bottom (grid0, 6);
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (grid0), GTK_ORIENTATION_VERTICAL);
+ gtk_grid_set_row_spacing (GTK_GRID (grid0), 12);
+ gtk_container_add (GTK_CONTAINER (vbox), grid0);
+
+ data->cluebar = gtk_info_bar_new ();
+ gtk_info_bar_set_message_type (GTK_INFO_BAR (data->cluebar), GTK_MESSAGE_ERROR);
+ gtk_widget_set_hexpand (data->cluebar, TRUE);
+ gtk_widget_set_no_show_all (data->cluebar, TRUE);
+ gtk_container_add (GTK_CONTAINER (grid0), data->cluebar);
+
+ data->cluebar_label = gtk_label_new ("");
+ gtk_label_set_line_wrap (GTK_LABEL (data->cluebar_label), TRUE);
+ gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (data->cluebar))),
+ data->cluebar_label);
+
+ data->notebook = gtk_notebook_new ();
+ gtk_notebook_set_show_border (GTK_NOTEBOOK (data->notebook), FALSE);
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (data->notebook), FALSE);
+ gtk_container_add (GTK_CONTAINER (grid0), data->notebook);
+
+ /* Introduction*/
+
+ grid1 = gtk_grid_new ();
+ gtk_grid_set_column_spacing (GTK_GRID (grid1), 12);
+ gtk_grid_set_row_spacing (GTK_GRID (grid1), 12);
+ gtk_notebook_append_page (GTK_NOTEBOOK (data->notebook), grid1, NULL);
+
+ row = 0;
+ add_entry (grid1, row++, _("_E-mail"), &data->email_address);
+ add_entry (grid1, row++, _("_Name"), &data->name);
+
+ g_signal_connect (data->email_address, "changed", G_CALLBACK (on_email_address_changed), data);
+
+ /* IMAP */
+
+ grid1 = gtk_grid_new ();
+ gtk_grid_set_column_spacing (GTK_GRID (grid1), 12);
+ gtk_grid_set_row_spacing (GTK_GRID (grid1), 12);
+ gtk_notebook_append_page (GTK_NOTEBOOK (data->notebook), grid1, NULL);
+
+ row = 0;
+ add_entry (grid1, row++, _("IMAP _Server"), &data->imap_server);
+ add_entry (grid1, row++, _("User_name"), &data->imap_username);
+ add_entry (grid1, row++, _("_Password"), &data->imap_password);
+ add_combo_box (grid1, row++, _("_Encryption"), &data->imap_encryption);
+
+ gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (data->imap_encryption),
+ "none",
+ _("None"));
+ gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (data->imap_encryption),
+ "starttls",
+ _("STARTTLS after connecting"));
+ gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (data->imap_encryption),
+ "ssl",
+ _("SSL on a dedicated port"));
+ gtk_combo_box_set_active_id (GTK_COMBO_BOX (data->imap_encryption), "starttls");
+
+ gtk_entry_set_visibility (GTK_ENTRY (data->imap_password), FALSE);
+
+ g_signal_connect (data->imap_server, "changed", G_CALLBACK (on_imap_changed), data);
+ g_signal_connect (data->imap_username, "changed", G_CALLBACK (on_imap_changed), data);
+ g_signal_connect (data->imap_password, "changed", G_CALLBACK (on_imap_changed), data);
+
+ /* SMTP */
+
+ grid1 = gtk_grid_new ();
+ gtk_grid_set_column_spacing (GTK_GRID (grid1), 12);
+ gtk_grid_set_row_spacing (GTK_GRID (grid1), 12);
+ gtk_notebook_append_page (GTK_NOTEBOOK (data->notebook), grid1, NULL);
+
+ row = 0;
+ add_entry (grid1, row++, _("SMTP _Server"), &data->smtp_server);
+ add_entry (grid1, row++, _("User_name"), &data->smtp_username);
+ add_entry (grid1, row++, _("_Password"), &data->smtp_password);
+ add_combo_box (grid1, row++, _("_Encryption"), &data->smtp_encryption);
+
+ gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (data->smtp_encryption),
+ "none",
+ _("None"));
+ gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (data->smtp_encryption),
+ "starttls",
+ _("STARTTLS after connecting"));
+ gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (data->smtp_encryption),
+ "ssl",
+ _("SSL on a dedicated port"));
+ gtk_combo_box_set_active_id (GTK_COMBO_BOX (data->smtp_encryption), "starttls");
+
+ gtk_entry_set_visibility (GTK_ENTRY (data->smtp_password), FALSE);
+
+ g_signal_connect (data->smtp_server, "changed", G_CALLBACK (on_smtp_changed), data);
+ g_signal_connect (data->smtp_username, "changed", G_CALLBACK (on_smtp_changed), data);
+ g_signal_connect (data->smtp_password, "changed", G_CALLBACK (on_smtp_changed), data);
+
+ /* -- */
+
+ data->forward_button = gtk_dialog_add_button (data->dialog, GTK_STOCK_GO_FORWARD, GTK_RESPONSE_OK);
+ gtk_dialog_set_default_response (data->dialog, GTK_RESPONSE_OK);
+ gtk_dialog_set_response_sensitive (data->dialog, GTK_RESPONSE_OK, FALSE);
+
+ action_area = gtk_dialog_get_action_area (data->dialog);
+
+ data->progress_grid = gtk_grid_new ();
+ gtk_widget_set_no_show_all (data->progress_grid, TRUE);
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (data->progress_grid), GTK_ORIENTATION_HORIZONTAL);
+ gtk_grid_set_column_spacing (GTK_GRID (data->progress_grid), 3);
+ gtk_box_pack_end (GTK_BOX (action_area), data->progress_grid, FALSE, FALSE, 0);
+ gtk_box_reorder_child (GTK_BOX (action_area), data->progress_grid, 0);
+ gtk_button_box_set_child_non_homogeneous (GTK_BUTTON_BOX (action_area), data->progress_grid, TRUE);
+
+ spinner = gtk_spinner_new ();
+ gtk_widget_set_size_request (spinner, 20, 20);
+ gtk_widget_show (spinner);
+ gtk_spinner_start (GTK_SPINNER (spinner));
+ gtk_container_add (GTK_CONTAINER (data->progress_grid), spinner);
+
+ label = gtk_label_new (_("Connectingâ"));
+ gtk_widget_show (label);
+ gtk_container_add (GTK_CONTAINER (data->progress_grid), label);
+
+ gtk_window_get_size (GTK_WINDOW (data->dialog), &width, NULL);
+ gtk_widget_set_size_request (GTK_WIDGET (data->dialog), width, -1);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GoaTlsType
+get_tls_type_from_string (const gchar *str)
+{
+ GoaTlsType tls_type;
+
+ if (g_strcmp0 (str, "none") == 0)
+ tls_type = GOA_TLS_TYPE_NONE;
+ else if (g_strcmp0 (str, "starttls") == 0)
+ tls_type = GOA_TLS_TYPE_STARTTLS;
+ else if (g_strcmp0 (str, "ssl") == 0)
+ tls_type = GOA_TLS_TYPE_SSL;
+ else
+ g_assert_not_reached ();
+
+ return tls_type;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+guess_imap_smtp (AddAccountData *data)
+{
+ const gchar *email_address;
+ gchar *imap_server;
+ gchar *smtp_server;
+ gchar *username;
+ gchar *domain;
+
+ domain = NULL;
+ imap_server = NULL;
+ smtp_server = NULL;
+ username = NULL;
+
+ email_address = gtk_entry_get_text (GTK_ENTRY (data->email_address));
+ if (!goa_utils_parse_email_address (email_address, &username, &domain))
+ goto out;
+
+ /* TODO: Consult http://api.gnome.org/evolution/autoconfig/1.1/<domain> */
+
+ imap_server = g_strconcat ("imap.", domain, NULL);
+ smtp_server = g_strconcat ("smtp.", domain, NULL);
+
+ gtk_entry_set_text (GTK_ENTRY (data->imap_username), username);
+ gtk_entry_set_text (GTK_ENTRY (data->smtp_username), username);
+ gtk_entry_set_text (GTK_ENTRY (data->imap_server), imap_server);
+ gtk_entry_set_text (GTK_ENTRY (data->smtp_server), smtp_server);
+
+ out:
+ g_free (imap_server);
+ g_free (smtp_server);
+ g_free (username);
+ g_free (domain);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+add_account_cb (GoaManager *manager, GAsyncResult *res, gpointer user_data)
+{
+ AddAccountData *data = user_data;
+ goa_manager_call_add_account_finish (manager,
+ &data->account_object_path,
+ res,
+ &data->error);
+ g_main_loop_quit (data->loop);
+}
+
+static void
+dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data)
+{
+ AddAccountData *data = user_data;
+
+ if (response_id == GTK_RESPONSE_CANCEL)
+ g_cancellable_cancel (data->cancellable);
+}
+
+static void
+imap_check_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GoaMailClient *client = GOA_MAIL_CLIENT (source_object);
+ AddAccountData *data = user_data;
+
+ goa_mail_client_check_finish (client, res, &data->error);
+ g_main_loop_quit (data->loop);
+ gtk_widget_set_sensitive (data->forward_button, TRUE);
+ gtk_widget_hide (data->progress_grid);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GoaObject *
+add_account (GoaProvider *provider,
+ GoaClient *client,
+ GtkDialog *dialog,
+ GtkBox *vbox,
+ GError **error)
+{
+ AddAccountData data;
+ GVariantBuilder credentials;
+ GVariantBuilder details;
+ GoaMailAuth *imap_auth;
+ GoaMailAuth *smtp_auth;
+ GoaMailClient *mail_client;
+ GoaObject *ret;
+ GoaTlsType imap_tls_type;
+ GoaTlsType smtp_tls_type;
+ gboolean imap_accept_ssl_errors;
+ gboolean smtp_accept_ssl_errors;
+ const gchar *email_address;
+ const gchar *encryption;
+ const gchar *imap_password;
+ const gchar *imap_server;
+ const gchar *imap_username;
+ const gchar *provider_type;
+ const gchar *smtp_password;
+ const gchar *smtp_server;
+ const gchar *smtp_username;
+ gchar *domain;
+ gint response;
+
+ imap_auth = NULL;
+ smtp_auth = NULL;
+ mail_client = NULL;
+ domain = NULL;
+
+ ret = NULL;
+
+ memset (&data, 0, sizeof (AddAccountData));
+ data.cancellable = g_cancellable_new ();
+ data.loop = g_main_loop_new (NULL, FALSE);
+ data.dialog = dialog;
+ data.error = NULL;
+
+ create_account_details_ui (provider, dialog, vbox, TRUE, &data);
+ gtk_widget_show_all (GTK_WIDGET (vbox));
+ g_signal_connect (dialog, "response", G_CALLBACK (dialog_response_cb), &data);
+
+ mail_client = goa_mail_client_new ();
+
+ /* Introduction */
+
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (data.notebook), 0);
+ gtk_widget_grab_focus (data.email_address);
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+ if (response != GTK_RESPONSE_OK)
+ {
+ g_set_error (&data.error,
+ GOA_ERROR,
+ GOA_ERROR_DIALOG_DISMISSED,
+ _("Dialog was dismissed"));
+ goto out;
+ }
+
+ email_address = gtk_entry_get_text (GTK_ENTRY (data.email_address));
+
+ /* See if there's already an account of this type with the
+ * given identity
+ */
+ provider_type = goa_provider_get_provider_type (provider);
+ if (!goa_utils_check_duplicate (client,
+ email_address,
+ provider_type,
+ (GoaPeekInterfaceFunc) goa_object_peek_password_based,
+ &data.error))
+ goto out;
+
+ guess_imap_smtp (&data);
+
+ /* IMAP */
+
+ gtk_notebook_next_page (GTK_NOTEBOOK (data.notebook));
+ gtk_widget_grab_focus (data.imap_password);
+
+ imap_accept_ssl_errors = FALSE;
+
+ imap_again:
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+ if (response != GTK_RESPONSE_OK)
+ {
+ g_set_error (&data.error,
+ GOA_ERROR,
+ GOA_ERROR_DIALOG_DISMISSED,
+ _("Dialog was dismissed"));
+ goto out;
+ }
+
+ encryption = gtk_combo_box_get_active_id (GTK_COMBO_BOX (data.imap_encryption));
+ imap_tls_type = get_tls_type_from_string (encryption);
+
+ imap_password = gtk_entry_get_text (GTK_ENTRY (data.imap_password));
+ imap_server = gtk_entry_get_text (GTK_ENTRY (data.imap_server));
+ imap_username = gtk_entry_get_text (GTK_ENTRY (data.imap_username));
+
+ g_cancellable_reset (data.cancellable);
+ imap_auth = goa_imap_auth_login_new (NULL, NULL, imap_username, imap_password);
+ goa_mail_client_check (mail_client,
+ imap_server,
+ imap_tls_type,
+ imap_accept_ssl_errors,
+ (imap_tls_type == GOA_TLS_TYPE_SSL) ? 993 : 143,
+ imap_auth,
+ data.cancellable,
+ imap_check_cb,
+ &data);
+
+ gtk_widget_set_sensitive (data.forward_button, FALSE);
+ gtk_widget_show (data.progress_grid);
+ g_main_loop_run (data.loop);
+
+ if (g_cancellable_is_cancelled (data.cancellable))
+ {
+ g_prefix_error (&data.error,
+ _("Dialog was dismissed (%s, %d): "),
+ g_quark_to_string (data.error->domain),
+ data.error->code);
+ data.error->domain = GOA_ERROR;
+ data.error->code = GOA_ERROR_DIALOG_DISMISSED;
+ goto out;
+ }
+ else if (data.error != NULL)
+ {
+ gchar *markup;
+
+ if (data.error->code == GOA_ERROR_SSL)
+ {
+ gtk_button_set_label (GTK_BUTTON (data.forward_button), _("_Ignore"));
+ imap_accept_ssl_errors = TRUE;
+ }
+ else
+ {
+ gtk_button_set_label (GTK_BUTTON (data.forward_button), _("_Try Again"));
+ imap_accept_ssl_errors = FALSE;
+ }
+
+ markup = g_strdup_printf ("<b>%s</b>\n%s",
+ _("Error connecting to IMAP server"),
+ data.error->message);
+ g_clear_error (&data.error);
+
+ gtk_label_set_markup (GTK_LABEL (data.cluebar_label), markup);
+ g_free (markup);
+
+ gtk_widget_set_no_show_all (data.cluebar, FALSE);
+ gtk_widget_show_all (data.cluebar);
+
+ g_clear_object (&imap_auth);
+ goto imap_again;
+ }
+
+ gtk_widget_set_no_show_all (data.cluebar, TRUE);
+ gtk_widget_hide (data.cluebar);
+ gtk_button_set_label (GTK_BUTTON (data.forward_button), GTK_STOCK_GO_FORWARD);
+
+ /* SMTP */
+
+ /* Re-use the password from the IMAP page */
+ gtk_entry_set_text (GTK_ENTRY (data.smtp_password), imap_password);
+
+ gtk_notebook_next_page (GTK_NOTEBOOK (data.notebook));
+ gtk_widget_grab_focus (data.smtp_password);
+
+ smtp_accept_ssl_errors = FALSE;
+
+ smtp_again:
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+ if (response != GTK_RESPONSE_OK)
+ {
+ g_set_error (&data.error,
+ GOA_ERROR,
+ GOA_ERROR_DIALOG_DISMISSED,
+ _("Dialog was dismissed"));
+ goto out;
+ }
+
+ encryption = gtk_combo_box_get_active_id (GTK_COMBO_BOX (data.smtp_encryption));
+ smtp_tls_type = get_tls_type_from_string (encryption);
+
+ smtp_password = gtk_entry_get_text (GTK_ENTRY (data.smtp_password));
+ smtp_server = gtk_entry_get_text (GTK_ENTRY (data.smtp_server));
+ smtp_username = gtk_entry_get_text (GTK_ENTRY (data.smtp_username));
+
+ g_cancellable_reset (data.cancellable);
+ goa_utils_parse_email_address (email_address, NULL, &domain);
+ smtp_auth = goa_smtp_auth_plain_new (NULL, NULL, domain, smtp_username, smtp_password);
+ goa_mail_client_check (mail_client,
+ smtp_server,
+ smtp_tls_type,
+ smtp_accept_ssl_errors,
+ (smtp_tls_type == GOA_TLS_TYPE_SSL) ? 465 : 587,
+ smtp_auth,
+ data.cancellable,
+ imap_check_cb,
+ &data);
+
+ gtk_widget_set_sensitive (data.forward_button, FALSE);
+ gtk_widget_show (data.progress_grid);
+ g_main_loop_run (data.loop);
+
+ if (g_cancellable_is_cancelled (data.cancellable))
+ {
+ g_prefix_error (&data.error,
+ _("Dialog was dismissed (%s, %d): "),
+ g_quark_to_string (data.error->domain),
+ data.error->code);
+ data.error->domain = GOA_ERROR;
+ data.error->code = GOA_ERROR_DIALOG_DISMISSED;
+ goto out;
+ }
+ else if (data.error != NULL)
+ {
+ gchar *markup;
+
+ if (data.error->code == GOA_ERROR_SSL)
+ {
+ gtk_button_set_label (GTK_BUTTON (data.forward_button), _("_Ignore"));
+ smtp_accept_ssl_errors = TRUE;
+ }
+ else
+ {
+ gtk_button_set_label (GTK_BUTTON (data.forward_button), _("_Try Again"));
+ smtp_accept_ssl_errors = FALSE;
+ }
+
+ markup = g_strdup_printf ("<b>%s</b>\n%s",
+ _("Error connecting to SMTP server"),
+ data.error->message);
+ g_clear_error (&data.error);
+
+ gtk_label_set_markup (GTK_LABEL (data.cluebar_label), markup);
+ g_free (markup);
+
+ gtk_widget_set_no_show_all (data.cluebar, FALSE);
+ gtk_widget_show_all (data.cluebar);
+
+ g_clear_object (&smtp_auth);
+ goto smtp_again;
+ }
+
+ gtk_widget_hide (GTK_WIDGET (dialog));
+
+ g_variant_builder_init (&credentials, G_VARIANT_TYPE_VARDICT);
+ g_variant_builder_add (&credentials, "{sv}", "imap-password", g_variant_new_string (imap_password));
+ g_variant_builder_add (&credentials, "{sv}", "smtp-password", g_variant_new_string (smtp_password));
+
+ g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
+ g_variant_builder_add (&details, "{ss}", "Enabled", "true");
+ g_variant_builder_add (&details, "{ss}", "EmailAddress", email_address);
+ g_variant_builder_add (&details, "{ss}", "ImapHost", imap_server);
+ g_variant_builder_add (&details, "{ss}", "ImapUserName", imap_username);
+ g_variant_builder_add (&details, "{ss}",
+ "ImapUseSsl", (imap_tls_type == GOA_TLS_TYPE_SSL) ? "true" : "false");
+ g_variant_builder_add (&details, "{ss}",
+ "ImapUseTls", (imap_tls_type == GOA_TLS_TYPE_STARTTLS) ? "true" : "false");
+ g_variant_builder_add (&details, "{ss}",
+ "ImapAcceptSslErrors", (imap_accept_ssl_errors) ? "true" : "false");
+ g_variant_builder_add (&details, "{ss}", "SmtpHost", smtp_server);
+ g_variant_builder_add (&details, "{ss}", "SmtpUserName", smtp_username);
+ g_variant_builder_add (&details, "{ss}",
+ "SmtpUseSsl", (smtp_tls_type == GOA_TLS_TYPE_SSL) ? "true" : "false");
+ g_variant_builder_add (&details, "{ss}",
+ "SmtpUseTls", (smtp_tls_type == GOA_TLS_TYPE_STARTTLS) ? "true" : "false");
+ g_variant_builder_add (&details, "{ss}",
+ "SmtpAcceptSslErrors", (smtp_accept_ssl_errors) ? "true" : "false");
+
+ /* OK, everything is dandy, add the account */
+ /* we want the GoaClient to update before this method returns (so it
+ * can create a proxy for the new object) so run the mainloop while
+ * waiting for this to complete
+ */
+ goa_manager_call_add_account (goa_client_get_manager (client),
+ goa_provider_get_provider_type (provider),
+ email_address,
+ email_address,
+ g_variant_builder_end (&credentials),
+ g_variant_builder_end (&details),
+ NULL, /* GCancellable* */
+ (GAsyncReadyCallback) add_account_cb,
+ &data);
+ g_main_loop_run (data.loop);
+ if (data.error != NULL)
+ goto out;
+
+ ret = GOA_OBJECT (g_dbus_object_manager_get_object (goa_client_get_object_manager (client),
+ data.account_object_path));
+ out:
+ /* We might have an object even when data.error is set.
+ * eg., if we failed to store the credentials in the keyring.
+ */
+ if (data.error != NULL)
+ g_propagate_error (error, data.error);
+ else
+ g_assert (ret != NULL);
+
+ g_free (domain);
+ g_free (data.account_object_path);
+ if (data.loop != NULL)
+ g_main_loop_unref (data.loop);
+ g_clear_object (&data.cancellable);
+ g_clear_object (&imap_auth);
+ g_clear_object (&smtp_auth);
+ g_clear_object (&mail_client);
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+show_account (GoaProvider *provider,
+ GoaClient *client,
+ GoaObject *object,
+ GtkBox *vbox,
+ GtkGrid *left,
+ GtkGrid *right)
+{
+ /* Chain up */
+ GOA_PROVIDER_CLASS (goa_imap_smtp_provider_parent_class)->show_account (provider,
+ client,
+ object,
+ vbox,
+ left,
+ right);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+goa_imap_smtp_provider_init (GoaImapSmtpProvider *provider)
+{
+}
+
+static void
+goa_imap_smtp_provider_class_init (GoaImapSmtpProviderClass *klass)
+{
+ GoaProviderClass *provider_class;
+
+ provider_class = GOA_PROVIDER_CLASS (klass);
+ provider_class->get_provider_type = get_provider_type;
+ provider_class->get_provider_name = get_provider_name;
+ provider_class->get_provider_group = get_provider_group;
+ provider_class->add_account = add_account;
+ provider_class->build_object = build_object;
+ provider_class->show_account = show_account;
+ provider_class->ensure_credentials_sync = ensure_credentials_sync;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+on_handle_get_password (GoaPasswordBased *interface,
+ GDBusMethodInvocation *invocation,
+ const gchar *id,
+ gpointer user_data)
+{
+ GoaObject *object;
+ GoaAccount *account;
+ GoaProvider *provider;
+ GError *error;
+ GVariant *credentials;
+ gchar *password;
+
+ /* TODO: maybe log what app is requesting access */
+
+ password = NULL;
+ credentials = NULL;
+
+ object = GOA_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (interface)));
+ account = goa_object_peek_account (object);
+ provider = goa_provider_get_for_provider_type (goa_account_get_provider_type (account));
+
+ error = NULL;
+ credentials = goa_utils_lookup_credentials_sync (provider,
+ object,
+ NULL, /* GCancellable* */
+ &error);
+ if (credentials == NULL)
+ {
+ g_dbus_method_invocation_take_error (invocation, error);
+ goto out;
+ }
+
+ if (!g_variant_lookup (credentials, id, "s", &password))
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ GOA_ERROR,
+ GOA_ERROR_FAILED, /* TODO: more specific */
+ "Did not find password with id `%s' in credentials",
+ id);
+ goto out;
+ }
+
+ goa_password_based_complete_get_password (interface, invocation, password);
+
+ out:
+ g_free (password);
+ if (credentials != NULL)
+ g_variant_unref (credentials);
+ g_object_unref (provider);
+ return TRUE; /* invocation was handled */
+}
diff --git a/src/goabackend/goaimapsmtpprovider.h b/src/goabackend/goaimapsmtpprovider.h
new file mode 100644
index 0000000..571e7f2
--- /dev/null
+++ b/src/goabackend/goaimapsmtpprovider.h
@@ -0,0 +1,45 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2011, 2013 Red Hat, Inc.
+ *
+ * This library 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) any later version.
+ *
+ * This library 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: David Zeuthen <davidz redhat com>
+ * Debarshi Ray <debarshir gnome org>
+ */
+
+#if !defined (__GOA_BACKEND_INSIDE_GOA_BACKEND_H__) && !defined (GOA_BACKEND_COMPILATION)
+#error "Only <goabackend/goabackend.h> can be included directly."
+#endif
+
+#ifndef __GOA_IMAP_SMTP_PROVIDER_H__
+#define __GOA_IMAP_SMTP_PROVIDER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GOA_TYPE_IMAP_SMTP_PROVIDER (goa_imap_smtp_provider_get_type ())
+#define GOA_IMAP_SMTP_PROVIDER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOA_TYPE_IMAP_SMTP_PROVIDER, GoaImapSmtpProvider))
+#define GOA_IS_IMAP_SMTP_PROVIDER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOA_TYPE_IMAP_SMTP_PROVIDER))
+
+typedef struct _GoaImapSmtpProvider GoaImapSmtpProvider;
+
+GType goa_imap_smtp_provider_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GOA_IMAP_SMTP_PROVIDER_H__ */
diff --git a/src/goabackend/goamailauth.c b/src/goabackend/goamailauth.c
new file mode 100644
index 0000000..8c733c9
--- /dev/null
+++ b/src/goabackend/goamailauth.c
@@ -0,0 +1,175 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2011, 2013 Red Hat, Inc.
+ *
+ * This library 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) any later version.
+ *
+ * This library 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: David Zeuthen <davidz redhat com>
+ * Debarshi Ray <debarshir gnome org>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+
+#include "goamailauth.h"
+
+G_DEFINE_ABSTRACT_TYPE (GoaMailAuth, goa_mail_auth, G_TYPE_OBJECT);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+ GAsyncReadyCallback callback;
+ GDataInputStream *input;
+ GDataOutputStream *output;
+ gpointer user_data;
+} RunData;
+
+static void
+mail_auth_run_data_free (RunData *data)
+{
+ g_object_unref (data->input);
+ g_object_unref (data->output);
+ g_slice_free (RunData, data);
+}
+
+static RunData *
+mail_auth_run_data_new (GDataInputStream *input,
+ GDataOutputStream *output,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ RunData *data;
+
+ data = g_slice_new0 (RunData);
+ data->input = g_object_ref (input);
+ data->output = g_object_ref (output);
+ data->callback = callback;
+ data->user_data = user_data;
+
+ return data;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+mail_auth_run_async_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ RunData *data = user_data;
+
+ if (data->callback != NULL)
+ data->callback (source_object, res, data->user_data);
+
+ mail_auth_run_data_free (data);
+}
+
+static void
+mail_auth_run_in_thread_func (GSimpleAsyncResult *res, GObject *object, GCancellable *cancellable)
+{
+ GError *error;
+ RunData *data;
+ gboolean op_res;
+
+ data = (RunData *) g_async_result_get_user_data (G_ASYNC_RESULT (res));
+ op_res = FALSE;
+
+ error = NULL;
+ if (!goa_mail_auth_run_sync (GOA_MAIL_AUTH (object), data->input, data->output, cancellable, &error))
+ {
+ g_simple_async_result_take_error (res, error);
+ goto out;
+ }
+
+ op_res = TRUE;
+
+ out:
+ g_simple_async_result_set_op_res_gboolean (res, op_res);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+goa_mail_auth_init (GoaMailAuth *client)
+{
+}
+
+static void
+goa_mail_auth_class_init (GoaMailAuthClass *klass)
+{
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+gboolean
+goa_mail_auth_run_sync (GoaMailAuth *auth,
+ GDataInputStream *input,
+ GDataOutputStream *output,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (GOA_IS_MAIL_AUTH (auth), FALSE);
+ g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (input), FALSE);
+ g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (output), FALSE);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+ return GOA_MAIL_AUTH_GET_CLASS (auth)->run_sync (auth, input, output, cancellable, error);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+void
+goa_mail_auth_run (GoaMailAuth *auth,
+ GDataInputStream *input,
+ GDataOutputStream *output,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ RunData *data;
+
+ g_return_if_fail (GOA_IS_MAIL_AUTH (auth));
+ g_return_if_fail (G_IS_DATA_INPUT_STREAM (input));
+ g_return_if_fail (G_IS_DATA_OUTPUT_STREAM (output));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ data = mail_auth_run_data_new (input, output, callback, user_data);
+
+ simple = g_simple_async_result_new (G_OBJECT (auth), mail_auth_run_async_cb, data, goa_mail_auth_run);
+ g_simple_async_result_set_handle_cancellation (simple, TRUE);
+
+ g_simple_async_result_run_in_thread (simple, mail_auth_run_in_thread_func, G_PRIORITY_DEFAULT, cancellable);
+
+ g_object_unref (simple);
+}
+
+gboolean
+goa_mail_auth_run_finish (GoaMailAuth *auth,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (auth), goa_mail_auth_run), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (res);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ return g_simple_async_result_get_op_res_gboolean (simple);
+}
diff --git a/src/goabackend/goamailauth.h b/src/goabackend/goamailauth.h
new file mode 100644
index 0000000..89df120
--- /dev/null
+++ b/src/goabackend/goamailauth.h
@@ -0,0 +1,83 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2011, 2013 Red Hat, Inc.
+ *
+ * This library 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) any later version.
+ *
+ * This library 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: David Zeuthen <davidz redhat com>
+ * Debarshi Ray <debarshir gnome org>
+ */
+
+#if !defined (__GOA_BACKEND_INSIDE_GOA_BACKEND_H__) && !defined (GOA_BACKEND_COMPILATION)
+#error "Only <goabackend/goabackend.h> can be included directly."
+#endif
+
+#ifndef __GOA_MAIL_AUTH_H__
+#define __GOA_MAIL_AUTH_H__
+
+#include <gio/gio.h>
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GOA_TYPE_MAIL_AUTH (goa_mail_auth_get_type ())
+#define GOA_MAIL_AUTH(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOA_TYPE_MAIL_AUTH, GoaMailAuth))
+#define GOA_MAIL_AUTH_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GOA_TYPE_MAIL_AUTH, GoaMailAuthClass))
+#define GOA_MAIL_AUTH_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOA_TYPE_MAIL_AUTH, GoaMailAuthClass))
+#define GOA_IS_MAIL_AUTH(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOA_TYPE_MAIL_AUTH))
+#define GOA_IS_MAIL_AUTH_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOA_TYPE_MAIL_AUTH))
+
+typedef struct _GoaMailAuth GoaMailAuth;
+typedef struct _GoaMailAuthClass GoaMailAuthClass;
+typedef struct _GoaMailAuthPrivate GoaMailAuthPrivate;
+
+struct _GoaMailAuth
+{
+ /*< private >*/
+ GObject parent_instance;
+ GoaMailAuthPrivate *priv;
+};
+
+struct _GoaMailAuthClass
+{
+ GObjectClass parent_class;
+ gboolean (*run_sync) (GoaMailAuth *auth,
+ GDataInputStream *input,
+ GDataOutputStream *output,
+ GCancellable *cancellable,
+ GError **error);
+};
+
+GType goa_mail_auth_get_type (void) G_GNUC_CONST;
+void goa_mail_auth_run (GoaMailAuth *auth,
+ GDataInputStream *input,
+ GDataOutputStream *output,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean goa_mail_auth_run_finish (GoaMailAuth *auth,
+ GAsyncResult *res,
+ GError **error);
+gboolean goa_mail_auth_run_sync (GoaMailAuth *auth,
+ GDataInputStream *input,
+ GDataOutputStream *output,
+ GCancellable *cancellable,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __GOA_MAIL_AUTH_H__ */
diff --git a/src/goabackend/goamailclient.c b/src/goabackend/goamailclient.c
new file mode 100644
index 0000000..2b7ec65
--- /dev/null
+++ b/src/goabackend/goamailclient.c
@@ -0,0 +1,330 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2011, 2013 Red Hat, Inc.
+ *
+ * This library 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) any later version.
+ *
+ * This library 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: David Zeuthen <davidz redhat com>
+ * Debarshi Ray <debarshir gnome org>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+
+#include "goamailclient.h"
+#include "goalogging.h"
+#include "goautils.h"
+
+/* The timeout used for non-IDLE commands */
+#define COMMAND_TIMEOUT_SEC 30
+
+struct _GoaMailClient
+{
+ /*< private >*/
+ GObject parent_instance;
+};
+
+typedef struct _GoaMailClientClass GoaMailClientClass;
+
+struct _GoaMailClientClass
+{
+ GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE (GoaMailClient, goa_mail_client, G_TYPE_OBJECT);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+goa_mail_client_init (GoaMailClient *client)
+{
+}
+
+static void
+goa_mail_client_class_init (GoaMailClientClass *klass)
+{
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+GoaMailClient *
+goa_mail_client_new (void)
+{
+ return GOA_MAIL_CLIENT (g_object_new (GOA_TYPE_MAIL_CLIENT, NULL));
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+ GCancellable *cancellable;
+ GDataInputStream *input;
+ GDataOutputStream *output;
+ GSimpleAsyncResult *res;
+ GSocketClient *sc;
+ GSocketConnection *conn;
+ GTlsCertificateFlags cert_flags;
+ GTlsClientConnection *tls_conn;
+ GoaMailAuth *auth;
+ GoaTlsType tls_type;
+} CheckData;
+
+static void
+mail_client_check_data_free (CheckData *data)
+{
+ g_object_unref (data->res);
+ g_object_unref (data->sc);
+ g_object_unref (data->auth);
+ g_clear_object (&data->cancellable);
+ g_clear_object (&data->input);
+ g_clear_object (&data->output);
+ g_clear_object (&data->conn);
+ g_clear_object (&data->tls_conn);
+ g_slice_free (CheckData, data);
+}
+
+static gboolean
+mail_client_check_accept_certificate_cb (GTlsConnection *conn,
+ GTlsCertificate *peer_cert,
+ GTlsCertificateFlags errors,
+ gpointer user_data)
+{
+ CheckData *data = user_data;
+
+ /* Fail the connection if the certificate is invalid. */
+ data->cert_flags = errors;
+ return FALSE;
+}
+
+static void
+mail_client_check_event_cb (GSocketClient *sc,
+ GSocketClientEvent event,
+ GSocketConnectable *connectable,
+ GIOStream *connection,
+ gpointer user_data)
+{
+ CheckData *data = user_data;
+
+ if (event != G_SOCKET_CLIENT_TLS_HANDSHAKING)
+ return;
+
+ data->tls_conn = G_TLS_CLIENT_CONNECTION (g_object_ref (connection));
+ if (data->tls_type == GOA_TLS_TYPE_SSL)
+ g_tls_client_connection_set_use_ssl3 (data->tls_conn, TRUE);
+
+ g_signal_connect (data->tls_conn,
+ "accept-certificate",
+ G_CALLBACK (mail_client_check_accept_certificate_cb),
+ data);
+}
+
+static void
+mail_client_check_auth_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ CheckData *data = user_data;
+ GError *error;
+ gboolean op_res;
+
+ op_res = FALSE;
+
+ error = NULL;
+ if (!goa_mail_auth_run_finish (data->auth, res, &error))
+ {
+ g_simple_async_result_take_error (data->res, error);
+ goto out;
+ }
+
+ op_res = TRUE;
+ g_io_stream_close (G_IO_STREAM (data->conn), NULL, NULL);
+
+ out:
+ g_simple_async_result_set_op_res_gboolean (data->res, op_res);
+ g_simple_async_result_complete_in_idle (data->res);
+ mail_client_check_data_free (data);
+}
+
+static void
+mail_client_check_connect_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ CheckData *data = user_data;
+ GInputStream *base_input;
+ GError *error;
+ GOutputStream *base_output;
+ GSocket *socket;
+
+ error = NULL;
+ data->conn = g_socket_client_connect_to_host_finish (data->sc, res, &error);
+ if (data->conn == NULL)
+ {
+ if (error->code == G_TLS_ERROR_BAD_CERTIFICATE)
+ {
+ GError *tls_error;
+
+ tls_error = NULL;
+ goa_utils_set_error_ssl (&tls_error, data->cert_flags);
+ g_simple_async_result_take_error (data->res, tls_error);
+ }
+ else if (error->code != G_IO_ERROR_CANCELLED)
+ {
+ g_simple_async_result_set_error (data->res,
+ GOA_ERROR,
+ GOA_ERROR_FAILED, /* TODO: more specific */
+ _("Connection failed: %s"),
+ error->message);
+ }
+ g_error_free (error);
+ goto error;
+ }
+
+ /* fail quickly */
+ socket = g_socket_connection_get_socket (data->conn);
+ g_socket_set_timeout (socket, COMMAND_TIMEOUT_SEC);
+
+ base_input = g_io_stream_get_input_stream (G_IO_STREAM (data->conn));
+ data->input = g_data_input_stream_new (base_input);
+ g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (data->input), FALSE);
+ g_data_input_stream_set_newline_type (data->input, G_DATA_STREAM_NEWLINE_TYPE_CR_LF);
+
+ base_output = g_io_stream_get_output_stream (G_IO_STREAM (data->conn));
+ data->output = g_data_output_stream_new (base_output);
+ g_filter_output_stream_set_close_base_stream (G_FILTER_OUTPUT_STREAM (data->output), FALSE);
+
+ goa_mail_auth_run (data->auth, data->input, data->output, data->cancellable, mail_client_check_auth_cb, data);
+ return;
+
+ error:
+ g_simple_async_result_set_op_res_gboolean (data->res, FALSE);
+ g_simple_async_result_complete_in_idle (data->res);
+ mail_client_check_data_free (data);
+}
+
+void
+goa_mail_client_check (GoaMailClient *client,
+ const gchar *host_and_port,
+ GoaTlsType tls_type,
+ gboolean accept_ssl_errors,
+ guint16 default_port,
+ GoaMailAuth *auth,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ CheckData *data;
+
+ g_return_if_fail (GOA_IS_MAIL_CLIENT (client));
+ g_return_if_fail (host_and_port != NULL || host_and_port[0] != '\0');
+ g_return_if_fail (GOA_IS_MAIL_AUTH (auth));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ data = g_slice_new0 (CheckData);
+ data->res = g_simple_async_result_new (G_OBJECT (client), callback, user_data, goa_mail_client_check);
+
+ data->sc = g_socket_client_new ();
+ if (tls_type != GOA_TLS_TYPE_NONE)
+ g_socket_client_set_tls (data->sc, TRUE);
+ g_signal_connect (data->sc, "event", G_CALLBACK (mail_client_check_event_cb), data);
+
+ data->tls_type = tls_type;
+ data->auth = g_object_ref (auth);
+
+ if (accept_ssl_errors)
+ g_socket_client_set_tls_validation_flags (data->sc, 0);
+
+ if (cancellable != NULL)
+ {
+ data->cancellable = g_object_ref (cancellable);
+ g_simple_async_result_set_check_cancellable (data->res, data->cancellable);
+ }
+
+ g_socket_client_connect_to_host_async (data->sc,
+ host_and_port,
+ default_port,
+ data->cancellable,
+ mail_client_check_connect_cb,
+ data);
+}
+
+gboolean
+goa_mail_client_check_finish (GoaMailClient *client, GAsyncResult *res, GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (client), goa_mail_client_check), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (res);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ return g_simple_async_result_get_op_res_gboolean (simple);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+ GError **error;
+ GMainLoop *loop;
+ gboolean op_res;
+} CheckSyncData;
+
+static void
+mail_client_check_sync_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ CheckSyncData *data = user_data;
+
+ data->op_res = goa_mail_client_check_finish (GOA_MAIL_CLIENT (source_object), res, data->error);
+ g_main_loop_quit (data->loop);
+}
+
+gboolean
+goa_mail_client_check_sync (GoaMailClient *client,
+ const gchar *host_and_port,
+ GoaTlsType tls_type,
+ gboolean accept_ssl_errors,
+ guint16 default_port,
+ GoaMailAuth *auth,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CheckSyncData data;
+ GMainContext *context = NULL;
+
+ data.error = error;
+
+ context = g_main_context_new ();
+ g_main_context_push_thread_default (context);
+ data.loop = g_main_loop_new (context, FALSE);
+
+ goa_mail_client_check (client,
+ host_and_port,
+ tls_type,
+ accept_ssl_errors,
+ default_port,
+ auth,
+ cancellable,
+ mail_client_check_sync_cb,
+ &data);
+ g_main_loop_run (data.loop);
+ g_main_loop_unref (data.loop);
+
+ g_main_context_pop_thread_default (context);
+ g_main_context_unref (context);
+
+ return data.op_res;
+}
diff --git a/src/goabackend/goamailclient.h b/src/goabackend/goamailclient.h
new file mode 100644
index 0000000..79b02d4
--- /dev/null
+++ b/src/goabackend/goamailclient.h
@@ -0,0 +1,71 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2011, 2013 Red Hat, Inc.
+ *
+ * This library 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) any later version.
+ *
+ * This library 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: David Zeuthen <davidz redhat com>
+ * Debarshi Ray <debarshir gnome org>
+ */
+
+#if !defined (__GOA_BACKEND_INSIDE_GOA_BACKEND_H__) && !defined (GOA_BACKEND_COMPILATION)
+#error "Only <goabackend/goabackend.h> can be included directly."
+#endif
+
+#ifndef __GOA_MAIL_CLIENT_H__
+#define __GOA_MAIL_CLIENT_H__
+
+#include <gio/gio.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include "goabackendenums-priv.h"
+#include "goamailauth.h"
+
+G_BEGIN_DECLS
+
+#define GOA_TYPE_MAIL_CLIENT (goa_mail_client_get_type ())
+#define GOA_MAIL_CLIENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOA_TYPE_MAIL_CLIENT, GoaMailClient))
+#define GOA_IS_MAIL_CLIENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOA_TYPE_MAIL_CLIENT))
+
+typedef struct _GoaMailClient GoaMailClient;
+
+GType goa_mail_client_get_type (void) G_GNUC_CONST;
+GoaMailClient *goa_mail_client_new (void);
+void goa_mail_client_check (GoaMailClient *client,
+ const gchar *host_and_port,
+ GoaTlsType tls_type,
+ gboolean accept_ssl_errors,
+ guint16 default_port,
+ GoaMailAuth *auth,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean goa_mail_client_check_finish (GoaMailClient *client,
+ GAsyncResult *res,
+ GError **error);
+gboolean goa_mail_client_check_sync (GoaMailClient *client,
+ const gchar *host_and_port,
+ GoaTlsType tls_type,
+ gboolean accept_ssl_errors,
+ guint16 default_port,
+ GoaMailAuth *auth,
+ GCancellable *cancellable,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __GOA_MAIL_CLIENT_H__ */
diff --git a/src/goabackend/goaprovider.c b/src/goabackend/goaprovider.c
index b768fb3..c49cbff 100644
--- a/src/goabackend/goaprovider.c
+++ b/src/goabackend/goaprovider.c
@@ -1,6 +1,6 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
- * Copyright (C) 2011, 2012 Red Hat, Inc.
+ * Copyright (C) 2011, 2012, 2013 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -31,6 +31,7 @@
#include "goaexchangeprovider.h"
#include "goagoogleprovider.h"
#include "goafacebookprovider.h"
+#include "goaimapsmtpprovider.h"
#include "goaowncloudprovider.h"
#include "goayahooprovider.h"
#include "goatwitterprovider.h"
@@ -678,6 +679,9 @@ ensure_builtins_loaded (void)
#ifdef GOA_EXCHANGE_ENABLED
type = GOA_TYPE_EXCHANGE_PROVIDER;
#endif
+#ifdef GOA_IMAP_SMTP_ENABLED
+ type = GOA_TYPE_IMAP_SMTP_PROVIDER;
+#endif
#ifdef GOA_KERBEROS_ENABLED
type = GOA_TYPE_KERBEROS_PROVIDER;
#endif
diff --git a/src/goabackend/goasmtpauthplain.c b/src/goabackend/goasmtpauthplain.c
new file mode 100644
index 0000000..000aaab
--- /dev/null
+++ b/src/goabackend/goasmtpauthplain.c
@@ -0,0 +1,520 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2011, 2013 Red Hat, Inc.
+ *
+ * This library 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) any later version.
+ *
+ * This library 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: David Zeuthen <davidz redhat com>
+ * Debarshi Ray <debarshir gnome org>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib/gi18n-lib.h>
+
+#include "goasmtpauthplain.h"
+#include "goaprovider.h"
+#include "goautils.h"
+
+/**
+ * SECTION:goasmtpauthplain
+ * @title: GoaSmtpAuthPlain
+ * @short_description: PLAIN authentication method for SMTP
+ *
+ * #GoaSmtpAuthPlain implements the <ulink
+ * url="http://tools.ietf.org/html/rfc4616">PLAIN</ulink>
+ * SASL mechanism (e.g. using usernames / passwords) for SMTP.
+ */
+
+/**
+ * GoaSmtpAuthPlain:
+ *
+ * The #GoaSmtpAuthPlain structure contains only private data
+ * and should only be accessed using the provided API.
+ */
+struct _GoaSmtpAuthPlain
+{
+ GoaMailAuth parent_instance;
+
+ GoaProvider *provider;
+ GoaObject *object;
+ gchar *domain;
+ gchar *username;
+ gchar *password;
+};
+
+typedef struct
+{
+ GoaMailAuthClass parent_class;
+
+} GoaSmtpAuthPlainClass;
+
+enum
+{
+ PROP_0,
+ PROP_PROVIDER,
+ PROP_OBJECT,
+ PROP_DOMAIN,
+ PROP_USERNAME,
+ PROP_PASSWORD
+};
+
+static gboolean goa_smtp_auth_plain_run_sync (GoaMailAuth *_auth,
+ GDataInputStream *input,
+ GDataOutputStream *output,
+ GCancellable *cancellable,
+ GError **error);
+
+G_DEFINE_TYPE (GoaSmtpAuthPlain, goa_smtp_auth_plain, GOA_TYPE_MAIL_AUTH);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+goa_smtp_auth_plain_finalize (GObject *object)
+{
+ GoaSmtpAuthPlain *auth = GOA_SMTP_AUTH_PLAIN (object);
+
+ g_clear_object (&auth->provider);
+ g_clear_object (&auth->object);
+ g_free (auth->domain);
+ g_free (auth->username);
+ g_free (auth->password);
+
+ G_OBJECT_CLASS (goa_smtp_auth_plain_parent_class)->finalize (object);
+}
+
+static void
+goa_smtp_auth_plain_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GoaSmtpAuthPlain *auth = GOA_SMTP_AUTH_PLAIN (object);
+
+ switch (prop_id)
+ {
+ case PROP_PROVIDER:
+ g_value_set_object (value, auth->provider);
+ break;
+
+ case PROP_OBJECT:
+ g_value_set_object (value, auth->object);
+ break;
+
+ case PROP_DOMAIN:
+ g_value_set_string (value, auth->domain);
+ break;
+
+ case PROP_USERNAME:
+ g_value_set_string (value, auth->username);
+ break;
+
+ case PROP_PASSWORD:
+ g_value_set_string (value, auth->password);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+goa_smtp_auth_plain_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GoaSmtpAuthPlain *auth = GOA_SMTP_AUTH_PLAIN (object);
+
+ switch (prop_id)
+ {
+ case PROP_PROVIDER:
+ auth->provider = g_value_dup_object (value);
+ break;
+
+ case PROP_OBJECT:
+ auth->object = g_value_dup_object (value);
+ break;
+
+ case PROP_DOMAIN:
+ auth->domain = g_value_dup_string (value);
+ break;
+
+ case PROP_USERNAME:
+ auth->username = g_value_dup_string (value);
+ break;
+
+ case PROP_PASSWORD:
+ auth->password = g_value_dup_string (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+
+static void
+goa_smtp_auth_plain_init (GoaSmtpAuthPlain *client)
+{
+}
+
+static void
+goa_smtp_auth_plain_class_init (GoaSmtpAuthPlainClass *klass)
+{
+ GObjectClass *gobject_class;
+ GoaMailAuthClass *auth_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = goa_smtp_auth_plain_finalize;
+ gobject_class->get_property = goa_smtp_auth_plain_get_property;
+ gobject_class->set_property = goa_smtp_auth_plain_set_property;
+
+ auth_class = GOA_MAIL_AUTH_CLASS (klass);
+ auth_class->run_sync = goa_smtp_auth_plain_run_sync;
+
+ /**
+ * GoaSmtpAuthPlain:provider:
+ *
+ * The #GoaProvider object for the account or %NULL.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_PROVIDER,
+ g_param_spec_object ("provider",
+ "provider",
+ "provider",
+ GOA_TYPE_PROVIDER,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GoaSmtpAuthPlain:object:
+ *
+ * The #GoaObject object for the account.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_OBJECT,
+ g_param_spec_object ("object",
+ "object",
+ "object",
+ GOA_TYPE_OBJECT,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GoaSmtpAuthPlain:domain:
+ *
+ * The domail or %NULL.
+ *
+ * If this is %NULL, the domain is obtained from the
+ * email address associated with the #GoaObject.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_DOMAIN,
+ g_param_spec_string ("domain",
+ "domain",
+ "domain",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GoaSmtpAuthPlain:user-name:
+ *
+ * The user name.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_USERNAME,
+ g_param_spec_string ("user-name",
+ "user-name",
+ "user-name",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GoaSmtpAuthPlain:password:
+ *
+ * The password or %NULL.
+ *
+ * If this is %NULL, the credentials are looked up using
+ * goa_utils_lookup_credentials_sync() using the
+ * #GoaSmtpAuthPlain:provider and #GoaSmtpAuthPlain:object for
+ * @provider and @object. The credentials are expected to be a
+ * %G_VARIANT_VARDICT and the key <literal>smtp-password</literal>
+ * is used to look up the password.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_PASSWORD,
+ g_param_spec_string ("password",
+ "password",
+ "password",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * goa_smtp_auth_plain_new:
+ * @provider: (allow-none): A #GoaPlainProvider or %NULL.
+ * @object: (allow-none): An account object or %NULL.
+ * @domain: (allow-none): The domain to use or %NULL to look it up
+ * (see the #GoaSmtpAuthPlain:domain property).
+ * @username: The user name to use.
+ * @password: (allow-none): The password to use or %NULL to look it up
+ * (see the #GoaSmtpAuthPlain:password property).
+ *
+ * Creates a new #GoaMailAuth to be used for username/password
+ * authentication using PLAIN over SMTP.
+ *
+ * Returns: (type GoaSmtpAuthPlain): A #GoaSmtpAuthPlain. Free with
+ * g_object_unref().
+ */
+GoaMailAuth *
+goa_smtp_auth_plain_new (GoaProvider *provider,
+ GoaObject *object,
+ const gchar *domain,
+ const gchar *username,
+ const gchar *password)
+{
+ g_return_val_if_fail (provider == NULL || GOA_IS_PROVIDER (provider), NULL);
+ g_return_val_if_fail (object == NULL || GOA_IS_OBJECT (object), NULL);
+ g_return_val_if_fail (username != NULL, NULL);
+ return GOA_MAIL_AUTH (g_object_new (GOA_TYPE_SMTP_AUTH_PLAIN,
+ "provider", provider,
+ "object", object,
+ "domain", domain,
+ "user-name", username,
+ "password", password,
+ NULL));
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+goa_smtp_auth_plain_run_sync (GoaMailAuth *_auth,
+ GDataInputStream *input,
+ GDataOutputStream *output,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GoaSmtpAuthPlain *auth = GOA_SMTP_AUTH_PLAIN (_auth);
+ gboolean ret;
+ gchar *auth_arg_base64;
+ gchar *auth_arg_plain;
+ gchar *domain;
+ gchar *password;
+ gchar *request;
+ gchar *response;
+ gsize auth_arg_plain_len;
+
+ auth_arg_base64 = NULL;
+ auth_arg_plain = NULL;
+ domain = NULL;
+ password = NULL;
+ request = NULL;
+ response = NULL;
+
+ ret = FALSE;
+
+ if (auth->password != NULL)
+ {
+ password = g_strdup (auth->password);
+ }
+ else if (auth->provider != NULL && auth->object != NULL)
+ {
+ GVariant *credentials;
+ credentials = goa_utils_lookup_credentials_sync (auth->provider,
+ auth->object,
+ cancellable,
+ error);
+ if (credentials == NULL)
+ {
+ g_prefix_error (error, "Error looking up credentials for SMTP PLAIN in keyring: ");
+ goto out;
+ }
+ if (!g_variant_lookup (credentials, "smtp-password", "s", &password))
+ {
+ g_set_error (error,
+ GOA_ERROR,
+ GOA_ERROR_FAILED, /* TODO: more specific */
+ _("Did not find smtp-password in credentials"));
+ g_variant_unref (credentials);
+ goto out;
+ }
+ g_variant_unref (credentials);
+ }
+ else
+ {
+ g_set_error (error,
+ GOA_ERROR,
+ GOA_ERROR_FAILED, /* TODO: more specific */
+ _("Cannot do SMTP PLAIN without a password"));
+ goto out;
+ }
+
+ if (auth->domain != NULL)
+ {
+ domain = g_strdup (auth->domain);
+ }
+ else if (auth->object != NULL)
+ {
+ GoaMail *mail;
+ gchar *email_address;
+
+ mail = goa_object_get_mail (auth->object);
+ if (mail == NULL)
+ {
+ g_set_error (error,
+ GOA_ERROR,
+ GOA_ERROR_FAILED, /* TODO: more specific */
+ _("org.gnome.OnlineAccounts.Mail is not available"));
+ goto out;
+ }
+
+ email_address = goa_mail_dup_email_address (mail);
+ if (!goa_utils_parse_email_address (email_address, NULL, &domain))
+ {
+ g_set_error (error,
+ GOA_ERROR,
+ GOA_ERROR_FAILED, /* TODO: more specific */
+ _("Failed to parse email address"));
+ goto out;
+ }
+
+ g_free (email_address);
+ g_object_unref (mail);
+ }
+ else
+ {
+ g_set_error (error,
+ GOA_ERROR,
+ GOA_ERROR_FAILED, /* TODO: more specific */
+ _("Cannot do SMTP PLAIN without a domain"));
+ goto out;
+ }
+
+ /* Check the greeting */
+
+ response = g_data_input_stream_read_line (input, NULL, cancellable, error);
+ if (response == NULL)
+ goto out;
+ if (g_str_has_prefix (response, "421"))
+ {
+ g_set_error (error,
+ GOA_ERROR,
+ GOA_ERROR_FAILED, /* TODO: more specific */
+ _("Service not available"));
+ goto out;
+ }
+ if (!g_str_has_prefix (response, "220"))
+ {
+ g_set_error (error,
+ GOA_ERROR,
+ GOA_ERROR_FAILED, /* TODO: more specific */
+ "Unexpected response `%s' while doing PLAIN authentication",
+ response);
+ goto out;
+ }
+ g_clear_pointer (&response, g_free);
+
+ /* Send EHLO */
+
+ request = g_strdup_printf ("EHLO %s\r\n", domain);
+ if (!g_data_output_stream_put_string (output, request, cancellable, error))
+ goto out;
+ g_clear_pointer (&request, g_free);
+
+ /* Check if PLAIN is supported or not */
+
+ ehlo_again:
+ response = g_data_input_stream_read_line (input, NULL, cancellable, error);
+ if (response == NULL)
+ goto out;
+ if (!g_str_has_prefix (response, "250-AUTH"))
+ {
+ g_free (response);
+ goto ehlo_again;
+ }
+ if (strstr (response, "PLAIN") == NULL)
+ {
+ g_set_error (error,
+ GOA_ERROR,
+ GOA_ERROR_NOT_SUPPORTED,
+ _("Server does not support PLAIN"));
+ goto out;
+ }
+ g_clear_pointer (&response, g_free);
+
+ /* Send AUTH PLAIN */
+
+ auth_arg_plain = g_strdup_printf ("%s%c%s%c%s", auth->username, '\0', auth->username, '\0', password);
+ auth_arg_plain_len = 2 * strlen (auth->username) + 2 + strlen (password);
+ auth_arg_base64 = g_base64_encode ((guchar *) auth_arg_plain, auth_arg_plain_len);
+
+ request = g_strdup_printf ("AUTH PLAIN %s\r\n", auth_arg_base64);
+ if (!g_data_output_stream_put_string (output, request, cancellable, error))
+ goto out;
+ g_clear_pointer (&request, g_free);
+
+ auth_again:
+ response = g_data_input_stream_read_line (input, NULL, cancellable, error);
+ if (response == NULL)
+ goto out;
+ if (g_str_has_prefix (response, "250"))
+ {
+ g_free (response);
+ goto auth_again;
+ }
+ if (!g_str_has_prefix (response, "235"))
+ {
+ g_set_error (error,
+ GOA_ERROR,
+ GOA_ERROR_FAILED, /* TODO: more specific */
+ _("Authentication failed"));
+ goto out;
+ }
+ g_clear_pointer (&response, g_free);
+
+ ret = TRUE;
+
+ out:
+ g_free (auth_arg_base64);
+ g_free (auth_arg_plain);
+ g_free (domain);
+ g_free (password);
+ g_free (response);
+ g_free (request);
+ return ret;
+}
diff --git a/src/goabackend/goasmtpauthplain.h b/src/goabackend/goasmtpauthplain.h
new file mode 100644
index 0000000..9880dcb
--- /dev/null
+++ b/src/goabackend/goasmtpauthplain.h
@@ -0,0 +1,56 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2011, 2013 Red Hat, Inc.
+ *
+ * This library 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) any later version.
+ *
+ * This library 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: David Zeuthen <davidz redhat com>
+ * Debarshi Ray <debarshir gnome org>
+ */
+
+#if !defined (__GOA_BACKEND_INSIDE_GOA_BACKEND_H__) && !defined (GOA_BACKEND_COMPILATION)
+#error "Only <goabackend/goabackend.h> can be included directly."
+#endif
+
+#ifndef __GOA_SMTP_AUTH_PLAIN_H__
+#define __GOA_SMTP_AUTH_PLAIN_H__
+
+#include <gio/gio.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include <goabackend/goabackendtypes.h>
+
+#include "goamailauth.h"
+
+G_BEGIN_DECLS
+
+#define GOA_TYPE_SMTP_AUTH_PLAIN (goa_smtp_auth_plain_get_type ())
+#define GOA_SMTP_AUTH_PLAIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOA_TYPE_SMTP_AUTH_PLAIN, GoaSmtpAuthPlain))
+#define GOA_IS_SMTP_AUTH_PLAIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOA_TYPE_SMTP_AUTH_PLAIN))
+
+typedef struct _GoaSmtpAuthPlain GoaSmtpAuthPlain;
+
+GType goa_smtp_auth_plain_get_type (void) G_GNUC_CONST;
+GoaMailAuth *goa_smtp_auth_plain_new (GoaProvider *provider,
+ GoaObject *object,
+ const gchar *domain,
+ const gchar *user_name,
+ const gchar *password);
+
+G_END_DECLS
+
+#endif /* __GOA_SMTP_AUTH_PLAIN_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]