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-error.h>
34 #include <tny-account.h>
35 #include <tny-account-store.h>
36 #include <tny-store-account.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-signal-mgr.h>
54 #include <modest-debug.h>
56 #include "modest-tny-account-store.h"
57 #include "modest-tny-platform-factory.h"
58 #include <tny-gtk-lockable.h>
59 #include <camel/camel.h>
60 #include <modest-platform.h>
61 #include "modest-ui-actions.h"
62 #include <widgets/modest-account-settings-dialog.h>
64 #ifdef MODEST_PLATFORM_MAEMO
65 #include <tny-maemo-conic-device.h>
66 #include <maemo/modest-maemo-utils.h>
69 #include <libgnomevfs/gnome-vfs-volume-monitor.h>
71 /* 'private'/'protected' functions */
72 static void modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass);
73 static void modest_tny_account_store_finalize (GObject *obj);
74 static void modest_tny_account_store_instance_init (ModestTnyAccountStore *obj);
75 static void modest_tny_account_store_init (gpointer g, gpointer iface_data);
76 static void modest_tny_account_store_base_init (gpointer g_class);
78 static void on_account_inserted (ModestAccountMgr *acc_mgr,
82 static void add_existing_accounts (ModestTnyAccountStore *self);
84 static void insert_account (ModestTnyAccountStore *self,
88 static void on_account_removed (ModestAccountMgr *acc_mgr,
92 static gchar* get_password (TnyAccount *account,
93 const gchar * prompt_not_used,
96 static void forget_password (TnyAccount *account);
98 static void on_vfs_volume_mounted (GnomeVFSVolumeMonitor *volume_monitor,
99 GnomeVFSVolume *volume,
102 static void on_vfs_volume_unmounted (GnomeVFSVolumeMonitor *volume_monitor,
103 GnomeVFSVolume *volume,
106 static void forget_password_in_memory (ModestTnyAccountStore *self,
107 const gchar *server_account_name);
109 static void add_connection_specific_transport_accounts (ModestTnyAccountStore *self);
111 static void remove_connection_specific_transport_accounts (ModestTnyAccountStore *self);
113 static void connection_status_changed (TnyAccount *account,
114 TnyConnectionStatus status,
117 static gboolean only_local_accounts (ModestTnyAccountStore *self);
119 /* list my signals */
121 ACCOUNT_CHANGED_SIGNAL,
122 ACCOUNT_INSERTED_SIGNAL,
123 ACCOUNT_REMOVED_SIGNAL,
125 PASSWORD_REQUESTED_SIGNAL,
129 typedef struct _ModestTnyAccountStorePrivate ModestTnyAccountStorePrivate;
130 struct _ModestTnyAccountStorePrivate {
132 GHashTable *password_hash;
133 GHashTable *account_settings_dialog_hash;
134 ModestAccountMgr *account_mgr;
135 TnySessionCamel *session;
140 /* We cache the lists of accounts here */
141 TnyList *store_accounts;
142 TnyList *transport_accounts;
143 TnyList *store_accounts_outboxes;
145 /* Matches transport accounts and outbox folder */
146 GHashTable *outbox_of_transport;
149 #define MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
150 MODEST_TYPE_TNY_ACCOUNT_STORE, \
151 ModestTnyAccountStorePrivate))
154 static GObjectClass *parent_class = NULL;
156 static guint signals[LAST_SIGNAL] = {0};
159 modest_tny_account_store_get_type (void)
161 static GType my_type = 0;
164 static const GTypeInfo my_info = {
165 sizeof(ModestTnyAccountStoreClass),
166 modest_tny_account_store_base_init, /* base init */
167 NULL, /* base finalize */
168 (GClassInitFunc) modest_tny_account_store_class_init,
169 NULL, /* class finalize */
170 NULL, /* class data */
171 sizeof(ModestTnyAccountStore),
173 (GInstanceInitFunc) modest_tny_account_store_instance_init,
177 static const GInterfaceInfo iface_info = {
178 (GInterfaceInitFunc) modest_tny_account_store_init,
179 NULL, /* interface_finalize */
180 NULL /* interface_data */
183 my_type = g_type_register_static (G_TYPE_OBJECT,
184 "ModestTnyAccountStore",
186 g_type_add_interface_static (my_type, TNY_TYPE_ACCOUNT_STORE,
194 modest_tny_account_store_base_init (gpointer g_class)
196 static gboolean tny_account_store_initialized = FALSE;
198 if (!tny_account_store_initialized) {
200 signals[ACCOUNT_CHANGED_SIGNAL] =
201 g_signal_new ("account_changed",
202 MODEST_TYPE_TNY_ACCOUNT_STORE,
204 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_changed),
206 g_cclosure_marshal_VOID__OBJECT,
207 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
209 signals[ACCOUNT_INSERTED_SIGNAL] =
210 g_signal_new ("account_inserted",
211 MODEST_TYPE_TNY_ACCOUNT_STORE,
213 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_inserted),
215 g_cclosure_marshal_VOID__OBJECT,
216 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
218 signals[ACCOUNT_REMOVED_SIGNAL] =
219 g_signal_new ("account_removed",
220 MODEST_TYPE_TNY_ACCOUNT_STORE,
222 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_removed),
224 g_cclosure_marshal_VOID__OBJECT,
225 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
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_verify_last_ref (TnyAccount *account, const gchar *str)
308 g_return_if_fail (account && TNY_IS_ACCOUNT(account));
310 txt = g_strdup_printf ("%s: %s", str ? str : "?", tny_account_get_name(account));
311 MODEST_DEBUG_VERIFY_OBJECT_LAST_REF(G_OBJECT(account),txt);
316 foreach_account_append_to_list (gpointer data,
321 list = TNY_LIST (user_data);
322 tny_list_append (list, G_OBJECT (data));
325 /********************************************************************/
326 /* Control the state of the MMC local account */
327 /********************************************************************/
329 /** Only call this if the memory card is really mounted.
332 add_mmc_account(ModestTnyAccountStore *self, gboolean emit_insert_signal)
334 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
335 g_return_if_fail (priv->session);
337 TnyAccount *mmc_account = modest_tny_account_new_for_local_folders (priv->account_mgr,
339 MODEST_MCC1_VOLUMEPATH);
341 /* Add to the list of store accounts */
342 tny_list_append (priv->store_accounts, G_OBJECT (mmc_account));
344 if (emit_insert_signal) {
345 g_signal_emit (G_OBJECT (self),
346 signals [ACCOUNT_INSERTED_SIGNAL],
351 g_object_unref (mmc_account);
355 on_vfs_volume_mounted(GnomeVFSVolumeMonitor *volume_monitor,
356 GnomeVFSVolume *volume,
359 ModestTnyAccountStore *self;
360 ModestTnyAccountStorePrivate *priv;
364 self = MODEST_TNY_ACCOUNT_STORE(user_data);
365 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
367 /* Check whether this was the external MMC1 card: */
368 uri = gnome_vfs_volume_get_activation_uri (volume);
370 if (uri && (!strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI))) {
371 add_mmc_account (self, TRUE /* emit the insert signal. */);
378 on_vfs_volume_unmounted(GnomeVFSVolumeMonitor *volume_monitor,
379 GnomeVFSVolume *volume,
382 ModestTnyAccountStore *self;
383 ModestTnyAccountStorePrivate *priv;
386 self = MODEST_TNY_ACCOUNT_STORE(user_data);
387 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
389 /* Check whether this was the external MMC1 card: */
390 uri = gnome_vfs_volume_get_activation_uri (volume);
391 if (uri && (strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI) == 0)) {
392 TnyAccount *mmc_account = NULL;
393 gboolean found = FALSE;
394 TnyIterator *iter = NULL;
396 iter = tny_list_create_iterator (priv->store_accounts);
397 while (!tny_iterator_is_done (iter) && !found) {
400 account = TNY_ACCOUNT (tny_iterator_get_current (iter));
401 if (modest_tny_account_is_memory_card_account (account)) {
403 mmc_account = g_object_ref (account);
405 g_object_unref (account);
406 tny_iterator_next (iter);
408 g_object_unref (iter);
411 /* Remove from the list */
412 tny_list_remove (priv->store_accounts, G_OBJECT (mmc_account));
414 /* Notify observers */
415 g_signal_emit (G_OBJECT (self),
416 signals [ACCOUNT_REMOVED_SIGNAL],
419 g_object_unref (mmc_account);
421 g_warning ("%s: there was no store account for the unmounted MMC",
429 * forget_password_in_memory
430 * @self: a TnyAccountStore instance
431 * @account: A server account.
433 * Forget any password stored in memory for this account.
434 * For instance, this should be called when the user has changed the password in the account settings.
437 forget_password_in_memory (ModestTnyAccountStore *self,
438 const gchar * server_account_name)
440 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
442 if (server_account_name && priv->password_hash) {
443 g_hash_table_remove (priv->password_hash, server_account_name);
448 on_account_changed (ModestAccountMgr *acc_mgr,
449 const gchar *account_name,
450 TnyAccountType account_type,
453 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
454 ModestTnyAccountStorePrivate *priv;
455 TnyList* account_list;
456 gboolean found = FALSE;
457 TnyIterator *iter = NULL;
459 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
460 account_list = (account_type == TNY_ACCOUNT_TYPE_STORE ?
461 priv->store_accounts :
462 priv->transport_accounts);
464 iter = tny_list_create_iterator (account_list);
465 while (!tny_iterator_is_done (iter) && !found) {
466 TnyAccount *tny_account;
467 tny_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
469 if (!strcmp (tny_account_get_id (tny_account), account_name)) {
471 modest_tny_account_update_from_account (tny_account, get_password, forget_password);
472 g_signal_emit (G_OBJECT(self), signals[ACCOUNT_CHANGED_SIGNAL], 0, tny_account);
474 g_object_unref (tny_account);
476 tny_iterator_next (iter);
480 g_object_unref (iter);
484 on_account_settings_hide (GtkWidget *widget, gpointer user_data)
486 /* This is easier than using a struct for the user_data: */
487 ModestTnyAccountStore *self = modest_runtime_get_account_store();
488 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
490 gchar *account_name = (gchar *) user_data;
492 g_hash_table_remove (priv->account_settings_dialog_hash, account_name);
496 show_password_warning_only (const gchar *msg)
498 ModestWindow *main_window =
499 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE); /* don't create */
501 /* Show an explanatory temporary banner: */
503 modest_platform_information_banner (NULL, NULL, msg);
507 show_wrong_password_dialog (TnyAccount *account)
509 /* This is easier than using a struct for the user_data: */
510 ModestTnyAccountStore *self = modest_runtime_get_account_store();
511 GtkWidget *dialog = NULL;
513 if (g_object_get_data (G_OBJECT (account), "connection_specific") != NULL) {
514 modest_ui_actions_on_smtp_servers (NULL, NULL);
516 const gchar *modest_account_name;
517 modest_account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
518 dialog = modest_tny_account_store_show_account_settings_dialog (self, modest_account_name);
520 /* Show an explanatory temporary banner: */
521 modest_platform_information_banner (dialog, NULL, _("mcen_ib_username_pw_incorrect"));
524 /* This callback will be called by Tinymail when it needs the password
525 * from the user or the account settings.
526 * It can also call forget_password() before calling this,
527 * so that we clear wrong passwords out of our account settings.
528 * Note that TnyAccount here will be the server account. */
530 get_password (TnyAccount *account, const gchar * prompt_not_used, gboolean *cancel)
532 ModestTnyAccountStore *self = NULL;
533 ModestTnyAccountStorePrivate *priv;
534 gchar *username = NULL;
536 gpointer pwd_ptr = NULL;
537 gboolean already_asked = FALSE;
538 const gchar *server_account_name;
541 g_return_val_if_fail (account, NULL);
544 g_debug ("%s: prompt (not shown) = %s\n", __FUNCTION__, prompt_not_used);
547 /* Get a reference to myself */
548 self = MODEST_TNY_ACCOUNT_STORE (g_object_get_data (G_OBJECT(account), "account_store"));
549 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
551 /* Ensure that we still have this account. It could happen
552 that a set_online was requested *before* removing an
553 account, and due to tinymail emits the get_password
554 function using a g_idle the account could be actually
555 removed *before* this function was really called */
556 url_string = tny_account_get_url_string (account);
558 TnyAccount *tmp_account;
560 tmp_account = tny_account_store_find_account (TNY_ACCOUNT_STORE (self),
568 g_object_unref (tmp_account);
571 server_account_name = tny_account_get_id (account);
572 if (!server_account_name || !self) {
573 g_warning ("modest: %s: could not retrieve account_store for account %s",
574 __FUNCTION__, server_account_name ? server_account_name : "<NULL>");
581 /* This hash map stores passwords, including passwords that are not stored in gconf. */
582 /* Is it in the hash? if it's already there, it must be wrong... */
583 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
584 * type-punned ptrs...*/
585 already_asked = priv->password_hash &&
586 g_hash_table_lookup_extended (priv->password_hash,
589 (gpointer*)&pwd_ptr);
591 g_debug ("%s: Already asked = %d\n", __FUNCTION__, already_asked);
594 /* If the password is not already there, try ModestConf */
595 if (!already_asked) {
596 pwd = modest_account_mgr_get_server_account_password (priv->account_mgr,
597 server_account_name);
598 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup (pwd));
601 /* If it was already asked, it must have been wrong, so ask again */
602 if (already_asked || !pwd || strlen(pwd) == 0) {
603 /* As per the UI spec, if no password was set in the account settings,
604 * ask for it now. But if the password is wrong in the account settings,
605 * then show a banner and the account settings dialog so it can be corrected:
607 ModestTransportStoreProtocol proto;
608 const gboolean settings_have_password =
609 modest_account_mgr_get_server_account_has_password (priv->account_mgr, server_account_name);
611 /* Show an error and after that ask for a password */
612 proto = modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (account));
613 if (proto == MODEST_PROTOCOL_TRANSPORT_SMTP) {
614 gchar *username = NULL, *msg = NULL;
615 username = modest_account_mgr_get_server_account_username (priv->account_mgr,
616 server_account_name);
617 if (!username || strlen(username) == 0) {
618 msg = g_strdup_printf (_("emev_ni_ui_smtp_userid_invalid"),
619 tny_account_get_name (account),
620 tny_account_get_hostname (account));
623 password = modest_account_mgr_get_server_account_password (priv->account_mgr,
624 server_account_name);
625 if (!password || strlen(password) == 0)
626 msg = g_strdup_printf (_("emev_ni_ui_smtp_passwd_invalid"),
627 tny_account_get_name (account),
628 tny_account_get_hostname (account));
630 msg = g_strdup_printf (_("emev_ni_ui_smtp_authentication_fail_error"),
631 tny_account_get_hostname (account));
636 modest_platform_run_information_dialog (NULL, msg, TRUE);
643 if (settings_have_password) {
644 /* The password must be wrong, so show the account settings dialog so it can be corrected: */
645 show_wrong_password_dialog (account);
653 /* we don't have it yet. Get the password from the user */
654 const gchar* account_id = tny_account_get_id (account);
655 gboolean remember = FALSE;
660 gboolean username_known =
661 modest_account_mgr_get_server_account_username_has_succeeded(priv->account_mgr,
662 server_account_name);
663 /* If the login has ever succeeded then show a specific message */
665 msg = dgettext ("hildon-common-strings", "ecdg_ib_set_password_incorrect");
667 msg = _("mcen_ib_username_pw_incorrect");
668 show_password_warning_only (msg);
671 /* Request password */
672 g_signal_emit (G_OBJECT (self), signals[PASSWORD_REQUESTED_SIGNAL], 0,
673 account_id, /* server_account_name */
674 &username, &pwd, cancel, &remember);
678 /* The password will be returned as the result,
679 * but we need to tell tinymail about the username too: */
681 /* WARNING: I disabled setting username as this can cause locks. Anyway,
682 * as now we have the password dialog username entry always dimmed
683 * this shouldn't be a problem */
686 /* tny_account_set_user (account, username); */
688 /* Do not save the password in gconf, because
689 * the UI spec says "The password will never
690 * be saved in the account": */
692 /* We need to dup the string even knowing that
693 it's already a dup of the contents of an
694 entry, because it if it's wrong, then camel
696 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup(pwd));
698 g_hash_table_remove (priv->password_hash, server_account_name);
713 modest_tny_account_store_forget_already_asked (ModestTnyAccountStore *self, TnyAccount *account)
715 g_return_if_fail (account);
717 ModestTnyAccountStorePrivate *priv;
719 gpointer pwd_ptr = NULL;
720 gboolean already_asked = FALSE;
722 const gchar *server_account_name = tny_account_get_id (account);
724 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
726 /* This hash map stores passwords, including passwords that are not stored in gconf. */
727 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
728 * type-punned ptrs...*/
729 already_asked = priv->password_hash &&
730 g_hash_table_lookup_extended (priv->password_hash,
733 (gpointer*)&pwd_ptr);
736 g_hash_table_remove (priv->password_hash, server_account_name);
744 /* tinymail calls this if the connection failed due to an incorrect password.
745 * And it seems to call this for any general connection failure. */
747 forget_password (TnyAccount *account)
749 ModestTnyAccountStore *self;
750 ModestTnyAccountStorePrivate *priv;
751 const TnyAccountStore *account_store;
755 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
757 self = MODEST_TNY_ACCOUNT_STORE (account_store);
758 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
759 key = tny_account_get_id (account);
761 /* Do not remove the key, this will allow us to detect that we
762 have already asked for it at least once */
763 pwd = g_hash_table_lookup (priv->password_hash, key);
765 memset (pwd, 0, strlen (pwd));
766 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
769 /* Remove from configuration system */
771 modest_account_mgr_unset (priv->account_mgr,
772 key, MODEST_ACCOUNT_PASSWORD, TRUE);
777 modest_tny_account_store_finalize (GObject *obj)
779 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(obj);
780 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
782 g_free (priv->cache_dir);
783 priv->cache_dir = NULL;
785 if (priv->password_hash) {
786 g_hash_table_destroy (priv->password_hash);
787 priv->password_hash = NULL;
790 if (priv->account_settings_dialog_hash) {
791 g_hash_table_destroy (priv->account_settings_dialog_hash);
792 priv->account_settings_dialog_hash = NULL;
795 if (priv->outbox_of_transport) {
796 g_hash_table_destroy (priv->outbox_of_transport);
797 priv->outbox_of_transport = NULL;
800 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
801 priv->sighandlers = NULL;
803 if (priv->account_mgr) {
804 g_object_unref (G_OBJECT(priv->account_mgr));
805 priv->account_mgr = NULL;
809 g_object_unref (G_OBJECT(priv->device));
813 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
814 if (priv->store_accounts) {
815 tny_list_foreach (priv->store_accounts, (GFunc)account_verify_last_ref, "store");
816 g_object_unref (priv->store_accounts);
817 priv->store_accounts = NULL;
820 if (priv->transport_accounts) {
821 tny_list_foreach (priv->transport_accounts, (GFunc)account_verify_last_ref, "transport");
822 g_object_unref (priv->transport_accounts);
823 priv->transport_accounts = NULL;
826 if (priv->store_accounts_outboxes) {
827 g_object_unref (priv->store_accounts_outboxes);
828 priv->store_accounts_outboxes = NULL;
832 camel_object_unref (CAMEL_OBJECT(priv->session));
833 priv->session = NULL;
836 G_OBJECT_CLASS(parent_class)->finalize (obj);
840 volume_path_is_mounted (const gchar* path)
842 g_return_val_if_fail (path, FALSE);
844 gboolean result = FALSE;
845 gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
846 g_return_val_if_fail (path_as_uri, FALSE);
848 /* Get the monitor singleton: */
849 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
851 /* This seems like a simpler way to do this, but it returns a
852 * GnomeVFSVolume even if the drive is not mounted: */
854 GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor,
855 MODEST_MCC1_VOLUMEPATH);
857 gnome_vfs_volume_unref(volume);
861 /* Get the mounted volumes from the monitor: */
862 GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
864 for (iter = list; iter; iter = g_list_next (iter)) {
865 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
869 gnome_vfs_volume_get_display_name (volume);
870 printf ("volume display name=%s\n", display_name);
871 g_free (display_name);
875 gnome_vfs_volume_get_activation_uri (volume);
876 /* printf (" uri=%s\n", uri); */
877 if (uri && (strcmp (uri, path_as_uri) == 0))
882 gnome_vfs_volume_unref (volume);
888 g_free (path_as_uri);
893 ModestTnyAccountStore*
894 modest_tny_account_store_new (ModestAccountMgr *account_mgr,
898 ModestTnyAccountStorePrivate *priv;
899 TnyAccount *local_account = NULL;
901 g_return_val_if_fail (account_mgr, NULL);
902 g_return_val_if_fail (device, NULL);
904 obj = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
905 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
907 priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
908 priv->device = g_object_ref (device);
910 priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
911 if (!priv->session) {
912 g_warning ("failed to get TnySessionCamel");
916 /* Set the ui locker */
917 tny_session_camel_set_ui_locker (priv->session, tny_gtk_lockable_new ());
919 /* Connect signals */
920 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
921 G_OBJECT(account_mgr), "account_inserted",
922 G_CALLBACK (on_account_inserted), obj);
923 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
924 G_OBJECT(account_mgr), "account_changed",
925 G_CALLBACK (on_account_changed), obj);
926 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
927 G_OBJECT(account_mgr), "account_removed",
928 G_CALLBACK (on_account_removed), obj);
930 /* Create the lists of accounts */
931 priv->store_accounts = tny_simple_list_new ();
932 priv->transport_accounts = tny_simple_list_new ();
933 priv->store_accounts_outboxes = tny_simple_list_new ();
935 /* Create the local folders account */
937 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
938 tny_list_append (priv->store_accounts, G_OBJECT(local_account));
939 g_object_unref (local_account);
941 /* Add the other remote accounts. Do this after adding the
942 local account, because we need to add our outboxes to the
943 global OUTBOX hosted in the local account */
944 add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
946 /* Add connection-specific transport accounts if there are any
947 accounts available */
948 if (!only_local_accounts (MODEST_TNY_ACCOUNT_STORE(obj)))
949 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
951 /* This is a singleton, so it does not need to be unrefed. */
952 if (volume_path_is_mounted (MODEST_MCC1_VOLUMEPATH)) {
954 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */);
957 return MODEST_TNY_ACCOUNT_STORE(obj);
961 modest_tny_account_store_get_accounts (TnyAccountStore *self,
963 TnyGetAccountsRequestType request_type)
965 ModestTnyAccountStorePrivate *priv;
967 g_return_if_fail (self);
968 g_return_if_fail (TNY_IS_LIST(list));
970 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
972 switch (request_type) {
973 case TNY_ACCOUNT_STORE_BOTH:
974 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
975 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
977 case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
978 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
980 case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
981 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
984 g_return_if_reached ();
987 /* Initialize session. Why do we need this ??? */
988 tny_session_camel_set_initialized (priv->session);
993 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
995 ModestTnyAccountStorePrivate *priv;
996 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
998 if (!priv->cache_dir)
999 priv->cache_dir = g_build_filename (g_get_home_dir(),
1000 MODEST_DIR, MODEST_CACHE_DIR, NULL);
1001 return priv->cache_dir;
1006 * callers need to unref
1009 modest_tny_account_store_get_device (TnyAccountStore *self)
1011 ModestTnyAccountStorePrivate *priv;
1013 g_return_val_if_fail (self, NULL);
1015 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1018 return g_object_ref (G_OBJECT(priv->device));
1025 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1027 return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self),
1028 MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1035 modest_tny_account_store_alert (TnyAccountStore *self,
1036 TnyAccount *account,
1041 ModestTransportStoreProtocol proto =
1042 MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
1043 const gchar* server_name = "";
1044 gchar *prompt = NULL;
1047 /* NOTE: account may be NULL in some cases */
1048 g_return_val_if_fail (error, FALSE);
1050 /* Get the server name: */
1052 server_name = tny_account_get_hostname (account);
1053 const gchar *proto_name = tny_account_get_proto (account);
1055 proto = modest_protocol_info_get_transport_store_protocol (proto_name);
1057 g_warning("modest: %s: account with id=%s has no proto.\n", __FUNCTION__,
1058 tny_account_get_id (account));
1063 switch (error->code) {
1064 case TNY_SYSTEM_ERROR_CANCEL:
1065 /* Don't show waste the user's time by showing him a dialog telling
1066 * him that he has just cancelled something: */
1069 case TNY_SERVICE_ERROR_PROTOCOL:
1070 /* Like a BAD from IMAP (protocol error) */
1071 case TNY_SERVICE_ERROR_LOST_CONNECTION:
1072 /* Lost the connection with the service */
1073 case TNY_SERVICE_ERROR_UNAVAILABLE:
1074 /* You must be working online for this operation */
1075 case TNY_SERVICE_ERROR_CONNECT:
1077 case MODEST_PROTOCOL_STORE_POP:
1078 prompt = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"),
1081 case MODEST_PROTOCOL_STORE_IMAP:
1082 prompt = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"),
1085 case MODEST_PROTOCOL_TRANSPORT_SMTP:
1086 prompt = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"),
1090 g_return_val_if_reached (FALSE);
1094 case TNY_SERVICE_ERROR_AUTHENTICATE:
1095 /* It seems that there's no better error to show with
1096 * POP and IMAP because TNY_SERVICE_ERROR_AUTHENTICATE
1097 * may appear if there's a timeout during auth */
1099 case MODEST_PROTOCOL_STORE_POP:
1100 prompt = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"),
1103 case MODEST_PROTOCOL_STORE_IMAP:
1104 prompt = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"),
1107 case MODEST_PROTOCOL_TRANSPORT_SMTP:
1108 prompt = g_strdup_printf (_("emev_ni_ui_smtp_authentication_fail_error"),
1112 g_return_val_if_reached (FALSE);
1116 case TNY_SERVICE_ERROR_CERTIFICATE:
1117 /* We'll show the proper dialog later */
1120 case TNY_SYSTEM_ERROR_MEMORY:
1121 /* Can't allocate memory for this operation */
1123 case TNY_SERVICE_ERROR_UNKNOWN:
1126 g_debug ("Unexpected error %d", error->code);
1127 g_return_val_if_reached (FALSE);
1131 if (error->code == TNY_SERVICE_ERROR_CERTIFICATE)
1132 retval = modest_platform_run_certificate_confirmation_dialog (server_name,
1134 else if (error->code == TNY_SERVICE_ERROR_AUTHENTICATE) {
1135 modest_platform_run_information_dialog (NULL, prompt, TRUE);
1137 /* Show the account dialog if it was wrong */
1138 if (error->code == TNY_SERVICE_ERROR_CONNECT ||
1139 error->code == TNY_SERVICE_ERROR_AUTHENTICATE)
1140 show_wrong_password_dialog (account);
1145 g_debug ("%s: error code %d (%s", __FUNCTION__, error->code, error->message);
1155 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1157 TnyAccountStoreIface *klass;
1159 g_return_if_fail (g);
1161 klass = (TnyAccountStoreIface *)g;
1163 klass->get_accounts =
1164 modest_tny_account_store_get_accounts;
1165 klass->get_cache_dir =
1166 modest_tny_account_store_get_cache_dir;
1168 modest_tny_account_store_get_device;
1170 modest_tny_account_store_alert;
1171 klass->find_account =
1172 modest_tny_account_store_find_account_by_url;
1176 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1177 ModestTnyGetPassFunc func)
1179 /* not implemented, we use signals */
1180 g_printerr ("modest: set_get_pass_func not implemented\n");
1184 modest_tny_account_store_get_session (TnyAccountStore *self)
1186 g_return_val_if_fail (self, NULL);
1187 return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1191 get_tny_account_by (TnyList *accounts,
1192 ModestTnyAccountStoreQueryType type,
1195 TnyIterator *iter = NULL;
1196 gboolean found = FALSE;
1197 TnyAccount *retval = NULL;
1199 g_return_val_if_fail (TNY_IS_LIST(accounts), NULL);
1201 if (tny_list_get_length(accounts) == 0) {
1202 g_warning ("%s: account list is empty", __FUNCTION__);
1206 iter = tny_list_create_iterator (accounts);
1207 while (!tny_iterator_is_done (iter) && !found) {
1208 TnyAccount *tmp_account = NULL;
1209 const gchar *val = NULL;
1211 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1212 if (!TNY_IS_ACCOUNT(tmp_account)) {
1213 g_warning ("%s: not a valid account", __FUNCTION__);
1219 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1220 val = tny_account_get_id (tmp_account);
1222 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1223 val = tny_account_get_url_string (tmp_account);
1227 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL &&
1228 tny_account_matches_url_string (tmp_account, str)) {
1229 retval = g_object_ref (tmp_account);
1232 if (val && str && strcmp (val, str) == 0) {
1233 retval = g_object_ref (tmp_account);
1237 g_object_unref (tmp_account);
1238 tny_iterator_next (iter);
1240 g_object_unref (iter);
1246 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self,
1247 ModestTnyAccountStoreQueryType type,
1250 TnyAccount *account = NULL;
1251 ModestTnyAccountStorePrivate *priv;
1253 g_return_val_if_fail (self, NULL);
1254 g_return_val_if_fail (str, NULL);
1256 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1258 /* Search in store accounts */
1259 account = get_tny_account_by (priv->store_accounts, type, str);
1261 /* If we already found something, no need to search the transport accounts */
1263 account = get_tny_account_by (priv->transport_accounts, type, str);
1265 /* If we already found something, no need to search the
1266 per-account outbox accounts */
1268 account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1271 /* Warn if nothing was found. This is generally unusual. */
1273 g_warning("%s: Failed to find account with %s=%s\n",
1275 (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",
1279 /* Returns a new reference to the account if found */
1285 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1286 const gchar *account_name,
1287 TnyAccountType type)
1289 ModestTnyAccountStorePrivate *priv = NULL;
1290 TnyAccount *retval = NULL;
1291 TnyList *account_list = NULL;
1292 TnyIterator *iter = NULL;
1295 g_return_val_if_fail (self, NULL);
1296 g_return_val_if_fail (account_name, NULL);
1297 g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE ||
1298 type == TNY_ACCOUNT_TYPE_TRANSPORT,
1301 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1303 account_list = (type == TNY_ACCOUNT_TYPE_STORE) ?
1304 priv->store_accounts :
1305 priv->transport_accounts;
1307 if (!account_list) {
1308 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__,
1309 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1313 /* Look for the server account */
1315 iter = tny_list_create_iterator (account_list);
1316 while (!tny_iterator_is_done (iter) && !found) {
1317 const gchar *modest_acc_name;
1318 TnyAccount *tmp_account;
1320 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1322 modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1324 if (account_name && modest_acc_name && !strcmp (account_name, modest_acc_name)) {
1326 retval = g_object_ref (tmp_account);
1328 /* Free and continue */
1329 g_object_unref (tmp_account);
1330 tny_iterator_next (iter);
1332 g_object_unref (iter);
1335 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1336 "Number of server accounts of this type=%d\n", __FUNCTION__,
1337 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1338 account_name, tny_list_get_length (account_list));
1341 /* Returns a new reference */
1346 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (
1347 ModestTnyAccountStore *self, const gchar *account_name)
1351 g_return_val_if_fail (self && MODEST_IS_TNY_ACCOUNT_STORE(self), NULL);
1352 g_return_val_if_fail (account_name, NULL);
1354 /* Get the current connection: */
1355 device = modest_runtime_get_device ();
1358 g_warning ("%s: could not get device", __FUNCTION__);
1362 if (!tny_device_is_online (device))
1365 #ifdef MODEST_HAVE_CONIC
1366 g_return_val_if_fail (TNY_IS_MAEMO_CONIC_DEVICE (device), NULL);
1368 TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);
1369 const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1370 /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1374 ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1378 const gchar *connection_id = con_ic_iap_get_id (connection);
1379 /* printf ("DEBUG: %s: connection_id=%s\n", __FUNCTION__, connection_id); */
1383 /* Get the connection-specific transport acccount, if any: */
1384 ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1386 /* Check if this account has connection-specific SMTP enabled */
1387 if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1391 gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager,
1394 /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1395 if (!server_account_name) {
1396 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1399 TnyAccount* account = modest_tny_account_store_get_tny_account_by (self,
1400 MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1401 server_account_name);
1403 /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1404 g_free (server_account_name);
1406 /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1407 g_object_unref (connection);
1411 return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1412 #endif /* MODEST_HAVE_CONIC */
1417 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1418 const gchar *account_name)
1420 g_return_val_if_fail (self, NULL);
1421 g_return_val_if_fail (account_name, NULL);
1423 if (!account_name || !self)
1426 /* Get the connection-specific transport acccount, if any: */
1427 /* Note: This gives us a reference: */
1428 TnyAccount *account =
1429 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (self, account_name);
1431 /* If there is no connection-specific transport account (the common case),
1432 * just get the regular transport account: */
1434 /* The special local folders don't have transport accounts. */
1435 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1438 /* Note: This gives us a reference: */
1439 account = modest_tny_account_store_get_server_account (self, account_name,
1440 TNY_ACCOUNT_TYPE_TRANSPORT);
1444 /* returns a reference. */
1449 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1451 TnyAccount *account = NULL;
1452 ModestTnyAccountStorePrivate *priv;
1456 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1458 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1461 iter = tny_list_create_iterator (priv->store_accounts);
1462 while (!tny_iterator_is_done (iter) && !found) {
1463 TnyAccount *tmp_account;
1465 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1466 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1467 account = g_object_ref (tmp_account);
1470 g_object_unref (tmp_account);
1471 tny_iterator_next (iter);
1473 g_object_unref (iter);
1475 /* Returns a new reference to the account */
1480 modest_tny_account_store_get_mmc_folders_account (ModestTnyAccountStore *self)
1482 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1485 return modest_tny_account_store_get_tny_account_by (self, MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1486 MODEST_MMC_ACCOUNT_ID);
1490 /*********************************************************************************/
1492 add_existing_accounts (ModestTnyAccountStore *self)
1494 GSList *account_names = NULL, *iter = NULL;
1495 ModestTnyAccountStorePrivate *priv = NULL;
1497 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1499 /* These are account names, not server_account names */
1500 account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1502 for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1503 const gchar *account_name = (const gchar*) iter->data;
1505 /* Insert all enabled accounts without notifying */
1506 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1507 insert_account (self, account_name, FALSE);
1509 modest_account_mgr_free_account_names (account_names);
1513 connection_status_changed (TnyAccount *account,
1514 TnyConnectionStatus status,
1517 /* We do this here and not in the connection policy because we
1518 don't want to do it for every account, just for the
1519 accounts that are interactively added when modest is
1521 if (status == TNY_CONNECTION_STATUS_CONNECTED) {
1522 const gchar *account_name;
1523 ModestWindow *main_window;
1524 ModestTnyAccountStorePrivate *priv = NULL;
1526 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (data);
1528 /* Remove this handler */
1529 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
1531 "connection_status_changed");
1533 /* Perform a send receive */
1534 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
1535 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1536 modest_ui_actions_do_send_receive (account_name, FALSE, FALSE, TRUE, main_window);
1541 create_tny_account (ModestTnyAccountStore *self,
1543 TnyAccountType type,
1546 TnyAccount *account = NULL;
1547 ModestTnyAccountStorePrivate *priv = NULL;
1549 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1551 account = modest_tny_account_new_from_account (priv->account_mgr,
1558 /* Forget any cached password for the account, so that
1559 we use a new account if any */
1560 forget_password_in_memory (self, tny_account_get_id (account));
1562 /* Install a signal handler that will refresh the
1563 account the first time it becomes online. Do this
1564 only if we're adding a new account while the
1565 program is running (we do not want to do this
1567 if (type == TNY_ACCOUNT_TYPE_STORE && notify)
1568 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
1570 "connection_status_changed",
1571 G_CALLBACK (connection_status_changed),
1574 /* Set the account store */
1575 g_object_set_data (G_OBJECT(account), "account_store", self);
1577 g_printerr ("modest: failed to create account for %s\n", name);
1583 typedef struct _AddOutboxInfo {
1584 ModestTnyAccountStore *account_store;
1585 TnyAccount *transport_account;
1589 add_outbox_from_transport_account_to_global_outbox_get_folders_cb (TnyFolderStore *folder_store,
1595 TnyIterator *iter_folders;
1596 TnyFolder *per_account_outbox;
1597 TnyAccount *local_account = NULL;
1598 AddOutboxInfo *info = (AddOutboxInfo *) userdata;
1599 ModestTnyAccountStorePrivate *priv = NULL;
1600 ModestTnyAccountStore *self;
1602 self = MODEST_TNY_ACCOUNT_STORE (info->account_store);
1603 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1605 /* Note that this could happen if there is not enough space
1606 available on disk, then the outbox folder could not be
1608 if (tny_list_get_length (list) != 1) {
1609 g_warning ("%s: could not create outbox folder (%d folders found)", __FUNCTION__,
1610 tny_list_get_length (list));
1614 iter_folders = tny_list_create_iterator (list);
1615 per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1616 g_object_unref (iter_folders);
1617 g_object_unref (list);
1619 /* Add the outbox of the new per-account-local-outbox account
1620 to the global local merged OUTBOX of the local folders
1622 local_account = modest_tny_account_store_get_local_folders_account (info->account_store);
1623 modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1624 per_account_outbox);
1625 /* Add the pair to the hash table */
1626 g_hash_table_insert (priv->outbox_of_transport,
1627 info->transport_account,
1628 per_account_outbox);
1630 /* Notify that the local account changed */
1631 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1632 g_object_unref (local_account);
1633 g_object_unref (per_account_outbox);
1636 g_object_unref (info->transport_account);
1637 g_slice_free (AddOutboxInfo, info);
1642 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1643 const gchar *account_name,
1644 TnyAccount *transport_account)
1646 TnyList *folders = NULL;
1647 TnyAccount *account_outbox = NULL;
1648 ModestTnyAccountStorePrivate *priv = NULL;
1649 AddOutboxInfo *info;
1651 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1653 /* Create per account local outbox */
1655 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr,
1659 if (!G_IS_OBJECT (account_outbox)) {
1660 g_warning ("%s: could not create per account local outbox folder", __FUNCTION__);
1664 tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1666 /* Get the outbox folder */
1667 folders = tny_simple_list_new ();
1668 info = g_slice_new0 (AddOutboxInfo);
1669 info->account_store = self;
1670 info->transport_account = g_object_ref (transport_account);
1671 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (account_outbox), folders, NULL,
1672 add_outbox_from_transport_account_to_global_outbox_get_folders_cb, NULL, (gpointer) info);
1673 g_object_unref (account_outbox);
1677 * This function will be used for both adding new accounts and for the
1678 * initialization. In the initialization we do not want to emit
1679 * signals so notify will be FALSE, in the case of account additions
1680 * we do want to notify the observers
1683 insert_account (ModestTnyAccountStore *self,
1684 const gchar *account,
1687 ModestTnyAccountStorePrivate *priv = NULL;
1688 TnyAccount *store_account = NULL, *transport_account = NULL;
1690 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1692 /* Get the server and the transport account */
1693 store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE, notify);
1694 if (!store_account || !TNY_IS_ACCOUNT(store_account)) {
1695 g_warning ("%s: failed to create store account", __FUNCTION__);
1699 transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT, notify);
1700 if (!transport_account || !TNY_IS_ACCOUNT(transport_account)) {
1701 g_warning ("%s: failed to create transport account", __FUNCTION__);
1702 g_object_unref (store_account);
1706 /* Add accounts to the lists */
1707 tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1708 tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1710 /* Create a new pseudo-account with an outbox for this
1711 transport account and add it to the global outbox
1712 in the local account */
1713 add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1715 /* Notify the observers. We do it after everything is
1718 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);
1719 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1723 g_object_unref (store_account);
1724 g_object_unref (transport_account);
1728 only_local_accounts (ModestTnyAccountStore *self)
1730 ModestTnyAccountStorePrivate *priv = NULL;
1731 gboolean only_local = TRUE;
1734 /* Check if this is the first remote account we add */
1735 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1736 iter = tny_list_create_iterator (priv->store_accounts);
1738 while (!tny_iterator_is_done (iter) && only_local) {
1739 TnyAccount *account = (TnyAccount *) tny_iterator_get_current (iter);
1740 if (modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1742 g_object_unref (account);
1743 tny_iterator_next (iter);
1745 g_object_unref (iter);
1751 on_account_inserted (ModestAccountMgr *acc_mgr,
1752 const gchar *account,
1755 gboolean add_specific;
1757 add_specific = only_local_accounts (MODEST_TNY_ACCOUNT_STORE (user_data));
1759 /* Insert the account and notify the observers */
1760 insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1762 /* If it's the first remote account then add the connection
1763 specific SMTP servers as well */
1765 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE (user_data));
1769 /* This is the callback of the tny_camel_account_set_online called in
1770 on_account_removed to disconnect the account */
1772 on_account_disconnect_when_removing (TnyCamelAccount *account,
1777 ModestTnyAccountStore *self;
1778 ModestTnyAccountStorePrivate *priv;
1780 self = MODEST_TNY_ACCOUNT_STORE (user_data);
1781 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1783 /* Remove the connection-status-changed handler if it's still there */
1784 if (modest_signal_mgr_is_connected (priv->sighandlers,
1786 "connection_status_changed")) {
1787 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
1789 "connection_status_changed");
1792 /* Cancel all pending operations */
1793 tny_account_cancel (TNY_ACCOUNT (account));
1795 /* Unref the extra reference added by get_server_account */
1796 g_object_unref (account);
1798 /* Clear the cache if it's an store account */
1799 if (TNY_IS_STORE_ACCOUNT (account)) {
1800 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (account));
1801 } else if (TNY_IS_TRANSPORT_ACCOUNT (account)) {
1802 ModestTnySendQueue* send_queue;
1803 send_queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (account), FALSE);
1804 if (TNY_IS_SEND_QUEUE (send_queue)) {
1805 if (modest_tny_send_queue_sending_in_progress (send_queue))
1806 tny_send_queue_cancel (TNY_SEND_QUEUE (send_queue),
1807 TNY_SEND_QUEUE_CANCEL_ACTION_REMOVE,
1809 modest_runtime_remove_send_queue (TNY_TRANSPORT_ACCOUNT (account));
1815 * We use this one for both removing "normal" and "connection
1816 * specific" transport accounts
1819 remove_transport_account (ModestTnyAccountStore *self,
1820 TnyTransportAccount *transport_account)
1822 ModestTnyAccountStorePrivate *priv;
1823 TnyFolder *outbox = NULL;
1825 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1827 /* Remove it from the list of accounts and notify the
1828 observers. Do not need to wait for account
1830 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, transport_account);
1831 tny_list_remove (priv->transport_accounts, (GObject *) transport_account);
1833 /* Remove the OUTBOX of the account from the global outbox */
1834 outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
1836 if (TNY_IS_FOLDER (outbox)) {
1837 TnyAccount *local_account = NULL;
1838 TnyAccount *outbox_account = tny_folder_get_account (outbox);
1840 if (outbox_account) {
1841 tny_list_remove (priv->store_accounts_outboxes, G_OBJECT (outbox_account));
1842 /* Remove existing emails to send */
1843 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (outbox_account));
1844 g_object_unref (outbox_account);
1847 local_account = modest_tny_account_store_get_local_folders_account (self);
1848 modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1851 g_hash_table_remove (priv->outbox_of_transport, transport_account);
1853 /* Notify the change in the local account */
1854 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1855 g_object_unref (local_account);
1857 g_warning ("Removing a transport account that has no outbox");
1860 /* Cancel all pending operations */
1861 tny_account_cancel (TNY_ACCOUNT (transport_account));
1863 /* Disconnect and notify the observers. The callback will free the reference */
1864 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (transport_account), FALSE,
1865 on_account_disconnect_when_removing, self);
1869 images_cache_remove_filter (TnyStreamCache *self, const gchar *id, const gchar *account_name)
1871 gchar *account_name_with_separator;
1873 if (account_name == NULL || account_name[0] == '\0')
1876 if (id == NULL || id[0] == '\0')
1879 account_name_with_separator = g_strconcat (account_name, "__", NULL);
1881 result = (g_str_has_prefix (id, account_name));
1882 g_free (account_name_with_separator);
1888 on_account_removed (ModestAccountMgr *acc_mgr,
1889 const gchar *account,
1892 TnyAccount *store_account = NULL, *transport_account = NULL;
1893 ModestTnyAccountStore *self;
1894 ModestTnyAccountStorePrivate *priv;
1895 TnyStreamCache *stream_cache;
1897 self = MODEST_TNY_ACCOUNT_STORE (user_data);
1898 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1900 /* Get the server and the transport account */
1902 modest_tny_account_store_get_server_account (self, account,
1903 TNY_ACCOUNT_TYPE_STORE);
1905 modest_tny_account_store_get_server_account (self, account,
1906 TNY_ACCOUNT_TYPE_TRANSPORT);
1908 /* If there was any problem creating the account, for example,
1909 with the configuration system this could not exist */
1910 if (TNY_IS_STORE_ACCOUNT(store_account)) {
1911 /* Forget any cached password for the account */
1912 forget_password_in_memory (self, tny_account_get_id (store_account));
1914 /* Remove it from the list of accounts and notify the
1915 observers. Do not need to wait for account
1917 tny_list_remove (priv->store_accounts, (GObject *) store_account);
1918 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, store_account);
1920 /* Cancel all pending operations */
1921 tny_account_cancel (TNY_ACCOUNT (store_account));
1923 /* Disconnect before deleting the cache, because the
1924 disconnection will rewrite the cache to the
1926 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (store_account), FALSE,
1927 on_account_disconnect_when_removing, self);
1929 g_warning ("%s: no store account for account %s\n",
1930 __FUNCTION__, account);
1933 /* If there was any problem creating the account, for example,
1934 with the configuration system this could not exist */
1935 if (TNY_IS_TRANSPORT_ACCOUNT(transport_account)) {
1937 /* Forget any cached password for the account */
1938 forget_password_in_memory (self, tny_account_get_id (transport_account));
1940 /* Remove transport account. It'll free the reference
1941 added by get_server_account */
1942 remove_transport_account (self, TNY_TRANSPORT_ACCOUNT (transport_account));
1944 g_warning ("%s: no transport account for account %s\n",
1945 __FUNCTION__, account);
1948 /* Remove cached images */
1949 stream_cache = modest_runtime_get_images_cache ();
1950 tny_stream_cache_remove (stream_cache, (TnyStreamCacheRemoveFilter) images_cache_remove_filter, (gpointer) account);
1952 /* If there are no more user accounts then delete the
1953 transport specific SMTP servers */
1954 if (only_local_accounts (self))
1955 remove_connection_specific_transport_accounts (self);
1958 TnyTransportAccount *
1959 modest_tny_account_store_new_connection_specific_transport_account (ModestTnyAccountStore *self,
1962 ModestTnyAccountStorePrivate *priv = NULL;
1963 TnyAccount * tny_account = NULL;
1965 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1967 /* Add the account: */
1969 modest_tny_account_new_from_server_account_name (priv->account_mgr,
1975 g_object_set_data (G_OBJECT(tny_account),
1978 g_object_set_data (G_OBJECT(tny_account),
1979 "connection_specific",
1980 GINT_TO_POINTER (TRUE));
1982 tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1983 add_outbox_from_transport_account_to_global_outbox (self,
1988 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1991 return TNY_TRANSPORT_ACCOUNT (tny_account);
1996 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1998 ModestTnyAccountStorePrivate *priv = NULL;
1999 GSList *list_specifics = NULL, *iter = NULL;
2002 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2004 list_specifics = modest_conf_get_list (modest_runtime_get_conf (),
2005 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
2006 MODEST_CONF_VALUE_STRING, &err);
2009 g_return_if_reached ();
2012 /* Look at each connection-specific transport account for the
2013 * modest account: */
2014 iter = list_specifics;
2016 /* The list alternates between the connection name and the transport name: */
2017 iter = g_slist_next (iter);
2019 const gchar* transport_account_name = (const gchar*) (iter->data);
2020 TnyTransportAccount * account = NULL;
2021 account = modest_tny_account_store_new_connection_specific_transport_account (
2022 self, transport_account_name);
2024 g_object_unref (account);
2026 iter = g_slist_next (iter);
2031 remove_connection_specific_transport_accounts (ModestTnyAccountStore *self)
2033 ModestTnyAccountStorePrivate *priv = NULL;
2034 GSList *list_specifics = NULL, *iter = NULL;
2037 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2040 list_specifics = modest_conf_get_list (modest_runtime_get_conf (),
2041 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
2042 MODEST_CONF_VALUE_STRING, &err);
2045 g_return_if_reached ();
2048 /* Look at each connection-specific transport account for the
2049 * modest account: */
2050 iter = list_specifics;
2052 /* The list alternates between the connection name and the transport name: */
2053 iter = g_slist_next (iter);
2055 const gchar* transport_account_name = (const gchar*) (iter->data);
2056 TnyAccount * account;
2057 account = modest_tny_account_store_get_server_account (self,
2058 transport_account_name,
2059 TNY_ACCOUNT_TYPE_TRANSPORT);
2061 /* the call will free the reference */
2063 remove_transport_account (self, TNY_TRANSPORT_ACCOUNT (account));
2065 iter = g_slist_next (iter);
2071 modest_tny_account_store_find_msg_in_outboxes (ModestTnyAccountStore *self,
2073 TnyAccount **ac_out)
2075 TnyIterator *acc_iter;
2076 ModestTnyAccountStorePrivate *priv;
2078 TnyAccount *msg_account = NULL;
2080 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
2081 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2083 acc_iter = tny_list_create_iterator (priv->store_accounts_outboxes);
2084 while (!msg && !tny_iterator_is_done (acc_iter)) {
2085 TnyList *folders = tny_simple_list_new ();
2086 TnyAccount *account = TNY_ACCOUNT (tny_iterator_get_current (acc_iter));
2087 TnyIterator *folders_iter = NULL;
2089 tny_folder_store_get_folders (TNY_FOLDER_STORE (account), folders, NULL, NULL);
2090 folders_iter = tny_list_create_iterator (folders);
2092 while (msg == NULL && !tny_iterator_is_done (folders_iter)) {
2093 TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (folders_iter));
2094 msg = tny_folder_find_msg (folder, uri, NULL);
2097 msg_account = g_object_ref (account);
2099 g_object_unref (folder);
2100 tny_iterator_next (folders_iter);
2102 g_object_unref (folders_iter);
2104 g_object_unref (folders);
2105 g_object_unref (account);
2106 tny_iterator_next (acc_iter);
2109 g_object_unref (acc_iter);
2112 *ac_out = msg_account;
2117 TnyTransportAccount *
2118 modest_tny_account_store_get_transport_account_from_outbox_header(ModestTnyAccountStore *self, TnyHeader *header)
2120 TnyIterator *acc_iter;
2121 ModestTnyAccountStorePrivate *priv;
2122 TnyTransportAccount *header_acc = NULL;
2125 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
2126 g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
2127 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2128 msg_id = modest_tny_send_queue_get_msg_id (header);
2129 acc_iter = tny_list_create_iterator (priv->transport_accounts);
2130 while (!header_acc && !tny_iterator_is_done (acc_iter)) {
2131 TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current (acc_iter));
2132 ModestTnySendQueue *send_queue;
2133 ModestTnySendQueueStatus status;
2134 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account), TRUE);
2135 if (TNY_IS_SEND_QUEUE (send_queue)) {
2136 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2137 if (status != MODEST_TNY_SEND_QUEUE_UNKNOWN)
2138 header_acc = g_object_ref(account);
2140 g_object_unref (account);
2141 tny_iterator_next (acc_iter);
2143 g_object_unref(acc_iter);
2151 modest_tny_account_store_show_account_settings_dialog (ModestTnyAccountStore *self,
2152 const gchar *account_name)
2154 ModestTnyAccountStorePrivate *priv;
2155 gpointer dialog_as_gpointer = NULL;
2158 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2159 found = g_hash_table_lookup_extended (priv->account_settings_dialog_hash,
2160 account_name, NULL, (gpointer*)&dialog_as_gpointer);
2163 modest_account_settings_dialog_check_allow_changes ((ModestAccountSettingsDialog *) dialog_as_gpointer);
2164 return (GtkWidget *) dialog_as_gpointer;
2166 ModestAccountSettings *settings;
2168 dialog = (GtkWidget *) modest_account_settings_dialog_new ();
2169 settings = modest_account_mgr_load_account_settings (priv->account_mgr, account_name);
2170 modest_account_settings_dialog_set_account (MODEST_ACCOUNT_SETTINGS_DIALOG (dialog), settings);
2171 g_object_unref (settings);
2172 modest_account_settings_dialog_switch_to_user_info (MODEST_ACCOUNT_SETTINGS_DIALOG (dialog));
2173 modest_account_settings_dialog_check_allow_changes (MODEST_ACCOUNT_SETTINGS_DIALOG (dialog));
2174 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
2176 g_hash_table_insert (priv->account_settings_dialog_hash, g_strdup (account_name), dialog);
2178 g_signal_connect (G_OBJECT (dialog), "hide", G_CALLBACK (on_account_settings_hide),
2179 g_strdup (account_name));
2181 /* Show it and delete it when it closes: */
2182 g_signal_connect_swapped (dialog,
2184 G_CALLBACK (gtk_widget_destroy),
2186 gtk_widget_show (GTK_WIDGET (dialog));
2194 ModestTnyAccountStore *account_store;
2195 ModestTnyAccountStoreShutdownCallback callback;
2201 account_shutdown_callback (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer userdata)
2203 ShutdownOpData *op_data = (ShutdownOpData *) userdata;
2205 if (op_data->pending == 0) {
2206 if (op_data->callback)
2207 op_data->callback (op_data->account_store, op_data->userdata);
2208 g_object_unref (op_data->account_store);
2214 account_shutdown (TnyAccount *account, ShutdownOpData *op_data)
2216 g_return_if_fail (account && TNY_IS_ACCOUNT(account));
2218 if (TNY_IS_STORE_ACCOUNT (account) &&
2219 !modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
2224 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(account), FALSE, account_shutdown_callback, op_data);
2229 modest_tny_account_store_shutdown (ModestTnyAccountStore *self,
2230 ModestTnyAccountStoreShutdownCallback callback,
2233 ShutdownOpData *op_data = g_new0 (ShutdownOpData, 1);
2234 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2235 op_data->callback = callback;
2236 op_data->userdata = userdata;
2237 op_data->pending = 0;
2238 op_data->account_store = g_object_ref (self);
2240 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
2241 if (priv->store_accounts) {
2242 tny_list_foreach (priv->store_accounts, (GFunc)account_shutdown, op_data);
2245 if (priv->transport_accounts) {
2246 tny_list_foreach (priv->transport_accounts, (GFunc)account_shutdown, op_data);
2249 if (op_data->pending == 0) {
2250 if (op_data->callback)
2251 op_data->callback (op_data->account_store, op_data->userdata);
2252 g_object_unref (op_data->account_store);