/* TMut * Copyright (C) 2006-2007 Philip Van Hoof * * 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 self library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include "tmut-account-store.h" #include "tmut-platform-factory.h" #include #include #include #include #include #include #include #include #include #include #include #include static GObjectClass *parent_class = NULL; typedef enum { TMUT_ACCOUNT_STORE_ACCOUNT_DELETED, TMUT_ACCOUNT_STORE_ACCOUNT_CREATED, TMUT_ACCOUNT_STORE_ACCOUNT_EDITED, TMUT_ACCOUNT_STORE_LAST_SIGNAL } TMutAccountStoreSignal; static guint tmut_account_store_signals [TMUT_ACCOUNT_STORE_LAST_SIGNAL]; typedef struct _TMutAccountStorePriv TMutAccountStorePriv; struct _TMutAccountStorePriv { gchar *cache_dir; TnySessionCamel *session; TnyDevice *device; guint notify; GList *accounts; }; #define TMUT_ACCOUNT_STORE_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), TMUT_TYPE_ACCOUNT_STORE, TMutAccountStorePriv)) static gchar* per_account_get_pass(TnyAccount *account, const gchar *prompt, gboolean *cancel) { TnyPlatformFactory *platfact = tmut_platform_factory_get_instance (); TnyPasswordGetter *pwdgetter; gchar *retval; pwdgetter = tny_platform_factory_new_password_getter (platfact); retval = (gchar*) tny_password_getter_get_password (pwdgetter, tny_account_get_id (account), prompt, cancel); g_object_unref (pwdgetter); return retval; } static void per_account_forget_pass(TnyAccount *account) { TnyPlatformFactory *platfact = tmut_platform_factory_get_instance (); TnyPasswordGetter *pwdgetter; pwdgetter = tny_platform_factory_new_password_getter (platfact); tny_password_getter_forget_password (pwdgetter, tny_account_get_id (account)); g_object_unref (pwdgetter); return; } static TnyAccount* create_account_instance (TMutAccountStorePriv *priv, const gchar *type, const gchar *proto, const gchar *mech, const gchar *name, gchar **options, const gchar *user, const gchar *hostname, gint port, const gchar *url_string, const gchar *fullfilen, const gchar *from) { TnyAccount *account = NULL; if (!g_ascii_strncasecmp (proto, "smtp", 4)) account = TNY_ACCOUNT (tny_camel_transport_account_new ()); else if (!g_ascii_strncasecmp (proto, "imap", 4)) account = TNY_ACCOUNT (tny_camel_imap_store_account_new ()); else if (!g_ascii_strncasecmp (proto, "nntp", 4)) account = TNY_ACCOUNT (tny_camel_nntp_store_account_new ()); else if (!g_ascii_strncasecmp (proto, "pop", 3)) account = TNY_ACCOUNT (tny_camel_pop_store_account_new ()); else /* Unknown, create a generic one? */ account = TNY_ACCOUNT (tny_camel_store_account_new ()); if (account) { gint i; tny_camel_account_set_session (TNY_CAMEL_ACCOUNT (account), priv->session); tny_account_set_proto (account, proto); if (name) tny_account_set_name (account, name); if (mech) tny_account_set_secure_auth_mech (account, mech); if (options) { gint i = 0; while (options[i] != NULL) { gchar *str = g_strdup (options [i]); gchar *key = str; gchar *value = strchr (str, '='); if (value) { *value = '\0'; value++; } else value = ""; tny_camel_account_add_option (TNY_CAMEL_ACCOUNT (account), tny_pair_new (key, value)); i++; g_free (str); } } if (!g_ascii_strncasecmp (proto, "pop", 3) || !g_ascii_strncasecmp (proto, "imap", 4) || !g_ascii_strncasecmp (proto, "smtp", 4)) { tny_account_set_user (account, user); tny_account_set_hostname (account, hostname); if (port != -1) tny_account_set_port (account, port); } tny_account_set_id (account, fullfilen); tny_account_set_forget_pass_func (TNY_ACCOUNT (account), per_account_forget_pass); tny_account_set_pass_func (TNY_ACCOUNT (account), per_account_get_pass); } if (TNY_IS_CAMEL_TRANSPORT_ACCOUNT (account)) tny_camel_transport_account_set_from (TNY_CAMEL_TRANSPORT_ACCOUNT (account), from); return account; } void tmut_account_store_create_account (TMutAccountStore *self, gboolean enabled, const gchar *name, const gchar *hostname, const gchar *proto, const gchar *type, const gchar *user, const gchar *mech, const gchar *from, gint port, const gchar **options) { TMutAccountStorePriv *priv = TMUT_ACCOUNT_STORE_GET_PRIVATE (self); GList *found; TnyAccount *account = NULL; FILE *file; GKeyFile *keyfile = g_key_file_new (); gchar *filen = g_build_filename (g_get_home_dir(), ".tmut", "accounts", name, NULL); gchar *dirn = g_build_filename (g_get_home_dir(), ".tmut", "accounts", NULL); if (!g_file_test (dirn, G_FILE_TEST_EXISTS)) g_mkdir_with_parents (dirn, S_IRUSR | S_IWUSR | S_IXUSR); g_free (dirn); if (g_file_test (filen, G_FILE_TEST_EXISTS)) { g_warning ("%s already existed\n", filen); g_unlink (filen); } g_key_file_set_value (keyfile, "tmut", "proto", proto); g_key_file_set_value (keyfile, "tmut", "name", name); g_key_file_set_value (keyfile, "tmut", "hostname", hostname); g_key_file_set_value (keyfile, "tmut", "user", user); g_key_file_set_value (keyfile, "tmut", "type", type); if (options) { gint options_len = 0; while (options[options_len] != NULL) options_len++; g_key_file_set_string_list (keyfile, "tmut", "options", options, options_len); } /* todo: port and mech */ file = fopen (filen, "w"); if (file) { gsize len; char *str = g_key_file_to_data (keyfile, &len, NULL); fputs (str, file); fclose (file); } account = create_account_instance (priv, type, proto, mech, name, (gchar **) options, user, hostname, port, NULL, filen, from); if (account) { priv->accounts = g_list_prepend (priv->accounts, account); g_signal_emit (self, tmut_account_store_signals [TMUT_ACCOUNT_STORE_ACCOUNT_CREATED], 0, account); } g_key_file_free (keyfile); g_free (filen); } void tmut_account_store_delete_account (TMutAccountStore *self, TnyAccount *account) { TMutAccountStorePriv *priv = TMUT_ACCOUNT_STORE_GET_PRIVATE (self); const gchar *filen = tny_account_get_id (account); GList *found; TnyAccount *found_account = NULL; if (g_file_test (filen, G_FILE_TEST_EXISTS)) g_unlink (filen); found = g_list_find (priv->accounts, account); if (found) { found_account = found->data; priv->accounts = g_list_delete_link (priv->accounts, found); } if (found_account) { g_signal_emit (self, tmut_account_store_signals [TMUT_ACCOUNT_STORE_ACCOUNT_DELETED], 0, found_account); g_object_unref (found_account); } } void tmut_account_store_edit_account (TMutAccountStore *self, TnyAccount *account, gboolean enabled, const gchar *name, const gchar *hostname, const gchar *proto, const gchar *user, const gchar *mech, const gchar *from, gint port, const gchar **options) { TMutAccountStorePriv *priv = TMUT_ACCOUNT_STORE_GET_PRIVATE (self); const gchar *filen = tny_account_get_id (account); FILE *file; GKeyFile *keyfile = g_key_file_new (); g_key_file_load_from_file (keyfile, filen, G_KEY_FILE_NONE, NULL); if (name) { tny_account_set_name (account, name); g_key_file_set_value (keyfile, "tmut", "name", name); } if (hostname) { tny_account_set_hostname (account, hostname); g_key_file_set_value (keyfile, "tmut", "hostname", hostname); } if (proto) { tny_account_set_proto (account, proto); g_key_file_set_value (keyfile, "tmut", "proto", proto); } if (user) { tny_account_set_user (account, user); g_key_file_set_value (keyfile, "tmut", "user", user); } if (port != -1) { tny_account_set_port (account, port); g_key_file_set_integer (keyfile, "tmut", "port", port); } if (mech) { tny_account_set_secure_auth_mech (account, mech); g_key_file_set_value (keyfile, "tmut", "mech", mech); } if (from && TNY_IS_CAMEL_TRANSPORT_ACCOUNT (account)) { tny_camel_transport_account_set_from (TNY_CAMEL_TRANSPORT_ACCOUNT (account), from); g_key_file_set_value (keyfile, "tmut", "from", from); } tny_camel_account_clear_options (TNY_CAMEL_ACCOUNT (account)); if (options) { gint i = 0; while (options[i] != NULL) { gchar *str = g_strdup (options [i]); gchar *key = str; gchar *value = strchr (str, '='); if (value) { *value = '\0'; value++; } else value = ""; tny_camel_account_add_option (TNY_CAMEL_ACCOUNT (account), tny_pair_new (key, value)); i++; g_free (str); } g_key_file_set_string_list (keyfile, "tmut", "options", options, i); } else { g_key_file_remove_key (keyfile, "tmut", "options", NULL); } file = fopen (filen, "w"); if (file) { gsize len; char *str = g_key_file_to_data (keyfile, &len, NULL); fputs (str, file); fclose (file); } g_signal_emit (self, tmut_account_store_signals [TMUT_ACCOUNT_STORE_ACCOUNT_EDITED], 0, account); g_key_file_free (keyfile); } static void kill_stored_accounts (TMutAccountStorePriv *priv) { if (priv->accounts) { g_list_foreach (priv->accounts, (GFunc) g_object_unref, NULL); g_list_free (priv->accounts); priv->accounts = NULL; } } static void load_accounts (TnyAccountStore *self) { TMutAccountStorePriv *priv = TMUT_ACCOUNT_STORE_GET_PRIVATE (self); const gchar *filen; gchar *configd; GDir *dir; configd = g_build_path (G_DIR_SEPARATOR_S, g_get_home_dir(), ".tmut", "accounts", NULL); dir = g_dir_open (configd, 0, NULL); g_free (configd); if (!dir) return; for (filen = g_dir_read_name (dir); filen; filen = g_dir_read_name (dir)) { GError *port_err = NULL; GKeyFile *keyfile; gchar *proto, *type, *from, *user, *hostname, *url_string; gchar *name, *mech, **options; gsize options_len; TnyAccount *account = NULL; gint port = 0; gchar *fullfilen = g_build_filename (g_get_home_dir(), ".tmut", "accounts", filen, NULL); keyfile = g_key_file_new (); if (!g_key_file_load_from_file (keyfile, fullfilen, G_KEY_FILE_NONE, NULL)) { g_free (fullfilen); continue; } if (g_key_file_get_boolean (keyfile, "tmut", "disabled", NULL)) { g_free (fullfilen); continue; } type = g_key_file_get_value (keyfile, "tmut", "type", NULL); proto = g_key_file_get_value (keyfile, "tmut", "proto", NULL); mech = g_key_file_get_value (keyfile, "tmut", "mech", NULL); name = g_key_file_get_value (keyfile, "tmut", "name", NULL); options = g_key_file_get_string_list (keyfile, "tmut", "options", &options_len, NULL); user = g_key_file_get_value (keyfile, "tmut", "user", NULL); hostname = g_key_file_get_value (keyfile, "tmut", "hostname", NULL); url_string = g_key_file_get_value (keyfile, "tmut", "url_string", NULL); port = g_key_file_get_integer (keyfile, "tmut", "port", &port_err); from = g_key_file_get_value (keyfile, "tmut", "from", NULL); if (port_err) { port = -1; g_error_free (port_err); } account = create_account_instance (priv, type, proto, mech, name, options, user, hostname, port, url_string, fullfilen, from); if (account) priv->accounts = g_list_prepend (priv->accounts, account); g_free (type); if (options) g_strfreev (options); g_free (url_string); g_free (hostname); g_free (user); g_free (proto); g_free (mech); g_key_file_free (keyfile); } g_dir_close (dir); tny_session_camel_set_initialized (priv->session); } static void tmut_account_store_get_accounts (TnyAccountStore *self, TnyList *list, TnyGetAccountsRequestType types) { TMutAccountStorePriv *priv = TMUT_ACCOUNT_STORE_GET_PRIVATE (self); g_assert (TNY_IS_LIST (list)); if (!priv->accounts) load_accounts (self); if (priv->accounts) { GList *copy = priv->accounts; while (copy) { TnyAccount *account = copy->data; if (types == TNY_ACCOUNT_STORE_BOTH || types == TNY_ACCOUNT_STORE_STORE_ACCOUNTS) { if (TNY_IS_STORE_ACCOUNT (account)) tny_list_prepend (list, (GObject*) account); } if (types == TNY_ACCOUNT_STORE_BOTH || types == TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS) { if (TNY_IS_TRANSPORT_ACCOUNT (account)) tny_list_prepend (list, (GObject*) account); } copy = g_list_next (copy); } } return; } static const gchar* tmut_account_store_get_cache_dir (TnyAccountStore *self) { TMutAccountStorePriv *priv = TMUT_ACCOUNT_STORE_GET_PRIVATE (self); if (!priv->cache_dir) priv->cache_dir = g_build_path (G_DIR_SEPARATOR_S, g_get_home_dir(), ".tmut", NULL); return priv->cache_dir; } static TnyDevice* tmut_account_store_get_device (TnyAccountStore *self) { TMutAccountStorePriv *priv = TMUT_ACCOUNT_STORE_GET_PRIVATE (self); return g_object_ref (priv->device); } static gboolean tmut_account_store_alert (TnyAccountStore *self, TnyAccount *account, TnyAlertType type, gboolean question, GError *error) { TMutAccountStorePriv *priv = TMUT_ACCOUNT_STORE_GET_PRIVATE (self); GtkMessageType gtktype; gboolean retval = FALSE; GtkWidget *dialog; switch (type) { case TNY_ALERT_TYPE_INFO: gtktype = GTK_MESSAGE_INFO; break; case TNY_ALERT_TYPE_WARNING: gtktype = GTK_MESSAGE_WARNING; break; case TNY_ALERT_TYPE_ERROR: default: gtktype = GTK_MESSAGE_ERROR; break; } dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, gtktype, GTK_BUTTONS_YES_NO, error->message); if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES) retval = TRUE; gtk_widget_destroy (dialog); return retval; } static TnyAccount* tmut_account_store_find_account (TnyAccountStore *self, const gchar *url_string) { TMutAccountStorePriv *priv = TMUT_ACCOUNT_STORE_GET_PRIVATE (self); TnyAccount *found = NULL; if (!priv->accounts) load_accounts (self); if (priv->accounts) { GList *copy = priv->accounts; while (copy) { TnyAccount *account = copy->data; if (tny_account_matches_url_string (account, url_string)) { found = TNY_ACCOUNT (g_object_ref (G_OBJECT (account))); break; } copy = g_list_next (copy); } } return found; } static void tmut_account_store_finalize (GObject *object) { TMutAccountStorePriv *priv = TMUT_ACCOUNT_STORE_GET_PRIVATE (object); kill_stored_accounts (priv); if (priv->cache_dir) g_free (priv->cache_dir); g_object_unref (priv->device); parent_class->finalize (object); } TnyAccountStore* tmut_account_store_new (void) { TMutAccountStore *self = g_object_new (TMUT_TYPE_ACCOUNT_STORE, NULL); TMutAccountStorePriv *priv = TMUT_ACCOUNT_STORE_GET_PRIVATE (self); priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE (self)); tny_session_camel_set_ui_locker (priv->session, tny_gtk_lockable_new ()); return TNY_ACCOUNT_STORE (self); } static void tmut_account_store_instance_init (GTypeInstance *instance, gpointer g_class) { TMutAccountStorePriv *priv = TMUT_ACCOUNT_STORE_GET_PRIVATE (instance); TnyPlatformFactory *platfact = tmut_platform_factory_get_instance (); priv->cache_dir = NULL; priv->accounts = NULL; priv->device = tny_platform_factory_new_device (platfact); return; } static void tny_account_store_init (TnyAccountStoreIface *klass) { klass->get_accounts = tmut_account_store_get_accounts; klass->get_cache_dir = tmut_account_store_get_cache_dir; klass->get_device = tmut_account_store_get_device; klass->alert = tmut_account_store_alert; klass->find_account = tmut_account_store_find_account; } static void tmut_account_store_class_init (TMutAccountStoreClass *klass) { GObjectClass *object_class; parent_class = g_type_class_peek_parent (klass); object_class = (GObjectClass*) klass; object_class->finalize = tmut_account_store_finalize; g_type_class_add_private (object_class, sizeof (TMutAccountStorePriv)); } static void tmut_account_store_base_init (gpointer g_class) { static gboolean tmut_account_store_initialized = FALSE; if (!tmut_account_store_initialized) { tmut_account_store_signals[TMUT_ACCOUNT_STORE_ACCOUNT_DELETED] = g_signal_new ("account_deleted", TMUT_TYPE_ACCOUNT_STORE, G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (TMutAccountStoreClass, account_deleted), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT); tmut_account_store_signals[TMUT_ACCOUNT_STORE_ACCOUNT_EDITED] = g_signal_new ("account_edited", TMUT_TYPE_ACCOUNT_STORE, G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (TMutAccountStoreClass, account_edited), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT); tmut_account_store_signals[TMUT_ACCOUNT_STORE_ACCOUNT_CREATED] = g_signal_new ("account_created", TMUT_TYPE_ACCOUNT_STORE, G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (TMutAccountStoreClass, account_created), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT); tmut_account_store_initialized = TRUE; } } GType tmut_account_store_get_type (void) { static GType type = 0; if (G_UNLIKELY(type == 0)) { static const GTypeInfo info = { sizeof (TMutAccountStoreClass), tmut_account_store_base_init, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) tmut_account_store_class_init, /* class_init */ NULL, /* class_finalize */ NULL, /* class_data */ sizeof (TMutAccountStore), 0, /* n_preallocs */ tmut_account_store_instance_init, /* instance_init */ NULL }; static const GInterfaceInfo tny_account_store_info = { (GInterfaceInitFunc) tny_account_store_init, /* interface_init */ NULL, /* interface_finalize */ NULL /* interface_data */ }; type = g_type_register_static (G_TYPE_OBJECT, "TMutAccountStore", &info, 0); g_type_add_interface_static (type, TNY_TYPE_ACCOUNT_STORE, &tny_account_store_info); } return type; }