1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <tny-account.h>
34 #include <tny-account-store.h>
35 #include <tny-store-account.h>
36 #include <tny-error.h>
37 #include <tny-transport-account.h>
38 #include <tny-simple-list.h>
39 #include <tny-account-store.h>
40 #include <tny-camel-transport-account.h>
41 #include <tny-camel-imap-store-account.h>
42 #include <tny-camel-pop-store-account.h>
44 #include <modest-runtime.h>
45 #include <modest-marshal.h>
46 #include <modest-protocol-info.h>
47 #include <modest-local-folder-info.h>
48 #include <modest-tny-account.h>
49 #include <modest-tny-local-folders-account.h>
50 #include <modest-account-mgr.h>
51 #include <modest-account-mgr-helpers.h>
52 #include <widgets/modest-window-mgr.h>
53 #include <modest-account-settings-dialog.h>
54 #include <maemo/modest-maemo-utils.h>
57 #include "modest-tny-account-store.h"
58 #include "modest-tny-platform-factory.h"
59 #include <tny-gtk-lockable.h>
60 #include <camel/camel.h>
62 #ifdef MODEST_PLATFORM_MAEMO
63 #include <tny-maemo-conic-device.h>
64 #ifdef MODEST_HAVE_HILDON0_WIDGETS
65 #include <hildon-widgets/hildon-note.h>
66 #include <hildon-widgets/hildon-banner.h>
68 #include <hildon/hildon-note.h>
69 #include <hildon/hildon-banner.h>
73 #include <libgnomevfs/gnome-vfs-volume-monitor.h>
75 /* 'private'/'protected' functions */
76 static void modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass);
78 static void modest_tny_account_store_finalize (GObject *obj);
80 static void modest_tny_account_store_instance_init (ModestTnyAccountStore *obj);
82 static void modest_tny_account_store_init (gpointer g, gpointer iface_data);
84 static void modest_tny_account_store_base_init (gpointer g_class);
86 static void get_server_accounts (TnyAccountStore *self,
92 ACCOUNT_CHANGED_SIGNAL,
93 ACCOUNT_INSERTED_SIGNAL,
94 ACCOUNT_REMOVED_SIGNAL,
95 ACCOUNT_UPDATE_SIGNAL,
96 PASSWORD_REQUESTED_SIGNAL,
100 typedef struct _ModestTnyAccountStorePrivate ModestTnyAccountStorePrivate;
101 struct _ModestTnyAccountStorePrivate {
103 GHashTable *password_hash;
104 GHashTable *account_settings_dialog_hash;
105 ModestAccountMgr *account_mgr;
106 TnySessionCamel *session;
109 /* We cache the lists of accounts here.
110 * They are created in our get_accounts_func() implementation. */
111 GSList *store_accounts;
112 GSList *transport_accounts;
114 /* This is also contained in store_accounts,
115 * but we cached it temporarily separately,
116 * because we create this while creating the transport accounts,
117 * but return it when requesting the store accounts:
119 GSList *store_accounts_outboxes;
122 #define MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
123 MODEST_TYPE_TNY_ACCOUNT_STORE, \
124 ModestTnyAccountStorePrivate))
127 static GObjectClass *parent_class = NULL;
129 static guint signals[LAST_SIGNAL] = {0};
132 modest_tny_account_store_get_type (void)
134 static GType my_type = 0;
137 static const GTypeInfo my_info = {
138 sizeof(ModestTnyAccountStoreClass),
139 modest_tny_account_store_base_init, /* base init */
140 NULL, /* base finalize */
141 (GClassInitFunc) modest_tny_account_store_class_init,
142 NULL, /* class finalize */
143 NULL, /* class data */
144 sizeof(ModestTnyAccountStore),
146 (GInstanceInitFunc) modest_tny_account_store_instance_init,
150 static const GInterfaceInfo iface_info = {
151 (GInterfaceInitFunc) modest_tny_account_store_init,
152 NULL, /* interface_finalize */
153 NULL /* interface_data */
156 my_type = g_type_register_static (G_TYPE_OBJECT,
157 "ModestTnyAccountStore",
159 g_type_add_interface_static (my_type, TNY_TYPE_ACCOUNT_STORE,
167 modest_tny_account_store_base_init (gpointer g_class)
169 static gboolean tny_account_store_initialized = FALSE;
171 if (!tny_account_store_initialized) {
173 signals[ACCOUNT_CHANGED_SIGNAL] =
174 g_signal_new ("account_changed",
175 MODEST_TYPE_TNY_ACCOUNT_STORE,
177 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_changed),
179 g_cclosure_marshal_VOID__POINTER,
180 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
182 signals[ACCOUNT_INSERTED_SIGNAL] =
183 g_signal_new ("account_inserted",
184 MODEST_TYPE_TNY_ACCOUNT_STORE,
186 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_inserted),
188 g_cclosure_marshal_VOID__POINTER,
189 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
191 signals[ACCOUNT_REMOVED_SIGNAL] =
192 g_signal_new ("account_removed",
193 MODEST_TYPE_TNY_ACCOUNT_STORE,
195 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_removed),
197 g_cclosure_marshal_VOID__POINTER,
198 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
200 /* signals[TNY_ACCOUNT_STORE_CONNECTING_FINISHED] = */
201 /* g_signal_new ("connecting_finished", */
202 /* TNY_TYPE_ACCOUNT_STORE, */
203 /* G_SIGNAL_RUN_FIRST, */
204 /* G_STRUCT_OFFSET (TnyAccountStoreIface, connecting_finished), */
206 /* g_cclosure_marshal_VOID__VOID, */
207 /* G_TYPE_NONE, 0); */
209 signals[ACCOUNT_UPDATE_SIGNAL] =
210 g_signal_new ("account_update",
211 MODEST_TYPE_TNY_ACCOUNT_STORE,
213 G_STRUCT_OFFSET(ModestTnyAccountStoreClass, account_update),
215 g_cclosure_marshal_VOID__STRING,
216 G_TYPE_NONE, 1, G_TYPE_STRING);
218 signals[PASSWORD_REQUESTED_SIGNAL] =
219 g_signal_new ("password_requested",
220 MODEST_TYPE_TNY_ACCOUNT_STORE,
222 G_STRUCT_OFFSET(ModestTnyAccountStoreClass, password_requested),
224 modest_marshal_VOID__STRING_POINTER_POINTER_POINTER_POINTER,
225 G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER,
228 tny_account_store_initialized = TRUE;
234 modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass)
236 GObjectClass *gobject_class;
237 gobject_class = (GObjectClass*) klass;
239 parent_class = g_type_class_peek_parent (klass);
240 gobject_class->finalize = modest_tny_account_store_finalize;
242 g_type_class_add_private (gobject_class,
243 sizeof(ModestTnyAccountStorePrivate));
249 on_vfs_volume_mounted(GnomeVFSVolumeMonitor *volume_monitor,
250 GnomeVFSVolume *volume, gpointer user_data);
253 on_vfs_volume_unmounted(GnomeVFSVolumeMonitor *volume_monitor,
254 GnomeVFSVolume *volume, gpointer user_data);
257 modest_tny_account_store_instance_init (ModestTnyAccountStore *obj)
259 ModestTnyAccountStorePrivate *priv =
260 MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
262 priv->cache_dir = NULL;
263 priv->account_mgr = NULL;
264 priv->session = NULL;
267 /* An in-memory store of passwords,
268 * for passwords that are not remembered in the configuration,
269 * so they need to be asked for from the user once in each session:
271 priv->password_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
274 /* A hash-map of modest account names to dialog pointers,
275 * so we can avoid showing the account settings twice for the same modest account: */
276 priv->account_settings_dialog_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
279 /* Respond to volume mounts and unmounts, such
280 * as the insertion/removal of the memory card: */
281 GnomeVFSVolumeMonitor* monitor =
282 gnome_vfs_get_volume_monitor();
283 g_signal_connect (G_OBJECT(monitor), "volume-mounted",
284 G_CALLBACK(on_vfs_volume_mounted),
286 g_signal_connect (G_OBJECT(monitor), "volume-unmounted",
287 G_CALLBACK(on_vfs_volume_unmounted),
292 account_list_free (GSList *accounts)
294 GSList *cursor = accounts;
297 if (G_IS_OBJECT(cursor->data)) { /* check twice... */
298 const gchar *id = tny_account_get_id(TNY_ACCOUNT(cursor->data));
299 modest_runtime_verify_object_last_ref(cursor->data,id);
301 g_object_unref (G_OBJECT(cursor->data));
302 cursor = cursor->next;
304 g_slist_free (accounts);
309 /* disconnect the list of TnyAccounts */
311 account_list_disconnect (GSList *accounts)
313 GSList *cursor = accounts;
316 if (TNY_IS_CAMEL_ACCOUNT(cursor->data)) /* check twice... */
317 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(cursor->data), FALSE, NULL);
318 cursor = g_slist_next (cursor);
325 recreate_all_accounts (ModestTnyAccountStore *self)
327 /* printf ("DEBUG: %s\n", __FUNCTION__); */
329 ModestTnyAccountStorePrivate *priv =
330 MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
332 if (priv->store_accounts_outboxes) {
333 account_list_free (priv->store_accounts_outboxes);
334 priv->store_accounts_outboxes = NULL;
338 if (priv->store_accounts) {
339 account_list_free (priv->store_accounts);
340 priv->store_accounts = NULL;
343 get_server_accounts (TNY_ACCOUNT_STORE(self),
344 NULL, TNY_ACCOUNT_TYPE_STORE);
347 if (priv->transport_accounts) {
348 account_list_free (priv->transport_accounts);
349 priv->transport_accounts = NULL;
352 get_server_accounts (TNY_ACCOUNT_STORE(self), NULL,
353 TNY_ACCOUNT_TYPE_TRANSPORT);
357 on_vfs_volume_mounted(GnomeVFSVolumeMonitor *volume_monitor,
358 GnomeVFSVolume *volume, gpointer user_data)
360 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
362 /* Check whether this was the external MMC1 card: */
363 gchar *uri = gnome_vfs_volume_get_activation_uri (volume);
364 if (uri && (strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI) == 0)) {
365 printf ("DEBUG: %s: MMC1 card mounted.\n", __FUNCTION__);
367 /* TODO: Just add an account and emit (and respond to)
368 * TnyAccountStore::accountinserted signal?
370 recreate_all_accounts (self);
372 g_signal_emit (G_OBJECT(self), signals[ACCOUNT_UPDATE_SIGNAL], 0,
380 on_vfs_volume_unmounted(GnomeVFSVolumeMonitor *volume_monitor,
381 GnomeVFSVolume *volume, gpointer user_data)
383 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
385 /* Check whether this was the external MMC1 card: */
386 gchar *uri = gnome_vfs_volume_get_activation_uri (volume);
387 if (uri && (strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI) == 0)) {
388 printf ("DEBUG: %s: MMC1 card unmounted.\n", __FUNCTION__);
390 /* TODO: Just add an account and emit (and respond to)
391 * TnyAccountStore::accountinserted signal?
393 recreate_all_accounts (self);
395 g_signal_emit (G_OBJECT(self), signals[ACCOUNT_UPDATE_SIGNAL], 0,
403 on_account_removed (ModestAccountMgr *acc_mgr,
404 const gchar *account,
407 TnyAccount *store_account = NULL, *transport_account = NULL;
408 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
410 /* Get the server and the transport account */
412 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_STORE);
414 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
416 /* Clear the cache */
417 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (store_account));
419 /* Notify the observers */
420 g_signal_emit (G_OBJECT (self),
421 signals [ACCOUNT_REMOVED_SIGNAL],
423 g_signal_emit (G_OBJECT (self),
424 signals [ACCOUNT_REMOVED_SIGNAL],
425 0, transport_account);
428 g_object_unref (store_account);
429 g_object_unref (transport_account);
433 * modest_tny_account_store_forget_password_in_memory
434 * @self: a TnyAccountStore instance
435 * @account: A server account.
437 * Forget any password stored in memory for this account.
438 * For instance, this should be called when the user has changed the password in the account settings.
441 modest_tny_account_store_forget_password_in_memory (ModestTnyAccountStore *self, const gchar * server_account_name)
443 /* printf ("DEBUG: %s\n", __FUNCTION__); */
444 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
446 if (server_account_name && priv->password_hash) {
447 g_hash_table_remove (priv->password_hash, server_account_name);
452 on_account_changed (ModestAccountMgr *acc_mgr, const gchar *account,
453 const GSList *keys, gboolean server_account, gpointer user_data)
456 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
459 printf ("DEBUG: %s\n", __FUNCTION__);
460 const GSList *iter = keys;
461 for (iter = keys; iter; iter = g_slist_next (iter)) {
462 printf (" DEBUG: %s: key=%s\n", __FUNCTION__, (const gchar*)iter->data);
466 /* Ignore the change if it's a change in the last_updated value */
467 if (g_slist_length ((GSList *)keys) == 1 &&
468 g_str_has_suffix ((const gchar *) keys->data, MODEST_ACCOUNT_LAST_UPDATED)) {
472 /* FIXME: make this more finegrained; changes do not really affect _all_
475 recreate_all_accounts (self);
477 /* TODO: This doesn't actually work, because
478 * a) The account name is not sent correctly per key:
479 * b) We should test the end of the key, not the whole keym
480 * c) We don't seem to be getting all keys here.
481 * Instead, we just forget the password for all accounts when we create them, for now.
484 /* If a password has changed, then forget the previously cached password for this account: */
485 if (server_account && keys && g_slist_find_custom ((GSList *)keys, MODEST_ACCOUNT_PASSWORD, (GCompareFunc)strcmp)) {
486 printf ("DEBUG: %s: Forgetting cached password for account ID=%s\n", __FUNCTION__, account);
487 modest_tny_account_store_forget_password_in_memory (self, account);
491 g_signal_emit (G_OBJECT(self), signals[ACCOUNT_UPDATE_SIGNAL], 0,
496 static ModestTnyAccountStore*
497 get_account_store_for_account (TnyAccount *account)
499 return MODEST_TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
504 void on_account_settings_hide (GtkWidget *widget, gpointer user_data)
506 TnyAccount *account = (TnyAccount*)user_data;
508 /* This is easier than using a struct for the user_data: */
509 ModestTnyAccountStore *self = modest_runtime_get_account_store();
510 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
512 const gchar *modest_account_name =
513 modest_tny_account_get_parent_modest_account_name_for_server_account (account);
514 if (modest_account_name)
515 g_hash_table_remove (priv->account_settings_dialog_hash, modest_account_name);
519 gboolean on_idle_wrong_password_warning_only (gpointer user_data)
523 ModestWindow *main_window =
524 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ());
526 /* Show an explanatory temporary banner: */
527 hildon_banner_show_information (
528 GTK_WIDGET(main_window), NULL, _("mcen_ib_username_pw_incorrect"));
532 return FALSE; /* Don't show again. */
536 gboolean on_idle_wrong_password (gpointer user_data)
538 TnyAccount *account = (TnyAccount*)user_data;
539 /* This is easier than using a struct for the user_data: */
540 ModestTnyAccountStore *self = modest_runtime_get_account_store();
541 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
543 const gchar *modest_account_name =
544 modest_tny_account_get_parent_modest_account_name_for_server_account (account);
545 if (!modest_account_name) {
546 g_warning ("%s: modest_tny_account_get_parent_modest_account_name_for_server_account() failed.\n",
549 g_object_unref (account);
554 /* Check whether this window is already open,
555 * for instance because of a previous get_password() call:
557 gpointer dialog_as_gpointer = NULL;
558 gboolean found = FALSE;
559 if (priv->account_settings_dialog_hash) {
560 found = g_hash_table_lookup_extended (priv->account_settings_dialog_hash,
561 modest_account_name, NULL, (gpointer*)&dialog_as_gpointer);
563 ModestAccountSettingsDialog *dialog = dialog_as_gpointer;
565 ModestWindow *main_window =
566 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ());
568 gdk_threads_enter ();
569 gboolean created_dialog = FALSE;
570 if (!found || !dialog) {
571 dialog = modest_account_settings_dialog_new ();
572 modest_account_settings_dialog_set_account_name (dialog, modest_account_name);
573 modest_account_settings_dialog_switch_to_user_info (dialog);
575 g_hash_table_insert (priv->account_settings_dialog_hash, g_strdup (modest_account_name), dialog);
577 created_dialog = TRUE;
580 /* Show an explanatory temporary banner: */
581 hildon_banner_show_information (
582 GTK_WIDGET(dialog), NULL, _("mcen_ib_username_pw_incorrect"));
584 if (created_dialog) {
585 /* Forget it when it closes: */
586 g_signal_connect_object (G_OBJECT (dialog), "hide", G_CALLBACK (on_account_settings_hide),
589 /* Show it and delete it when it closes: */
590 modest_maemo_show_dialog_and_forget (GTK_WINDOW (main_window), GTK_DIALOG (dialog));
593 /* Just show it instead of showing it and deleting it when it closes,
594 * though it is probably open already: */
595 gtk_window_present (GTK_WINDOW (dialog));
598 g_object_unref (account);
599 gdk_threads_leave ();
601 return FALSE; /* Dont' call this again. */
607 ModestTnyAccountStore* account_store;
608 const gchar* server_account_id;
613 } IdlePasswordRequest;
616 on_idle_request_password (gpointer user_data)
620 IdlePasswordRequest* info = (IdlePasswordRequest*)user_data;
621 g_signal_emit (G_OBJECT(info->account_store), signals[PASSWORD_REQUESTED_SIGNAL], 0,
622 info->server_account_id, /* server_account_name */
623 info->username, info->password, info->cancel, info->remember);
626 g_main_loop_quit (info->loop);
630 return FALSE; /* Don't call again. */
634 request_password_in_main_loop_and_wait (ModestTnyAccountStore *account_store,
635 const gchar* server_account_id,
641 IdlePasswordRequest *data = g_slice_new0 (IdlePasswordRequest);
642 data->account_store = account_store;
643 data->server_account_id = server_account_id;
644 data->username = username;
645 data->password = password;
646 data->cancel = cancel;
647 data->remember = remember;
649 data->loop = g_main_loop_new (NULL, FALSE /* not running */);
651 /* Cause the function to be run in an idle-handler, which is always
652 * in the main thread:
654 g_idle_add (&on_idle_request_password, data);
656 /* This main loop will run until the idle handler has stopped it: */
657 printf ("DEBUG: %s: before g_main_loop_run()\n", __FUNCTION__);
659 g_main_loop_run (data->loop);
661 printf ("DEBUG: %s: after g_main_loop_run()\n", __FUNCTION__);
662 printf ("DEBUG: %s: Finished\n", __FUNCTION__);
663 g_main_loop_unref (data->loop);
665 g_slice_free (IdlePasswordRequest, data);
668 /* This callback will be called by Tinymail when it needs the password
669 * from the user or the account settings.
670 * It can also call forget_password() before calling this,
671 * so that we clear wrong passwords out of our account settings.
672 * Note that TnyAccount here will be the server account. */
674 get_password (TnyAccount *account, const gchar * prompt_not_used, gboolean *cancel)
676 /* TODO: Settting cancel to FALSE does not actually cancel everything.
677 * We still get multiple requests afterwards, so we end up showing the
678 * same dialogs repeatedly.
681 printf ("DEBUG: modest: %s: prompt (not shown) = %s\n", __FUNCTION__, prompt_not_used);
683 g_return_val_if_fail (account, NULL);
685 const TnyAccountStore *account_store = NULL;
686 ModestTnyAccountStore *self = NULL;
687 ModestTnyAccountStorePrivate *priv;
688 gchar *username = NULL;
690 gpointer pwd_ptr = NULL;
691 gboolean already_asked = FALSE;
693 /* Initialize the output parameter: */
697 const gchar *server_account_name = tny_account_get_id (account);
698 account_store = TNY_ACCOUNT_STORE(get_account_store_for_account (account));
700 if (!server_account_name || !account_store) {
701 g_warning ("modest: %s: could not retrieve account_store for account %s",
702 __FUNCTION__, server_account_name ? server_account_name : "<NULL>");
709 self = MODEST_TNY_ACCOUNT_STORE (account_store);
710 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
712 /* This hash map stores passwords, including passwords that are not stored in gconf. */
713 /* Is it in the hash? if it's already there, it must be wrong... */
714 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
715 * type-punned ptrs...*/
716 already_asked = priv->password_hash &&
717 g_hash_table_lookup_extended (priv->password_hash,
720 (gpointer*)&pwd_ptr);
722 printf ("DEBUG: modest: %s: Already asked = %d\n", __FUNCTION__, already_asked);
724 /* If the password is not already there, try ModestConf */
725 if (!already_asked) {
726 pwd = modest_server_account_get_password (priv->account_mgr,
727 server_account_name);
728 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup (pwd));
731 /* If it was already asked, it must have been wrong, so ask again */
732 if (already_asked || !pwd || strlen(pwd) == 0) {
733 /* As per the UI spec, if no password was set in the account settings,
734 * ask for it now. But if the password is wrong in the account settings,
735 * then show a banner and the account settings dialog so it can be corrected:
737 const gboolean settings_have_password =
738 modest_server_account_get_has_password (priv->account_mgr, server_account_name);
739 printf ("DEBUG: modest: %s: settings_have_password=%d\n", __FUNCTION__, settings_have_password);
740 if (settings_have_password) {
743 /* The password must be wrong, so show the account settings dialog so it can be corrected: */
744 /* We show it in the main loop, because this function might not be in the main loop. */
745 g_object_ref (account); /* unrefed in the idle handler. */
746 g_idle_add (on_idle_wrong_password, account);
754 /* we don't have it yet. Get the password from the user */
755 const gchar* account_id = tny_account_get_id (account);
756 gboolean remember = FALSE;
760 /* Show an info banner, before we show the protected password dialog: */
761 g_idle_add (on_idle_wrong_password_warning_only, NULL);
764 request_password_in_main_loop_and_wait (self, account_id,
765 &username, &pwd, cancel, &remember);
768 /* The password will be returned as the result,
769 * but we need to tell tinymail about the username too: */
770 tny_account_set_user (account, username);
772 /* Do not save the password in gconf,
773 * because the UI spec says "The password will never be saved in the account": */
776 printf ("%s: Storing username=%s, password=%s\n",
777 __FUNCTION__, username, pwd);
778 modest_server_account_set_username (priv->account_mgr, server_account_name,
780 modest_server_account_set_password (priv->account_mgr, server_account_name,
785 /* We need to dup the string even knowing that
786 it's already a dup of the contents of an
787 entry, because it if it's wrong, then camel
789 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup(pwd));
791 g_hash_table_remove (priv->password_hash, server_account_name);
802 /* printf(" DEBUG: %s: returning %s\n", __FUNCTION__, pwd); */
807 /* tinymail calls this if the connection failed due to an incorrect password.
808 * And it seems to call this for any general connection failure. */
810 forget_password (TnyAccount *account)
812 printf ("DEBUG: %s\n", __FUNCTION__);
813 ModestTnyAccountStore *self;
814 ModestTnyAccountStorePrivate *priv;
815 const TnyAccountStore *account_store;
819 account_store = TNY_ACCOUNT_STORE(get_account_store_for_account (account));
820 self = MODEST_TNY_ACCOUNT_STORE (account_store);
821 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
822 key = tny_account_get_id (account);
824 /* Do not remove the key, this will allow us to detect that we
825 have already asked for it at least once */
826 pwd = g_hash_table_lookup (priv->password_hash, key);
828 memset (pwd, 0, strlen (pwd));
829 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
832 /* Remove from configuration system */
834 modest_account_mgr_unset (priv->account_mgr,
835 key, MODEST_ACCOUNT_PASSWORD, TRUE);
840 destroy_password_hashtable (ModestTnyAccountStore *self)
842 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
844 g_free (priv->cache_dir);
845 priv->cache_dir = NULL;
847 if (priv->password_hash) {
848 g_hash_table_destroy (priv->password_hash);
849 priv->password_hash = NULL;
854 modest_tny_account_store_finalize (GObject *obj)
856 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(obj);
857 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
859 //gboolean debug = modest_runtime_get_debug_flags() & MODEST_RUNTIME_DEBUG_DEBUG_OBJECTS;
861 g_free (priv->cache_dir);
862 priv->cache_dir = NULL;
864 if (priv->password_hash) {
865 g_hash_table_destroy (priv->password_hash);
866 priv->password_hash = NULL;
869 destroy_password_hashtable (self);
871 if (priv->account_mgr) {
872 g_object_unref (G_OBJECT(priv->account_mgr));
873 priv->account_mgr = NULL;
877 g_object_unref (G_OBJECT(priv->device));
881 /* disconnect all accounts when we are destroyed */
882 g_debug ("modest: disconnecting all store accounts");
883 account_list_disconnect (priv->store_accounts);
884 g_debug ("modest: disconnecting all transport accounts");
885 account_list_disconnect (priv->transport_accounts);
887 /* this includes the local folder */
888 account_list_free (priv->store_accounts);
889 priv->store_accounts = NULL;
891 account_list_free (priv->transport_accounts);
892 priv->transport_accounts = NULL;
895 camel_object_unref (CAMEL_OBJECT(priv->session));
896 priv->session = NULL;
899 G_OBJECT_CLASS(parent_class)->finalize (obj);
903 ModestTnyAccountStore*
904 modest_tny_account_store_new (ModestAccountMgr *account_mgr, TnyDevice *device) {
907 ModestTnyAccountStorePrivate *priv;
910 g_return_val_if_fail (account_mgr, NULL);
911 g_return_val_if_fail (device, NULL);
913 obj = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
914 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
916 priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
917 priv->device = g_object_ref (device);
919 priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
920 if (!priv->session) {
921 g_warning ("failed to get TnySessionCamel");
925 tny_session_camel_set_ui_locker (priv->session, tny_gtk_lockable_new ());
926 /* tny_session_camel_set_async_connecting (priv->session, TRUE); */
928 /* Connect signals */
929 g_signal_connect (G_OBJECT(account_mgr), "account_changed",
930 G_CALLBACK (on_account_changed), obj);
931 g_signal_connect (G_OBJECT(account_mgr), "account_removed",
932 G_CALLBACK (on_account_removed), obj);
934 return MODEST_TNY_ACCOUNT_STORE(obj);
937 /** Fill the TnyList from the appropriate cached GSList of accounts. */
939 get_cached_accounts (TnyAccountStore *self, TnyList *list, TnyAccountType type)
941 ModestTnyAccountStorePrivate *priv;
942 GSList *accounts, *cursor;
944 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
945 accounts = (type == TNY_ACCOUNT_TYPE_STORE ? priv->store_accounts : priv->transport_accounts);
950 GObject *object = G_OBJECT(cursor->data);
951 tny_list_prepend (list, object);
954 cursor = cursor->next;
959 create_per_account_local_outbox_folders (TnyAccountStore *self)
961 g_return_if_fail (self);
963 ModestTnyAccountStorePrivate *priv =
964 MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
966 /* printf("DEBUG: %s: priv->store_accounts_outboxes = %p\n", __FUNCTION__, priv->store_accounts_outboxes); */
968 GSList *accounts = NULL;
970 GSList *account_names = modest_account_mgr_account_names (priv->account_mgr,
971 TRUE /* including disabled accounts */);
974 for (iter = account_names; iter; iter = g_slist_next (iter)) {
976 const gchar* account_name = (const gchar*)iter->data;
978 /* Create a per-account local outbox folder (a _store_ account)
979 * for each _transport_ account: */
980 TnyAccount *tny_account_outbox =
981 modest_tny_account_new_for_per_account_local_outbox_folder (
982 priv->account_mgr, account_name, priv->session);
984 accounts = g_slist_append (accounts, tny_account_outbox); /* cache it */
987 modest_account_mgr_free_account_names (account_names);
988 account_names = NULL;
990 priv->store_accounts_outboxes = accounts;
993 /* This function fills the TnyList, and also stores a GSList of the accounts,
994 * for caching purposes. It creates the TnyAccount objects if necessary.
995 * The @list parameter may be NULL, if you just want to fill the cache.
998 get_server_accounts (TnyAccountStore *self, TnyList *list, TnyAccountType type)
1000 g_return_if_fail (self);
1002 ModestTnyAccountStorePrivate *priv =
1003 MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1005 /* Do nothing if the accounts are already cached: */
1006 if (type == TNY_ACCOUNT_TYPE_STORE) {
1007 if (priv->store_accounts)
1009 } else if (type == TNY_ACCOUNT_TYPE_TRANSPORT) {
1010 if (priv->transport_accounts)
1014 GSList *account_names = NULL, *cursor = NULL;
1015 GSList *accounts = NULL;
1017 /* These are account names, not server_account names */
1018 account_names = modest_account_mgr_account_names (priv->account_mgr,FALSE);
1020 for (cursor = account_names; cursor; cursor = cursor->next) {
1022 gchar *account_name = (gchar*)cursor->data;
1024 /* we get the server_accounts for enabled accounts */
1025 if (modest_account_mgr_get_enabled(priv->account_mgr, account_name)) {
1027 /* Add the account: */
1028 TnyAccount *tny_account =
1029 modest_tny_account_new_from_account (priv->account_mgr,
1031 type, priv->session,
1035 /* Forget any cached password for the account,
1036 * so that we use a new account if any.
1037 * TODO: Really we should do this in a more precise way in
1038 * on_account_changed().
1040 modest_tny_account_store_forget_password_in_memory (
1041 MODEST_TNY_ACCOUNT_STORE (self),
1042 tny_account_get_id (tny_account));
1044 g_object_set_data (G_OBJECT(tny_account), "account_store",
1047 tny_list_prepend (list, G_OBJECT(tny_account));
1049 accounts = g_slist_append (accounts, tny_account); /* cache it */
1051 g_printerr ("modest: failed to create account for %s\n",
1056 if (type == TNY_ACCOUNT_TYPE_STORE) {
1057 /* Also add the Memory card account if it is mounted: */
1058 gboolean mmc_is_mounted = FALSE;
1059 GnomeVFSVolumeMonitor* monitor =
1060 gnome_vfs_get_volume_monitor();
1061 GList* list_volumes = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
1062 GList *iter = list_volumes;
1064 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
1066 if (!mmc_is_mounted) {
1067 gchar *uri = gnome_vfs_volume_get_activation_uri (volume);
1068 if (uri && (strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI) == 0)) {
1069 mmc_is_mounted = TRUE;
1074 gnome_vfs_volume_unref(volume);
1077 iter = g_list_next (iter);
1079 g_list_free (list_volumes);
1081 if (mmc_is_mounted) {
1082 TnyAccount *tny_account =
1083 modest_tny_account_new_for_local_folders (priv->account_mgr,
1084 priv->session, MODEST_MCC1_VOLUMEPATH);
1086 tny_list_prepend (list, G_OBJECT(tny_account));
1087 accounts = g_slist_append (accounts, tny_account); /* cache it */
1091 /* And add the connection-specific transport accounts, if any.
1092 * Note that these server account instances might never be used
1093 * if their connections are never active: */
1094 /* Look at each modest account: */
1095 if (type == TNY_ACCOUNT_TYPE_TRANSPORT) {
1096 GSList *iter_account_names = account_names;
1097 while (iter_account_names) {
1098 const gchar* account_name = (const gchar*)(iter_account_names->data);
1099 GSList *list_specifics = modest_account_mgr_get_list (priv->account_mgr,
1101 MODEST_ACCOUNT_CONNECTION_SPECIFIC_SMTP_LIST,
1102 MODEST_CONF_VALUE_STRING, FALSE);
1104 /* Look at each connection-specific transport account for the
1105 * modest account: */
1106 GSList *iter = list_specifics;
1108 /* The list alternates between the connection name and the transport name: */
1109 /* const gchar* this_connection_name = (const gchar*)(iter->data); */
1110 iter = g_slist_next (iter);
1112 const gchar* transport_account_name = (const gchar*)(iter->data);
1113 if (transport_account_name) {
1114 TnyAccount * tny_account = NULL;
1115 /* Add the account: */
1116 tny_account = modest_tny_account_new_from_server_account_name (
1117 priv->account_mgr, priv->session, transport_account_name);
1119 modest_tny_account_set_parent_modest_account_name_for_server_account (tny_account, account_name);
1120 g_object_set_data (G_OBJECT(tny_account), "account_store",
1123 tny_list_prepend (list, G_OBJECT(tny_account));
1125 accounts = g_slist_append (accounts, tny_account); /* cache it */
1127 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1128 transport_account_name);
1132 iter = g_slist_next (iter);
1135 iter_account_names = g_slist_next (iter_account_names);
1139 /* free the account_names */
1140 modest_account_mgr_free_account_names (account_names);
1141 account_names = NULL;
1143 /* We also create a per-account local outbox folder (a _store_ account)
1144 * for each _transport_ account. */
1145 if (type == TNY_ACCOUNT_TYPE_TRANSPORT) {
1146 /* Now would be a good time to create the per-account local outbox folder
1147 * _store_ accounts corresponding to each transport account: */
1148 if (!priv->store_accounts_outboxes) {
1149 create_per_account_local_outbox_folders (self);
1153 /* But we only return the per-account local outbox folder when
1154 * _store_ accounts are requested. */
1155 if (type == TNY_ACCOUNT_TYPE_STORE) {
1156 /* Create them if necessary,
1157 * (which also requires creating the transport accounts,
1159 if (!priv->store_accounts_outboxes) {
1160 create_per_account_local_outbox_folders (self);
1163 /* Also add the local folder pseudo-account: */
1164 TnyAccount *tny_account =
1165 modest_tny_account_new_for_local_folders (priv->account_mgr,
1166 priv->session, NULL);
1168 /* Add them to the TnyList: */
1169 if (priv->store_accounts_outboxes) {
1170 GSList *iter = NULL;
1171 for (iter = priv->store_accounts_outboxes; iter; iter = g_slist_next (iter)) {
1172 TnyAccount *outbox_account = (TnyAccount*)iter->data;
1173 if (list && outbox_account)
1174 tny_list_prepend (list, G_OBJECT(outbox_account));
1176 g_object_ref (outbox_account);
1177 accounts = g_slist_append (accounts, outbox_account);
1181 /* Add a merged folder, merging all the per-account outbox folders: */
1182 modest_tny_local_folders_account_add_merged_outbox_folders (
1183 MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (tny_account), priv->store_accounts_outboxes);
1185 if (priv->store_accounts_outboxes) {
1186 /* We have finished with this temporary list, so free it: */
1187 account_list_free (priv->store_accounts_outboxes);
1188 priv->store_accounts_outboxes = NULL;
1192 tny_list_prepend (list, G_OBJECT(tny_account));
1193 accounts = g_slist_append (accounts, tny_account); /* cache it */
1196 if (type == TNY_ACCOUNT_TYPE_STORE) {
1197 /* Store the cache: */
1198 priv->store_accounts = accounts;
1199 } else if (type == TNY_ACCOUNT_TYPE_TRANSPORT) {
1200 /* Store the cache: */
1201 priv->transport_accounts = accounts;
1207 modest_tny_account_store_get_accounts (TnyAccountStore *self, TnyList *list,
1208 TnyGetAccountsRequestType request_type)
1210 ModestTnyAccountStorePrivate *priv;
1212 g_return_if_fail (self);
1213 g_return_if_fail (TNY_IS_LIST(list));
1215 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1217 if (request_type == TNY_ACCOUNT_STORE_BOTH) {
1218 modest_tny_account_store_get_accounts (self, list,
1219 TNY_ACCOUNT_STORE_STORE_ACCOUNTS);
1220 modest_tny_account_store_get_accounts (self, list,
1221 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
1223 tny_session_camel_set_initialized (priv->session);
1228 if (request_type == TNY_ACCOUNT_STORE_STORE_ACCOUNTS) {
1229 if (!priv->store_accounts)
1230 get_server_accounts (self, list, TNY_ACCOUNT_TYPE_STORE);
1232 get_cached_accounts (self, list, TNY_ACCOUNT_TYPE_STORE);
1234 tny_session_camel_set_initialized (priv->session);
1236 } else if (request_type == TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS) {
1237 if (!priv->transport_accounts)
1238 get_server_accounts (self, list, TNY_ACCOUNT_TYPE_TRANSPORT);
1240 get_cached_accounts (self, list, TNY_ACCOUNT_TYPE_TRANSPORT);
1242 tny_session_camel_set_initialized (priv->session);
1244 g_return_if_reached (); /* incorrect req type */
1249 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1251 ModestTnyAccountStorePrivate *priv;
1252 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1254 if (!priv->cache_dir)
1255 priv->cache_dir = g_build_filename (g_get_home_dir(),
1256 MODEST_DIR, MODEST_CACHE_DIR, NULL);
1257 return priv->cache_dir;
1262 * callers need to unref
1265 modest_tny_account_store_get_device (TnyAccountStore *self)
1267 ModestTnyAccountStorePrivate *priv;
1269 g_return_val_if_fail (self, NULL);
1271 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1274 return g_object_ref (G_OBJECT(priv->device));
1281 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1283 return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self),
1284 MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1291 modest_tny_account_store_alert (TnyAccountStore *self, TnyAccount *account, TnyAlertType type,
1292 gboolean question, const GError *error)
1294 g_return_val_if_fail (error, FALSE);
1296 if ((error->domain != TNY_ACCOUNT_ERROR)
1297 && (error->domain != TNY_ACCOUNT_STORE_ERROR)) {
1298 g_warning("modest: %s: Unexpected error domain: != TNY_ACCOUNT_ERROR: %d, message=%s",
1299 __FUNCTION__, error->domain, error->message);
1304 printf("DEBUG: %s: GError code: %d, message=%s\n",
1305 __FUNCTION__, error->code, error->message);
1307 /* Get the server name: */
1308 const gchar* server_name = NULL;
1309 if (account && TNY_IS_ACCOUNT (account)) {
1310 server_name = tny_account_get_hostname (account);
1311 printf ("modest: %s: account name = %s, server_name=%s\n", __FUNCTION__,
1312 tny_account_get_id (account), server_name);
1316 server_name = _("Unknown Server");
1318 ModestTransportStoreProtocol proto = MODEST_PROTOCOL_STORE_POP; /* Arbitrary default. */
1320 const gchar *proto_name = tny_account_get_proto (account);
1322 proto = modest_protocol_info_get_transport_store_protocol (proto_name);
1324 g_warning("modest: %s: account with id=%s has no proto.\n", __FUNCTION__,
1325 tny_account_get_id (account));
1329 /* const gchar *prompt = NULL; */
1330 gchar *prompt = NULL;
1331 switch (error->code) {
1332 case TNY_ACCOUNT_STORE_ERROR_CANCEL_ALERT:
1333 case TNY_ACCOUNT_ERROR_TRY_CONNECT_USER_CANCEL:
1334 /* Don't show waste the user's time by showing him a dialog telling
1335 * him that he has just cancelled something: */
1336 g_debug ("%s: Handling GError domain=%d, code=%d (cancelled) without showing a dialog, message=%s",
1337 __FUNCTION__, error->domain, error->code, error->message);
1341 case TNY_ACCOUNT_ERROR_TRY_CONNECT_HOST_LOOKUP_FAILED:
1342 /* TODO: Show the appropriate message, depending on whether it's POP or IMAP: */
1343 g_debug ("%s: Handling GError domain=%d, code=%d (lookup failed), message=%s",
1344 __FUNCTION__, error->domain, error->code, error->message);
1347 case MODEST_PROTOCOL_STORE_POP:
1348 prompt = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"), server_name);
1350 case MODEST_PROTOCOL_STORE_IMAP:
1351 prompt = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"), server_name);
1353 case MODEST_PROTOCOL_TRANSPORT_SMTP:
1354 default: /* Arbitrary default. */
1355 prompt = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"), server_name);
1360 prompt = g_strdup_printf(
1361 _("Incorrect Account Settings:\n Host lookup failed.%s"),
1366 case TNY_ACCOUNT_ERROR_TRY_CONNECT_AUTHENTICATION_NOT_SUPPORTED:
1367 g_debug ("%s: Handling GError domain=%d, code=%d (authentication not supported), message=%s",
1368 __FUNCTION__, error->domain, error->code, error->message);
1369 /* TODO: This needs a logical ID for the string: */
1370 prompt = g_strdup_printf(
1371 _("Incorrect Account Settings:\nThe secure authentication method is not supported.\n%s"),
1375 case TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE:
1376 g_debug ("%s: Handling GError domain=%d, code=%d (certificatae), message=%s",
1377 __FUNCTION__, error->domain, error->code, error->message);
1378 prompt = g_strdup_printf(
1379 _("Certificate Problem:\n%s"),
1383 case TNY_ACCOUNT_ERROR_TRY_CONNECT:
1384 /* The tinymail camel implementation just sends us this for almost
1385 * everything, so we have to guess at the cause.
1386 * It could be a wrong password, or inability to resolve a hostname,
1387 * or lack of network, or incorrect authentication method, or something entirely different: */
1388 /* TODO: Fix camel to provide specific error codes, and then use the
1389 * specific dialog messages from Chapter 12 of the UI spec.
1391 case TNY_ACCOUNT_STORE_ERROR_UNKNOWN_ALERT:
1392 /* This debug output is useful. Please keep it uncommented until
1393 * we have fixed the problems in this function: */
1394 g_debug ("%s: Handling GError domain=%d, code=%d, message=%s",
1395 __FUNCTION__, error->domain, error->code, error->message);
1397 /* TODO: Remove the internal error message for the real release.
1398 * This is just so the testers can give us more information: */
1399 /* prompt = _("Modest account not yet fully configured."); */
1400 prompt = g_strdup_printf(
1401 "%s\n (Internal error message, often very misleading):\n%s",
1402 _("Incorrect Account Settings"),
1405 /* Note: If the password was wrong then get_password() would be called again,
1406 * instead of this vfunc being called. */
1411 g_warning ("%s: Unhandled GError code: %d, message=%s",
1412 __FUNCTION__, error->code, error->message);
1420 ModestWindow *main_window =
1421 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ());
1422 gboolean retval = TRUE;
1424 /* The Tinymail documentation says that we should show Yes and No buttons,
1425 * when it is a question.
1426 * Obviously, we need tinymail to use more specific error codes instead,
1427 * so we know what buttons to show. */
1429 /* TODO: Do this in the main context: */
1430 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_window),
1432 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1434 retval = (response == GTK_RESPONSE_YES) ||
1435 (response == GTK_RESPONSE_OK);
1438 gtk_widget_destroy (dialog);
1441 /* Just show the error text and use the default response: */
1442 modest_maemo_show_information_note_in_main_context_and_forget (GTK_WINDOW (main_window),
1446 /* TODO: Don't free this when we no longer strdup the message for testers. */
1450 /* printf("DEBUG: %s: returning %d\n", __FUNCTION__, retval); */
1456 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1458 TnyAccountStoreIface *klass;
1460 g_return_if_fail (g);
1462 klass = (TnyAccountStoreIface *)g;
1464 klass->get_accounts_func =
1465 modest_tny_account_store_get_accounts;
1466 klass->get_cache_dir_func =
1467 modest_tny_account_store_get_cache_dir;
1468 klass->get_device_func =
1469 modest_tny_account_store_get_device;
1471 modest_tny_account_store_alert;
1472 klass->find_account_func =
1473 modest_tny_account_store_find_account_by_url;
1477 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1478 ModestTnyGetPassFunc func)
1480 /* not implemented, we use signals */
1481 g_printerr ("modest: set_get_pass_func not implemented\n");
1485 modest_tny_account_store_get_session (TnyAccountStore *self)
1487 g_return_val_if_fail (self, NULL);
1488 return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1494 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self,
1495 ModestTnyAccountStoreQueryType type,
1498 TnyAccount *account = NULL;
1499 ModestTnyAccountStorePrivate *priv;
1501 const gchar *val = NULL;
1505 g_return_val_if_fail (self, NULL);
1506 g_return_val_if_fail (str, NULL);
1508 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1510 /* fill the caches, as that may not have happened yet */
1511 list = TNY_LIST(tny_simple_list_new());
1512 modest_tny_account_store_get_accounts (TNY_ACCOUNT_STORE(self),
1513 list, TNY_ACCOUNT_STORE_BOTH);
1514 g_object_unref (list);
1518 /* Search in store accounts */
1519 for (cursor = priv->store_accounts; cursor ; cursor = cursor->next) {
1521 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1522 val = tny_account_get_id (TNY_ACCOUNT(cursor->data));
1524 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1525 val = tny_account_get_url_string (TNY_ACCOUNT(cursor->data));
1529 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL &&
1530 tny_account_matches_url_string (TNY_ACCOUNT(cursor->data), str)) {
1531 account = TNY_ACCOUNT (cursor->data);
1534 if (strcmp (val, str) == 0) {
1535 account = TNY_ACCOUNT(cursor->data);
1541 /* if we already found something, no need to search the transport accounts */
1542 for (cursor = priv->transport_accounts; !account && cursor ; cursor = cursor->next) {
1544 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1545 val = tny_account_get_id (TNY_ACCOUNT(cursor->data));
1547 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1548 val = tny_account_get_url_string (TNY_ACCOUNT(cursor->data));
1552 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL &&
1553 tny_account_matches_url_string (TNY_ACCOUNT(cursor->data), val)) {
1554 account = TNY_ACCOUNT (cursor->data);
1557 if (strcmp (val, str) == 0) {
1558 account = TNY_ACCOUNT(cursor->data);
1565 g_object_ref (G_OBJECT(account));
1567 /* Warn if nothing was found. This is generally unusual. */
1569 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1570 g_warning("%s: Failed to find account with ID=%s\n", __FUNCTION__, str);
1572 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1573 g_warning("%s: Failed to find account with URL=%s\n", __FUNCTION__, str);
1582 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1583 const gchar *account_name,
1584 TnyAccountType type)
1586 ModestTnyAccountStorePrivate *priv = NULL;
1587 TnyAccount *account = NULL;
1588 GSList *account_list = NULL;
1589 gboolean found = FALSE;
1591 g_return_val_if_fail (self, NULL);
1592 g_return_val_if_fail (account_name, NULL);
1593 g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE ||
1594 type == TNY_ACCOUNT_TYPE_TRANSPORT,
1597 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1599 /* Make sure that the tny accounts have been created:
1600 * TODO: We might want to do this in several places.
1602 if (!priv->store_accounts || !priv->transport_accounts)
1603 recreate_all_accounts (self);
1605 account_list = (type == TNY_ACCOUNT_TYPE_STORE) ?
1606 priv->store_accounts :
1607 priv->transport_accounts;
1609 if (!account_list) {
1610 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__,
1611 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1615 /* Look for the server account */
1616 while (account_list && !found) {
1617 const gchar *modest_acc_name;
1619 account = TNY_ACCOUNT (account_list->data);
1621 modest_tny_account_get_parent_modest_account_name_for_server_account (account);
1623 if (!strcmp (account_name, modest_acc_name))
1626 account_list = g_slist_next (account_list);
1630 g_printerr ("modest: %s: could not get tny %s account for %s\n. Number of server accounts of this type=%d\n", __FUNCTION__,
1631 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1632 account_name, g_slist_length (account_list));
1634 /* Pick a reference */
1635 g_object_ref (account);
1642 get_smtp_specific_transport_account_for_open_connection (ModestTnyAccountStore *self,
1643 const gchar *account_name)
1645 /* Get the current connection: */
1646 TnyDevice *device = modest_runtime_get_device ();
1648 if (!tny_device_is_online (device))
1651 g_return_val_if_fail (self, NULL);
1652 g_return_val_if_fail (account_name, NULL);
1655 #ifdef MODEST_PLATFORM_MAEMO
1656 g_assert (TNY_IS_MAEMO_CONIC_DEVICE (device));
1657 TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);
1658 const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1659 /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1663 ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1667 const gchar *connection_name = con_ic_iap_get_name (connection);
1668 /* printf ("DEBUG: %s: connection_name=%s\n", __FUNCTION__, connection_name); */
1669 if (!connection_name)
1672 /* Get the connection-specific transport acccount, if any: */
1673 ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1674 gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager,
1675 account_name, connection_name);
1677 /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1678 if (!server_account_name) {
1679 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1682 TnyAccount* account = modest_tny_account_store_get_tny_account_by (self,
1683 MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1684 server_account_name);
1686 /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1687 g_free (server_account_name);
1689 /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1690 g_object_unref (connection);
1694 return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1695 #endif /* MODEST_PLATFORM_MAEMO */
1700 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1701 const gchar *account_name)
1703 g_return_val_if_fail (self, NULL);
1704 g_return_val_if_fail (account_name, NULL);
1706 if (!account_name || !self)
1709 /* Get the connection-specific transport acccount, if any: */
1710 TnyAccount *account =
1711 get_smtp_specific_transport_account_for_open_connection (self, account_name);
1713 /* If there is no connection-specific transport account (the common case),
1714 * just get the regular transport account: */
1716 /* printf("DEBUG: %s: using regular transport account for account %s.\n", __FUNCTION__, account_name); */
1718 /* The special local folders don't have transport accounts. */
1719 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1722 account = modest_tny_account_store_get_server_account (self, account_name,
1723 TNY_ACCOUNT_TYPE_TRANSPORT);
1730 modest_tny_account_is_virtual_local_folders (TnyAccount *self)
1732 /* We should make this more sophisticated if we ever use ModestTnyLocalFoldersAccount
1733 * for anything else. */
1734 return MODEST_IS_TNY_LOCAL_FOLDERS_ACCOUNT (self);
1739 modest_tny_account_is_memory_card_account (TnyAccount *self)
1744 const gchar* account_id = tny_account_get_id (self);
1748 return (strcmp (account_id, MODEST_MMC_ACCOUNT_ID) == 0);
1752 modest_tny_account_store_get_local_folders_account (TnyAccountStore *self)
1754 TnyAccount *account = NULL;
1755 ModestTnyAccountStorePrivate *priv;
1758 g_return_val_if_fail (self, NULL);
1760 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1762 for (cursor = priv->store_accounts; cursor ; cursor = cursor->next) {
1763 TnyAccount *this_account = TNY_ACCOUNT(cursor->data);
1764 if (modest_tny_account_is_virtual_local_folders (this_account)) {
1765 account = this_account;
1771 g_object_ref (G_OBJECT(account));