1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <tny-account.h>
34 #include <tny-account-store.h>
35 #include <tny-store-account.h>
36 #include <tny-error.h>
37 #include <tny-transport-account.h>
38 #include <tny-simple-list.h>
39 #include <tny-account-store.h>
40 #include <tny-camel-transport-account.h>
41 #include <tny-camel-imap-store-account.h>
42 #include <tny-camel-pop-store-account.h>
44 #include <modest-runtime.h>
45 #include <modest-marshal.h>
46 #include <modest-protocol-info.h>
47 #include <modest-local-folder-info.h>
48 #include <modest-tny-account.h>
49 #include <modest-tny-local-folders-account.h>
50 #include <modest-account-mgr.h>
51 #include <modest-account-mgr-helpers.h>
52 #include <widgets/modest-window-mgr.h>
53 #include <modest-account-settings-dialog.h>
54 #include <maemo/modest-maemo-utils.h>
57 #include "modest-tny-account-store.h"
58 #include "modest-tny-platform-factory.h"
59 #include <tny-gtk-lockable.h>
60 #include <camel/camel.h>
61 #include <modest-platform.h>
63 #ifdef MODEST_PLATFORM_MAEMO
64 #include <tny-maemo-conic-device.h>
67 #include <libgnomevfs/gnome-vfs-volume-monitor.h>
69 /* 'private'/'protected' functions */
70 static void modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass);
71 static void modest_tny_account_store_finalize (GObject *obj);
72 static void modest_tny_account_store_instance_init (ModestTnyAccountStore *obj);
73 static void modest_tny_account_store_init (gpointer g, gpointer iface_data);
74 static void modest_tny_account_store_base_init (gpointer g_class);
76 static void on_account_inserted (ModestAccountMgr *acc_mgr,
80 static void add_existing_accounts (ModestTnyAccountStore *self);
82 static void insert_account (ModestTnyAccountStore *self,
86 static void on_account_removed (ModestAccountMgr *acc_mgr,
90 static gchar* get_password (TnyAccount *account,
91 const gchar * prompt_not_used,
94 static void forget_password (TnyAccount *account);
96 static void on_vfs_volume_mounted (GnomeVFSVolumeMonitor *volume_monitor,
97 GnomeVFSVolume *volume,
100 static void on_vfs_volume_unmounted (GnomeVFSVolumeMonitor *volume_monitor,
101 GnomeVFSVolume *volume,
104 static void modest_tny_account_store_forget_password_in_memory (ModestTnyAccountStore *self,
105 const gchar *server_account_name);
107 static void add_connection_specific_transport_accounts (ModestTnyAccountStore *self);
109 /* list my signals */
111 ACCOUNT_CHANGED_SIGNAL,
112 ACCOUNT_INSERTED_SIGNAL,
113 ACCOUNT_REMOVED_SIGNAL,
115 PASSWORD_REQUESTED_SIGNAL,
119 typedef struct _ModestTnyAccountStorePrivate ModestTnyAccountStorePrivate;
120 struct _ModestTnyAccountStorePrivate {
122 GHashTable *password_hash;
123 GHashTable *account_settings_dialog_hash;
124 ModestAccountMgr *account_mgr;
125 TnySessionCamel *session;
128 gulong acc_inserted_handler;
129 gulong acc_changed_handler;
130 gulong acc_removed_handler;
131 gulong volume_mounted_handler;
132 gulong volume_unmounted_handler;
134 /* We cache the lists of accounts here */
135 TnyList *store_accounts;
136 TnyList *transport_accounts;
137 TnyList *store_accounts_outboxes;
139 /* Matches transport accounts and outbox folder */
140 GHashTable *outbox_of_transport;
143 #define MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
144 MODEST_TYPE_TNY_ACCOUNT_STORE, \
145 ModestTnyAccountStorePrivate))
148 static GObjectClass *parent_class = NULL;
150 static guint signals[LAST_SIGNAL] = {0};
153 modest_tny_account_store_get_type (void)
155 static GType my_type = 0;
158 static const GTypeInfo my_info = {
159 sizeof(ModestTnyAccountStoreClass),
160 modest_tny_account_store_base_init, /* base init */
161 NULL, /* base finalize */
162 (GClassInitFunc) modest_tny_account_store_class_init,
163 NULL, /* class finalize */
164 NULL, /* class data */
165 sizeof(ModestTnyAccountStore),
167 (GInstanceInitFunc) modest_tny_account_store_instance_init,
171 static const GInterfaceInfo iface_info = {
172 (GInterfaceInitFunc) modest_tny_account_store_init,
173 NULL, /* interface_finalize */
174 NULL /* interface_data */
177 my_type = g_type_register_static (G_TYPE_OBJECT,
178 "ModestTnyAccountStore",
180 g_type_add_interface_static (my_type, TNY_TYPE_ACCOUNT_STORE,
188 modest_tny_account_store_base_init (gpointer g_class)
190 static gboolean tny_account_store_initialized = FALSE;
192 if (!tny_account_store_initialized) {
194 signals[ACCOUNT_CHANGED_SIGNAL] =
195 g_signal_new ("account_changed",
196 MODEST_TYPE_TNY_ACCOUNT_STORE,
198 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_changed),
200 g_cclosure_marshal_VOID__OBJECT,
201 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
203 signals[ACCOUNT_INSERTED_SIGNAL] =
204 g_signal_new ("account_inserted",
205 MODEST_TYPE_TNY_ACCOUNT_STORE,
207 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_inserted),
209 g_cclosure_marshal_VOID__OBJECT,
210 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
212 signals[ACCOUNT_REMOVED_SIGNAL] =
213 g_signal_new ("account_removed",
214 MODEST_TYPE_TNY_ACCOUNT_STORE,
216 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_removed),
218 g_cclosure_marshal_VOID__OBJECT,
219 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
221 /* signals[TNY_ACCOUNT_STORE_CONNECTING_FINISHED] = */
222 /* g_signal_new ("connecting_finished", */
223 /* TNY_TYPE_ACCOUNT_STORE, */
224 /* G_SIGNAL_RUN_FIRST, */
225 /* G_STRUCT_OFFSET (TnyAccountStoreIface, connecting_finished), */
227 /* g_cclosure_marshal_VOID__VOID, */
228 /* G_TYPE_NONE, 0); */
230 signals[PASSWORD_REQUESTED_SIGNAL] =
231 g_signal_new ("password_requested",
232 MODEST_TYPE_TNY_ACCOUNT_STORE,
234 G_STRUCT_OFFSET(ModestTnyAccountStoreClass, password_requested),
236 modest_marshal_VOID__STRING_POINTER_POINTER_POINTER_POINTER,
237 G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER,
240 tny_account_store_initialized = TRUE;
246 modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass)
248 GObjectClass *gobject_class;
249 gobject_class = (GObjectClass*) klass;
251 parent_class = g_type_class_peek_parent (klass);
252 gobject_class->finalize = modest_tny_account_store_finalize;
254 g_type_class_add_private (gobject_class,
255 sizeof(ModestTnyAccountStorePrivate));
259 modest_tny_account_store_instance_init (ModestTnyAccountStore *obj)
261 GnomeVFSVolumeMonitor* monitor = NULL;
262 ModestTnyAccountStorePrivate *priv;
264 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
266 priv->cache_dir = NULL;
267 priv->account_mgr = NULL;
268 priv->session = NULL;
271 priv->outbox_of_transport = g_hash_table_new_full (g_direct_hash,
276 /* An in-memory store of passwords,
277 * for passwords that are not remembered in the configuration,
278 * so they need to be asked for from the user once in each session:
280 priv->password_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
283 /* A hash-map of modest account names to dialog pointers,
284 * so we can avoid showing the account settings twice for the same modest account: */
285 priv->account_settings_dialog_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
288 /* Respond to volume mounts and unmounts, such
289 * as the insertion/removal of the memory card: */
290 /* This is a singleton, so it does not need to be unrefed. */
291 monitor = gnome_vfs_get_volume_monitor();
293 priv->volume_mounted_handler = g_signal_connect (G_OBJECT(monitor),
295 G_CALLBACK(on_vfs_volume_mounted),
298 priv->volume_unmounted_handler = g_signal_connect (G_OBJECT(monitor), "volume-unmounted",
299 G_CALLBACK(on_vfs_volume_unmounted),
303 /* disconnect the list of TnyAccounts */
305 foreach_account_disconnect (gpointer data,
308 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(data), FALSE, NULL, NULL);
313 foreach_account_append_to_list (gpointer data,
318 list = TNY_LIST (user_data);
319 tny_list_append (list, G_OBJECT (data));
322 /********************************************************************/
323 /* Control the state of the MMC local account */
324 /********************************************************************/
326 /** Only call this if the memory card is really mounted.
329 add_mmc_account(ModestTnyAccountStore *self, gboolean emit_insert_signal)
331 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
332 g_return_if_fail (priv->session);
334 TnyAccount *mmc_account = modest_tny_account_new_for_local_folders (priv->account_mgr,
336 MODEST_MCC1_VOLUMEPATH);
338 /* Add to the list of store accounts */
339 tny_list_append (priv->store_accounts, G_OBJECT (mmc_account));
341 if (emit_insert_signal) {
342 g_signal_emit (G_OBJECT (self),
343 signals [ACCOUNT_INSERTED_SIGNAL],
348 g_object_unref (mmc_account);
352 on_vfs_volume_mounted(GnomeVFSVolumeMonitor *volume_monitor,
353 GnomeVFSVolume *volume,
356 ModestTnyAccountStore *self;
357 ModestTnyAccountStorePrivate *priv;
361 self = MODEST_TNY_ACCOUNT_STORE(user_data);
362 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
364 /* Check whether this was the external MMC1 card: */
365 uri = gnome_vfs_volume_get_activation_uri (volume);
367 if (uri && (!strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI))) {
368 add_mmc_account (self, TRUE /* emit the insert signal. */);
375 on_vfs_volume_unmounted(GnomeVFSVolumeMonitor *volume_monitor,
376 GnomeVFSVolume *volume,
379 ModestTnyAccountStore *self;
380 ModestTnyAccountStorePrivate *priv;
383 self = MODEST_TNY_ACCOUNT_STORE(user_data);
384 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
386 /* Check whether this was the external MMC1 card: */
387 uri = gnome_vfs_volume_get_activation_uri (volume);
388 if (uri && (strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI) == 0)) {
389 TnyAccount *mmc_account = NULL;
390 gboolean found = FALSE;
391 TnyIterator *iter = NULL;
393 iter = tny_list_create_iterator (priv->store_accounts);
394 while (!tny_iterator_is_done (iter) && !found) {
397 account = TNY_ACCOUNT (tny_iterator_get_current (iter));
398 if (modest_tny_account_is_memory_card_account (account)) {
400 mmc_account = g_object_ref (account);
402 g_object_unref (account);
403 tny_iterator_next (iter);
405 g_object_unref (iter);
408 /* Remove from the list */
409 tny_list_remove (priv->store_accounts, G_OBJECT (mmc_account));
411 /* Notify observers */
412 g_signal_emit (G_OBJECT (self),
413 signals [ACCOUNT_REMOVED_SIGNAL],
416 g_object_unref (mmc_account);
418 g_warning ("%s: there was no store account for the unmounted MMC",
426 * modest_tny_account_store_forget_password_in_memory
427 * @self: a TnyAccountStore instance
428 * @account: A server account.
430 * Forget any password stored in memory for this account.
431 * For instance, this should be called when the user has changed the password in the account settings.
434 modest_tny_account_store_forget_password_in_memory (ModestTnyAccountStore *self, const gchar * server_account_name)
436 /* printf ("DEBUG: %s\n", __FUNCTION__); */
437 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
439 if (server_account_name && priv->password_hash) {
440 g_hash_table_remove (priv->password_hash, server_account_name);
446 update_tny_account_for_account (ModestTnyAccountStore *self, ModestAccountMgr *acc_mgr,
447 const gchar *account_name, TnyAccountType type)
449 ModestTnyAccountStorePrivate *priv;
450 TnyList* account_list;
451 gboolean found = FALSE;
452 TnyIterator *iter = NULL;
454 g_return_val_if_fail (self, FALSE);
455 g_return_val_if_fail (account_name, FALSE);
456 g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE ||
457 type == TNY_ACCOUNT_TYPE_TRANSPORT,
460 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
461 account_list = (type == TNY_ACCOUNT_TYPE_STORE ? priv->store_accounts : priv->transport_accounts);
463 iter = tny_list_create_iterator (account_list);
464 while (!tny_iterator_is_done (iter) && !found) {
465 TnyAccount *tny_account;
466 tny_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
468 const gchar* parent_name =
469 modest_tny_account_get_parent_modest_account_name_for_server_account (tny_account);
470 if (parent_name && strcmp (parent_name, account_name) == 0) {
472 modest_tny_account_update_from_account (tny_account, acc_mgr, account_name, type);
473 g_signal_emit (G_OBJECT(self), signals[ACCOUNT_CHANGED_SIGNAL], 0, tny_account);
475 g_object_unref (tny_account);
477 tny_iterator_next (iter);
481 g_object_unref (iter);
488 on_account_changed (ModestAccountMgr *acc_mgr,
489 const gchar *account_name,
492 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
494 g_debug ("DEBUG: modest: %s\n", __FUNCTION__);
496 /* Ignore the change if it's a change in the last_updated value */
497 // if (key && g_str_has_suffix ((const gchar *) key, MODEST_ACCOUNT_LAST_UPDATED))
500 if (!update_tny_account_for_account (self, acc_mgr, account_name, TNY_ACCOUNT_TYPE_STORE))
501 g_warning ("%s: failed to update store account for %s", __FUNCTION__, account_name);
502 if (!update_tny_account_for_account (self, acc_mgr, account_name, TNY_ACCOUNT_TYPE_TRANSPORT))
503 g_warning ("%s: failed to update transport account for %s", __FUNCTION__, account_name);
507 on_account_settings_hide (GtkWidget *widget, gpointer user_data)
509 TnyAccount *account = (TnyAccount*)user_data;
511 /* This is easier than using a struct for the user_data: */
512 ModestTnyAccountStore *self = modest_runtime_get_account_store();
513 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
515 const gchar *modest_account_name =
516 modest_tny_account_get_parent_modest_account_name_for_server_account (account);
517 if (modest_account_name)
518 g_hash_table_remove (priv->account_settings_dialog_hash, modest_account_name);
522 show_password_warning_only ()
524 ModestWindow *main_window =
525 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ());
527 /* Show an explanatory temporary banner: */
528 hildon_banner_show_information (
529 GTK_WIDGET(main_window), NULL, _("mcen_ib_username_pw_incorrect"));
533 show_wrong_password_dialog (TnyAccount *account)
535 /* This is easier than using a struct for the user_data: */
536 ModestTnyAccountStore *self = modest_runtime_get_account_store();
537 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
539 const gchar *modest_account_name =
540 modest_tny_account_get_parent_modest_account_name_for_server_account (account);
541 if (!modest_account_name) {
542 g_warning ("%s: modest_tny_account_get_parent_modest_account_name_for_server_account() failed.\n",
546 /* Check whether this window is already open,
547 * for instance because of a previous get_password() call:
549 gpointer dialog_as_gpointer = NULL;
550 gboolean found = FALSE;
551 if (priv->account_settings_dialog_hash) {
552 found = g_hash_table_lookup_extended (priv->account_settings_dialog_hash,
553 modest_account_name, NULL, (gpointer*)&dialog_as_gpointer);
555 ModestAccountSettingsDialog *dialog = dialog_as_gpointer;
557 ModestWindow *main_window =
558 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ());
560 gboolean created_dialog = FALSE;
561 if (!found || !dialog) {
562 dialog = modest_account_settings_dialog_new ();
563 modest_account_settings_dialog_set_account_name (dialog, modest_account_name);
564 modest_account_settings_dialog_switch_to_user_info (dialog);
566 g_hash_table_insert (priv->account_settings_dialog_hash, g_strdup (modest_account_name), dialog);
568 created_dialog = TRUE;
571 /* Show an explanatory temporary banner: */
572 hildon_banner_show_information (
573 GTK_WIDGET(dialog), NULL, _("mcen_ib_username_pw_incorrect"));
575 if (created_dialog) {
576 /* Forget it when it closes: */
577 g_signal_connect_object (G_OBJECT (dialog), "hide", G_CALLBACK (on_account_settings_hide),
580 /* Show it and delete it when it closes: */
581 modest_maemo_show_dialog_and_forget (GTK_WINDOW (main_window), GTK_DIALOG (dialog));
584 /* Just show it instead of showing it and deleting it when it closes,
585 * though it is probably open already: */
586 gtk_window_present (GTK_WINDOW (dialog));
593 request_password_and_wait (ModestTnyAccountStore *account_store,
594 const gchar* server_account_id,
600 g_signal_emit (G_OBJECT(account_store), signals[PASSWORD_REQUESTED_SIGNAL], 0,
601 server_account_id, /* server_account_name */
602 username, password, cancel, remember);
605 /* This callback will be called by Tinymail when it needs the password
606 * from the user or the account settings.
607 * It can also call forget_password() before calling this,
608 * so that we clear wrong passwords out of our account settings.
609 * Note that TnyAccount here will be the server account. */
611 get_password (TnyAccount *account, const gchar * prompt_not_used, gboolean *cancel)
613 /* TODO: Settting cancel to FALSE does not actually cancel everything.
614 * We still get multiple requests afterwards, so we end up showing the
615 * same dialogs repeatedly.
618 printf ("DEBUG: modest: %s: prompt (not shown) = %s\n", __FUNCTION__, prompt_not_used);
620 g_return_val_if_fail (account, NULL);
622 const TnyAccountStore *account_store = NULL;
623 ModestTnyAccountStore *self = NULL;
624 ModestTnyAccountStorePrivate *priv;
625 gchar *username = NULL;
627 gpointer pwd_ptr = NULL;
628 gboolean already_asked = FALSE;
630 /* Initialize the output parameter: */
634 const gchar *server_account_name = tny_account_get_id (account);
635 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
638 if (!server_account_name || !account_store) {
639 g_warning ("modest: %s: could not retrieve account_store for account %s",
640 __FUNCTION__, server_account_name ? server_account_name : "<NULL>");
647 self = MODEST_TNY_ACCOUNT_STORE (account_store);
648 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
650 /* This hash map stores passwords, including passwords that are not stored in gconf. */
651 /* Is it in the hash? if it's already there, it must be wrong... */
652 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
653 * type-punned ptrs...*/
654 already_asked = priv->password_hash &&
655 g_hash_table_lookup_extended (priv->password_hash,
658 (gpointer*)&pwd_ptr);
660 printf ("DEBUG: modest: %s: Already asked = %d\n", __FUNCTION__, already_asked);
662 /* If the password is not already there, try ModestConf */
663 if (!already_asked) {
664 pwd = modest_server_account_get_password (priv->account_mgr,
665 server_account_name);
666 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup (pwd));
669 /* If it was already asked, it must have been wrong, so ask again */
670 if (already_asked || !pwd || strlen(pwd) == 0) {
671 /* As per the UI spec, if no password was set in the account settings,
672 * ask for it now. But if the password is wrong in the account settings,
673 * then show a banner and the account settings dialog so it can be corrected:
675 const gboolean settings_have_password =
676 modest_server_account_get_has_password (priv->account_mgr, server_account_name);
677 printf ("DEBUG: modest: %s: settings_have_password=%d\n", __FUNCTION__, settings_have_password);
678 if (settings_have_password) {
679 /* The password must be wrong, so show the account settings dialog so it can be corrected: */
680 show_wrong_password_dialog (account);
688 /* we don't have it yet. Get the password from the user */
689 const gchar* account_id = tny_account_get_id (account);
690 gboolean remember = FALSE;
694 /* Show an info banner, before we show the protected password dialog: */
695 show_password_warning_only();
698 request_password_and_wait (self, account_id,
699 &username, &pwd, cancel, &remember);
702 /* The password will be returned as the result,
703 * but we need to tell tinymail about the username too: */
704 tny_account_set_user (account, username);
706 /* Do not save the password in gconf,
707 * because the UI spec says "The password will never be saved in the account": */
710 printf ("%s: Storing username=%s, password=%s\n",
711 __FUNCTION__, username, pwd);
712 modest_server_account_set_username (priv->account_mgr, server_account_name,
714 modest_server_account_set_password (priv->account_mgr, server_account_name,
719 /* We need to dup the string even knowing that
720 it's already a dup of the contents of an
721 entry, because it if it's wrong, then camel
723 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup(pwd));
725 g_hash_table_remove (priv->password_hash, server_account_name);
736 /* printf(" DEBUG: %s: returning %s\n", __FUNCTION__, pwd); */
741 /* tinymail calls this if the connection failed due to an incorrect password.
742 * And it seems to call this for any general connection failure. */
744 forget_password (TnyAccount *account)
746 printf ("DEBUG: %s\n", __FUNCTION__);
747 ModestTnyAccountStore *self;
748 ModestTnyAccountStorePrivate *priv;
749 const TnyAccountStore *account_store;
753 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
755 self = MODEST_TNY_ACCOUNT_STORE (account_store);
756 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
757 key = tny_account_get_id (account);
759 /* Do not remove the key, this will allow us to detect that we
760 have already asked for it at least once */
761 pwd = g_hash_table_lookup (priv->password_hash, key);
763 memset (pwd, 0, strlen (pwd));
764 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
767 /* Remove from configuration system */
769 modest_account_mgr_unset (priv->account_mgr,
770 key, MODEST_ACCOUNT_PASSWORD, TRUE);
775 modest_tny_account_store_finalize (GObject *obj)
777 GnomeVFSVolumeMonitor *volume_monitor;
778 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(obj);
779 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
781 g_free (priv->cache_dir);
782 priv->cache_dir = NULL;
784 if (priv->password_hash) {
785 g_hash_table_destroy (priv->password_hash);
786 priv->password_hash = NULL;
789 if (priv->account_settings_dialog_hash) {
790 g_hash_table_destroy (priv->account_settings_dialog_hash);
791 priv->account_settings_dialog_hash = NULL;
794 if (priv->outbox_of_transport) {
795 g_hash_table_destroy (priv->outbox_of_transport);
796 priv->outbox_of_transport = NULL;
800 /* Disconnect VFS signals */
801 volume_monitor = gnome_vfs_get_volume_monitor ();
802 if (g_signal_handler_is_connected (volume_monitor,
803 priv->volume_mounted_handler))
804 g_signal_handler_disconnect (volume_monitor,
805 priv->volume_mounted_handler);
806 if (g_signal_handler_is_connected (volume_monitor,
807 priv->volume_unmounted_handler))
808 g_signal_handler_disconnect (volume_monitor,
809 priv->volume_unmounted_handler);
811 if (priv->account_mgr) {
812 /* Disconnect signals */
813 if (g_signal_handler_is_connected (priv->account_mgr,
814 priv->acc_inserted_handler))
815 g_signal_handler_disconnect (priv->account_mgr,
816 priv->acc_inserted_handler);
817 if (g_signal_handler_is_connected (priv->account_mgr,
818 priv->acc_changed_handler))
819 g_signal_handler_disconnect (priv->account_mgr,
820 priv->acc_changed_handler);
821 if (g_signal_handler_is_connected (priv->account_mgr,
822 priv->acc_removed_handler))
823 g_signal_handler_disconnect (priv->account_mgr,
824 priv->acc_removed_handler);
826 g_object_unref (G_OBJECT(priv->account_mgr));
827 priv->account_mgr = NULL;
831 g_object_unref (G_OBJECT(priv->device));
835 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
836 if (priv->store_accounts) {
837 tny_list_foreach (priv->store_accounts, foreach_account_disconnect, NULL);
838 g_object_unref (priv->store_accounts);
839 priv->store_accounts = NULL;
842 if (priv->transport_accounts) {
843 tny_list_foreach (priv->transport_accounts, foreach_account_disconnect, NULL);
844 g_object_unref (priv->transport_accounts);
845 priv->transport_accounts = NULL;
848 if (priv->store_accounts_outboxes) {
849 g_object_unref (priv->store_accounts_outboxes);
850 priv->store_accounts_outboxes = NULL;
854 camel_object_unref (CAMEL_OBJECT(priv->session));
855 priv->session = NULL;
858 G_OBJECT_CLASS(parent_class)->finalize (obj);
862 volume_path_is_mounted (const gchar* path)
864 g_return_val_if_fail (path, FALSE);
866 gboolean result = FALSE;
867 gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
868 g_return_val_if_fail (path_as_uri, FALSE);
870 /* Get the monitor singleton: */
871 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
873 /* This seems like a simpler way to do this, but it returns a
874 * GnomeVFSVolume even if the drive is not mounted: */
876 GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor,
877 MODEST_MCC1_VOLUMEPATH);
879 gnome_vfs_volume_unref(volume);
883 /* Get the mounted volumes from the monitor: */
884 GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
886 for (iter = list; iter; iter = g_list_next (iter)) {
887 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
891 gnome_vfs_volume_get_display_name (volume);
892 printf ("volume display name=%s\n", display_name);
893 g_free (display_name);
897 gnome_vfs_volume_get_activation_uri (volume);
898 /* printf (" uri=%s\n", uri); */
899 if (uri && (strcmp (uri, path_as_uri) == 0))
904 gnome_vfs_volume_unref (volume);
910 g_free (path_as_uri);
915 ModestTnyAccountStore*
916 modest_tny_account_store_new (ModestAccountMgr *account_mgr,
920 ModestTnyAccountStorePrivate *priv;
921 TnyAccount *local_account = NULL;
923 g_return_val_if_fail (account_mgr, NULL);
924 g_return_val_if_fail (device, NULL);
926 obj = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
927 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
929 priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
930 priv->device = g_object_ref (device);
932 priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
933 if (!priv->session) {
934 g_warning ("failed to get TnySessionCamel");
938 /* Set the ui locker */
939 tny_session_camel_set_ui_locker (priv->session, tny_gtk_lockable_new ());
941 /* Connect signals */
942 priv->acc_inserted_handler = g_signal_connect (G_OBJECT(account_mgr), "account_inserted",
943 G_CALLBACK (on_account_inserted), obj);
944 priv->acc_changed_handler = g_signal_connect (G_OBJECT(account_mgr), "account_changed",
945 G_CALLBACK (on_account_changed), obj);
946 priv->acc_removed_handler = g_signal_connect (G_OBJECT(account_mgr), "account_removed",
947 G_CALLBACK (on_account_removed), obj);
949 /* Create the lists of accounts */
950 priv->store_accounts = tny_simple_list_new ();
951 priv->transport_accounts = tny_simple_list_new ();
952 priv->store_accounts_outboxes = tny_simple_list_new ();
954 /* Create the local folders account */
956 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
957 tny_list_append (priv->store_accounts, G_OBJECT(local_account));
958 g_object_unref (local_account);
960 /* Add the other remote accounts. Do this after adding the
961 local account, because we need to add our outboxes to the
962 global OUTBOX hosted in the local account */
963 add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
965 /* FIXME: I'm doing this (adding an "if (FALSE)"because this
966 stuff is not working properly and could cause SIGSEVs, for
967 example one send queue will be created for each connection
968 specific SMTP server, so when tinymail asks for the outbox
969 it will return NULL because there is no outbox folder for
970 this specific transport accounts, and it's a must that the
971 send queue returns an outbox */
973 /* Add connection-specific transport accounts */
974 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
976 /* This is a singleton, so it does not need to be unrefed. */
977 if (volume_path_is_mounted (MODEST_MCC1_VOLUMEPATH)) {
979 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */);
982 return MODEST_TNY_ACCOUNT_STORE(obj);
986 modest_tny_account_store_get_accounts (TnyAccountStore *self,
988 TnyGetAccountsRequestType request_type)
990 ModestTnyAccountStorePrivate *priv;
992 g_return_if_fail (self);
993 g_return_if_fail (TNY_IS_LIST(list));
995 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
997 switch (request_type) {
998 case TNY_ACCOUNT_STORE_BOTH:
999 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1000 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1002 case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
1003 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1005 case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
1006 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1009 g_return_if_reached ();
1012 /* Initialize session. Why do we need this ??? */
1013 tny_session_camel_set_initialized (priv->session);
1018 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1020 ModestTnyAccountStorePrivate *priv;
1021 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1023 if (!priv->cache_dir)
1024 priv->cache_dir = g_build_filename (g_get_home_dir(),
1025 MODEST_DIR, MODEST_CACHE_DIR, NULL);
1026 return priv->cache_dir;
1031 * callers need to unref
1034 modest_tny_account_store_get_device (TnyAccountStore *self)
1036 ModestTnyAccountStorePrivate *priv;
1038 g_return_val_if_fail (self, NULL);
1040 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1043 return g_object_ref (G_OBJECT(priv->device));
1050 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1052 return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self),
1053 MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1060 modest_tny_account_store_alert (TnyAccountStore *self,
1061 TnyAccount *account,
1064 const GError *error)
1066 ModestTransportStoreProtocol proto =
1067 MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
1068 const gchar* server_name = NULL;
1069 gchar *prompt = NULL;
1073 g_return_val_if_fail (account, FALSE);
1074 g_return_val_if_fail (error, FALSE);
1076 if ((error->domain != TNY_ACCOUNT_ERROR) && (error->domain != TNY_ACCOUNT_STORE_ERROR))
1079 /* Get the server name: */
1080 server_name = tny_account_get_hostname (account);
1083 const gchar *proto_name = tny_account_get_proto (account);
1085 proto = modest_protocol_info_get_transport_store_protocol (proto_name);
1087 g_warning("modest: %s: account with id=%s has no proto.\n", __FUNCTION__,
1088 tny_account_get_id (account));
1093 switch (error->code) {
1094 case TNY_ACCOUNT_STORE_ERROR_CANCEL_ALERT:
1095 case TNY_ACCOUNT_ERROR_TRY_CONNECT_USER_CANCEL:
1096 /* Don't show waste the user's time by showing him a dialog telling
1097 * him that he has just cancelled something: */
1100 case TNY_ACCOUNT_ERROR_TRY_CONNECT_HOST_LOOKUP_FAILED:
1101 case TNY_ACCOUNT_ERROR_TRY_CONNECT_SERVICE_UNAVAILABLE:
1102 /* TODO: Show the appropriate message, depending on whether it's POP or IMAP: */
1104 case MODEST_PROTOCOL_STORE_POP:
1105 prompt = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"),
1108 case MODEST_PROTOCOL_STORE_IMAP:
1109 prompt = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"),
1112 case MODEST_PROTOCOL_TRANSPORT_SMTP:
1113 prompt = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"),
1117 g_return_val_if_reached (FALSE);
1121 case TNY_ACCOUNT_ERROR_TRY_CONNECT_AUTHENTICATION_NOT_SUPPORTED:
1122 /* This is "Secure connection failed", even though the logical
1123 * ID has _certificate_ in the name: */
1124 prompt = g_strdup (_("mail_ni_ssl_certificate_error"));
1127 case TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE:
1128 /* We'll show the proper dialog later */
1131 case TNY_ACCOUNT_ERROR_TRY_CONNECT:
1132 /* The tinymail camel implementation just sends us this for almost
1133 * everything, so we have to guess at the cause.
1134 * It could be a wrong password, or inability to resolve a hostname,
1135 * or lack of network, or incorrect authentication method, or something entirely different: */
1136 /* TODO: Fix camel to provide specific error codes, and then use the
1137 * specific dialog messages from Chapter 12 of the UI spec.
1139 case TNY_ACCOUNT_STORE_ERROR_UNKNOWN_ALERT:
1142 g_return_val_if_reached (FALSE);
1146 if (error->code == TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE)
1147 retval = modest_platform_run_certificate_conformation_dialog (server_name,
1150 retval = modest_platform_run_alert_dialog (prompt, question);
1160 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1162 TnyAccountStoreIface *klass;
1164 g_return_if_fail (g);
1166 klass = (TnyAccountStoreIface *)g;
1168 klass->get_accounts_func =
1169 modest_tny_account_store_get_accounts;
1170 klass->get_cache_dir_func =
1171 modest_tny_account_store_get_cache_dir;
1172 klass->get_device_func =
1173 modest_tny_account_store_get_device;
1175 modest_tny_account_store_alert;
1176 klass->find_account_func =
1177 modest_tny_account_store_find_account_by_url;
1181 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1182 ModestTnyGetPassFunc func)
1184 /* not implemented, we use signals */
1185 g_printerr ("modest: set_get_pass_func not implemented\n");
1189 modest_tny_account_store_get_session (TnyAccountStore *self)
1191 g_return_val_if_fail (self, NULL);
1192 return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1196 get_tny_account_by (TnyList *accounts,
1197 ModestTnyAccountStoreQueryType type,
1200 TnyIterator *iter = NULL;
1201 gboolean found = FALSE;
1202 TnyAccount *retval = NULL;
1204 iter = tny_list_create_iterator (accounts);
1205 while (!tny_iterator_is_done (iter) && !found) {
1206 TnyAccount *tmp_account = NULL;
1207 const gchar *val = NULL;
1209 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1211 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1212 val = tny_account_get_id (tmp_account);
1214 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1215 val = tny_account_get_url_string (tmp_account);
1219 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL &&
1220 tny_account_matches_url_string (tmp_account, str)) {
1221 retval = g_object_ref (tmp_account);
1224 if (strcmp (val, str) == 0) {
1225 retval = g_object_ref (tmp_account);
1229 g_object_unref (tmp_account);
1230 tny_iterator_next (iter);
1232 g_object_unref (iter);
1238 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self,
1239 ModestTnyAccountStoreQueryType type,
1242 TnyAccount *account = NULL;
1243 ModestTnyAccountStorePrivate *priv;
1245 g_return_val_if_fail (self, NULL);
1246 g_return_val_if_fail (str, NULL);
1248 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1250 /* Search in store accounts */
1251 account = get_tny_account_by (priv->store_accounts, type, str);
1253 /* If we already found something, no need to search the transport accounts */
1255 account = get_tny_account_by (priv->transport_accounts, type, str);
1257 /* If we already found something, no need to search the
1258 per-account outbox accounts */
1260 account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1263 /* Warn if nothing was found. This is generally unusual. */
1265 g_warning("%s: Failed to find account with %s=%s\n",
1267 (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",
1271 /* Returns a new reference to the account if found */
1276 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1277 const gchar *account_name,
1278 TnyAccountType type)
1280 ModestTnyAccountStorePrivate *priv = NULL;
1281 TnyAccount *retval = NULL;
1282 TnyList *account_list = NULL;
1283 TnyIterator *iter = NULL;
1286 g_return_val_if_fail (self, NULL);
1287 g_return_val_if_fail (account_name, NULL);
1288 g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE ||
1289 type == TNY_ACCOUNT_TYPE_TRANSPORT,
1292 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1294 account_list = (type == TNY_ACCOUNT_TYPE_STORE) ?
1295 priv->store_accounts :
1296 priv->transport_accounts;
1298 if (!account_list) {
1299 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__,
1300 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1304 /* Look for the server account */
1306 iter = tny_list_create_iterator (account_list);
1307 while (!tny_iterator_is_done (iter) && !found) {
1308 const gchar *modest_acc_name;
1309 TnyAccount *tmp_account;
1311 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1313 modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1315 if (!strcmp (account_name, modest_acc_name)) {
1317 retval = g_object_ref (tmp_account);
1319 /* Free and continue */
1320 g_object_unref (tmp_account);
1321 tny_iterator_next (iter);
1325 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1326 "Number of server accounts of this type=%d\n", __FUNCTION__,
1327 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1328 account_name, tny_list_get_length (account_list));
1331 /* Returns a new reference */
1336 get_smtp_specific_transport_account_for_open_connection (ModestTnyAccountStore *self,
1337 const gchar *account_name)
1339 /* Get the current connection: */
1340 TnyDevice *device = modest_runtime_get_device ();
1342 if (!tny_device_is_online (device))
1345 g_return_val_if_fail (self, NULL);
1348 #ifdef MODEST_PLATFORM_MAEMO
1349 g_assert (TNY_IS_MAEMO_CONIC_DEVICE (device));
1350 TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);
1351 const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1352 /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1356 ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1360 const gchar *connection_name = con_ic_iap_get_name (connection);
1361 /* printf ("DEBUG: %s: connection_name=%s\n", __FUNCTION__, connection_name); */
1362 if (!connection_name)
1365 /* Get the connection-specific transport acccount, if any: */
1366 ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1368 /* Check if this account has connection-specific SMTP enabled */
1369 if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1373 gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager,
1376 /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1377 if (!server_account_name) {
1378 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1381 TnyAccount* account = modest_tny_account_store_get_tny_account_by (self,
1382 MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1383 server_account_name);
1385 /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1386 g_free (server_account_name);
1388 /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1389 g_object_unref (connection);
1393 return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1394 #endif /* MODEST_PLATFORM_MAEMO */
1399 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1400 const gchar *account_name)
1402 g_return_val_if_fail (self, NULL);
1403 g_return_val_if_fail (account_name, NULL);
1405 if (!account_name || !self)
1408 /* Get the connection-specific transport acccount, if any: */
1409 /* Note: This gives us a reference: */
1410 TnyAccount *account =
1411 get_smtp_specific_transport_account_for_open_connection (self, account_name);
1413 /* If there is no connection-specific transport account (the common case),
1414 * just get the regular transport account: */
1416 /* The special local folders don't have transport accounts. */
1417 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1420 /* Note: This gives us a reference: */
1421 account = modest_tny_account_store_get_server_account (self, account_name,
1422 TNY_ACCOUNT_TYPE_TRANSPORT);
1426 /* returns a reference. */
1431 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1433 TnyAccount *account = NULL;
1434 ModestTnyAccountStorePrivate *priv;
1438 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1440 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1443 iter = tny_list_create_iterator (priv->store_accounts);
1444 while (!tny_iterator_is_done (iter) && !found) {
1445 TnyAccount *tmp_account;
1447 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1448 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1449 account = g_object_ref (tmp_account);
1452 g_object_unref (tmp_account);
1453 tny_iterator_next (iter);
1455 g_object_unref (iter);
1457 /* Returns a new reference to the account */
1461 /*********************************************************************************/
1463 add_existing_accounts (ModestTnyAccountStore *self)
1465 GSList *account_names = NULL, *iter = NULL;
1466 ModestTnyAccountStorePrivate *priv = NULL;
1468 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1470 /* These are account names, not server_account names */
1471 account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1473 for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1474 const gchar *account_name = (const gchar*) iter->data;
1476 /* Insert all enabled accounts without notifying */
1477 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1478 insert_account (self, account_name, FALSE);
1480 modest_account_mgr_free_account_names (account_names);
1484 create_tny_account (ModestTnyAccountStore *self,
1486 TnyAccountType type)
1488 TnyAccount *account = NULL;
1489 ModestTnyAccountStorePrivate *priv = NULL;
1491 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1493 account = modest_tny_account_new_from_account (priv->account_mgr,
1500 /* Forget any cached password for the account, so that
1501 we use a new account if any */
1502 modest_tny_account_store_forget_password_in_memory (self,
1503 tny_account_get_id (account));
1504 /* Set the account store */
1505 g_object_set_data (G_OBJECT(account), "account_store", self);
1507 g_printerr ("modest: failed to create account for %s\n", name);
1515 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1516 const gchar *account_name,
1517 TnyAccount *transport_account)
1519 TnyList *folders = NULL;
1520 TnyIterator *iter_folders = NULL;
1521 TnyAccount *local_account = NULL, *account_outbox = NULL;
1522 TnyFolder *per_account_outbox = NULL;
1523 ModestTnyAccountStorePrivate *priv = NULL;
1525 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1527 /* Create per account local outbox */
1529 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr,
1532 tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1534 /* Get the outbox folder */
1535 folders = tny_simple_list_new ();
1536 tny_folder_store_get_folders (TNY_FOLDER_STORE (account_outbox), folders, NULL, NULL);
1537 g_assert (tny_list_get_length (folders) == 1);
1539 iter_folders = tny_list_create_iterator (folders);
1540 per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1541 g_object_unref (iter_folders);
1542 g_object_unref (folders);
1543 g_object_unref (account_outbox);
1545 /* Add the outbox of the new per-account-local-outbox account
1546 to the global local merged OUTBOX of the local folders
1548 local_account = modest_tny_account_store_get_local_folders_account (self);
1549 modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1550 per_account_outbox);
1551 /* Add the pair to the hash table */
1552 g_hash_table_insert (priv->outbox_of_transport,
1554 per_account_outbox);
1556 g_object_unref (local_account);
1557 g_object_unref (per_account_outbox);
1562 * This function will be used for both adding new accounts and for the
1563 * initialization. In the initialization we do not want to emit
1564 * signals so notify will be FALSE, in the case of account additions
1565 * we do want to notify the observers
1568 insert_account (ModestTnyAccountStore *self,
1569 const gchar *account,
1572 ModestTnyAccountStorePrivate *priv = NULL;
1573 TnyAccount *store_account = NULL, *transport_account = NULL;
1575 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1577 /* Get the server and the transport account */
1578 store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1579 transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1581 /* Add to the list, and notify the observers */
1582 if (store_account) {
1583 tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1585 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);
1586 g_object_unref (store_account);
1589 /* Add to the list, and notify the observers */
1590 if (transport_account) {
1591 /* Add account to the list */
1592 tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1593 g_assert (TNY_IS_ACCOUNT (transport_account));
1595 /* Create a new pseudo-account with an outbox for this
1596 transport account and add it to the global outbox
1597 in the local account */
1598 add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1601 TnyAccount *local_account = NULL;
1603 /* Notify that the local account changed */
1604 local_account = modest_tny_account_store_get_local_folders_account (self);
1605 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1606 g_object_unref (local_account);
1608 /* Notify the observers about the new account */
1609 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1612 g_object_unref (transport_account);
1617 on_account_inserted (ModestAccountMgr *acc_mgr,
1618 const gchar *account,
1621 /* Insert the account and notify the observers */
1622 insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1626 on_account_removed (ModestAccountMgr *acc_mgr,
1627 const gchar *account,
1630 TnyAccount *store_account = NULL, *transport_account = NULL;
1631 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
1633 /* Get the server and the transport account */
1635 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1637 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1639 /* If there was any problem creating the account, for example,
1640 with the configuration system this could not exist */
1641 if (store_account) {
1642 /* Clear the cache */
1643 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (store_account));
1645 /* Notify the observers */
1646 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, store_account);
1647 g_object_unref (store_account);
1649 g_warning ("There is no store account for account %s\n", account);
1652 /* If there was any problem creating the account, for example,
1653 with the configuration system this could not exist */
1654 if (transport_account) {
1655 TnyAccount *local_account = NULL;
1656 TnyFolder *outbox = NULL;
1657 ModestTnyAccountStorePrivate *priv = NULL;
1659 /* Remove the OUTBOX of the account from the global outbox */
1660 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1661 outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
1663 if (TNY_IS_FOLDER (outbox)) {
1664 local_account = modest_tny_account_store_get_local_folders_account (self);
1665 modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1667 g_hash_table_remove (priv->outbox_of_transport, transport_account);
1669 /* Notify the change in the local account */
1670 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1671 g_object_unref (local_account);
1673 g_warning ("Removing a transport account that has no outbox");
1676 /* Notify the observers */
1677 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, transport_account);
1678 g_object_unref (transport_account);
1680 g_warning ("There is no transport account for account %s\n", account);
1685 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1687 ModestTnyAccountStorePrivate *priv = NULL;
1688 GSList *list_specifics = NULL, *iter = NULL;
1690 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1692 ModestConf *conf = modest_runtime_get_conf ();
1695 list_specifics = modest_conf_get_list (conf,
1696 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
1697 MODEST_CONF_VALUE_STRING, &err);
1699 g_printerr ("modest: %s: error getting list: %s\n.", __FUNCTION__, err->message);
1704 /* Look at each connection-specific transport account for the
1705 * modest account: */
1706 iter = list_specifics;
1708 /* The list alternates between the connection name and the transport name: */
1709 iter = g_slist_next (iter);
1711 const gchar* transport_account_name = (const gchar*) (iter->data);
1712 if (transport_account_name) {
1713 TnyAccount * tny_account = NULL;
1714 /* Add the account: */
1716 modest_tny_account_new_from_server_account_name (priv->account_mgr,
1718 transport_account_name);
1720 g_object_set_data (G_OBJECT(tny_account),
1724 tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1725 g_object_unref (tny_account);
1727 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1728 transport_account_name);
1731 iter = g_slist_next (iter);