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>
55 #include <modest-signal-mgr.h>
56 #include <modest-debug.h>
58 #include "modest-tny-account-store.h"
59 #include "modest-tny-platform-factory.h"
60 #include <tny-gtk-lockable.h>
61 #include <camel/camel.h>
62 #include <modest-platform.h>
64 #ifdef MODEST_PLATFORM_MAEMO
65 #include <tny-maemo-conic-device.h>
68 #include <libgnomevfs/gnome-vfs-volume-monitor.h>
70 /* 'private'/'protected' functions */
71 static void modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass);
72 static void modest_tny_account_store_finalize (GObject *obj);
73 static void modest_tny_account_store_instance_init (ModestTnyAccountStore *obj);
74 static void modest_tny_account_store_init (gpointer g, gpointer iface_data);
75 static void modest_tny_account_store_base_init (gpointer g_class);
77 static void on_account_inserted (ModestAccountMgr *acc_mgr,
81 static void add_existing_accounts (ModestTnyAccountStore *self);
83 static void insert_account (ModestTnyAccountStore *self,
87 static void on_account_removed (ModestAccountMgr *acc_mgr,
91 static gchar* get_password (TnyAccount *account,
92 const gchar * prompt_not_used,
95 static void forget_password (TnyAccount *account);
97 static void on_vfs_volume_mounted (GnomeVFSVolumeMonitor *volume_monitor,
98 GnomeVFSVolume *volume,
101 static void on_vfs_volume_unmounted (GnomeVFSVolumeMonitor *volume_monitor,
102 GnomeVFSVolume *volume,
105 static void modest_tny_account_store_forget_password_in_memory (ModestTnyAccountStore *self,
106 const gchar *server_account_name);
108 static void add_connection_specific_transport_accounts (ModestTnyAccountStore *self);
110 /* list my signals */
112 ACCOUNT_CHANGED_SIGNAL,
113 ACCOUNT_INSERTED_SIGNAL,
114 ACCOUNT_REMOVED_SIGNAL,
116 PASSWORD_REQUESTED_SIGNAL,
120 typedef struct _ModestTnyAccountStorePrivate ModestTnyAccountStorePrivate;
121 struct _ModestTnyAccountStorePrivate {
123 GHashTable *password_hash;
124 GHashTable *account_settings_dialog_hash;
125 ModestAccountMgr *account_mgr;
126 TnySessionCamel *session;
131 /* We cache the lists of accounts here */
132 TnyList *store_accounts;
133 TnyList *transport_accounts;
134 TnyList *store_accounts_outboxes;
136 /* Matches transport accounts and outbox folder */
137 GHashTable *outbox_of_transport;
140 #define MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
141 MODEST_TYPE_TNY_ACCOUNT_STORE, \
142 ModestTnyAccountStorePrivate))
145 static GObjectClass *parent_class = NULL;
147 static guint signals[LAST_SIGNAL] = {0};
150 modest_tny_account_store_get_type (void)
152 static GType my_type = 0;
155 static const GTypeInfo my_info = {
156 sizeof(ModestTnyAccountStoreClass),
157 modest_tny_account_store_base_init, /* base init */
158 NULL, /* base finalize */
159 (GClassInitFunc) modest_tny_account_store_class_init,
160 NULL, /* class finalize */
161 NULL, /* class data */
162 sizeof(ModestTnyAccountStore),
164 (GInstanceInitFunc) modest_tny_account_store_instance_init,
168 static const GInterfaceInfo iface_info = {
169 (GInterfaceInitFunc) modest_tny_account_store_init,
170 NULL, /* interface_finalize */
171 NULL /* interface_data */
174 my_type = g_type_register_static (G_TYPE_OBJECT,
175 "ModestTnyAccountStore",
177 g_type_add_interface_static (my_type, TNY_TYPE_ACCOUNT_STORE,
185 modest_tny_account_store_base_init (gpointer g_class)
187 static gboolean tny_account_store_initialized = FALSE;
189 if (!tny_account_store_initialized) {
191 signals[ACCOUNT_CHANGED_SIGNAL] =
192 g_signal_new ("account_changed",
193 MODEST_TYPE_TNY_ACCOUNT_STORE,
195 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_changed),
197 g_cclosure_marshal_VOID__OBJECT,
198 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
200 signals[ACCOUNT_INSERTED_SIGNAL] =
201 g_signal_new ("account_inserted",
202 MODEST_TYPE_TNY_ACCOUNT_STORE,
204 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_inserted),
206 g_cclosure_marshal_VOID__OBJECT,
207 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
209 signals[ACCOUNT_REMOVED_SIGNAL] =
210 g_signal_new ("account_removed",
211 MODEST_TYPE_TNY_ACCOUNT_STORE,
213 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_removed),
215 g_cclosure_marshal_VOID__OBJECT,
216 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
218 /* signals[TNY_ACCOUNT_STORE_CONNECTING_FINISHED] = */
219 /* g_signal_new ("connecting_finished", */
220 /* TNY_TYPE_ACCOUNT_STORE, */
221 /* G_SIGNAL_RUN_FIRST, */
222 /* G_STRUCT_OFFSET (TnyAccountStoreIface, connecting_finished), */
224 /* g_cclosure_marshal_VOID__VOID, */
225 /* G_TYPE_NONE, 0); */
227 signals[PASSWORD_REQUESTED_SIGNAL] =
228 g_signal_new ("password_requested",
229 MODEST_TYPE_TNY_ACCOUNT_STORE,
231 G_STRUCT_OFFSET(ModestTnyAccountStoreClass, password_requested),
233 modest_marshal_VOID__STRING_POINTER_POINTER_POINTER_POINTER,
234 G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER,
237 tny_account_store_initialized = TRUE;
243 modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass)
245 GObjectClass *gobject_class;
246 gobject_class = (GObjectClass*) klass;
248 parent_class = g_type_class_peek_parent (klass);
249 gobject_class->finalize = modest_tny_account_store_finalize;
251 g_type_class_add_private (gobject_class,
252 sizeof(ModestTnyAccountStorePrivate));
256 modest_tny_account_store_instance_init (ModestTnyAccountStore *obj)
258 GnomeVFSVolumeMonitor* monitor = NULL;
259 ModestTnyAccountStorePrivate *priv;
261 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
263 priv->cache_dir = NULL;
264 priv->account_mgr = NULL;
265 priv->session = NULL;
267 priv->sighandlers = NULL;
269 priv->outbox_of_transport = g_hash_table_new_full (g_direct_hash,
274 /* An in-memory store of passwords,
275 * for passwords that are not remembered in the configuration,
276 * so they need to be asked for from the user once in each session:
278 priv->password_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
281 /* A hash-map of modest account names to dialog pointers,
282 * so we can avoid showing the account settings twice for the same modest account: */
283 priv->account_settings_dialog_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
286 /* Respond to volume mounts and unmounts, such
287 * as the insertion/removal of the memory card: */
288 /* This is a singleton, so it does not need to be unrefed. */
289 monitor = gnome_vfs_get_volume_monitor();
291 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
294 G_CALLBACK(on_vfs_volume_mounted),
296 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
297 G_OBJECT(monitor), "volume-unmounted",
298 G_CALLBACK(on_vfs_volume_unmounted),
302 /* disconnect the list of TnyAccounts */
304 account_disconnect (TnyAccount *account)
306 g_return_if_fail (account && TNY_IS_ACCOUNT(account));
307 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(account), FALSE, NULL, NULL);
311 /* disconnect the list of TnyAccounts */
313 account_verify_last_ref (TnyAccount *account, const gchar *str)
317 g_return_if_fail (account && TNY_IS_ACCOUNT(account));
319 txt = g_strdup_printf ("%s: %s", str ? str : "?", tny_account_get_name(account));
320 MODEST_DEBUG_VERIFY_OBJECT_LAST_REF(G_OBJECT(account),txt);
328 foreach_account_append_to_list (gpointer data,
333 list = TNY_LIST (user_data);
334 tny_list_append (list, G_OBJECT (data));
337 /********************************************************************/
338 /* Control the state of the MMC local account */
339 /********************************************************************/
341 /** Only call this if the memory card is really mounted.
344 add_mmc_account(ModestTnyAccountStore *self, gboolean emit_insert_signal)
346 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
347 g_return_if_fail (priv->session);
349 TnyAccount *mmc_account = modest_tny_account_new_for_local_folders (priv->account_mgr,
351 MODEST_MCC1_VOLUMEPATH);
353 /* Add to the list of store accounts */
354 tny_list_append (priv->store_accounts, G_OBJECT (mmc_account));
356 if (emit_insert_signal) {
357 g_signal_emit (G_OBJECT (self),
358 signals [ACCOUNT_INSERTED_SIGNAL],
363 g_object_unref (mmc_account);
367 on_vfs_volume_mounted(GnomeVFSVolumeMonitor *volume_monitor,
368 GnomeVFSVolume *volume,
371 ModestTnyAccountStore *self;
372 ModestTnyAccountStorePrivate *priv;
376 self = MODEST_TNY_ACCOUNT_STORE(user_data);
377 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
379 /* Check whether this was the external MMC1 card: */
380 uri = gnome_vfs_volume_get_activation_uri (volume);
382 if (uri && (!strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI))) {
383 add_mmc_account (self, TRUE /* emit the insert signal. */);
390 on_vfs_volume_unmounted(GnomeVFSVolumeMonitor *volume_monitor,
391 GnomeVFSVolume *volume,
394 ModestTnyAccountStore *self;
395 ModestTnyAccountStorePrivate *priv;
398 self = MODEST_TNY_ACCOUNT_STORE(user_data);
399 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
401 /* Check whether this was the external MMC1 card: */
402 uri = gnome_vfs_volume_get_activation_uri (volume);
403 if (uri && (strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI) == 0)) {
404 TnyAccount *mmc_account = NULL;
405 gboolean found = FALSE;
406 TnyIterator *iter = NULL;
408 iter = tny_list_create_iterator (priv->store_accounts);
409 while (!tny_iterator_is_done (iter) && !found) {
412 account = TNY_ACCOUNT (tny_iterator_get_current (iter));
413 if (modest_tny_account_is_memory_card_account (account)) {
415 mmc_account = g_object_ref (account);
417 g_object_unref (account);
418 tny_iterator_next (iter);
420 g_object_unref (iter);
423 /* Remove from the list */
424 tny_list_remove (priv->store_accounts, G_OBJECT (mmc_account));
426 /* Notify observers */
427 g_signal_emit (G_OBJECT (self),
428 signals [ACCOUNT_REMOVED_SIGNAL],
431 g_object_unref (mmc_account);
433 g_warning ("%s: there was no store account for the unmounted MMC",
441 * modest_tny_account_store_forget_password_in_memory
442 * @self: a TnyAccountStore instance
443 * @account: A server account.
445 * Forget any password stored in memory for this account.
446 * For instance, this should be called when the user has changed the password in the account settings.
449 modest_tny_account_store_forget_password_in_memory (ModestTnyAccountStore *self, const gchar * server_account_name)
451 /* printf ("DEBUG: %s\n", __FUNCTION__); */
452 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
454 if (server_account_name && priv->password_hash) {
455 g_hash_table_remove (priv->password_hash, server_account_name);
460 on_account_changed (ModestAccountMgr *acc_mgr,
461 const gchar *account_name,
462 TnyAccountType account_type,
465 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
466 ModestTnyAccountStorePrivate *priv;
467 TnyList* account_list;
468 gboolean found = FALSE;
469 TnyIterator *iter = NULL;
471 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
472 account_list = (account_type == TNY_ACCOUNT_TYPE_STORE ?
473 priv->store_accounts :
474 priv->transport_accounts);
476 iter = tny_list_create_iterator (account_list);
477 while (!tny_iterator_is_done (iter) && !found) {
478 TnyAccount *tny_account;
479 tny_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
481 TnyConnectionStatus conn_status = tny_account_get_connection_status (tny_account);
483 if (conn_status != TNY_CONNECTION_STATUS_RECONNECTING &&
484 conn_status != TNY_CONNECTION_STATUS_INIT) {
485 if (!strcmp (tny_account_get_id (tny_account), account_name)) {
487 modest_tny_account_update_from_account (tny_account);
488 g_signal_emit (G_OBJECT(self), signals[ACCOUNT_CHANGED_SIGNAL], 0, tny_account);
491 g_object_unref (tny_account);
493 tny_iterator_next (iter);
497 g_object_unref (iter);
501 on_account_settings_hide (GtkWidget *widget, gpointer user_data)
503 TnyAccount *account = (TnyAccount*)user_data;
505 /* This is easier than using a struct for the user_data: */
506 ModestTnyAccountStore *self = modest_runtime_get_account_store();
507 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
509 const gchar *modest_account_name =
510 modest_tny_account_get_parent_modest_account_name_for_server_account (account);
511 if (modest_account_name)
512 g_hash_table_remove (priv->account_settings_dialog_hash, modest_account_name);
516 show_password_warning_only ()
518 ModestWindow *main_window =
519 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE); /* don't create */
521 /* Show an explanatory temporary banner: */
523 modest_platform_information_banner (GTK_WIDGET(main_window), NULL,
524 _("mcen_ib_username_pw_incorrect"));
526 g_warning ("%s: %s", __FUNCTION__, _("mcen_ib_username_pw_incorrect"));
531 show_wrong_password_dialog (TnyAccount *account)
533 /* This is easier than using a struct for the user_data: */
534 ModestTnyAccountStore *self = modest_runtime_get_account_store();
535 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
536 ModestWindow *main_window;
537 const gchar *modest_account_name;
539 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
540 FALSE); /* don't create */
542 g_warning ("%s: password was wrong; ignoring because no main window", __FUNCTION__);
546 modest_account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
547 if (!modest_account_name) {
548 g_warning ("%s: modest_tny_account_get_parent_modest_account_name_for_server_account() failed.\n",
552 /* Check whether this window is already open,
553 * for instance because of a previous get_password() call:
555 gpointer dialog_as_gpointer = NULL;
556 gboolean found = FALSE;
557 if (priv->account_settings_dialog_hash) {
558 found = g_hash_table_lookup_extended (priv->account_settings_dialog_hash,
559 modest_account_name, NULL, (gpointer*)&dialog_as_gpointer);
561 ModestAccountSettingsDialog *dialog = dialog_as_gpointer;
563 gboolean created_dialog = FALSE;
564 if (!found || !dialog) {
565 dialog = modest_account_settings_dialog_new ();
566 modest_account_settings_dialog_set_account_name (dialog, modest_account_name);
567 modest_account_settings_dialog_switch_to_user_info (dialog);
568 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
570 g_hash_table_insert (priv->account_settings_dialog_hash, g_strdup (modest_account_name), dialog);
572 created_dialog = TRUE;
575 /* Show an explanatory temporary banner: */
576 modest_platform_information_banner (GTK_WIDGET(dialog), NULL, _("mcen_ib_username_pw_incorrect"));
578 if (created_dialog) {
579 /* Forget it when it closes: */
580 g_signal_connect_object (G_OBJECT (dialog), "hide", G_CALLBACK (on_account_settings_hide),
583 /* Show it and delete it when it closes: */
584 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (main_window));
585 g_signal_connect_swapped (dialog,
587 G_CALLBACK (gtk_widget_destroy),
589 gtk_widget_show (GTK_WIDGET (dialog));
592 /* Just show it instead of showing it and deleting it when it closes,
593 * though it is probably open already: */
594 gtk_window_present (GTK_WINDOW (dialog));
601 request_password_and_wait (ModestTnyAccountStore *account_store,
602 const gchar* server_account_id,
608 g_signal_emit (G_OBJECT(account_store), signals[PASSWORD_REQUESTED_SIGNAL], 0,
609 server_account_id, /* server_account_name */
610 username, password, cancel, remember);
613 /* This callback will be called by Tinymail when it needs the password
614 * from the user or the account settings.
615 * It can also call forget_password() before calling this,
616 * so that we clear wrong passwords out of our account settings.
617 * Note that TnyAccount here will be the server account. */
619 get_password (TnyAccount *account, const gchar * prompt_not_used, gboolean *cancel)
621 /* TODO: Settting cancel to FALSE does not actually cancel everything.
622 * We still get multiple requests afterwards, so we end up showing the
623 * same dialogs repeatedly.
625 const TnyAccountStore *account_store = NULL;
626 ModestTnyAccountStore *self = NULL;
627 ModestTnyAccountStorePrivate *priv;
628 gchar *username = NULL;
630 gpointer pwd_ptr = NULL;
631 gboolean already_asked = FALSE;
633 g_return_val_if_fail (account, NULL);
636 g_debug ("DEBUG: modest: %s: prompt (not shown) = %s\n", __FUNCTION__, prompt_not_used);
639 /* Initialize the output parameter: */
643 const gchar *server_account_name = tny_account_get_id (account);
644 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
647 if (!server_account_name || !account_store) {
648 g_warning ("modest: %s: could not retrieve account_store for account %s",
649 __FUNCTION__, server_account_name ? server_account_name : "<NULL>");
656 self = MODEST_TNY_ACCOUNT_STORE (account_store);
657 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
659 /* This hash map stores passwords, including passwords that are not stored in gconf. */
660 /* Is it in the hash? if it's already there, it must be wrong... */
661 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
662 * type-punned ptrs...*/
663 already_asked = priv->password_hash &&
664 g_hash_table_lookup_extended (priv->password_hash,
667 (gpointer*)&pwd_ptr);
669 g_debug ("DEBUG: modest: %s: Already asked = %d\n", __FUNCTION__, already_asked);
672 /* If the password is not already there, try ModestConf */
673 if (!already_asked) {
674 pwd = modest_account_mgr_get_server_account_password (priv->account_mgr,
675 server_account_name);
676 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup (pwd));
679 /* If it was already asked, it must have been wrong, so ask again */
680 if (already_asked || !pwd || strlen(pwd) == 0) {
681 /* As per the UI spec, if no password was set in the account settings,
682 * ask for it now. But if the password is wrong in the account settings,
683 * then show a banner and the account settings dialog so it can be corrected:
685 const gboolean settings_have_password =
686 modest_account_mgr_get_server_account_has_password (priv->account_mgr, server_account_name);
688 printf ("DEBUG: modest: %s: settings_have_password=%d\n",
689 __FUNCTION__, settings_have_password);
691 if (settings_have_password) {
692 /* The password must be wrong, so show the account settings dialog so it can be corrected: */
693 show_wrong_password_dialog (account);
701 /* we don't have it yet. Get the password from the user */
702 const gchar* account_id = tny_account_get_id (account);
703 gboolean remember = FALSE;
707 /* Show an info banner, before we show the protected password dialog: */
708 show_password_warning_only();
711 request_password_and_wait (self, account_id,
712 &username, &pwd, cancel, &remember);
715 /* The password will be returned as the result,
716 * but we need to tell tinymail about the username too: */
717 tny_account_set_user (account, username);
719 /* Do not save the password in gconf, because
720 * the UI spec says "The password will never
721 * be saved in the account": */
723 /* We need to dup the string even knowing that
724 it's already a dup of the contents of an
725 entry, because it if it's wrong, then camel
727 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup(pwd));
729 g_hash_table_remove (priv->password_hash, server_account_name);
744 modest_tny_account_store_forget_already_asked (ModestTnyAccountStore *self, TnyAccount *account)
746 g_return_if_fail (account);
748 ModestTnyAccountStorePrivate *priv;
750 gpointer pwd_ptr = NULL;
751 gboolean already_asked = FALSE;
753 const gchar *server_account_name = tny_account_get_id (account);
755 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
757 /* This hash map stores passwords, including passwords that are not stored in gconf. */
758 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
759 * type-punned ptrs...*/
760 already_asked = priv->password_hash &&
761 g_hash_table_lookup_extended (priv->password_hash,
764 (gpointer*)&pwd_ptr);
767 g_hash_table_remove (priv->password_hash, server_account_name);
775 /* tinymail calls this if the connection failed due to an incorrect password.
776 * And it seems to call this for any general connection failure. */
778 forget_password (TnyAccount *account)
780 printf ("DEBUG: %s\n", __FUNCTION__);
781 ModestTnyAccountStore *self;
782 ModestTnyAccountStorePrivate *priv;
783 const TnyAccountStore *account_store;
787 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
789 self = MODEST_TNY_ACCOUNT_STORE (account_store);
790 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
791 key = tny_account_get_id (account);
793 /* Do not remove the key, this will allow us to detect that we
794 have already asked for it at least once */
795 pwd = g_hash_table_lookup (priv->password_hash, key);
797 memset (pwd, 0, strlen (pwd));
798 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
801 /* Remove from configuration system */
803 modest_account_mgr_unset (priv->account_mgr,
804 key, MODEST_ACCOUNT_PASSWORD, TRUE);
809 modest_tny_account_store_finalize (GObject *obj)
811 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(obj);
812 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
814 g_free (priv->cache_dir);
815 priv->cache_dir = NULL;
817 if (priv->password_hash) {
818 g_hash_table_destroy (priv->password_hash);
819 priv->password_hash = NULL;
822 if (priv->account_settings_dialog_hash) {
823 g_hash_table_destroy (priv->account_settings_dialog_hash);
824 priv->account_settings_dialog_hash = NULL;
827 if (priv->outbox_of_transport) {
828 g_hash_table_destroy (priv->outbox_of_transport);
829 priv->outbox_of_transport = NULL;
832 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
833 priv->sighandlers = NULL;
835 if (priv->account_mgr) {
836 g_object_unref (G_OBJECT(priv->account_mgr));
837 priv->account_mgr = NULL;
841 g_object_unref (G_OBJECT(priv->device));
845 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
846 if (priv->store_accounts) {
847 tny_list_foreach (priv->store_accounts, (GFunc)account_disconnect, NULL);
848 tny_list_foreach (priv->store_accounts, (GFunc)account_verify_last_ref, "store");
849 g_object_unref (priv->store_accounts);
850 priv->store_accounts = NULL;
853 if (priv->transport_accounts) {
854 tny_list_foreach (priv->transport_accounts, (GFunc)account_disconnect, NULL);
855 tny_list_foreach (priv->transport_accounts, (GFunc)account_verify_last_ref, "transport");
856 g_object_unref (priv->transport_accounts);
857 priv->transport_accounts = NULL;
860 if (priv->store_accounts_outboxes) {
861 g_object_unref (priv->store_accounts_outboxes);
862 priv->store_accounts_outboxes = NULL;
866 camel_object_unref (CAMEL_OBJECT(priv->session));
867 priv->session = NULL;
870 G_OBJECT_CLASS(parent_class)->finalize (obj);
874 volume_path_is_mounted (const gchar* path)
876 g_return_val_if_fail (path, FALSE);
878 gboolean result = FALSE;
879 gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
880 g_return_val_if_fail (path_as_uri, FALSE);
882 /* Get the monitor singleton: */
883 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
885 /* This seems like a simpler way to do this, but it returns a
886 * GnomeVFSVolume even if the drive is not mounted: */
888 GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor,
889 MODEST_MCC1_VOLUMEPATH);
891 gnome_vfs_volume_unref(volume);
895 /* Get the mounted volumes from the monitor: */
896 GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
898 for (iter = list; iter; iter = g_list_next (iter)) {
899 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
903 gnome_vfs_volume_get_display_name (volume);
904 printf ("volume display name=%s\n", display_name);
905 g_free (display_name);
909 gnome_vfs_volume_get_activation_uri (volume);
910 /* printf (" uri=%s\n", uri); */
911 if (uri && (strcmp (uri, path_as_uri) == 0))
916 gnome_vfs_volume_unref (volume);
922 g_free (path_as_uri);
927 ModestTnyAccountStore*
928 modest_tny_account_store_new (ModestAccountMgr *account_mgr,
932 ModestTnyAccountStorePrivate *priv;
933 TnyAccount *local_account = NULL;
935 g_return_val_if_fail (account_mgr, NULL);
936 g_return_val_if_fail (device, NULL);
938 obj = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
939 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
941 priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
942 priv->device = g_object_ref (device);
944 priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
945 if (!priv->session) {
946 g_warning ("failed to get TnySessionCamel");
950 /* Set the ui locker */
951 tny_session_camel_set_ui_locker (priv->session, tny_gtk_lockable_new ());
953 /* Connect signals */
954 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
955 G_OBJECT(account_mgr), "account_inserted",
956 G_CALLBACK (on_account_inserted), obj);
957 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
958 G_OBJECT(account_mgr), "account_changed",
959 G_CALLBACK (on_account_changed), obj);
960 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
961 G_OBJECT(account_mgr), "account_removed",
962 G_CALLBACK (on_account_removed), obj);
964 /* Create the lists of accounts */
965 priv->store_accounts = tny_simple_list_new ();
966 priv->transport_accounts = tny_simple_list_new ();
967 priv->store_accounts_outboxes = tny_simple_list_new ();
969 /* Create the local folders account */
971 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
972 tny_list_append (priv->store_accounts, G_OBJECT(local_account));
973 g_object_unref (local_account);
975 /* Add the other remote accounts. Do this after adding the
976 local account, because we need to add our outboxes to the
977 global OUTBOX hosted in the local account */
978 add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
980 /* FIXME: I'm doing this (adding an "if (FALSE)"because this
981 stuff is not working properly and could cause SIGSEVs, for
982 example one send queue will be created for each connection
983 specific SMTP server, so when tinymail asks for the outbox
984 it will return NULL because there is no outbox folder for
985 this specific transport accounts, and it's a must that the
986 send queue returns an outbox */
988 /* Add connection-specific transport accounts */
989 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
991 /* This is a singleton, so it does not need to be unrefed. */
992 if (volume_path_is_mounted (MODEST_MCC1_VOLUMEPATH)) {
994 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */);
997 return MODEST_TNY_ACCOUNT_STORE(obj);
1001 modest_tny_account_store_get_accounts (TnyAccountStore *self,
1003 TnyGetAccountsRequestType request_type)
1005 ModestTnyAccountStorePrivate *priv;
1007 g_return_if_fail (self);
1008 g_return_if_fail (TNY_IS_LIST(list));
1010 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1012 switch (request_type) {
1013 case TNY_ACCOUNT_STORE_BOTH:
1014 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1015 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1017 case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
1018 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1020 case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
1021 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1024 g_return_if_reached ();
1027 /* Initialize session. Why do we need this ??? */
1028 tny_session_camel_set_initialized (priv->session);
1033 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1035 ModestTnyAccountStorePrivate *priv;
1036 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1038 if (!priv->cache_dir)
1039 priv->cache_dir = g_build_filename (g_get_home_dir(),
1040 MODEST_DIR, MODEST_CACHE_DIR, NULL);
1041 return priv->cache_dir;
1046 * callers need to unref
1049 modest_tny_account_store_get_device (TnyAccountStore *self)
1051 ModestTnyAccountStorePrivate *priv;
1053 g_return_val_if_fail (self, NULL);
1055 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1058 return g_object_ref (G_OBJECT(priv->device));
1065 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1067 return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self),
1068 MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1075 modest_tny_account_store_alert (TnyAccountStore *self,
1076 TnyAccount *account,
1079 const GError *error)
1081 ModestTransportStoreProtocol proto =
1082 MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
1083 const gchar* server_name = NULL;
1084 gchar *prompt = NULL;
1088 g_return_val_if_fail (account, FALSE);
1089 g_return_val_if_fail (error, FALSE);
1091 if ((error->domain != TNY_ACCOUNT_ERROR) && (error->domain != TNY_ACCOUNT_STORE_ERROR))
1094 /* Get the server name: */
1095 server_name = tny_account_get_hostname (account);
1098 const gchar *proto_name = tny_account_get_proto (account);
1100 proto = modest_protocol_info_get_transport_store_protocol (proto_name);
1102 g_warning("modest: %s: account with id=%s has no proto.\n", __FUNCTION__,
1103 tny_account_get_id (account));
1108 switch (error->code) {
1109 case TNY_ACCOUNT_STORE_ERROR_CANCEL_ALERT:
1110 case TNY_ACCOUNT_ERROR_TRY_CONNECT_USER_CANCEL:
1111 /* Don't show waste the user's time by showing him a dialog telling
1112 * him that he has just cancelled something: */
1115 case TNY_ACCOUNT_ERROR_TRY_CONNECT_HOST_LOOKUP_FAILED:
1116 case TNY_ACCOUNT_ERROR_TRY_CONNECT_SERVICE_UNAVAILABLE:
1117 /* TODO: Show the appropriate message, depending on whether it's POP or IMAP: */
1119 case MODEST_PROTOCOL_STORE_POP:
1120 prompt = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"),
1123 case MODEST_PROTOCOL_STORE_IMAP:
1124 prompt = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"),
1127 case MODEST_PROTOCOL_TRANSPORT_SMTP:
1128 prompt = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"),
1132 g_return_val_if_reached (FALSE);
1136 case TNY_ACCOUNT_ERROR_TRY_CONNECT_AUTHENTICATION_NOT_SUPPORTED:
1137 /* This is "Secure connection failed", even though the logical
1138 * ID has _certificate_ in the name: */
1139 prompt = g_strdup (_("mail_ni_ssl_certificate_error"));
1142 case TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE:
1143 /* We'll show the proper dialog later */
1146 case TNY_ACCOUNT_ERROR_TRY_CONNECT:
1147 /* The tinymail camel implementation just sends us this for almost
1148 * everything, so we have to guess at the cause.
1149 * It could be a wrong password, or inability to resolve a hostname,
1150 * or lack of network, or incorrect authentication method, or something entirely different: */
1151 /* TODO: Fix camel to provide specific error codes, and then use the
1152 * specific dialog messages from Chapter 12 of the UI spec.
1154 case TNY_ACCOUNT_STORE_ERROR_UNKNOWN_ALERT:
1157 g_return_val_if_reached (FALSE);
1161 if (error->code == TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE)
1162 retval = modest_platform_run_certificate_confirmation_dialog (server_name,
1165 retval = modest_platform_run_alert_dialog (prompt, question);
1175 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1177 TnyAccountStoreIface *klass;
1179 g_return_if_fail (g);
1181 klass = (TnyAccountStoreIface *)g;
1183 klass->get_accounts_func =
1184 modest_tny_account_store_get_accounts;
1185 klass->get_cache_dir_func =
1186 modest_tny_account_store_get_cache_dir;
1187 klass->get_device_func =
1188 modest_tny_account_store_get_device;
1190 modest_tny_account_store_alert;
1191 klass->find_account_func =
1192 modest_tny_account_store_find_account_by_url;
1196 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1197 ModestTnyGetPassFunc func)
1199 /* not implemented, we use signals */
1200 g_printerr ("modest: set_get_pass_func not implemented\n");
1204 modest_tny_account_store_get_session (TnyAccountStore *self)
1206 g_return_val_if_fail (self, NULL);
1207 return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1211 get_tny_account_by (TnyList *accounts,
1212 ModestTnyAccountStoreQueryType type,
1215 TnyIterator *iter = NULL;
1216 gboolean found = FALSE;
1217 TnyAccount *retval = NULL;
1219 iter = tny_list_create_iterator (accounts);
1220 while (!tny_iterator_is_done (iter) && !found) {
1221 TnyAccount *tmp_account = NULL;
1222 const gchar *val = NULL;
1224 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1226 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1227 val = tny_account_get_id (tmp_account);
1229 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1230 val = tny_account_get_url_string (tmp_account);
1234 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL &&
1235 tny_account_matches_url_string (tmp_account, str)) {
1236 retval = g_object_ref (tmp_account);
1239 if (strcmp (val, str) == 0) {
1240 retval = g_object_ref (tmp_account);
1244 g_object_unref (tmp_account);
1245 tny_iterator_next (iter);
1247 g_object_unref (iter);
1253 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self,
1254 ModestTnyAccountStoreQueryType type,
1257 TnyAccount *account = NULL;
1258 ModestTnyAccountStorePrivate *priv;
1260 g_return_val_if_fail (self, NULL);
1261 g_return_val_if_fail (str, NULL);
1263 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1265 /* Search in store accounts */
1266 account = get_tny_account_by (priv->store_accounts, type, str);
1268 /* If we already found something, no need to search the transport accounts */
1270 account = get_tny_account_by (priv->transport_accounts, type, str);
1272 /* If we already found something, no need to search the
1273 per-account outbox accounts */
1275 account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1278 /* Warn if nothing was found. This is generally unusual. */
1280 g_warning("%s: Failed to find account with %s=%s\n",
1282 (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",
1286 /* Returns a new reference to the account if found */
1292 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1293 const gchar *account_name,
1294 TnyAccountType type)
1296 ModestTnyAccountStorePrivate *priv = NULL;
1297 TnyAccount *retval = NULL;
1298 TnyList *account_list = NULL;
1299 TnyIterator *iter = NULL;
1302 g_return_val_if_fail (self, NULL);
1303 g_return_val_if_fail (account_name, NULL);
1304 g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE ||
1305 type == TNY_ACCOUNT_TYPE_TRANSPORT,
1308 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1310 account_list = (type == TNY_ACCOUNT_TYPE_STORE) ?
1311 priv->store_accounts :
1312 priv->transport_accounts;
1314 if (!account_list) {
1315 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__,
1316 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1320 /* Look for the server account */
1322 iter = tny_list_create_iterator (account_list);
1323 while (!tny_iterator_is_done (iter) && !found) {
1324 const gchar *modest_acc_name;
1325 TnyAccount *tmp_account;
1327 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1329 modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1331 if (account_name && modest_acc_name && !strcmp (account_name, modest_acc_name)) {
1333 retval = g_object_ref (tmp_account);
1335 /* Free and continue */
1336 g_object_unref (tmp_account);
1337 tny_iterator_next (iter);
1341 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1342 "Number of server accounts of this type=%d\n", __FUNCTION__,
1343 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1344 account_name, tny_list_get_length (account_list));
1347 /* Returns a new reference */
1352 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (ModestTnyAccountStore *self,
1353 const gchar *account_name)
1355 /* Get the current connection: */
1356 TnyDevice *device = modest_runtime_get_device ();
1358 if (!tny_device_is_online (device))
1361 g_return_val_if_fail (self, NULL);
1364 #ifdef MODEST_PLATFORM_MAEMO
1365 g_assert (TNY_IS_MAEMO_CONIC_DEVICE (device));
1366 TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);
1367 const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1368 /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1372 ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1376 const gchar *connection_name = con_ic_iap_get_name (connection);
1377 /* printf ("DEBUG: %s: connection_name=%s\n", __FUNCTION__, connection_name); */
1378 if (!connection_name)
1381 /* Get the connection-specific transport acccount, if any: */
1382 ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1384 /* Check if this account has connection-specific SMTP enabled */
1385 if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1389 gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager,
1392 /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1393 if (!server_account_name) {
1394 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1397 TnyAccount* account = modest_tny_account_store_get_tny_account_by (self,
1398 MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1399 server_account_name);
1401 /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1402 g_free (server_account_name);
1404 /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1405 g_object_unref (connection);
1409 return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1410 #endif /* MODEST_PLATFORM_MAEMO */
1415 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1416 const gchar *account_name)
1418 g_return_val_if_fail (self, NULL);
1419 g_return_val_if_fail (account_name, NULL);
1421 if (!account_name || !self)
1424 /* Get the connection-specific transport acccount, if any: */
1425 /* Note: This gives us a reference: */
1426 TnyAccount *account =
1427 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (self, account_name);
1429 /* If there is no connection-specific transport account (the common case),
1430 * just get the regular transport account: */
1432 /* The special local folders don't have transport accounts. */
1433 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1436 /* Note: This gives us a reference: */
1437 account = modest_tny_account_store_get_server_account (self, account_name,
1438 TNY_ACCOUNT_TYPE_TRANSPORT);
1442 /* returns a reference. */
1447 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1449 TnyAccount *account = NULL;
1450 ModestTnyAccountStorePrivate *priv;
1454 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1456 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1459 iter = tny_list_create_iterator (priv->store_accounts);
1460 while (!tny_iterator_is_done (iter) && !found) {
1461 TnyAccount *tmp_account;
1463 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1464 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1465 account = g_object_ref (tmp_account);
1468 g_object_unref (tmp_account);
1469 tny_iterator_next (iter);
1471 g_object_unref (iter);
1473 /* Returns a new reference to the account */
1478 modest_tny_account_store_get_mmc_folders_account (ModestTnyAccountStore *self)
1480 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1482 return modest_tny_account_store_get_tny_account_by (self, MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1483 MODEST_MMC_ACCOUNT_ID);
1487 /*********************************************************************************/
1489 add_existing_accounts (ModestTnyAccountStore *self)
1491 GSList *account_names = NULL, *iter = NULL;
1492 ModestTnyAccountStorePrivate *priv = NULL;
1494 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1496 /* These are account names, not server_account names */
1497 account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1499 for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1500 const gchar *account_name = (const gchar*) iter->data;
1502 /* Insert all enabled accounts without notifying */
1503 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1504 insert_account (self, account_name, FALSE);
1506 modest_account_mgr_free_account_names (account_names);
1510 create_tny_account (ModestTnyAccountStore *self,
1512 TnyAccountType type)
1514 TnyAccount *account = NULL;
1515 ModestTnyAccountStorePrivate *priv = NULL;
1517 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1519 account = modest_tny_account_new_from_account (priv->account_mgr,
1526 /* Forget any cached password for the account, so that
1527 we use a new account if any */
1528 modest_tny_account_store_forget_password_in_memory (self,
1529 tny_account_get_id (account));
1530 /* Set the account store */
1531 g_object_set_data (G_OBJECT(account), "account_store", self);
1533 g_printerr ("modest: failed to create account for %s\n", name);
1541 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1542 const gchar *account_name,
1543 TnyAccount *transport_account)
1545 TnyList *folders = NULL;
1546 TnyIterator *iter_folders = NULL;
1547 TnyAccount *local_account = NULL, *account_outbox = NULL;
1548 TnyFolder *per_account_outbox = NULL;
1549 ModestTnyAccountStorePrivate *priv = NULL;
1551 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1553 /* Create per account local outbox */
1555 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr,
1558 tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1560 /* Get the outbox folder */
1561 folders = tny_simple_list_new ();
1562 tny_folder_store_get_folders (TNY_FOLDER_STORE (account_outbox), folders, NULL, NULL);
1563 g_assert (tny_list_get_length (folders) == 1);
1565 iter_folders = tny_list_create_iterator (folders);
1566 per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1567 g_object_unref (iter_folders);
1568 g_object_unref (folders);
1569 g_object_unref (account_outbox);
1571 /* Add the outbox of the new per-account-local-outbox account
1572 to the global local merged OUTBOX of the local folders
1574 local_account = modest_tny_account_store_get_local_folders_account (self);
1575 modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1576 per_account_outbox);
1577 /* Add the pair to the hash table */
1578 g_hash_table_insert (priv->outbox_of_transport,
1580 per_account_outbox);
1582 g_object_unref (local_account);
1583 g_object_unref (per_account_outbox);
1587 * This function will be used for both adding new accounts and for the
1588 * initialization. In the initialization we do not want to emit
1589 * signals so notify will be FALSE, in the case of account additions
1590 * we do want to notify the observers
1593 insert_account (ModestTnyAccountStore *self,
1594 const gchar *account,
1597 ModestTnyAccountStorePrivate *priv = NULL;
1598 TnyAccount *store_account = NULL, *transport_account = NULL;
1600 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1602 /* Get the server and the transport account */
1603 store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1604 transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1606 g_assert (store_account);
1607 g_assert (transport_account);
1609 /* Add accounts to the lists */
1610 tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1611 tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1613 /* Create a new pseudo-account with an outbox for this
1614 transport account and add it to the global outbox
1615 in the local account */
1616 add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1618 /* Notify the observers. We do it after everything is
1621 TnyAccount *local_account = NULL;
1623 /* Notify the observers about the new server & transport accounts */
1624 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);
1625 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1627 /* Notify that the local account changed */
1628 local_account = modest_tny_account_store_get_local_folders_account (self);
1629 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1630 g_object_unref (local_account);
1634 g_object_unref (store_account);
1635 g_object_unref (transport_account);
1639 on_account_inserted (ModestAccountMgr *acc_mgr,
1640 const gchar *account,
1643 /* Insert the account and notify the observers */
1644 insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1648 on_account_removed (ModestAccountMgr *acc_mgr, const gchar *account,
1651 TnyAccount *store_account = NULL, *transport_account = NULL;
1652 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
1654 /* Get the server and the transport account */
1656 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1658 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1660 /* If there was any problem creating the account, for example,
1661 with the configuration system this could not exist */
1662 if (store_account) {
1663 /* Clear the cache */
1664 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (store_account));
1666 /* Notify the observers */
1667 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, store_account);
1668 account_disconnect (store_account); /* disconnect the account */
1669 g_object_unref (store_account);
1671 g_warning ("There is no store account for account %s\n", account);
1674 /* If there was any problem creating the account, for example,
1675 with the configuration system this could not exist */
1676 if (transport_account) {
1677 TnyAccount *local_account = NULL;
1678 TnyFolder *outbox = NULL;
1679 ModestTnyAccountStorePrivate *priv = NULL;
1681 /* Remove the OUTBOX of the account from the global outbox */
1682 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1683 outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
1685 if (TNY_IS_FOLDER (outbox)) {
1686 local_account = modest_tny_account_store_get_local_folders_account (self);
1687 modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1689 g_hash_table_remove (priv->outbox_of_transport, transport_account);
1691 /* Notify the change in the local account */
1692 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1693 g_object_unref (local_account);
1695 g_warning ("Removing a transport account that has no outbox");
1698 /* Notify the observers */
1699 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, transport_account);
1700 account_disconnect (transport_account); /* disconnect the account */
1701 g_object_unref (transport_account);
1703 g_warning ("There is no transport account for account %s\n", account);
1707 TnyTransportAccount *
1708 modest_tny_account_store_new_connection_specific_transport_account (ModestTnyAccountStore *self,
1711 ModestTnyAccountStorePrivate *priv = NULL;
1712 TnyAccount * tny_account = NULL;
1714 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1716 /* Add the account: */
1718 modest_tny_account_new_from_server_account_name (priv->account_mgr,
1724 g_object_set_data (G_OBJECT(tny_account),
1728 tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1729 add_outbox_from_transport_account_to_global_outbox (self,
1734 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1737 return TNY_TRANSPORT_ACCOUNT (tny_account);
1742 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1744 ModestTnyAccountStorePrivate *priv = NULL;
1745 GSList *list_specifics = NULL, *iter = NULL;
1747 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1749 ModestConf *conf = modest_runtime_get_conf ();
1752 list_specifics = modest_conf_get_list (conf,
1753 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
1754 MODEST_CONF_VALUE_STRING, &err);
1756 g_printerr ("modest: %s: error getting list: %s\n.", __FUNCTION__, err->message);
1761 /* Look at each connection-specific transport account for the
1762 * modest account: */
1763 iter = list_specifics;
1765 /* The list alternates between the connection name and the transport name: */
1766 iter = g_slist_next (iter);
1768 const gchar* transport_account_name = (const gchar*) (iter->data);
1769 TnyTransportAccount * account = NULL;
1770 account = modest_tny_account_store_new_connection_specific_transport_account (
1771 self, transport_account_name);
1773 g_object_unref (account);
1775 iter = g_slist_next (iter);
1780 modest_tny_account_store_find_msg_in_outboxes (ModestTnyAccountStore *self,
1782 TnyAccount **ac_out)
1784 TnyIterator *acc_iter;
1785 ModestTnyAccountStorePrivate *priv;
1787 TnyAccount *msg_account = NULL;
1789 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1790 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1792 acc_iter = tny_list_create_iterator (priv->store_accounts_outboxes);
1793 while (!msg && !tny_iterator_is_done (acc_iter)) {
1794 TnyList *folders = tny_simple_list_new ();
1795 TnyAccount *account = TNY_ACCOUNT (tny_iterator_get_current (acc_iter));
1796 TnyIterator *folders_iter = NULL;
1798 tny_folder_store_get_folders (TNY_FOLDER_STORE (account), folders, NULL, NULL);
1799 folders_iter = tny_list_create_iterator (folders);
1801 while (msg == NULL && !tny_iterator_is_done (folders_iter)) {
1802 TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (folders_iter));
1803 msg = tny_folder_find_msg (folder, uri, NULL);
1806 msg_account = g_object_ref (account);
1808 g_object_unref (folder);
1809 tny_iterator_next (folders_iter);
1812 g_object_unref (folders);
1813 g_object_unref (account);
1814 tny_iterator_next (acc_iter);
1817 g_object_unref (acc_iter);
1820 *ac_out = msg_account;
1825 TnyTransportAccount *
1826 modest_tny_account_store_get_transport_account_from_outbox_header(ModestTnyAccountStore *self, TnyHeader *header)
1828 TnyIterator *acc_iter;
1829 ModestTnyAccountStorePrivate *priv;
1830 TnyTransportAccount *header_acc = NULL;
1831 const gchar *msg_id;
1833 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1834 g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
1835 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1837 msg_id = modest_tny_send_queue_get_msg_id (header);
1838 acc_iter = tny_list_create_iterator (priv->transport_accounts);
1839 while (!header_acc && !tny_iterator_is_done (acc_iter)) {
1840 TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current (acc_iter));
1841 ModestTnySendQueue *send_queue;
1842 ModestTnySendQueueStatus status;
1843 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account));
1844 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
1845 if (status != MODEST_TNY_SEND_QUEUE_UNKNOWN) {
1846 header_acc = g_object_ref(account);
1848 g_object_unref (account);
1849 tny_iterator_next (acc_iter);
1852 g_object_unref(acc_iter);