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>
66 #ifdef MODEST_PLATFORM_MAEMO
67 #include <tny-maemo-conic-device.h>
70 #include <libgnomevfs/gnome-vfs-volume-monitor.h>
72 /* 'private'/'protected' functions */
73 static void modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass);
74 static void modest_tny_account_store_finalize (GObject *obj);
75 static void modest_tny_account_store_instance_init (ModestTnyAccountStore *obj);
76 static void modest_tny_account_store_init (gpointer g, gpointer iface_data);
77 static void modest_tny_account_store_base_init (gpointer g_class);
79 static void on_account_inserted (ModestAccountMgr *acc_mgr,
83 static void add_existing_accounts (ModestTnyAccountStore *self);
85 static void insert_account (ModestTnyAccountStore *self,
89 static void on_account_removed (ModestAccountMgr *acc_mgr,
93 static gchar* get_password (TnyAccount *account,
94 const gchar * prompt_not_used,
97 static void forget_password (TnyAccount *account);
99 static void on_vfs_volume_mounted (GnomeVFSVolumeMonitor *volume_monitor,
100 GnomeVFSVolume *volume,
103 static void on_vfs_volume_unmounted (GnomeVFSVolumeMonitor *volume_monitor,
104 GnomeVFSVolume *volume,
107 static void add_connection_specific_transport_accounts (ModestTnyAccountStore *self);
109 static void remove_connection_specific_transport_accounts (ModestTnyAccountStore *self);
111 static inline gboolean only_local_accounts (ModestTnyAccountStore *self);
113 /* list my signals */
115 ACCOUNT_CHANGED_SIGNAL,
116 ACCOUNT_INSERTED_SIGNAL,
117 ACCOUNT_REMOVED_SIGNAL,
119 PASSWORD_REQUESTED_SIGNAL,
123 typedef struct _ModestTnyAccountStorePrivate ModestTnyAccountStorePrivate;
124 struct _ModestTnyAccountStorePrivate {
126 GHashTable *password_hash;
127 ModestAccountMgr *account_mgr;
128 TnySessionCamel *session;
133 /* We cache the lists of accounts here */
134 TnyList *store_accounts;
135 TnyList *transport_accounts;
136 TnyList *store_accounts_outboxes;
138 /* Matches transport accounts and outbox folder */
139 GHashTable *outbox_of_transport;
141 /* is sending mail blocked? */
142 gboolean send_mail_blocked;
145 #define MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
146 MODEST_TYPE_TNY_ACCOUNT_STORE, \
147 ModestTnyAccountStorePrivate))
150 static GObjectClass *parent_class = NULL;
152 static guint signals[LAST_SIGNAL] = {0};
155 modest_tny_account_store_get_type (void)
157 static GType my_type = 0;
160 static const GTypeInfo my_info = {
161 sizeof(ModestTnyAccountStoreClass),
162 modest_tny_account_store_base_init, /* base init */
163 NULL, /* base finalize */
164 (GClassInitFunc) modest_tny_account_store_class_init,
165 NULL, /* class finalize */
166 NULL, /* class data */
167 sizeof(ModestTnyAccountStore),
169 (GInstanceInitFunc) modest_tny_account_store_instance_init,
173 static const GInterfaceInfo iface_info = {
174 (GInterfaceInitFunc) modest_tny_account_store_init,
175 NULL, /* interface_finalize */
176 NULL /* interface_data */
179 my_type = g_type_register_static (G_TYPE_OBJECT,
180 "ModestTnyAccountStore",
182 g_type_add_interface_static (my_type, TNY_TYPE_ACCOUNT_STORE,
190 modest_tny_account_store_base_init (gpointer g_class)
192 static gboolean tny_account_store_initialized = FALSE;
194 if (!tny_account_store_initialized) {
196 signals[ACCOUNT_CHANGED_SIGNAL] =
197 g_signal_new ("account_changed",
198 MODEST_TYPE_TNY_ACCOUNT_STORE,
200 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_changed),
202 g_cclosure_marshal_VOID__OBJECT,
203 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
205 signals[ACCOUNT_INSERTED_SIGNAL] =
206 g_signal_new ("account_inserted",
207 MODEST_TYPE_TNY_ACCOUNT_STORE,
209 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_inserted),
211 g_cclosure_marshal_VOID__OBJECT,
212 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
214 signals[ACCOUNT_REMOVED_SIGNAL] =
215 g_signal_new ("account_removed",
216 MODEST_TYPE_TNY_ACCOUNT_STORE,
218 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_removed),
220 g_cclosure_marshal_VOID__OBJECT,
221 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
223 signals[PASSWORD_REQUESTED_SIGNAL] =
224 g_signal_new ("password_requested",
225 MODEST_TYPE_TNY_ACCOUNT_STORE,
227 G_STRUCT_OFFSET(ModestTnyAccountStoreClass, password_requested),
229 modest_marshal_VOID__STRING_POINTER_POINTER_POINTER_POINTER,
230 G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER,
233 tny_account_store_initialized = TRUE;
239 modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass)
241 GObjectClass *gobject_class;
242 gobject_class = (GObjectClass*) klass;
244 parent_class = g_type_class_peek_parent (klass);
245 gobject_class->finalize = modest_tny_account_store_finalize;
247 g_type_class_add_private (gobject_class,
248 sizeof(ModestTnyAccountStorePrivate));
252 modest_tny_account_store_instance_init (ModestTnyAccountStore *obj)
254 ModestTnyAccountStorePrivate *priv;
256 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
258 priv->cache_dir = NULL;
259 priv->account_mgr = NULL;
260 priv->session = NULL;
262 priv->sighandlers = NULL;
263 priv->send_mail_blocked = FALSE;
265 priv->outbox_of_transport = g_hash_table_new_full (g_direct_hash,
270 /* An in-memory store of passwords,
271 * for passwords that are not remembered in the configuration,
272 * so they need to be asked for from the user once in each session:
274 priv->password_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
278 /* disconnect the list of TnyAccounts */
280 account_verify_last_ref (TnyAccount *account, const gchar *str)
284 g_return_if_fail (account && TNY_IS_ACCOUNT(account));
286 txt = g_strdup_printf ("%s: %s", str ? str : "?", tny_account_get_name(account));
287 MODEST_DEBUG_VERIFY_OBJECT_LAST_REF(G_OBJECT(account),txt);
292 foreach_account_append_to_list (gpointer data,
297 list = TNY_LIST (user_data);
298 tny_list_append (list, G_OBJECT (data));
301 /********************************************************************/
302 /* Control the state of the MMC local account */
303 /********************************************************************/
305 /** Only call this if the memory card is really mounted.
308 add_mmc_account(ModestTnyAccountStore *self, gboolean emit_insert_signal)
310 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
311 g_return_if_fail (priv->session);
313 TnyAccount *mmc_account = modest_tny_account_new_for_local_folders (priv->account_mgr,
315 g_getenv (MODEST_MMC1_VOLUMEPATH_ENV));
317 /* Add to the list of store accounts */
318 tny_list_append (priv->store_accounts, G_OBJECT (mmc_account));
320 if (emit_insert_signal) {
321 g_signal_emit (G_OBJECT (self),
322 signals [ACCOUNT_INSERTED_SIGNAL],
327 g_object_unref (mmc_account);
331 on_vfs_volume_mounted(GnomeVFSVolumeMonitor *volume_monitor,
332 GnomeVFSVolume *volume,
335 ModestTnyAccountStore *self;
336 ModestTnyAccountStorePrivate *priv;
337 gchar *volume_path_uri;
341 self = MODEST_TNY_ACCOUNT_STORE(user_data);
342 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
344 /* Check whether this was the external MMC1 card: */
345 uri = gnome_vfs_volume_get_activation_uri (volume);
347 volume_path_uri = g_strconcat (MODEST_MMC1_VOLUMEPATH_URI_PREFIX,
348 g_getenv (MODEST_MMC1_VOLUMEPATH_ENV),
350 if (uri && (!strcmp (uri, volume_path_uri))) {
351 add_mmc_account (self, TRUE /* emit the insert signal. */);
354 g_free (volume_path_uri);
359 on_vfs_volume_unmounted(GnomeVFSVolumeMonitor *volume_monitor,
360 GnomeVFSVolume *volume,
363 ModestTnyAccountStore *self;
364 ModestTnyAccountStorePrivate *priv;
366 gchar *volume_path_uri;
368 self = MODEST_TNY_ACCOUNT_STORE(user_data);
369 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
371 /* Check whether this was the external MMC1 card: */
372 uri = gnome_vfs_volume_get_activation_uri (volume);
373 volume_path_uri = g_strconcat (MODEST_MMC1_VOLUMEPATH_URI_PREFIX,
374 g_getenv (MODEST_MMC1_VOLUMEPATH_ENV),
376 if (uri && (strcmp (uri, volume_path_uri) == 0)) {
377 TnyAccount *mmc_account = NULL;
378 gboolean found = FALSE;
379 TnyIterator *iter = NULL;
381 iter = tny_list_create_iterator (priv->store_accounts);
382 while (!tny_iterator_is_done (iter) && !found) {
385 account = TNY_ACCOUNT (tny_iterator_get_current (iter));
386 if (modest_tny_account_is_memory_card_account (account)) {
388 mmc_account = g_object_ref (account);
390 g_object_unref (account);
391 tny_iterator_next (iter);
393 g_object_unref (iter);
396 /* Remove from the list */
397 tny_list_remove (priv->store_accounts, G_OBJECT (mmc_account));
399 /* Notify observers */
400 g_signal_emit (G_OBJECT (self),
401 signals [ACCOUNT_REMOVED_SIGNAL],
404 g_object_unref (mmc_account);
406 g_debug ("%s: there was no store account for the unmounted MMC",
410 g_free (volume_path_uri);
415 modest_tny_account_store_forget_password_in_memory (ModestTnyAccountStore *self,
416 const gchar * server_account_name)
418 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
420 if (server_account_name && priv->password_hash)
421 g_hash_table_remove (priv->password_hash, server_account_name);
425 on_account_changed (ModestAccountMgr *acc_mgr,
426 const gchar *account_name,
427 TnyAccountType account_type,
430 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
431 ModestTnyAccountStorePrivate *priv;
432 TnyList* account_list;
433 gboolean found = FALSE;
434 TnyIterator *iter = NULL;
436 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
437 account_list = (account_type == TNY_ACCOUNT_TYPE_STORE ?
438 priv->store_accounts :
439 priv->transport_accounts);
441 iter = tny_list_create_iterator (account_list);
442 while (!tny_iterator_is_done (iter) && !found) {
443 TnyAccount *tny_account;
444 tny_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
446 if (!strcmp (tny_account_get_id (tny_account), account_name)) {
448 modest_tny_account_update_from_account (tny_account, get_password, forget_password);
449 g_signal_emit (G_OBJECT(self), signals[ACCOUNT_CHANGED_SIGNAL], 0, tny_account);
451 g_object_unref (tny_account);
453 tny_iterator_next (iter);
455 g_object_unref (iter);
459 show_wrong_password_dialog (TnyAccount *account,
460 gboolean show_banner)
462 g_debug ("%s: %s", __FUNCTION__, tny_account_get_id (account));
464 if (g_object_get_data (G_OBJECT (account), "connection_specific") != NULL) {
465 modest_ui_actions_on_smtp_servers (NULL, NULL);
467 ModestAccountProtocol *proto;
468 ModestProtocolType proto_type;
469 const gchar *modest_account_name;
470 modest_account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
473 proto_type = modest_account_mgr_get_store_protocol (modest_runtime_get_account_mgr (),
474 modest_account_name);
475 proto = (ModestAccountProtocol *)
476 modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
479 /* Create and show the dialog */
480 if (proto && MODEST_IS_ACCOUNT_PROTOCOL (proto)) {
482 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
483 ModestAccountSettingsDialog *dialog =
484 modest_account_protocol_get_account_settings_dialog (proto, modest_account_name);
486 parent = modest_window_mgr_get_modal (mgr);
488 parent = (GtkWindow *) modest_window_mgr_get_current_top (mgr);
490 modest_window_mgr_set_modal (mgr, GTK_WINDOW (dialog), parent);
491 gtk_widget_show (GTK_WIDGET (dialog));
494 /* Show an explanatory temporary banner: */
496 modest_platform_information_banner (NULL, NULL, _("mcen_ib_username_pw_incorrect"));
499 /* This callback will be called by Tinymail when it needs the password
500 * from the user or the account settings.
501 * It can also call forget_password() before calling this,
502 * so that we clear wrong passwords out of our account settings.
503 * Note that TnyAccount here will be the server account. */
505 get_password (TnyAccount *account, const gchar * prompt_not_used, gboolean *cancel)
507 ModestTnyAccountStore *self = NULL;
508 ModestTnyAccountStorePrivate *priv;
509 gchar *username = NULL;
512 gboolean already_asked = FALSE;
513 const gchar *server_account_name;
516 g_return_val_if_fail (account, NULL);
518 g_debug ("%s: %s", __FUNCTION__, prompt_not_used);
520 /* Get a reference to myself */
521 self = MODEST_TNY_ACCOUNT_STORE (g_object_get_data (G_OBJECT(account), "account_store"));
522 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
524 /* Ensure that we still have this account. It could happen
525 that a set_online was requested *before* removing an
526 account, and due to tinymail emits the get_password
527 function using a g_idle the account could be actually
528 removed *before* this function was really called */
529 url_string = tny_account_get_url_string (account);
531 TnyAccount *tmp_account;
533 tmp_account = tny_account_store_find_account (TNY_ACCOUNT_STORE (self),
541 g_object_unref (tmp_account);
544 server_account_name = tny_account_get_id (account);
545 if (!server_account_name || !self) {
546 g_warning ("%s: could not retrieve account_store for account %s",
547 __FUNCTION__, server_account_name ? server_account_name : "<NULL>");
554 /* We need to do this to avoid "dereferencing type-punned pointer will break strict-aliasing rules" */
555 pwd_ptr = (gpointer) &pwd;
557 /* This hash map stores passwords, including passwords that are not stored in gconf. */
558 /* Is it in the hash? if it's already there, it must be wrong... */
559 already_asked = priv->password_hash && g_hash_table_lookup_extended (priv->password_hash,
564 /* If the password is not already there, try ModestConf */
565 if (!already_asked) {
566 pwd = modest_account_mgr_get_server_account_password (priv->account_mgr,
567 server_account_name);
568 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup (pwd));
570 /* We need to get it again because forget_password has cleared it */
571 pwd = modest_account_mgr_get_server_account_password (priv->account_mgr, server_account_name);
574 /* This is horrible but we need it until we don't get a proper
575 fix into tinymail. Thing is that tinymail incorrectly asks
576 for password when the connection to the server failed due a
577 timeout (slow network connection, firewalls...). In those
578 cases it makes no sense to ask the user. It's better just
580 if (g_strstr_len (prompt_not_used, -1, "Connection timed out")) {
581 g_debug ("%s, Incorrect get_password with connection issue", __FUNCTION__);
582 modest_tny_account_store_forget_password_in_memory (self, tny_account_get_id (account));
588 /* If it was already asked, it must have been wrong, so ask again */
589 if (already_asked || !pwd || strlen(pwd) == 0) {
590 gboolean settings_have_password;
591 ModestProtocolType protocol_type;
593 /* As per the UI spec, if no password was set in the account settings,
594 * ask for it now. But if the password is wrong in the account settings,
595 * then show a banner and the account settings dialog so it can be corrected:
597 settings_have_password =
598 modest_account_mgr_get_server_account_has_password (priv->account_mgr, server_account_name);
600 protocol_type = modest_tny_account_get_protocol_type (account);
602 /* Show an error and after that ask for a password */
603 if (modest_protocol_registry_protocol_type_has_tag(modest_runtime_get_protocol_registry (),
604 protocol_type, MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS)) {
605 gchar *username = NULL, *msg = NULL;
606 username = modest_account_mgr_get_server_account_username (priv->account_mgr,
607 server_account_name);
608 if (!username || strlen(username) == 0) {
609 msg = g_strdup_printf (_("emev_ni_ui_smtp_userid_invalid"),
610 tny_account_get_name (account),
611 tny_account_get_hostname (account));
614 password = modest_account_mgr_get_server_account_password (priv->account_mgr,
615 server_account_name);
617 if (!password || strlen(password) == 0) {
618 msg = g_strdup_printf (_("emev_ni_ui_smtp_passwd_invalid"),
619 tny_account_get_name (account),
620 tny_account_get_hostname (account));
622 msg = g_strdup_printf (_("emev_ni_ui_smtp_authentication_fail_error"),
623 tny_account_get_hostname (account));
629 modest_platform_run_information_dialog (NULL, msg, TRUE);
637 gboolean username_known =
638 modest_account_mgr_get_server_account_username_has_succeeded(priv->account_mgr,
639 server_account_name);
640 /* If the login has ever succeeded then show a specific message */
642 msg = _CS ("ecdg_ib_set_password_incorrect");
644 msg = _("mcen_ib_username_pw_incorrect");
645 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()))
646 modest_platform_information_banner (NULL, NULL, msg);
650 if (settings_have_password) {
653 /* Never show it if the UI is not launched */
654 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ())) {
655 g_debug ("%s: going to show the dialog (%d windows)", __FUNCTION__,
656 modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()));
657 /* The password must be wrong, so show the account settings dialog so it can be corrected: */
658 show_wrong_password_dialog (account, TRUE);
660 g_debug ("%s: not showing the dialog (no windows)", __FUNCTION__);
668 /* Get the password from the account settings */
669 return modest_account_mgr_get_server_account_password (priv->account_mgr, server_account_name);
673 /* we don't have it yet. Get the password from the user */
675 const gchar* account_id = tny_account_get_id (account);
676 gboolean remember = FALSE;
677 g_signal_emit (G_OBJECT (self), signals[PASSWORD_REQUESTED_SIGNAL], 0,
678 account_id, /* server_account_name */
679 &username, &pwd, cancel, &remember);
682 g_hash_table_remove (priv->password_hash, server_account_name);
697 modest_tny_account_store_forget_already_asked (ModestTnyAccountStore *self, TnyAccount *account)
699 g_return_if_fail (account);
701 ModestTnyAccountStorePrivate *priv;
703 gpointer pwd_ptr = NULL;
704 gboolean already_asked = FALSE;
706 const gchar *server_account_name = tny_account_get_id (account);
708 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
710 /* This hash map stores passwords, including passwords that are not stored in gconf. */
711 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
712 * type-punned ptrs...*/
713 already_asked = priv->password_hash &&
714 g_hash_table_lookup_extended (priv->password_hash,
717 (gpointer*)&pwd_ptr);
720 g_hash_table_remove (priv->password_hash, server_account_name);
728 /* tinymail calls this if the connection failed due to an incorrect password.
729 * And it seems to call this for any general connection failure. */
731 forget_password (TnyAccount *account)
733 ModestTnyAccountStore *self;
734 ModestTnyAccountStorePrivate *priv;
735 const TnyAccountStore *account_store;
739 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
741 self = MODEST_TNY_ACCOUNT_STORE (account_store);
742 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
743 key = tny_account_get_id (account);
745 /* Do not remove the key, this will allow us to detect that we
746 have already asked for it at least once */
747 pwd = g_hash_table_lookup (priv->password_hash, key);
749 g_debug ("%s, forgetting %s for account %s", __FUNCTION__, pwd, key);
750 memset (pwd, 0, strlen (pwd));
751 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
756 modest_tny_account_store_finalize (GObject *obj)
758 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(obj);
759 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
761 g_free (priv->cache_dir);
762 priv->cache_dir = NULL;
764 if (priv->password_hash) {
765 g_hash_table_destroy (priv->password_hash);
766 priv->password_hash = NULL;
769 if (priv->outbox_of_transport) {
770 g_hash_table_destroy (priv->outbox_of_transport);
771 priv->outbox_of_transport = NULL;
774 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
775 priv->sighandlers = NULL;
777 if (priv->account_mgr) {
778 g_object_unref (G_OBJECT(priv->account_mgr));
779 priv->account_mgr = NULL;
783 g_object_unref (G_OBJECT(priv->device));
787 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
788 if (priv->store_accounts) {
789 tny_list_foreach (priv->store_accounts, (GFunc)account_verify_last_ref, "store");
790 g_object_unref (priv->store_accounts);
791 priv->store_accounts = NULL;
794 if (priv->transport_accounts) {
795 tny_list_foreach (priv->transport_accounts, (GFunc)account_verify_last_ref, "transport");
796 g_object_unref (priv->transport_accounts);
797 priv->transport_accounts = NULL;
800 if (priv->store_accounts_outboxes) {
801 g_object_unref (priv->store_accounts_outboxes);
802 priv->store_accounts_outboxes = NULL;
806 camel_object_unref (CAMEL_OBJECT(priv->session));
807 priv->session = NULL;
810 G_OBJECT_CLASS(parent_class)->finalize (obj);
814 volume_path_is_mounted (const gchar* path)
816 g_return_val_if_fail (path, FALSE);
818 gboolean result = FALSE;
819 gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
820 g_return_val_if_fail (path_as_uri, FALSE);
822 /* Get the monitor singleton: */
823 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
825 /* This seems like a simpler way to do this, but it returns a
826 * GnomeVFSVolume even if the drive is not mounted: */
828 GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor,
829 g_getenv (MODEST_MMC1_VOLUMEPATH_ENV));
831 gnome_vfs_volume_unref(volume);
835 /* Get the mounted volumes from the monitor: */
836 GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
838 for (iter = list; iter; iter = g_list_next (iter)) {
839 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
843 gnome_vfs_volume_get_display_name (volume);
844 printf ("volume display name=%s\n", display_name);
845 g_free (display_name);
849 gnome_vfs_volume_get_activation_uri (volume);
850 /* printf (" uri=%s\n", uri); */
851 if (uri && (strcmp (uri, path_as_uri) == 0))
856 gnome_vfs_volume_unref (volume);
862 g_free (path_as_uri);
867 ModestTnyAccountStore*
868 modest_tny_account_store_new (ModestAccountMgr *account_mgr,
872 ModestTnyAccountStorePrivate *priv;
873 TnyAccount *local_account = NULL;
874 TnyLockable *lockable;
875 GnomeVFSVolumeMonitor* monitor = NULL;
876 gboolean auto_update;
878 g_return_val_if_fail (account_mgr, NULL);
879 g_return_val_if_fail (device, NULL);
881 obj = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
882 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
884 priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
885 priv->device = g_object_ref (device);
887 /* If autoupdate is off then we don't try to connect to the
888 accounts when they're added to the account store*/
889 auto_update = modest_conf_get_bool (modest_runtime_get_conf (),
890 MODEST_CONF_AUTO_UPDATE, NULL);
892 tny_device_force_offline (priv->device);
894 priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
895 if (!priv->session) {
896 g_warning ("failed to get TnySessionCamel");
900 /* Set the ui locker */
901 lockable = tny_gtk_lockable_new ();
902 tny_session_camel_set_ui_locker (priv->session, lockable);
903 g_object_unref (lockable);
905 /* Connect signals */
906 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
907 G_OBJECT(account_mgr), "account_inserted",
908 G_CALLBACK (on_account_inserted), obj);
909 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
910 G_OBJECT(account_mgr), "account_changed",
911 G_CALLBACK (on_account_changed), obj);
912 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
913 G_OBJECT(account_mgr), "account_removed",
914 G_CALLBACK (on_account_removed), obj);
916 /* Respond to volume mounts and unmounts, such as the
917 insertion/removal of the memory card. This is a singleton,
918 so it does not need to be unrefed */
919 monitor = gnome_vfs_get_volume_monitor();
920 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
923 G_CALLBACK(on_vfs_volume_mounted),
925 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
926 G_OBJECT(monitor), "volume-unmounted",
927 G_CALLBACK(on_vfs_volume_unmounted),
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 (g_getenv (MODEST_MMC1_VOLUMEPATH_ENV))) {
954 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */);
957 /* Initialize session */
958 tny_session_camel_set_initialized (priv->session);
960 return MODEST_TNY_ACCOUNT_STORE(obj);
964 modest_tny_account_store_get_accounts (TnyAccountStore *self,
966 TnyGetAccountsRequestType request_type)
968 ModestTnyAccountStorePrivate *priv;
970 g_return_if_fail (self);
971 g_return_if_fail (TNY_IS_LIST(list));
973 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
975 switch (request_type) {
976 case TNY_ACCOUNT_STORE_BOTH:
977 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
978 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
980 case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
981 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
983 case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
984 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
987 g_return_if_reached ();
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 ModestProtocolType protocol_type = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
1042 ModestProtocol *protocol = NULL;
1043 const gchar* server_name = "";
1044 gchar *prompt = NULL;
1045 gboolean retval = TRUE;
1047 /* NOTE: account may be NULL in some cases */
1051 /* Get the server name: */
1053 server_name = tny_account_get_hostname (account);
1054 protocol_type = modest_tny_account_get_protocol_type (account);
1055 if (protocol_type == MODEST_PROTOCOL_REGISTRY_TYPE_INVALID){
1056 g_warning("%s: account with id=%s has no proto.\n", __FUNCTION__,
1057 tny_account_get_id (account));
1060 protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
1064 switch (error->code) {
1065 case TNY_SYSTEM_ERROR_CANCEL:
1066 /* Don't show waste the user's time by showing him a dialog telling
1067 * him that he has just cancelled something: */
1070 case TNY_SERVICE_ERROR_PROTOCOL:
1071 /* Like a BAD from IMAP (protocol error) */
1072 case TNY_SERVICE_ERROR_LOST_CONNECTION:
1073 /* Lost the connection with the service */
1074 case TNY_SERVICE_ERROR_UNAVAILABLE:
1075 /* You must be working online for this operation */
1076 case TNY_SERVICE_ERROR_CONNECT:
1078 prompt = modest_protocol_get_translation (protocol, MODEST_PROTOCOL_TRANSLATION_CONNECT_ERROR, server_name);
1081 g_return_val_if_reached (FALSE);
1084 case TNY_SERVICE_ERROR_AUTHENTICATE:
1085 /* It seems that there's no better error to show with
1086 * POP and IMAP because TNY_SERVICE_ERROR_AUTHENTICATE
1087 * may appear if there's a timeout during auth */
1089 prompt = modest_protocol_get_translation (protocol, MODEST_PROTOCOL_TRANSLATION_AUTH_ERROR, server_name);
1092 g_return_val_if_reached (FALSE);
1095 case TNY_SERVICE_ERROR_CERTIFICATE:
1096 /* We'll show the proper dialog later */
1099 case TNY_SYSTEM_ERROR_MEMORY:
1100 /* Can't allocate memory for this operation */
1101 if (modest_tny_account_store_check_disk_full_error ((ModestTnyAccountStore*)self,
1102 NULL, error, account, NULL))
1105 case TNY_SERVICE_ERROR_UNKNOWN:
1108 /* We don't treat this as an error, but as a not handled message. Then,
1109 * debug message, and return false */
1110 g_debug ("Unexpected error %d (%s)", error->code, error->message);
1115 if (error->code == TNY_SERVICE_ERROR_CERTIFICATE)
1116 retval = modest_platform_run_certificate_confirmation_dialog (server_name,
1118 else if (error->code == TNY_SERVICE_ERROR_AUTHENTICATE ||
1119 error->code == TNY_SERVICE_ERROR_CONNECT) {
1120 TnyDevice *device = modest_runtime_get_device ();
1123 /* If we get the connection error after establishing a
1124 proper connection then do not show the dialog as we
1125 are probably behind a firewall, or in a network
1126 with connection issues. We just keep this code to
1127 detect situations were the user does not enter the
1128 server info properly */
1129 success = modest_account_mgr_get_server_account_username_has_succeeded (modest_runtime_get_account_mgr (),
1130 tny_account_get_id (account));
1133 g_debug ("%s: %s alert received (%s)", __FUNCTION__,
1134 (error->code == TNY_SERVICE_ERROR_CONNECT) ? "connect" : "aunthenticate",
1137 modest_platform_run_information_dialog (NULL, prompt, TRUE);
1139 /* Show the account dialog. Checking the
1140 online status allows us to minimize the
1141 number of times that we incorrectly show
1142 the dialog. Also do not show it if the UI
1144 if (tny_device_is_online (device) &&
1145 modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ())) {
1146 show_wrong_password_dialog (account,
1147 (error->code == TNY_SERVICE_ERROR_CONNECT) ? FALSE : TRUE);
1149 if (tny_device_is_online (device))
1150 g_debug ("%s: not showing the dialog (no windows)", __FUNCTION__);
1152 g_debug ("%s: not showing the dialog (no connection)", __FUNCTION__);
1158 g_debug ("%s: error code %d (%s", __FUNCTION__, error->code, error->message);
1168 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1170 TnyAccountStoreIface *klass;
1172 g_return_if_fail (g);
1174 klass = (TnyAccountStoreIface *)g;
1176 klass->get_accounts =
1177 modest_tny_account_store_get_accounts;
1178 klass->get_cache_dir =
1179 modest_tny_account_store_get_cache_dir;
1181 modest_tny_account_store_get_device;
1183 modest_tny_account_store_alert;
1184 klass->find_account =
1185 modest_tny_account_store_find_account_by_url;
1189 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1190 ModestTnyGetPassFunc func)
1192 /* not implemented, we use signals */
1193 g_printerr ("modest: set_get_pass_func not implemented\n");
1197 modest_tny_account_store_get_session (TnyAccountStore *self)
1199 g_return_val_if_fail (self, NULL);
1200 return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1204 get_tny_account_by (TnyList *accounts,
1205 ModestTnyAccountStoreQueryType type,
1208 TnyIterator *iter = NULL;
1209 gboolean found = FALSE;
1210 TnyAccount *retval = NULL;
1212 g_return_val_if_fail (TNY_IS_LIST(accounts), NULL);
1214 if (tny_list_get_length(accounts) == 0) {
1215 g_warning ("%s: account list is empty", __FUNCTION__);
1219 iter = tny_list_create_iterator (accounts);
1220 while (!tny_iterator_is_done (iter) && !found) {
1221 TnyAccount *tmp_account = NULL;
1222 const gchar *val = NULL;
1224 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1225 if (!TNY_IS_ACCOUNT(tmp_account)) {
1226 g_warning ("%s: not a valid account", __FUNCTION__);
1232 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1233 val = tny_account_get_id (tmp_account);
1235 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1236 val = tny_account_get_url_string (tmp_account);
1240 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL &&
1241 tny_account_matches_url_string (tmp_account, str)) {
1242 retval = g_object_ref (tmp_account);
1245 if (val && str && strcmp (val, str) == 0) {
1246 retval = g_object_ref (tmp_account);
1250 g_object_unref (tmp_account);
1251 tny_iterator_next (iter);
1253 g_object_unref (iter);
1259 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self,
1260 ModestTnyAccountStoreQueryType type,
1263 TnyAccount *account = NULL;
1264 ModestTnyAccountStorePrivate *priv;
1266 g_return_val_if_fail (self, NULL);
1267 g_return_val_if_fail (str, NULL);
1269 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1271 /* Search in store accounts */
1272 account = get_tny_account_by (priv->store_accounts, type, str);
1274 /* If we already found something, no need to search the transport accounts */
1276 account = get_tny_account_by (priv->transport_accounts, type, str);
1278 /* If we already found something, no need to search the
1279 per-account outbox accounts */
1281 account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1284 /* Warn if nothing was found. This is generally unusual. */
1286 g_warning("%s: Failed to find account with %s=%s\n",
1288 (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",
1292 /* Returns a new reference to the account if found */
1298 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1299 const gchar *account_name,
1300 TnyAccountType type)
1302 ModestTnyAccountStorePrivate *priv = NULL;
1303 TnyAccount *retval = NULL;
1304 TnyList *account_list = NULL;
1305 TnyIterator *iter = NULL;
1308 g_return_val_if_fail (self, NULL);
1309 g_return_val_if_fail (account_name, NULL);
1310 g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE ||
1311 type == TNY_ACCOUNT_TYPE_TRANSPORT,
1314 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1316 account_list = (type == TNY_ACCOUNT_TYPE_STORE) ?
1317 priv->store_accounts :
1318 priv->transport_accounts;
1320 if (!account_list) {
1321 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__,
1322 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1326 /* Look for the server account */
1328 iter = tny_list_create_iterator (account_list);
1329 while (!tny_iterator_is_done (iter) && !found) {
1330 const gchar *modest_acc_name;
1331 TnyAccount *tmp_account;
1333 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1335 modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1337 if (account_name && modest_acc_name && !strcmp (account_name, modest_acc_name)) {
1339 retval = g_object_ref (tmp_account);
1341 /* Free and continue */
1342 g_object_unref (tmp_account);
1343 tny_iterator_next (iter);
1345 g_object_unref (iter);
1348 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1349 "Number of server accounts of this type=%d\n", __FUNCTION__,
1350 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1351 account_name, tny_list_get_length (account_list));
1354 /* Returns a new reference */
1359 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (
1360 ModestTnyAccountStore *self, const gchar *account_name)
1364 g_return_val_if_fail (self && MODEST_IS_TNY_ACCOUNT_STORE(self), NULL);
1365 g_return_val_if_fail (account_name, NULL);
1367 /* Get the current connection: */
1368 device = modest_runtime_get_device ();
1371 g_warning ("%s: could not get device", __FUNCTION__);
1375 if (!tny_device_is_online (device))
1378 #ifdef MODEST_HAVE_CONIC
1379 g_return_val_if_fail (TNY_IS_MAEMO_CONIC_DEVICE (device), NULL);
1381 TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);
1382 const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1383 /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1387 ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1391 const gchar *connection_id = con_ic_iap_get_id (connection);
1392 /* printf ("DEBUG: %s: connection_id=%s\n", __FUNCTION__, connection_id); */
1396 /* Get the connection-specific transport acccount, if any: */
1397 ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1399 /* Check if this account has connection-specific SMTP enabled */
1400 if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1404 gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager,
1407 /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1408 if (!server_account_name) {
1409 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1412 TnyAccount* account = modest_tny_account_store_get_tny_account_by (self,
1413 MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1414 server_account_name);
1416 /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1417 g_free (server_account_name);
1419 /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1420 g_object_unref (connection);
1424 return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1425 #endif /* MODEST_HAVE_CONIC */
1430 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1431 const gchar *account_name)
1433 g_return_val_if_fail (self, NULL);
1434 g_return_val_if_fail (account_name, NULL);
1436 if (!account_name || !self)
1439 /* Get the connection-specific transport acccount, if any: */
1440 /* Note: This gives us a reference: */
1441 TnyAccount *account =
1442 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (self, account_name);
1444 /* If there is no connection-specific transport account (the common case),
1445 * just get the regular transport account: */
1447 /* The special local folders don't have transport accounts. */
1448 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1451 /* Note: This gives us a reference: */
1452 account = modest_tny_account_store_get_server_account (self, account_name,
1453 TNY_ACCOUNT_TYPE_TRANSPORT);
1457 /* returns a reference. */
1462 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1464 TnyAccount *account = NULL;
1465 ModestTnyAccountStorePrivate *priv;
1469 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1471 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1474 iter = tny_list_create_iterator (priv->store_accounts);
1475 while (!tny_iterator_is_done (iter) && !found) {
1476 TnyAccount *tmp_account;
1478 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1479 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1480 account = g_object_ref (tmp_account);
1483 g_object_unref (tmp_account);
1484 tny_iterator_next (iter);
1486 g_object_unref (iter);
1488 /* Returns a new reference to the account */
1493 modest_tny_account_store_get_mmc_folders_account (ModestTnyAccountStore *self)
1495 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1498 return modest_tny_account_store_get_tny_account_by (self, MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1499 MODEST_MMC_ACCOUNT_ID);
1503 /*********************************************************************************/
1505 add_existing_accounts (ModestTnyAccountStore *self)
1507 GSList *account_names = NULL, *iter = NULL;
1508 ModestTnyAccountStorePrivate *priv = NULL;
1510 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1512 /* These are account names, not server_account names */
1513 account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1515 for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1516 const gchar *account_name = (const gchar*) iter->data;
1518 /* Insert all enabled accounts without notifying */
1519 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1520 insert_account (self, account_name, FALSE);
1522 modest_account_mgr_free_account_names (account_names);
1526 create_tny_account (ModestTnyAccountStore *self,
1528 TnyAccountType type,
1531 TnyAccount *account = NULL;
1532 ModestTnyAccountStorePrivate *priv = NULL;
1534 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1536 account = modest_tny_account_new_from_account (priv->account_mgr,
1543 /* Forget any cached password for the account, so that
1544 we use a new account if any */
1545 modest_tny_account_store_forget_password_in_memory (self, tny_account_get_id (account));
1547 /* Set the account store */
1548 g_object_set_data (G_OBJECT(account), "account_store", self);
1550 g_printerr ("modest: failed to create account for %s\n", name);
1556 typedef struct _AddOutboxInfo {
1557 ModestTnyAccountStore *account_store;
1558 TnyAccount *transport_account;
1562 add_outbox_from_transport_account_to_global_outbox_get_folders_cb (TnyFolderStore *folder_store,
1568 TnyIterator *iter_folders;
1569 TnyFolder *per_account_outbox;
1570 TnyAccount *local_account = NULL;
1571 AddOutboxInfo *info = (AddOutboxInfo *) userdata;
1572 ModestTnyAccountStorePrivate *priv = NULL;
1573 ModestTnyAccountStore *self;
1575 self = MODEST_TNY_ACCOUNT_STORE (info->account_store);
1576 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1578 /* Note that this could happen if there is not enough space
1579 available on disk, then the outbox folder could not be
1581 if (tny_list_get_length (list) != 1) {
1582 g_warning ("%s: could not create outbox folder (%d folders found)", __FUNCTION__,
1583 tny_list_get_length (list));
1587 iter_folders = tny_list_create_iterator (list);
1588 per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1589 g_object_unref (iter_folders);
1590 g_object_unref (list);
1592 /* Add the outbox of the new per-account-local-outbox account
1593 to the global local merged OUTBOX of the local folders
1595 local_account = modest_tny_account_store_get_local_folders_account (info->account_store);
1596 modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1597 per_account_outbox);
1598 /* Add the pair to the hash table */
1599 g_hash_table_insert (priv->outbox_of_transport,
1600 info->transport_account,
1601 per_account_outbox);
1603 /* Notify that the local account changed */
1604 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1605 g_object_unref (local_account);
1606 g_object_unref (per_account_outbox);
1609 g_object_unref (info->transport_account);
1610 g_slice_free (AddOutboxInfo, info);
1615 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1616 const gchar *account_name,
1617 TnyAccount *transport_account)
1619 TnyList *folders = NULL;
1620 TnyAccount *account_outbox = NULL;
1621 ModestTnyAccountStorePrivate *priv = NULL;
1622 AddOutboxInfo *info;
1624 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1626 /* Create per account local outbox */
1628 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr,
1632 if (!G_IS_OBJECT (account_outbox)) {
1633 g_warning ("%s: could not create per account local outbox folder", __FUNCTION__);
1637 tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1639 /* Get the outbox folder */
1640 folders = tny_simple_list_new ();
1641 info = g_slice_new0 (AddOutboxInfo);
1642 info->account_store = self;
1643 info->transport_account = g_object_ref (transport_account);
1644 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (account_outbox), folders, NULL, FALSE,
1645 add_outbox_from_transport_account_to_global_outbox_get_folders_cb, NULL, (gpointer) info);
1646 g_object_unref (account_outbox);
1650 * This function will be used for both adding new accounts and for the
1651 * initialization. In the initialization we do not want to emit
1652 * signals so notify will be FALSE, in the case of account additions
1653 * we do want to notify the observers
1656 insert_account (ModestTnyAccountStore *self,
1657 const gchar *account,
1660 ModestTnyAccountStorePrivate *priv = NULL;
1661 TnyAccount *store_account = NULL, *transport_account = NULL;
1663 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1665 /* Get the server and the transport account */
1666 store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE, is_new);
1667 if (!store_account || !TNY_IS_ACCOUNT(store_account)) {
1668 g_warning ("%s: failed to create store account", __FUNCTION__);
1672 transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT, is_new);
1673 if (!transport_account || !TNY_IS_ACCOUNT(transport_account)) {
1674 g_warning ("%s: failed to create transport account", __FUNCTION__);
1675 g_object_unref (store_account);
1679 /* Add accounts to the lists */
1680 tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1681 tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1683 /* Create a new pseudo-account with an outbox for this
1684 transport account and add it to the global outbox
1685 in the local account */
1686 add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1688 /* Force the creation of the send queue, this way send queues
1689 will automatically send missing emails when the connections
1691 /* Notify the observers. We do it after everything is
1694 /* We only have to do this for new accounts, already
1695 existing accounts at boot time are instantiated by
1696 modest_tny_account_store_start_send_queues */
1697 modest_runtime_get_send_queue ((TnyTransportAccount *) transport_account, TRUE);
1699 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);
1700 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1704 g_object_unref (store_account);
1705 g_object_unref (transport_account);
1708 static inline gboolean
1709 only_local_accounts (ModestTnyAccountStore *self)
1711 return (modest_tny_account_store_get_num_remote_accounts (self) > 0) ? FALSE : TRUE;
1715 on_account_inserted (ModestAccountMgr *acc_mgr,
1716 const gchar *account,
1719 gboolean add_specific;
1721 add_specific = only_local_accounts (MODEST_TNY_ACCOUNT_STORE (user_data));
1723 /* Insert the account and notify the observers */
1724 insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1726 /* If it's the first remote account then add the connection
1727 specific SMTP servers as well */
1729 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE (user_data));
1733 /* This is the callback of the tny_camel_account_set_online called in
1734 on_account_removed to disconnect the account */
1736 on_account_disconnect_when_removing (TnyCamelAccount *account,
1741 ModestTnyAccountStore *self;
1742 ModestTnyAccountStorePrivate *priv;
1744 self = MODEST_TNY_ACCOUNT_STORE (user_data);
1745 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1747 /* Cancel all pending operations */
1748 tny_account_cancel (TNY_ACCOUNT (account));
1750 /* Unref the extra reference added by get_server_account */
1751 g_object_unref (account);
1753 /* Clear the cache if it's an store account */
1754 if (TNY_IS_STORE_ACCOUNT (account)) {
1755 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (account));
1756 } else if (TNY_IS_TRANSPORT_ACCOUNT (account)) {
1757 ModestTnySendQueue* send_queue;
1758 send_queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (account), FALSE);
1759 if (TNY_IS_SEND_QUEUE (send_queue)) {
1760 if (modest_tny_send_queue_sending_in_progress (send_queue))
1761 tny_send_queue_cancel (TNY_SEND_QUEUE (send_queue),
1762 TNY_SEND_QUEUE_CANCEL_ACTION_REMOVE,
1764 modest_runtime_remove_send_queue (TNY_TRANSPORT_ACCOUNT (account));
1770 * We use this one for both removing "normal" and "connection
1771 * specific" transport accounts
1774 remove_transport_account (ModestTnyAccountStore *self,
1775 TnyTransportAccount *transport_account)
1777 ModestTnyAccountStorePrivate *priv;
1778 TnyFolder *outbox = NULL;
1780 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1782 /* Remove it from the list of accounts and notify the
1783 observers. Do not need to wait for account
1785 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, transport_account);
1786 tny_list_remove (priv->transport_accounts, (GObject *) transport_account);
1788 /* Remove the OUTBOX of the account from the global outbox */
1789 outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
1791 if (TNY_IS_FOLDER (outbox)) {
1792 TnyAccount *local_account = NULL;
1793 TnyAccount *outbox_account = tny_folder_get_account (outbox);
1795 if (outbox_account) {
1796 tny_list_remove (priv->store_accounts_outboxes, G_OBJECT (outbox_account));
1797 /* Remove existing emails to send */
1798 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (outbox_account));
1799 g_object_unref (outbox_account);
1802 local_account = modest_tny_account_store_get_local_folders_account (self);
1803 modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1806 g_hash_table_remove (priv->outbox_of_transport, transport_account);
1808 /* Notify the change in the local account */
1809 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1810 g_object_unref (local_account);
1812 g_warning ("Removing a transport account that has no outbox");
1815 /* Cancel all pending operations */
1816 tny_account_cancel (TNY_ACCOUNT (transport_account));
1818 /* Disconnect and notify the observers. The callback will free the reference */
1819 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (transport_account), FALSE,
1820 on_account_disconnect_when_removing, self);
1824 images_cache_remove_filter (TnyStreamCache *self, const gchar *id, const gchar *account_name)
1826 gchar *account_name_with_separator;
1828 if (account_name == NULL || account_name[0] == '\0')
1831 if (id == NULL || id[0] == '\0')
1834 account_name_with_separator = g_strconcat (account_name, "__", NULL);
1836 result = (g_str_has_prefix (id, account_name));
1837 g_free (account_name_with_separator);
1843 on_account_removed (ModestAccountMgr *acc_mgr,
1844 const gchar *account,
1847 TnyAccount *store_account = NULL, *transport_account = NULL;
1848 ModestTnyAccountStore *self;
1849 ModestTnyAccountStorePrivate *priv;
1850 TnyStreamCache *stream_cache;
1852 self = MODEST_TNY_ACCOUNT_STORE (user_data);
1853 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1855 /* Get the server and the transport account */
1857 modest_tny_account_store_get_server_account (self, account,
1858 TNY_ACCOUNT_TYPE_STORE);
1860 modest_tny_account_store_get_server_account (self, account,
1861 TNY_ACCOUNT_TYPE_TRANSPORT);
1863 /* If there was any problem creating the account, for example,
1864 with the configuration system this could not exist */
1865 if (TNY_IS_STORE_ACCOUNT(store_account)) {
1866 /* Forget any cached password for the account */
1867 modest_tny_account_store_forget_password_in_memory (self, tny_account_get_id (store_account));
1869 /* Remove it from the list of accounts and notify the
1870 observers. Do not need to wait for account
1872 tny_list_remove (priv->store_accounts, (GObject *) store_account);
1873 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, store_account);
1875 /* Cancel all pending operations */
1876 tny_account_cancel (TNY_ACCOUNT (store_account));
1878 /* Disconnect before deleting the cache, because the
1879 disconnection will rewrite the cache to the
1881 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (store_account), FALSE,
1882 on_account_disconnect_when_removing, self);
1884 g_warning ("%s: no store account for account %s\n",
1885 __FUNCTION__, account);
1888 /* If there was any problem creating the account, for example,
1889 with the configuration system this could not exist */
1890 if (TNY_IS_TRANSPORT_ACCOUNT(transport_account)) {
1892 /* Forget any cached password for the account */
1893 modest_tny_account_store_forget_password_in_memory (self, tny_account_get_id (transport_account));
1895 /* Remove transport account. It'll free the reference
1896 added by get_server_account */
1897 remove_transport_account (self, TNY_TRANSPORT_ACCOUNT (transport_account));
1899 g_warning ("%s: no transport account for account %s\n",
1900 __FUNCTION__, account);
1903 /* Remove cached images */
1904 stream_cache = modest_runtime_get_images_cache ();
1905 tny_stream_cache_remove (stream_cache, (TnyStreamCacheRemoveFilter) images_cache_remove_filter, (gpointer) account);
1907 /* If there are no more user accounts then delete the
1908 transport specific SMTP servers */
1909 if (only_local_accounts (self))
1910 remove_connection_specific_transport_accounts (self);
1913 TnyTransportAccount *
1914 modest_tny_account_store_new_connection_specific_transport_account (ModestTnyAccountStore *self,
1917 ModestTnyAccountStorePrivate *priv = NULL;
1918 TnyAccount * tny_account = NULL;
1920 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1922 /* Add the account: */
1924 modest_tny_account_new_from_server_account_name (priv->account_mgr,
1930 g_object_set_data (G_OBJECT(tny_account),
1933 g_object_set_data (G_OBJECT(tny_account),
1934 "connection_specific",
1935 GINT_TO_POINTER (TRUE));
1937 tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1938 add_outbox_from_transport_account_to_global_outbox (self,
1943 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1946 return TNY_TRANSPORT_ACCOUNT (tny_account);
1950 foreach_free_string(gpointer data,
1957 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1959 ModestTnyAccountStorePrivate *priv = NULL;
1960 GSList *list_specifics = NULL, *iter = NULL;
1963 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1965 list_specifics = modest_conf_get_list (modest_runtime_get_conf (),
1966 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
1967 MODEST_CONF_VALUE_STRING, &err);
1970 g_return_if_reached ();
1974 /* Look at each connection-specific transport account for the
1975 * modest account: */
1976 iter = list_specifics;
1978 /* The list alternates between the connection name and the transport name: */
1979 iter = g_slist_next (iter);
1981 const gchar* transport_account_name = (const gchar*) (iter->data);
1982 TnyTransportAccount * account = NULL;
1983 account = modest_tny_account_store_new_connection_specific_transport_account (
1984 self, transport_account_name);
1986 g_object_unref (account);
1988 iter = g_slist_next (iter);
1992 g_slist_foreach (list_specifics, foreach_free_string, NULL);
1993 g_slist_free (list_specifics);
1997 remove_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1999 ModestTnyAccountStorePrivate *priv = NULL;
2000 GSList *list_specifics = NULL, *iter = NULL;
2003 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2006 list_specifics = modest_conf_get_list (modest_runtime_get_conf (),
2007 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
2008 MODEST_CONF_VALUE_STRING, &err);
2011 g_return_if_reached ();
2015 /* Look at each connection-specific transport account for the
2016 * modest account: */
2017 iter = list_specifics;
2019 /* The list alternates between the connection name and the transport name: */
2020 iter = g_slist_next (iter);
2022 const gchar* transport_account_name = (const gchar*) (iter->data);
2023 TnyAccount * account;
2024 account = modest_tny_account_store_get_server_account (self,
2025 transport_account_name,
2026 TNY_ACCOUNT_TYPE_TRANSPORT);
2028 /* the call will free the reference */
2030 remove_transport_account (self, TNY_TRANSPORT_ACCOUNT (account));
2032 iter = g_slist_next (iter);
2036 g_slist_foreach (list_specifics, foreach_free_string, NULL);
2037 g_slist_free (list_specifics);
2042 modest_tny_account_store_find_msg_in_outboxes (ModestTnyAccountStore *self,
2044 TnyAccount **ac_out)
2046 TnyIterator *acc_iter;
2047 ModestTnyAccountStorePrivate *priv;
2049 TnyAccount *msg_account = NULL;
2051 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
2052 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2054 acc_iter = tny_list_create_iterator (priv->store_accounts_outboxes);
2055 while (!msg && !tny_iterator_is_done (acc_iter)) {
2056 TnyList *folders = tny_simple_list_new ();
2057 TnyAccount *account = TNY_ACCOUNT (tny_iterator_get_current (acc_iter));
2058 TnyIterator *folders_iter = NULL;
2060 tny_folder_store_get_folders (TNY_FOLDER_STORE (account), folders, NULL, FALSE, NULL);
2061 folders_iter = tny_list_create_iterator (folders);
2063 while (msg == NULL && !tny_iterator_is_done (folders_iter)) {
2064 TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (folders_iter));
2065 msg = tny_folder_find_msg (folder, uri, NULL);
2068 msg_account = g_object_ref (account);
2070 g_object_unref (folder);
2071 tny_iterator_next (folders_iter);
2073 g_object_unref (folders_iter);
2075 g_object_unref (folders);
2076 g_object_unref (account);
2077 tny_iterator_next (acc_iter);
2080 g_object_unref (acc_iter);
2083 *ac_out = msg_account;
2088 TnyTransportAccount *
2089 modest_tny_account_store_get_transport_account_from_outbox_header(ModestTnyAccountStore *self, TnyHeader *header)
2091 TnyIterator *acc_iter;
2092 ModestTnyAccountStorePrivate *priv;
2093 TnyTransportAccount *header_acc = NULL;
2096 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
2097 g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
2098 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2099 msg_id = modest_tny_send_queue_get_msg_id (header);
2100 acc_iter = tny_list_create_iterator (priv->transport_accounts);
2101 while (!header_acc && !tny_iterator_is_done (acc_iter)) {
2102 TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current (acc_iter));
2103 ModestTnySendQueue *send_queue;
2104 ModestTnySendQueueStatus status;
2105 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account), TRUE);
2106 if (TNY_IS_SEND_QUEUE (send_queue)) {
2107 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2108 if (status != MODEST_TNY_SEND_QUEUE_UNKNOWN)
2109 header_acc = g_object_ref(account);
2111 g_object_unref (account);
2112 tny_iterator_next (acc_iter);
2114 g_object_unref(acc_iter);
2122 ModestTnyAccountStore *account_store;
2123 ModestTnyAccountStoreShutdownCallback callback;
2129 account_shutdown_callback (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer userdata)
2131 ShutdownOpData *op_data = (ShutdownOpData *) userdata;
2133 if (op_data->pending == 0) {
2134 if (op_data->callback)
2135 op_data->callback (op_data->account_store, op_data->userdata);
2136 g_object_unref (op_data->account_store);
2142 account_shutdown (TnyAccount *account, ShutdownOpData *op_data)
2144 g_return_if_fail (account && TNY_IS_ACCOUNT(account));
2146 if (TNY_IS_STORE_ACCOUNT (account) &&
2147 !modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2152 /* Disconnect account */
2153 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(account), FALSE,
2154 account_shutdown_callback, op_data);
2160 modest_tny_account_store_shutdown (ModestTnyAccountStore *self,
2161 ModestTnyAccountStoreShutdownCallback callback,
2165 ShutdownOpData *op_data;
2166 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2168 /* Get references */
2170 if (priv->store_accounts)
2171 num_accounts += tny_list_get_length (priv->store_accounts);
2172 if (priv->transport_accounts)
2173 num_accounts += tny_list_get_length (priv->transport_accounts);
2175 /* Create the helper object */
2176 op_data = g_new0 (ShutdownOpData, 1);
2177 op_data->callback = callback;
2178 op_data->userdata = userdata;
2179 op_data->pending = num_accounts;
2180 op_data->account_store = g_object_ref (self);
2182 /* Force the TnyDevice to be offline. This way new
2183 undesired connections won't be initiated */
2184 tny_device_force_offline (priv->device);
2186 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
2187 if (priv->store_accounts) {
2188 tny_list_foreach (priv->store_accounts, (GFunc)account_shutdown, op_data);
2191 if (priv->transport_accounts) {
2192 tny_list_foreach (priv->transport_accounts, (GFunc)account_shutdown, op_data);
2195 if (op_data->pending == 0) {
2196 if (op_data->callback)
2197 op_data->callback (op_data->account_store, op_data->userdata);
2198 g_object_unref (op_data->account_store);
2204 modest_tny_account_store_is_shutdown (ModestTnyAccountStore *self)
2206 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2212 for (iter = tny_list_create_iterator (priv->store_accounts);
2213 !found && !tny_iterator_is_done (iter);
2214 tny_iterator_next (iter)) {
2215 TnyAccount *account;
2217 account = (TnyAccount *) tny_iterator_get_current (iter);
2218 if (TNY_IS_ACCOUNT (account)) {
2219 found = (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_CONNECTED) ||
2220 (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_RECONNECTING);
2222 g_object_unref (account);
2224 g_object_unref (iter);
2229 for (iter = tny_list_create_iterator (priv->transport_accounts);
2230 !found && !tny_iterator_is_done (iter);
2231 tny_iterator_next (iter)) {
2232 TnyAccount *account;
2234 account = (TnyAccount *) tny_iterator_get_current (iter);
2235 if (TNY_IS_ACCOUNT (account)) {
2236 found = (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_CONNECTED) ||
2237 (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_RECONNECTING);
2239 g_object_unref (account);
2241 g_object_unref (iter);
2249 modest_tny_account_store_is_send_mail_blocked (ModestTnyAccountStore *self)
2251 ModestTnyAccountStorePrivate *priv;
2253 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2255 return priv->send_mail_blocked;
2259 modest_tny_account_store_set_send_mail_blocked (ModestTnyAccountStore *self,
2262 ModestTnyAccountStorePrivate *priv;
2264 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2266 priv->send_mail_blocked = blocked;
2270 count_remote_accounts (gpointer data, gpointer user_data)
2272 TnyFolderStore *account = TNY_FOLDER_STORE (data);
2273 gint *count = (gint *) user_data;
2275 if (modest_tny_folder_store_is_remote (account))
2280 modest_tny_account_store_get_num_remote_accounts (ModestTnyAccountStore *self)
2282 ModestTnyAccountStorePrivate *priv;
2285 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), 0);
2287 /* Count remote accounts */
2288 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2289 tny_list_foreach (priv->store_accounts, (GFunc) count_remote_accounts, &count);
2295 init_send_queue (TnyAccount *account, gpointer user_data)
2297 modest_runtime_get_send_queue ((TnyTransportAccount *) account, TRUE);
2301 modest_tny_account_store_start_send_queues (ModestTnyAccountStore *self)
2303 ModestTnyAccountStorePrivate *priv;
2306 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self));
2308 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2310 /* We need to create a copy of the list because if the send
2311 queues are created they'll directly access to the TnyList
2312 of transport accounts, and thus we'll end up blocked in the
2313 mutex the TnyList uses to synchronize accesses */
2314 tmp = tny_list_copy (priv->transport_accounts);
2316 /* Just instantiate them. They'll begin to listen for
2317 connection changes to send messages ASAP */
2318 tny_list_foreach (tmp, (GFunc) init_send_queue, NULL);
2319 g_object_unref (tmp);
2324 modest_tny_account_store_check_disk_full_error (ModestTnyAccountStore *self,
2325 GtkWidget *parent_window,
2327 TnyAccount *account,
2328 const gchar *alternate)
2333 if (modest_tny_account_store_is_disk_full_error (self, err, account)) {
2334 gboolean is_mcc = modest_tny_account_is_memory_card_account (account);
2335 if (is_mcc && alternate) {
2336 modest_platform_information_banner (parent_window, NULL, alternate);
2338 gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2339 modest_platform_information_banner (parent_window, NULL, msg);
2342 } else if (err->code == TNY_SYSTEM_ERROR_MEMORY)
2343 /* If the account was created in memory full
2344 conditions then tinymail won't be able to
2345 connect so it'll return this error code */
2346 modest_platform_information_banner (parent_window,
2347 NULL, _("emev_ui_imap_inbox_select_error"));
2355 modest_tny_account_store_is_disk_full_error (ModestTnyAccountStore *self,
2357 TnyAccount *account)
2359 gboolean enough_free_space = TRUE;
2360 GnomeVFSURI *cache_dir_uri;
2361 const gchar *cache_dir = NULL;
2362 GnomeVFSFileSize free_space;
2364 /* Cache dir is different in case we're using an external storage (like MMC account) */
2365 if (account && modest_tny_account_is_memory_card_account (account))
2366 cache_dir = g_getenv (MODEST_MMC1_VOLUMEPATH_ENV);
2368 /* Get the default local cache dir */
2370 cache_dir = tny_account_store_get_cache_dir ((TnyAccountStore *) self);
2372 cache_dir_uri = gnome_vfs_uri_new (cache_dir);
2373 if (cache_dir_uri) {
2374 if (gnome_vfs_get_volume_free_space (cache_dir_uri, &free_space) == GNOME_VFS_OK) {
2375 if (free_space < MODEST_TNY_ACCOUNT_STORE_MIN_FREE_SPACE)
2376 enough_free_space = FALSE;
2378 gnome_vfs_uri_unref (cache_dir_uri);
2381 if ((error->code == TNY_SYSTEM_ERROR_MEMORY ||
2382 /* When asking for a mail and no space left on device
2383 tinymail returns this error */
2384 error->code == TNY_SERVICE_ERROR_MESSAGE_NOT_AVAILABLE ||
2385 /* When the folder summary could not be read or
2387 error->code == TNY_IO_ERROR_WRITE ||
2388 error->code == TNY_IO_ERROR_READ) &&
2389 !enough_free_space) {