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>
43 #include "modest-text-utils.h"
44 #include <modest-runtime.h>
45 #include <modest-marshal.h>
46 #include <modest-protocol-registry.h>
47 #include <modest-local-folder-info.h>
48 #include "modest-account-protocol.h"
49 #include <modest-tny-account.h>
50 #include <modest-tny-local-folders-account.h>
51 #include <modest-account-mgr.h>
52 #include <modest-account-mgr-helpers.h>
53 #include <widgets/modest-window-mgr.h>
54 #include <modest-signal-mgr.h>
55 #include <modest-debug.h>
56 #include "modest-utils.h"
57 #include <modest-defs.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>
63 #include "modest-ui-actions.h"
64 #include <widgets/modest-account-settings-dialog.h>
65 #include <tny-camel-bs-msg-receive-strategy.h>
66 #include <modest-tny-msg.h>
68 #ifdef MODEST_PLATFORM_MAEMO
69 #include <tny-maemo-conic-device.h>
72 #include <libgnomevfs/gnome-vfs-volume-monitor.h>
74 /* 'private'/'protected' functions */
75 static void modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass);
76 static void modest_tny_account_store_finalize (GObject *obj);
77 static void modest_tny_account_store_instance_init (ModestTnyAccountStore *obj);
78 static void modest_tny_account_store_init (gpointer g, gpointer iface_data);
79 static void modest_tny_account_store_base_init (gpointer g_class);
81 static void on_account_inserted (ModestAccountMgr *acc_mgr,
85 static void add_existing_accounts (ModestTnyAccountStore *self);
87 static void insert_account (ModestTnyAccountStore *self,
91 static void on_account_removed (ModestAccountMgr *acc_mgr,
95 static gchar* get_password (TnyAccount *account,
96 const gchar * prompt_not_used,
99 static void forget_password (TnyAccount *account);
101 static void on_vfs_volume_mounted (GnomeVFSVolumeMonitor *volume_monitor,
102 GnomeVFSVolume *volume,
105 static void on_vfs_volume_unmounted (GnomeVFSVolumeMonitor *volume_monitor,
106 GnomeVFSVolume *volume,
109 static void add_connection_specific_transport_accounts (ModestTnyAccountStore *self);
111 static void remove_connection_specific_transport_accounts (ModestTnyAccountStore *self);
113 static inline gboolean only_local_accounts (ModestTnyAccountStore *self);
115 /* list my signals */
117 ACCOUNT_CHANGED_SIGNAL,
118 ACCOUNT_INSERTED_SIGNAL,
119 ACCOUNT_REMOVED_SIGNAL,
121 PASSWORD_REQUESTED_SIGNAL,
125 typedef struct _ModestTnyAccountStorePrivate ModestTnyAccountStorePrivate;
126 struct _ModestTnyAccountStorePrivate {
128 GHashTable *password_hash;
129 ModestAccountMgr *account_mgr;
130 TnySessionCamel *session;
135 /* We cache the lists of accounts here */
136 TnyList *store_accounts;
137 TnyList *transport_accounts;
138 TnyList *store_accounts_outboxes;
140 /* Matches transport accounts and outbox folder */
141 GHashTable *outbox_of_transport;
143 /* is sending mail blocked? */
144 gboolean send_mail_blocked;
147 #define MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
148 MODEST_TYPE_TNY_ACCOUNT_STORE, \
149 ModestTnyAccountStorePrivate))
152 static GObjectClass *parent_class = NULL;
154 static guint signals[LAST_SIGNAL] = {0};
157 modest_tny_account_store_get_type (void)
159 static GType my_type = 0;
162 static const GTypeInfo my_info = {
163 sizeof(ModestTnyAccountStoreClass),
164 modest_tny_account_store_base_init, /* base init */
165 NULL, /* base finalize */
166 (GClassInitFunc) modest_tny_account_store_class_init,
167 NULL, /* class finalize */
168 NULL, /* class data */
169 sizeof(ModestTnyAccountStore),
171 (GInstanceInitFunc) modest_tny_account_store_instance_init,
175 static const GInterfaceInfo iface_info = {
176 (GInterfaceInitFunc) modest_tny_account_store_init,
177 NULL, /* interface_finalize */
178 NULL /* interface_data */
181 my_type = g_type_register_static (G_TYPE_OBJECT,
182 "ModestTnyAccountStore",
184 g_type_add_interface_static (my_type, TNY_TYPE_ACCOUNT_STORE,
192 modest_tny_account_store_base_init (gpointer g_class)
194 static gboolean tny_account_store_initialized = FALSE;
196 if (!tny_account_store_initialized) {
198 signals[ACCOUNT_CHANGED_SIGNAL] =
199 g_signal_new ("account_changed",
200 MODEST_TYPE_TNY_ACCOUNT_STORE,
202 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_changed),
204 g_cclosure_marshal_VOID__OBJECT,
205 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
207 signals[ACCOUNT_INSERTED_SIGNAL] =
208 g_signal_new ("account_inserted",
209 MODEST_TYPE_TNY_ACCOUNT_STORE,
211 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_inserted),
213 g_cclosure_marshal_VOID__OBJECT,
214 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
216 signals[ACCOUNT_REMOVED_SIGNAL] =
217 g_signal_new ("account_removed",
218 MODEST_TYPE_TNY_ACCOUNT_STORE,
220 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_removed),
222 g_cclosure_marshal_VOID__OBJECT,
223 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
225 signals[PASSWORD_REQUESTED_SIGNAL] =
226 g_signal_new ("password_requested",
227 MODEST_TYPE_TNY_ACCOUNT_STORE,
229 G_STRUCT_OFFSET(ModestTnyAccountStoreClass, password_requested),
231 modest_marshal_VOID__STRING_POINTER_POINTER_POINTER_POINTER,
232 G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER,
235 tny_account_store_initialized = TRUE;
241 modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass)
243 GObjectClass *gobject_class;
244 gobject_class = (GObjectClass*) klass;
246 parent_class = g_type_class_peek_parent (klass);
247 gobject_class->finalize = modest_tny_account_store_finalize;
249 g_type_class_add_private (gobject_class,
250 sizeof(ModestTnyAccountStorePrivate));
254 modest_tny_account_store_instance_init (ModestTnyAccountStore *obj)
256 ModestTnyAccountStorePrivate *priv;
258 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
260 priv->cache_dir = NULL;
261 priv->account_mgr = NULL;
262 priv->session = NULL;
264 priv->sighandlers = NULL;
265 priv->send_mail_blocked = FALSE;
267 priv->outbox_of_transport = g_hash_table_new_full (g_direct_hash,
272 /* An in-memory store of passwords,
273 * for passwords that are not remembered in the configuration,
274 * so they need to be asked for from the user once in each session:
276 priv->password_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
280 /* disconnect the list of TnyAccounts */
282 account_verify_last_ref (TnyAccount *account, const gchar *str)
286 g_return_if_fail (account && TNY_IS_ACCOUNT(account));
288 txt = g_strdup_printf ("%s: %s", str ? str : "?", tny_account_get_name(account));
289 MODEST_DEBUG_VERIFY_OBJECT_LAST_REF(G_OBJECT(account),txt);
294 foreach_account_append_to_list (gpointer data,
299 list = TNY_LIST (user_data);
300 tny_list_append (list, G_OBJECT (data));
303 /********************************************************************/
304 /* Control the state of the MMC local account */
305 /********************************************************************/
307 /** Only call this if the memory card is really mounted.
310 add_mmc_account(ModestTnyAccountStore *self, gboolean emit_insert_signal)
312 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
313 g_return_if_fail (priv->session);
315 TnyAccount *mmc_account = modest_tny_account_new_for_local_folders (priv->account_mgr,
317 g_getenv (MODEST_MMC1_VOLUMEPATH_ENV));
319 /* Add to the list of store accounts */
320 tny_list_append (priv->store_accounts, G_OBJECT (mmc_account));
322 if (emit_insert_signal) {
323 g_signal_emit (G_OBJECT (self),
324 signals [ACCOUNT_INSERTED_SIGNAL],
329 g_object_unref (mmc_account);
333 on_vfs_volume_mounted(GnomeVFSVolumeMonitor *volume_monitor,
334 GnomeVFSVolume *volume,
337 ModestTnyAccountStore *self;
338 ModestTnyAccountStorePrivate *priv;
339 gchar *volume_path_uri;
343 self = MODEST_TNY_ACCOUNT_STORE(user_data);
344 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
346 /* Check whether this was the external MMC1 card: */
347 uri = gnome_vfs_volume_get_activation_uri (volume);
349 volume_path_uri = g_strconcat (MODEST_MMC1_VOLUMEPATH_URI_PREFIX,
350 g_getenv (MODEST_MMC1_VOLUMEPATH_ENV),
352 if (uri && (!strcmp (uri, volume_path_uri))) {
353 add_mmc_account (self, TRUE /* emit the insert signal. */);
356 g_free (volume_path_uri);
361 on_vfs_volume_unmounted(GnomeVFSVolumeMonitor *volume_monitor,
362 GnomeVFSVolume *volume,
365 ModestTnyAccountStore *self;
366 ModestTnyAccountStorePrivate *priv;
368 gchar *volume_path_uri;
370 self = MODEST_TNY_ACCOUNT_STORE(user_data);
371 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
373 /* Check whether this was the external MMC1 card: */
374 uri = gnome_vfs_volume_get_activation_uri (volume);
375 volume_path_uri = g_strconcat (MODEST_MMC1_VOLUMEPATH_URI_PREFIX,
376 g_getenv (MODEST_MMC1_VOLUMEPATH_ENV),
378 if (uri && (strcmp (uri, volume_path_uri) == 0)) {
379 TnyAccount *mmc_account = NULL;
380 gboolean found = FALSE;
381 TnyIterator *iter = NULL;
383 iter = tny_list_create_iterator (priv->store_accounts);
384 while (!tny_iterator_is_done (iter) && !found) {
387 account = TNY_ACCOUNT (tny_iterator_get_current (iter));
388 if (modest_tny_account_is_memory_card_account (account)) {
390 mmc_account = g_object_ref (account);
392 g_object_unref (account);
393 tny_iterator_next (iter);
395 g_object_unref (iter);
398 /* Remove from the list */
399 tny_list_remove (priv->store_accounts, G_OBJECT (mmc_account));
401 /* Notify observers */
402 g_signal_emit (G_OBJECT (self),
403 signals [ACCOUNT_REMOVED_SIGNAL],
406 g_object_unref (mmc_account);
408 g_debug ("%s: there was no store account for the unmounted MMC",
412 g_free (volume_path_uri);
417 modest_tny_account_store_forget_password_in_memory (ModestTnyAccountStore *self,
418 const gchar * server_account_name)
420 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
422 if (server_account_name && priv->password_hash)
423 g_hash_table_remove (priv->password_hash, server_account_name);
427 on_account_changed (ModestAccountMgr *acc_mgr,
428 const gchar *account_name,
429 TnyAccountType account_type,
432 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
433 ModestTnyAccountStorePrivate *priv;
434 TnyList* account_list;
435 gboolean found = FALSE;
436 TnyIterator *iter = NULL;
438 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
439 account_list = (account_type == TNY_ACCOUNT_TYPE_STORE ?
440 priv->store_accounts :
441 priv->transport_accounts);
443 iter = tny_list_create_iterator (account_list);
444 while (!tny_iterator_is_done (iter) && !found) {
445 TnyAccount *tny_account;
446 tny_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
448 if (!strcmp (tny_account_get_id (tny_account), account_name)) {
450 modest_tny_account_update_from_account (tny_account, get_password, forget_password);
451 g_signal_emit (G_OBJECT(self), signals[ACCOUNT_CHANGED_SIGNAL], 0, tny_account);
453 g_object_unref (tny_account);
455 tny_iterator_next (iter);
457 g_object_unref (iter);
461 show_wrong_password_dialog (TnyAccountStore *self,
463 gboolean show_banner)
468 g_debug ("%s: %s", __FUNCTION__, tny_account_get_id (account));
470 device = tny_account_store_get_device (self);
471 is_online = tny_device_is_online (device);
472 g_object_unref (device);
475 g_debug ("%s: not showing the acc settings dialog. Device OFFLINE", __FUNCTION__);
479 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0) {
480 g_debug ("%s: not showing the account settings dialog. NO windows", __FUNCTION__);
484 if (g_object_get_data (G_OBJECT (account), "connection_specific") != NULL) {
485 modest_ui_actions_on_smtp_servers (NULL, NULL);
487 ModestAccountProtocol *proto;
488 ModestProtocolType proto_type;
489 const gchar *modest_account_name;
490 modest_account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
493 proto_type = modest_account_mgr_get_store_protocol (modest_runtime_get_account_mgr (),
494 modest_account_name);
495 proto = (ModestAccountProtocol *)
496 modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
499 /* Create and show the dialog */
500 if (proto && MODEST_IS_ACCOUNT_PROTOCOL (proto)) {
501 ModestAccountSettingsDialog *dialog =
502 modest_account_protocol_get_account_settings_dialog (proto, modest_account_name);
505 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
506 GtkWindow *parent = modest_window_mgr_get_modal (mgr);
508 parent = (GtkWindow *) modest_window_mgr_get_current_top (mgr);
510 modest_window_mgr_set_modal (mgr, GTK_WINDOW (dialog), parent);
511 gtk_widget_show (GTK_WIDGET (dialog));
515 /* Show an explanatory temporary banner: */
517 modest_platform_information_banner (NULL, NULL, _("mcen_ib_username_pw_incorrect"));
520 /* This callback will be called by Tinymail when it needs the password
521 * from the user or the account settings.
522 * It can also call forget_password() before calling this,
523 * so that we clear wrong passwords out of our account settings.
524 * Note that TnyAccount here will be the server account. */
526 get_password (TnyAccount *account, const gchar * prompt_not_used, gboolean *cancel)
528 ModestTnyAccountStore *self = NULL;
529 ModestTnyAccountStorePrivate *priv;
530 gchar *username = NULL;
533 gboolean already_asked = FALSE;
534 const gchar *server_account_name;
537 g_return_val_if_fail (account, NULL);
539 g_debug ("%s: %s", __FUNCTION__, prompt_not_used);
541 /* Get a reference to myself */
542 self = MODEST_TNY_ACCOUNT_STORE (g_object_get_data (G_OBJECT(account), "account_store"));
543 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
545 /* Ensure that we still have this account. It could happen
546 that a set_online was requested *before* removing an
547 account, and due to tinymail emits the get_password
548 function using a g_idle the account could be actually
549 removed *before* this function was really called */
550 url_string = tny_account_get_url_string (account);
552 TnyAccount *tmp_account;
554 tmp_account = tny_account_store_find_account (TNY_ACCOUNT_STORE (self),
562 g_object_unref (tmp_account);
565 server_account_name = tny_account_get_id (account);
566 if (!server_account_name || !self) {
567 g_warning ("%s: could not retrieve account_store for account %s",
568 __FUNCTION__, server_account_name ? server_account_name : "<NULL>");
575 /* We need to do this to avoid "dereferencing type-punned pointer will break strict-aliasing rules" */
576 pwd_ptr = (gpointer) &pwd;
578 /* This hash map stores passwords, including passwords that are not stored in gconf. */
579 /* Is it in the hash? if it's already there, it must be wrong... */
580 already_asked = priv->password_hash && g_hash_table_lookup_extended (priv->password_hash,
585 /* If the password is not already there, try ModestConf */
586 if (!already_asked) {
587 pwd = modest_account_mgr_get_server_account_password (priv->account_mgr,
588 server_account_name);
589 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup (pwd));
591 /* We need to get it again because forget_password has cleared it */
592 pwd = modest_account_mgr_get_server_account_password (priv->account_mgr, server_account_name);
595 /* This is horrible but we need it until we don't get a proper
596 fix into tinymail. Thing is that tinymail incorrectly asks
597 for password when the connection to the server failed due a
598 timeout (slow network connection, firewalls...). In those
599 cases it makes no sense to ask the user. It's better just
601 if (g_strstr_len (prompt_not_used, -1, "Connection timed out")) {
602 g_debug ("%s, Incorrect get_password with connection issue", __FUNCTION__);
603 modest_tny_account_store_forget_password_in_memory (self, tny_account_get_id (account));
609 /* If it was already asked, it must have been wrong, so ask again */
610 if (already_asked || !pwd || strlen(pwd) == 0) {
611 gboolean settings_have_password;
612 ModestProtocolType protocol_type;
614 /* As per the UI spec, if no password was set in the account settings,
615 * ask for it now. But if the password is wrong in the account settings,
616 * then show a banner and the account settings dialog so it can be corrected:
618 settings_have_password =
619 modest_account_mgr_get_server_account_has_password (priv->account_mgr, server_account_name);
621 protocol_type = modest_tny_account_get_protocol_type (account);
623 /* Show an error and after that ask for a password */
624 if (modest_protocol_registry_protocol_type_has_tag(modest_runtime_get_protocol_registry (),
625 protocol_type, MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS)) {
626 gchar *username = NULL, *msg = NULL;
627 username = modest_account_mgr_get_server_account_username (priv->account_mgr,
628 server_account_name);
629 if (!username || strlen(username) == 0) {
630 msg = g_strdup_printf (_("emev_ni_ui_smtp_userid_invalid"),
631 tny_account_get_name (account),
632 tny_account_get_hostname (account));
635 password = modest_account_mgr_get_server_account_password (priv->account_mgr,
636 server_account_name);
638 if (!password || strlen(password) == 0) {
639 msg = g_strdup_printf (_("emev_ni_ui_smtp_passwd_invalid"),
640 tny_account_get_name (account),
641 tny_account_get_hostname (account));
643 msg = g_strdup_printf (_("emev_ni_ui_smtp_authentication_fail_error"),
644 tny_account_get_hostname (account));
650 modest_platform_run_information_dialog (NULL, msg, TRUE);
658 gboolean username_known =
659 modest_account_mgr_get_server_account_username_has_succeeded(priv->account_mgr,
660 server_account_name);
661 /* If the login has ever succeeded then show a specific message */
663 msg = _CS_SET_PASSWORD_INCORRECT;
665 msg = _("mcen_ib_username_pw_incorrect");
666 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()))
667 modest_platform_information_banner (NULL, NULL, msg);
671 if (settings_have_password) {
673 /* The password must be wrong, so show
674 the account settings dialog so it
676 g_debug ("%s: going to show the settings dialog", __FUNCTION__);
677 show_wrong_password_dialog ((TnyAccountStore *) self, account, TRUE);
684 /* Get the password from the account settings */
685 return modest_account_mgr_get_server_account_password (priv->account_mgr,
686 server_account_name);
690 /* we don't have it yet. Get the password from the user */
692 const gchar* account_id = tny_account_get_id (account);
693 gboolean remember = FALSE;
694 g_signal_emit (G_OBJECT (self), signals[PASSWORD_REQUESTED_SIGNAL], 0,
695 account_id, /* server_account_name */
696 &username, &pwd, cancel, &remember);
699 g_hash_table_remove (priv->password_hash, server_account_name);
714 modest_tny_account_store_forget_already_asked (ModestTnyAccountStore *self, TnyAccount *account)
716 g_return_if_fail (account);
718 ModestTnyAccountStorePrivate *priv;
720 gpointer pwd_ptr = NULL;
721 gboolean already_asked = FALSE;
723 const gchar *server_account_name = tny_account_get_id (account);
725 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
727 /* This hash map stores passwords, including passwords that are not stored in gconf. */
728 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
729 * type-punned ptrs...*/
730 already_asked = priv->password_hash &&
731 g_hash_table_lookup_extended (priv->password_hash,
734 (gpointer*)&pwd_ptr);
737 g_hash_table_remove (priv->password_hash, server_account_name);
745 /* tinymail calls this if the connection failed due to an incorrect password.
746 * And it seems to call this for any general connection failure. */
748 forget_password (TnyAccount *account)
750 ModestTnyAccountStore *self;
751 ModestTnyAccountStorePrivate *priv;
752 const TnyAccountStore *account_store;
756 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
758 self = MODEST_TNY_ACCOUNT_STORE (account_store);
759 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
760 key = tny_account_get_id (account);
762 /* Do not remove the key, this will allow us to detect that we
763 have already asked for it at least once */
764 pwd = g_hash_table_lookup (priv->password_hash, key);
766 g_debug ("%s, forgetting %s for account %s", __FUNCTION__, pwd, key);
767 memset (pwd, 0, strlen (pwd));
768 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
773 modest_tny_account_store_finalize (GObject *obj)
775 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(obj);
776 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
778 g_free (priv->cache_dir);
779 priv->cache_dir = NULL;
781 if (priv->password_hash) {
782 g_hash_table_destroy (priv->password_hash);
783 priv->password_hash = NULL;
786 if (priv->outbox_of_transport) {
787 g_hash_table_destroy (priv->outbox_of_transport);
788 priv->outbox_of_transport = NULL;
791 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
792 priv->sighandlers = NULL;
794 if (priv->account_mgr) {
795 g_object_unref (G_OBJECT(priv->account_mgr));
796 priv->account_mgr = NULL;
800 g_object_unref (G_OBJECT(priv->device));
804 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
805 if (priv->store_accounts) {
806 tny_list_foreach (priv->store_accounts, (GFunc)account_verify_last_ref, "store");
807 g_object_unref (priv->store_accounts);
808 priv->store_accounts = NULL;
811 if (priv->transport_accounts) {
812 tny_list_foreach (priv->transport_accounts, (GFunc)account_verify_last_ref, "transport");
813 g_object_unref (priv->transport_accounts);
814 priv->transport_accounts = NULL;
817 if (priv->store_accounts_outboxes) {
818 g_object_unref (priv->store_accounts_outboxes);
819 priv->store_accounts_outboxes = NULL;
823 camel_object_unref (CAMEL_OBJECT(priv->session));
824 priv->session = NULL;
827 G_OBJECT_CLASS(parent_class)->finalize (obj);
831 volume_path_is_mounted (const gchar* path)
833 g_return_val_if_fail (path, FALSE);
835 gboolean result = FALSE;
836 gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
837 g_return_val_if_fail (path_as_uri, FALSE);
839 /* Get the monitor singleton: */
840 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
842 /* This seems like a simpler way to do this, but it returns a
843 * GnomeVFSVolume even if the drive is not mounted: */
845 GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor,
846 g_getenv (MODEST_MMC1_VOLUMEPATH_ENV));
848 gnome_vfs_volume_unref(volume);
852 /* Get the mounted volumes from the monitor: */
853 GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
855 for (iter = list; iter; iter = g_list_next (iter)) {
856 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
860 gnome_vfs_volume_get_display_name (volume);
861 printf ("volume display name=%s\n", display_name);
862 g_free (display_name);
866 gnome_vfs_volume_get_activation_uri (volume);
867 /* printf (" uri=%s\n", uri); */
868 if (uri && (strcmp (uri, path_as_uri) == 0))
873 gnome_vfs_volume_unref (volume);
879 g_free (path_as_uri);
884 static void _bodies_filter (TnyMsg *msg, TnyList *list)
886 TnyMimePart *html_part, *text_part, *calendar_part;
888 html_part = modest_tny_msg_find_body_part (msg, TRUE);
889 text_part = modest_tny_msg_find_body_part (msg, FALSE);
890 calendar_part = modest_tny_msg_find_calendar (msg);
892 if (text_part && TNY_IS_MIME_PART (text_part) && html_part == text_part) {
893 g_object_unref (text_part);
897 if (html_part && TNY_IS_MIME_PART (html_part)) {
898 tny_list_prepend (list, G_OBJECT (html_part));
899 g_object_unref (html_part);
902 if (text_part && TNY_IS_MIME_PART (text_part)) {
903 tny_list_prepend (list, G_OBJECT (text_part));
904 g_object_unref (text_part);
907 if (calendar_part && TNY_IS_MIME_PART (calendar_part)) {
908 tny_list_prepend (list, G_OBJECT (calendar_part));
909 g_object_unref (calendar_part);
914 ModestTnyAccountStore*
915 modest_tny_account_store_new (ModestAccountMgr *account_mgr,
919 ModestTnyAccountStorePrivate *priv;
920 TnyAccount *local_account = NULL;
921 TnyLockable *lockable;
922 GnomeVFSVolumeMonitor* monitor = NULL;
923 gboolean auto_update;
924 const gchar *mmc_path = NULL;
926 g_return_val_if_fail (account_mgr, NULL);
927 g_return_val_if_fail (device, NULL);
929 tny_camel_bs_msg_receive_strategy_set_global_bodies_filter (
930 (TnyCamelBsMsgReceiveStrategyBodiesFilter) _bodies_filter);
932 obj = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
933 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
935 priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
936 priv->device = g_object_ref (device);
938 /* If autoupdate is off then we don't try to connect to the
939 accounts when they're added to the account store*/
940 auto_update = modest_conf_get_bool (modest_runtime_get_conf (),
941 MODEST_CONF_AUTO_UPDATE, NULL);
943 tny_device_force_offline (priv->device);
945 priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
946 if (!priv->session) {
947 g_warning ("failed to get TnySessionCamel");
951 /* Set the ui locker */
952 lockable = tny_gtk_lockable_new ();
953 tny_session_camel_set_ui_locker (priv->session, lockable);
954 g_object_unref (lockable);
956 /* Connect signals */
957 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
958 G_OBJECT(account_mgr), "account_inserted",
959 G_CALLBACK (on_account_inserted), obj);
960 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
961 G_OBJECT(account_mgr), "account_changed",
962 G_CALLBACK (on_account_changed), obj);
963 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
964 G_OBJECT(account_mgr), "account_removed",
965 G_CALLBACK (on_account_removed), obj);
967 /* Respond to volume mounts and unmounts, such as the
968 insertion/removal of the memory card. This is a singleton,
969 so it does not need to be unrefed */
970 monitor = gnome_vfs_get_volume_monitor();
971 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
974 G_CALLBACK(on_vfs_volume_mounted),
976 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
977 G_OBJECT(monitor), "volume-unmounted",
978 G_CALLBACK(on_vfs_volume_unmounted),
981 /* Create the lists of accounts */
982 priv->store_accounts = tny_simple_list_new ();
983 priv->transport_accounts = tny_simple_list_new ();
984 priv->store_accounts_outboxes = tny_simple_list_new ();
986 /* Create the local folders account */
988 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
989 tny_list_append (priv->store_accounts, G_OBJECT(local_account));
990 g_object_unref (local_account);
992 /* Add the other remote accounts. Do this after adding the
993 local account, because we need to add our outboxes to the
994 global OUTBOX hosted in the local account */
995 add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
997 /* Add connection-specific transport accounts if there are any
998 accounts available */
999 if (!only_local_accounts (MODEST_TNY_ACCOUNT_STORE(obj)))
1000 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
1002 /* This is a singleton, so it does not need to be unrefed. */
1003 mmc_path = g_getenv (MODEST_MMC1_VOLUMEPATH_ENV);
1004 if (mmc_path && volume_path_is_mounted (mmc_path)) {
1005 /* It is mounted: */
1006 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */);
1009 /* Initialize session */
1010 tny_session_camel_set_initialized (priv->session);
1012 return MODEST_TNY_ACCOUNT_STORE(obj);
1016 modest_tny_account_store_get_accounts (TnyAccountStore *self,
1018 TnyGetAccountsRequestType request_type)
1020 ModestTnyAccountStorePrivate *priv;
1022 g_return_if_fail (self);
1023 g_return_if_fail (TNY_IS_LIST(list));
1025 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1027 switch (request_type) {
1028 case TNY_ACCOUNT_STORE_BOTH:
1029 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1030 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1032 case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
1033 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1035 case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
1036 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1039 g_return_if_reached ();
1045 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1047 ModestTnyAccountStorePrivate *priv;
1048 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1050 if (!priv->cache_dir)
1051 priv->cache_dir = g_build_filename (g_get_home_dir(),
1052 MODEST_DIR, MODEST_CACHE_DIR, NULL);
1053 return priv->cache_dir;
1058 * callers need to unref
1061 modest_tny_account_store_get_device (TnyAccountStore *self)
1063 ModestTnyAccountStorePrivate *priv;
1065 g_return_val_if_fail (self, NULL);
1067 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1070 return g_object_ref (G_OBJECT(priv->device));
1077 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1079 return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self),
1080 MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1087 modest_tny_account_store_alert (TnyAccountStore *self,
1088 TnyAccount *account,
1093 ModestProtocolType protocol_type = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
1094 ModestProtocol *protocol = NULL;
1095 const gchar* server_name = "";
1096 gchar *prompt = NULL;
1097 gboolean retval = TRUE;
1099 /* NOTE: account may be NULL in some cases */
1103 /* Get the server name: */
1105 server_name = tny_account_get_hostname (account);
1106 protocol_type = modest_tny_account_get_protocol_type (account);
1107 if (protocol_type == MODEST_PROTOCOL_REGISTRY_TYPE_INVALID){
1108 g_warning("%s: account with id=%s has no proto.\n", __FUNCTION__,
1109 tny_account_get_id (account));
1112 protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
1116 switch (error->code) {
1117 case TNY_SYSTEM_ERROR_CANCEL:
1118 /* Don't show waste the user's time by showing him a dialog telling
1119 * him that he has just cancelled something: */
1122 case TNY_SERVICE_ERROR_PROTOCOL:
1123 /* Like a BAD from IMAP (protocol error) */
1124 case TNY_SERVICE_ERROR_LOST_CONNECTION:
1125 /* Lost the connection with the service */
1126 case TNY_SERVICE_ERROR_UNAVAILABLE:
1127 /* You must be working online for this operation */
1128 case TNY_SERVICE_ERROR_CONNECT:
1130 prompt = modest_protocol_get_translation (protocol, MODEST_PROTOCOL_TRANSLATION_CONNECT_ERROR, server_name);
1133 g_return_val_if_reached (FALSE);
1136 case TNY_SERVICE_ERROR_AUTHENTICATE:
1137 /* It seems that there's no better error to show with
1138 * POP and IMAP because TNY_SERVICE_ERROR_AUTHENTICATE
1139 * may appear if there's a timeout during auth */
1141 prompt = modest_protocol_get_translation (protocol, MODEST_PROTOCOL_TRANSLATION_AUTH_ERROR, server_name);
1144 g_return_val_if_reached (FALSE);
1147 case TNY_SERVICE_ERROR_CERTIFICATE:
1148 /* We'll show the proper dialog later */
1151 case TNY_SYSTEM_ERROR_MEMORY:
1152 /* Can't allocate memory for this operation */
1153 if (modest_tny_account_store_check_disk_full_error ((ModestTnyAccountStore*)self,
1154 NULL, error, account, NULL))
1157 case TNY_SERVICE_ERROR_UNKNOWN:
1160 /* We don't treat this as an error, but as a not handled message. Then,
1161 * debug message, and return false */
1162 g_debug ("Unexpected error %d (%s)", error->code, error->message);
1167 if (error->code == TNY_SERVICE_ERROR_CERTIFICATE)
1168 retval = modest_platform_run_certificate_confirmation_dialog (server_name,
1170 else if (error->code == TNY_SERVICE_ERROR_AUTHENTICATE ||
1171 error->code == TNY_SERVICE_ERROR_CONNECT) {
1172 TnyDevice *device = modest_runtime_get_device ();
1175 /* If we get the connection error after establishing a
1176 proper connection then do not show the dialog as we
1177 are probably behind a firewall, or in a network
1178 with connection issues. We just keep this code to
1179 detect situations were the user does not enter the
1180 server info properly */
1181 success = modest_account_mgr_get_server_account_username_has_succeeded (modest_runtime_get_account_mgr (),
1182 tny_account_get_id (account));
1185 gboolean show_banner;
1187 g_debug ("%s: %s alert received (%s)", __FUNCTION__,
1188 (error->code == TNY_SERVICE_ERROR_CONNECT) ? "connect" : "aunthenticate",
1191 if (tny_device_is_online (device) &&
1192 modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()))
1193 modest_platform_run_information_dialog (NULL, prompt, TRUE);
1195 /* Show the account dialog */
1196 show_banner = (error->code == TNY_SERVICE_ERROR_CONNECT) ? FALSE : TRUE;
1197 g_debug ("%s: going to show settings dialog", __FUNCTION__);
1198 show_wrong_password_dialog (self, account, show_banner);
1203 g_debug ("%s: error code %d (%s", __FUNCTION__, error->code, error->message);
1213 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1215 TnyAccountStoreIface *klass;
1217 g_return_if_fail (g);
1219 klass = (TnyAccountStoreIface *)g;
1221 klass->get_accounts =
1222 modest_tny_account_store_get_accounts;
1223 klass->get_cache_dir =
1224 modest_tny_account_store_get_cache_dir;
1226 modest_tny_account_store_get_device;
1228 modest_tny_account_store_alert;
1229 klass->find_account =
1230 modest_tny_account_store_find_account_by_url;
1234 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1235 ModestTnyGetPassFunc func)
1237 /* not implemented, we use signals */
1238 g_printerr ("modest: set_get_pass_func not implemented\n");
1242 modest_tny_account_store_get_session (TnyAccountStore *self)
1244 g_return_val_if_fail (self, NULL);
1245 return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1249 get_tny_account_by (TnyList *accounts,
1250 ModestTnyAccountStoreQueryType type,
1253 TnyIterator *iter = NULL;
1254 gboolean found = FALSE;
1255 TnyAccount *retval = NULL;
1257 g_return_val_if_fail (TNY_IS_LIST(accounts), NULL);
1259 if (tny_list_get_length(accounts) == 0) {
1260 g_warning ("%s: account list is empty", __FUNCTION__);
1264 iter = tny_list_create_iterator (accounts);
1265 while (!tny_iterator_is_done (iter) && !found) {
1266 TnyAccount *tmp_account = NULL;
1267 const gchar *val = NULL;
1269 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1270 if (!TNY_IS_ACCOUNT(tmp_account)) {
1271 g_warning ("%s: not a valid account", __FUNCTION__);
1277 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1278 val = tny_account_get_id (tmp_account);
1280 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1281 val = tny_account_get_url_string (tmp_account);
1285 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL &&
1286 tny_account_matches_url_string (tmp_account, str)) {
1287 retval = g_object_ref (tmp_account);
1290 if (val && str && strcmp (val, str) == 0) {
1291 retval = g_object_ref (tmp_account);
1295 g_object_unref (tmp_account);
1296 tny_iterator_next (iter);
1298 g_object_unref (iter);
1304 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self,
1305 ModestTnyAccountStoreQueryType type,
1308 TnyAccount *account = NULL;
1309 ModestTnyAccountStorePrivate *priv;
1311 g_return_val_if_fail (self, NULL);
1312 g_return_val_if_fail (str, NULL);
1314 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1316 /* Search in store accounts */
1317 account = get_tny_account_by (priv->store_accounts, type, str);
1319 /* If we already found something, no need to search the transport accounts */
1321 account = get_tny_account_by (priv->transport_accounts, type, str);
1323 /* If we already found something, no need to search the
1324 per-account outbox accounts */
1326 account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1329 /* Warn if nothing was found. This is generally unusual. */
1331 g_warning("%s: Failed to find account with %s=%s\n",
1333 (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",
1337 /* Returns a new reference to the account if found */
1343 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1344 const gchar *account_name,
1345 TnyAccountType type)
1347 ModestTnyAccountStorePrivate *priv = NULL;
1348 TnyAccount *retval = NULL;
1349 TnyList *account_list = NULL;
1350 TnyIterator *iter = NULL;
1353 g_return_val_if_fail (self, NULL);
1354 g_return_val_if_fail (account_name, NULL);
1355 g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE ||
1356 type == TNY_ACCOUNT_TYPE_TRANSPORT,
1359 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1361 account_list = (type == TNY_ACCOUNT_TYPE_STORE) ?
1362 priv->store_accounts :
1363 priv->transport_accounts;
1365 if (!account_list) {
1366 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__,
1367 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1371 /* Look for the server account */
1373 iter = tny_list_create_iterator (account_list);
1374 while (!tny_iterator_is_done (iter) && !found) {
1375 const gchar *modest_acc_name;
1376 TnyAccount *tmp_account;
1378 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1380 modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1382 if (account_name && modest_acc_name && !strcmp (account_name, modest_acc_name)) {
1384 retval = g_object_ref (tmp_account);
1386 /* Free and continue */
1387 g_object_unref (tmp_account);
1388 tny_iterator_next (iter);
1390 g_object_unref (iter);
1393 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1394 "Number of server accounts of this type=%d\n", __FUNCTION__,
1395 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1396 account_name, tny_list_get_length (account_list));
1399 /* Returns a new reference */
1404 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (
1405 ModestTnyAccountStore *self, const gchar *account_name)
1409 g_return_val_if_fail (self && MODEST_IS_TNY_ACCOUNT_STORE(self), NULL);
1410 g_return_val_if_fail (account_name, NULL);
1412 /* Get the current connection: */
1413 device = modest_runtime_get_device ();
1416 g_warning ("%s: could not get device", __FUNCTION__);
1420 if (!tny_device_is_online (device))
1423 #ifdef MODEST_HAVE_CONIC
1424 g_return_val_if_fail (TNY_IS_MAEMO_CONIC_DEVICE (device), NULL);
1426 TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);
1427 const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1428 /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1432 ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1436 const gchar *connection_id = con_ic_iap_get_id (connection);
1437 /* printf ("DEBUG: %s: connection_id=%s\n", __FUNCTION__, connection_id); */
1441 /* Get the connection-specific transport acccount, if any: */
1442 ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1444 /* Check if this account has connection-specific SMTP enabled */
1445 if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1449 gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager,
1452 /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1453 if (!server_account_name) {
1454 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1457 TnyAccount* account = modest_tny_account_store_get_tny_account_by (self,
1458 MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1459 server_account_name);
1461 /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1462 g_free (server_account_name);
1464 /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1465 g_object_unref (connection);
1469 return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1470 #endif /* MODEST_HAVE_CONIC */
1475 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1476 const gchar *account_name)
1478 g_return_val_if_fail (self, NULL);
1479 g_return_val_if_fail (account_name, NULL);
1481 if (!account_name || !self)
1484 /* Get the connection-specific transport acccount, if any: */
1485 /* Note: This gives us a reference: */
1486 TnyAccount *account =
1487 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (self, account_name);
1489 /* If there is no connection-specific transport account (the common case),
1490 * just get the regular transport account: */
1492 /* The special local folders don't have transport accounts. */
1493 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1496 /* Note: This gives us a reference: */
1497 account = modest_tny_account_store_get_server_account (self, account_name,
1498 TNY_ACCOUNT_TYPE_TRANSPORT);
1502 /* returns a reference. */
1507 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1509 TnyAccount *account = NULL;
1510 ModestTnyAccountStorePrivate *priv;
1514 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1516 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1519 iter = tny_list_create_iterator (priv->store_accounts);
1520 while (!tny_iterator_is_done (iter) && !found) {
1521 TnyAccount *tmp_account;
1523 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1524 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1525 account = g_object_ref (tmp_account);
1528 g_object_unref (tmp_account);
1529 tny_iterator_next (iter);
1531 g_object_unref (iter);
1533 /* Returns a new reference to the account */
1538 modest_tny_account_store_get_mmc_folders_account (ModestTnyAccountStore *self)
1540 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1543 return modest_tny_account_store_get_tny_account_by (self, MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1544 MODEST_MMC_ACCOUNT_ID);
1548 /*********************************************************************************/
1550 add_existing_accounts (ModestTnyAccountStore *self)
1552 GSList *account_names = NULL, *iter = NULL;
1553 ModestTnyAccountStorePrivate *priv = NULL;
1555 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1557 /* These are account names, not server_account names */
1558 account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1560 for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1561 const gchar *account_name = (const gchar*) iter->data;
1563 /* Insert all enabled accounts without notifying */
1564 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1565 insert_account (self, account_name, FALSE);
1567 modest_account_mgr_free_account_names (account_names);
1571 create_tny_account (ModestTnyAccountStore *self,
1573 TnyAccountType type,
1576 TnyAccount *account = NULL;
1577 ModestTnyAccountStorePrivate *priv = NULL;
1579 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1581 account = modest_tny_account_new_from_account (priv->account_mgr,
1588 /* Forget any cached password for the account, so that
1589 we use a new account if any */
1590 modest_tny_account_store_forget_password_in_memory (self, tny_account_get_id (account));
1592 /* Set the account store */
1593 g_object_set_data (G_OBJECT(account), "account_store", self);
1595 g_printerr ("modest: failed to create account for %s\n", name);
1601 typedef struct _AddOutboxInfo {
1602 ModestTnyAccountStore *account_store;
1603 TnyAccount *transport_account;
1607 add_outbox_from_transport_account_to_global_outbox_get_folders_cb (TnyFolderStore *folder_store,
1613 TnyIterator *iter_folders;
1614 TnyFolder *per_account_outbox;
1615 TnyAccount *local_account = NULL;
1616 AddOutboxInfo *info = (AddOutboxInfo *) userdata;
1617 ModestTnyAccountStorePrivate *priv = NULL;
1618 ModestTnyAccountStore *self;
1620 self = MODEST_TNY_ACCOUNT_STORE (info->account_store);
1621 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1623 /* Note that this could happen if there is not enough space
1624 available on disk, then the outbox folder could not be
1626 if (tny_list_get_length (list) != 1) {
1627 g_warning ("%s: could not create outbox folder (%d folders found)", __FUNCTION__,
1628 tny_list_get_length (list));
1632 iter_folders = tny_list_create_iterator (list);
1633 per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1634 g_object_unref (iter_folders);
1635 g_object_unref (list);
1637 /* Add the outbox of the new per-account-local-outbox account
1638 to the global local merged OUTBOX of the local folders
1640 local_account = modest_tny_account_store_get_local_folders_account (info->account_store);
1641 modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1642 per_account_outbox);
1643 /* Add the pair to the hash table */
1644 g_hash_table_insert (priv->outbox_of_transport,
1645 info->transport_account,
1646 per_account_outbox);
1648 /* Notify that the local account changed */
1649 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1650 g_object_unref (local_account);
1651 g_object_unref (per_account_outbox);
1654 g_object_unref (info->transport_account);
1655 g_slice_free (AddOutboxInfo, info);
1660 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1661 const gchar *account_name,
1662 TnyAccount *transport_account)
1664 TnyList *folders = NULL;
1665 TnyAccount *account_outbox = NULL;
1666 ModestTnyAccountStorePrivate *priv = NULL;
1667 AddOutboxInfo *info;
1669 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1671 /* Create per account local outbox */
1673 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr,
1677 if (!G_IS_OBJECT (account_outbox)) {
1678 g_warning ("%s: could not create per account local outbox folder", __FUNCTION__);
1682 tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1684 /* Get the outbox folder */
1685 folders = tny_simple_list_new ();
1686 info = g_slice_new0 (AddOutboxInfo);
1687 info->account_store = self;
1688 info->transport_account = g_object_ref (transport_account);
1689 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (account_outbox), folders, NULL, FALSE,
1690 add_outbox_from_transport_account_to_global_outbox_get_folders_cb, NULL, (gpointer) info);
1691 g_object_unref (account_outbox);
1695 * This function will be used for both adding new accounts and for the
1696 * initialization. In the initialization we do not want to emit
1697 * signals so notify will be FALSE, in the case of account additions
1698 * we do want to notify the observers
1701 insert_account (ModestTnyAccountStore *self,
1702 const gchar *account,
1705 ModestTnyAccountStorePrivate *priv = NULL;
1706 TnyAccount *store_account = NULL, *transport_account = NULL;
1708 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1710 /* Get the server and the transport account */
1711 store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE, is_new);
1712 if (!store_account || !TNY_IS_ACCOUNT(store_account)) {
1713 g_warning ("%s: failed to create store account", __FUNCTION__);
1717 transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT, is_new);
1718 if (!transport_account || !TNY_IS_ACCOUNT(transport_account)) {
1719 g_warning ("%s: failed to create transport account", __FUNCTION__);
1720 g_object_unref (store_account);
1724 /* Add accounts to the lists */
1725 tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1726 tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1728 /* Create a new pseudo-account with an outbox for this
1729 transport account and add it to the global outbox
1730 in the local account */
1731 add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1733 /* Force the creation of the send queue, this way send queues
1734 will automatically send missing emails when the connections
1736 /* Notify the observers. We do it after everything is
1739 /* We only have to do this for new accounts, already
1740 existing accounts at boot time are instantiated by
1741 modest_tny_account_store_start_send_queues */
1742 modest_runtime_get_send_queue ((TnyTransportAccount *) transport_account, TRUE);
1744 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);
1745 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1749 g_object_unref (store_account);
1750 g_object_unref (transport_account);
1753 static inline gboolean
1754 only_local_accounts (ModestTnyAccountStore *self)
1756 return (modest_tny_account_store_get_num_remote_accounts (self) > 0) ? FALSE : TRUE;
1760 on_account_inserted (ModestAccountMgr *acc_mgr,
1761 const gchar *account,
1764 gboolean add_specific;
1766 add_specific = only_local_accounts (MODEST_TNY_ACCOUNT_STORE (user_data));
1768 /* Insert the account and notify the observers */
1769 insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1771 /* If it's the first remote account then add the connection
1772 specific SMTP servers as well */
1774 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE (user_data));
1778 /* This is the callback of the tny_camel_account_set_online called in
1779 on_account_removed to disconnect the account */
1781 on_account_disconnect_when_removing (TnyCamelAccount *account,
1786 ModestTnyAccountStore *self;
1787 ModestTnyAccountStorePrivate *priv;
1789 self = MODEST_TNY_ACCOUNT_STORE (user_data);
1790 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
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 modest_tny_account_store_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 modest_tny_account_store_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);
1995 foreach_free_string(gpointer data,
2002 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
2004 ModestTnyAccountStorePrivate *priv = NULL;
2005 GSList *list_specifics = NULL, *iter = NULL;
2008 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2010 list_specifics = modest_conf_get_list (modest_runtime_get_conf (),
2011 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
2012 MODEST_CONF_VALUE_STRING, &err);
2015 g_return_if_reached ();
2019 /* Look at each connection-specific transport account for the
2020 * modest account: */
2021 iter = list_specifics;
2023 /* The list alternates between the connection name and the transport name: */
2024 iter = g_slist_next (iter);
2026 const gchar* transport_account_name = (const gchar*) (iter->data);
2027 TnyTransportAccount * account = NULL;
2028 account = modest_tny_account_store_new_connection_specific_transport_account (
2029 self, transport_account_name);
2031 g_object_unref (account);
2033 iter = g_slist_next (iter);
2037 g_slist_foreach (list_specifics, foreach_free_string, NULL);
2038 g_slist_free (list_specifics);
2042 remove_connection_specific_transport_accounts (ModestTnyAccountStore *self)
2044 ModestTnyAccountStorePrivate *priv = NULL;
2045 GSList *list_specifics = NULL, *iter = NULL;
2048 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2051 list_specifics = modest_conf_get_list (modest_runtime_get_conf (),
2052 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
2053 MODEST_CONF_VALUE_STRING, &err);
2056 g_return_if_reached ();
2060 /* Look at each connection-specific transport account for the
2061 * modest account: */
2062 iter = list_specifics;
2064 /* The list alternates between the connection name and the transport name: */
2065 iter = g_slist_next (iter);
2067 const gchar* transport_account_name = (const gchar*) (iter->data);
2068 TnyAccount * account;
2069 account = modest_tny_account_store_get_server_account (self,
2070 transport_account_name,
2071 TNY_ACCOUNT_TYPE_TRANSPORT);
2073 /* the call will free the reference */
2075 remove_transport_account (self, TNY_TRANSPORT_ACCOUNT (account));
2077 iter = g_slist_next (iter);
2081 g_slist_foreach (list_specifics, foreach_free_string, NULL);
2082 g_slist_free (list_specifics);
2087 modest_tny_account_store_find_msg_in_outboxes (ModestTnyAccountStore *self,
2089 TnyAccount **ac_out)
2091 TnyIterator *acc_iter;
2092 ModestTnyAccountStorePrivate *priv;
2094 TnyAccount *msg_account = NULL;
2096 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
2097 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2099 acc_iter = tny_list_create_iterator (priv->store_accounts_outboxes);
2100 while (!msg && !tny_iterator_is_done (acc_iter)) {
2101 TnyList *folders = tny_simple_list_new ();
2102 TnyAccount *account = TNY_ACCOUNT (tny_iterator_get_current (acc_iter));
2103 TnyIterator *folders_iter = NULL;
2105 tny_folder_store_get_folders (TNY_FOLDER_STORE (account), folders, NULL, FALSE, NULL);
2106 folders_iter = tny_list_create_iterator (folders);
2108 while (msg == NULL && !tny_iterator_is_done (folders_iter)) {
2109 TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (folders_iter));
2110 msg = tny_folder_find_msg (folder, uri, NULL);
2113 msg_account = g_object_ref (account);
2115 g_object_unref (folder);
2116 tny_iterator_next (folders_iter);
2118 g_object_unref (folders_iter);
2120 g_object_unref (folders);
2121 g_object_unref (account);
2122 tny_iterator_next (acc_iter);
2125 g_object_unref (acc_iter);
2128 *ac_out = msg_account;
2133 TnyTransportAccount *
2134 modest_tny_account_store_get_transport_account_from_outbox_header(ModestTnyAccountStore *self, TnyHeader *header)
2136 TnyIterator *acc_iter;
2137 ModestTnyAccountStorePrivate *priv;
2138 TnyTransportAccount *header_acc = NULL;
2141 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
2142 g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
2143 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2144 msg_id = modest_tny_send_queue_get_msg_id (header);
2145 acc_iter = tny_list_create_iterator (priv->transport_accounts);
2146 while (!header_acc && !tny_iterator_is_done (acc_iter)) {
2147 TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current (acc_iter));
2148 ModestTnySendQueue *send_queue;
2149 ModestTnySendQueueStatus status;
2150 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account), TRUE);
2151 if (TNY_IS_SEND_QUEUE (send_queue)) {
2152 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2153 if (status != MODEST_TNY_SEND_QUEUE_UNKNOWN)
2154 header_acc = g_object_ref(account);
2156 g_object_unref (account);
2157 tny_iterator_next (acc_iter);
2159 g_object_unref(acc_iter);
2167 ModestTnyAccountStore *account_store;
2168 ModestTnyAccountStoreShutdownCallback callback;
2174 account_shutdown_callback (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer userdata)
2176 ShutdownOpData *op_data = (ShutdownOpData *) userdata;
2178 if (op_data->pending == 0) {
2179 if (op_data->callback)
2180 op_data->callback (op_data->account_store, op_data->userdata);
2181 g_object_unref (op_data->account_store);
2187 account_shutdown (TnyAccount *account, ShutdownOpData *op_data)
2189 g_return_if_fail (account && TNY_IS_ACCOUNT(account));
2191 if (TNY_IS_STORE_ACCOUNT (account) &&
2192 !modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2197 /* Disconnect account */
2198 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(account), FALSE,
2199 account_shutdown_callback, op_data);
2205 modest_tny_account_store_shutdown (ModestTnyAccountStore *self,
2206 ModestTnyAccountStoreShutdownCallback callback,
2210 ShutdownOpData *op_data;
2211 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2213 /* Get references */
2215 if (priv->store_accounts)
2216 num_accounts += tny_list_get_length (priv->store_accounts);
2217 if (priv->transport_accounts)
2218 num_accounts += tny_list_get_length (priv->transport_accounts);
2220 /* Create the helper object */
2221 op_data = g_new0 (ShutdownOpData, 1);
2222 op_data->callback = callback;
2223 op_data->userdata = userdata;
2224 op_data->pending = num_accounts;
2225 op_data->account_store = g_object_ref (self);
2227 /* Force the TnyDevice to be offline. This way new
2228 undesired connections won't be initiated */
2229 tny_device_force_offline (priv->device);
2231 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
2232 if (priv->store_accounts) {
2233 tny_list_foreach (priv->store_accounts, (GFunc)account_shutdown, op_data);
2236 if (priv->transport_accounts) {
2237 tny_list_foreach (priv->transport_accounts, (GFunc)account_shutdown, op_data);
2240 if (op_data->pending == 0) {
2241 if (op_data->callback)
2242 op_data->callback (op_data->account_store, op_data->userdata);
2243 g_object_unref (op_data->account_store);
2249 modest_tny_account_store_is_shutdown (ModestTnyAccountStore *self)
2251 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2257 for (iter = tny_list_create_iterator (priv->store_accounts);
2258 !found && !tny_iterator_is_done (iter);
2259 tny_iterator_next (iter)) {
2260 TnyAccount *account;
2262 account = (TnyAccount *) tny_iterator_get_current (iter);
2263 if (TNY_IS_ACCOUNT (account)) {
2264 found = (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_CONNECTED) ||
2265 (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_RECONNECTING);
2267 g_object_unref (account);
2269 g_object_unref (iter);
2274 for (iter = tny_list_create_iterator (priv->transport_accounts);
2275 !found && !tny_iterator_is_done (iter);
2276 tny_iterator_next (iter)) {
2277 TnyAccount *account;
2279 account = (TnyAccount *) tny_iterator_get_current (iter);
2280 if (TNY_IS_ACCOUNT (account)) {
2281 found = (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_CONNECTED) ||
2282 (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_RECONNECTING);
2284 g_object_unref (account);
2286 g_object_unref (iter);
2294 modest_tny_account_store_is_send_mail_blocked (ModestTnyAccountStore *self)
2296 ModestTnyAccountStorePrivate *priv;
2298 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2300 return priv->send_mail_blocked;
2304 modest_tny_account_store_set_send_mail_blocked (ModestTnyAccountStore *self,
2307 ModestTnyAccountStorePrivate *priv;
2309 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2311 priv->send_mail_blocked = blocked;
2315 count_remote_accounts (gpointer data, gpointer user_data)
2317 TnyFolderStore *account = TNY_FOLDER_STORE (data);
2318 gint *count = (gint *) user_data;
2320 if (modest_tny_folder_store_is_remote (account))
2325 modest_tny_account_store_get_num_remote_accounts (ModestTnyAccountStore *self)
2327 ModestTnyAccountStorePrivate *priv;
2330 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), 0);
2332 /* Count remote accounts */
2333 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2334 tny_list_foreach (priv->store_accounts, (GFunc) count_remote_accounts, &count);
2340 init_send_queue (TnyAccount *account, gpointer user_data)
2342 modest_runtime_get_send_queue ((TnyTransportAccount *) account, TRUE);
2346 modest_tny_account_store_start_send_queues (ModestTnyAccountStore *self)
2348 ModestTnyAccountStorePrivate *priv;
2351 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self));
2353 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2355 /* We need to create a copy of the list because if the send
2356 queues are created they'll directly access to the TnyList
2357 of transport accounts, and thus we'll end up blocked in the
2358 mutex the TnyList uses to synchronize accesses */
2359 tmp = tny_list_copy (priv->transport_accounts);
2361 /* Just instantiate them. They'll begin to listen for
2362 connection changes to send messages ASAP */
2363 tny_list_foreach (tmp, (GFunc) init_send_queue, NULL);
2364 g_object_unref (tmp);
2369 modest_tny_account_store_check_disk_full_error (ModestTnyAccountStore *self,
2370 GtkWidget *parent_window,
2372 TnyAccount *account,
2373 const gchar *alternate)
2378 if (modest_tny_account_store_is_disk_full_error (self, err, account)) {
2379 gboolean is_mcc = modest_tny_account_is_memory_card_account (account);
2380 if (is_mcc && alternate) {
2381 modest_platform_information_banner (parent_window, NULL, alternate);
2383 gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2384 modest_platform_information_banner (parent_window, NULL, msg);
2387 } else if (err->code == TNY_SYSTEM_ERROR_MEMORY)
2388 /* If the account was created in memory full
2389 conditions then tinymail won't be able to
2390 connect so it'll return this error code */
2391 modest_platform_information_banner (parent_window,
2392 NULL, _("emev_ui_imap_inbox_select_error"));
2400 modest_tny_account_store_is_disk_full_error (ModestTnyAccountStore *self,
2402 TnyAccount *account)
2404 gboolean enough_free_space = TRUE;
2405 GnomeVFSURI *cache_dir_uri;
2406 const gchar *cache_dir = NULL;
2407 GnomeVFSFileSize free_space;
2409 /* Cache dir is different in case we're using an external storage (like MMC account) */
2410 if (account && modest_tny_account_is_memory_card_account (account))
2411 cache_dir = g_getenv (MODEST_MMC1_VOLUMEPATH_ENV);
2413 /* Get the default local cache dir */
2415 cache_dir = tny_account_store_get_cache_dir ((TnyAccountStore *) self);
2417 cache_dir_uri = gnome_vfs_uri_new (cache_dir);
2418 if (cache_dir_uri) {
2419 if (gnome_vfs_get_volume_free_space (cache_dir_uri, &free_space) == GNOME_VFS_OK) {
2420 if (free_space < MODEST_TNY_ACCOUNT_STORE_MIN_FREE_SPACE)
2421 enough_free_space = FALSE;
2423 gnome_vfs_uri_unref (cache_dir_uri);
2426 if ((error->code == TNY_SYSTEM_ERROR_MEMORY ||
2427 /* When asking for a mail and no space left on device
2428 tinymail returns this error */
2429 error->code == TNY_SERVICE_ERROR_MESSAGE_NOT_AVAILABLE ||
2430 /* When the folder summary could not be read or
2432 error->code == TNY_IO_ERROR_WRITE ||
2433 error->code == TNY_IO_ERROR_READ) &&
2434 !enough_free_space) {