* speed up modest_account_mgr_has_accounts by caching the status
[modest] / src / modest-account-mgr.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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.
16  *
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.
28  */
29
30 #include <string.h>
31 #include <modest-marshal.h>
32 #include <modest-runtime.h>
33 #include <modest-account-mgr.h>
34 #include <modest-account-mgr-priv.h>
35 #include <modest-account-mgr-helpers.h>
36 #include <modest-platform.h>
37
38 /* 'private'/'protected' functions */
39 static void modest_account_mgr_class_init (ModestAccountMgrClass * klass);
40 static void modest_account_mgr_init       (ModestAccountMgr * obj);
41 static void modest_account_mgr_finalize   (GObject * obj);
42 static void modest_account_mgr_base_init  (gpointer g_class);
43
44 static const gchar *_modest_account_mgr_get_account_keyname_cached (ModestAccountMgrPrivate *priv, 
45                                                                     const gchar* account_name,
46                                                                     const gchar *name, 
47                                                                     gboolean is_server);
48
49 static gboolean modest_account_mgr_unset_default_account (ModestAccountMgr *self);
50
51 /* list my signals */
52 enum {
53         ACCOUNT_INSERTED_SIGNAL,
54         ACCOUNT_CHANGED_SIGNAL,
55         ACCOUNT_REMOVED_SIGNAL,
56         ACCOUNT_BUSY_SIGNAL,
57         DEFAULT_ACCOUNT_CHANGED_SIGNAL,
58         DISPLAY_NAME_CHANGED_SIGNAL,
59         LAST_SIGNAL
60 };
61
62 /* globals */
63 static GObjectClass *parent_class = NULL;
64 static guint signals[LAST_SIGNAL] = {0};
65
66 GType
67 modest_account_mgr_get_type (void)
68 {
69         static GType my_type = 0;
70
71         if (!my_type) {
72                 static const GTypeInfo my_info = {
73                         sizeof (ModestAccountMgrClass),
74                         modest_account_mgr_base_init,   /* base init */
75                         NULL,   /* base finalize */
76                         (GClassInitFunc) modest_account_mgr_class_init,
77                         NULL,   /* class finalize */
78                         NULL,   /* class data */
79                         sizeof (ModestAccountMgr),
80                         1,      /* n_preallocs */
81                         (GInstanceInitFunc) modest_account_mgr_init,
82                         NULL
83                 };
84
85                 my_type = g_type_register_static (G_TYPE_OBJECT,
86                                                   "ModestAccountMgr",
87                                                   &my_info, 0);
88         }
89         return my_type;
90 }
91
92 static void 
93 modest_account_mgr_base_init (gpointer g_class)
94 {
95         static gboolean modest_account_mgr_initialized = FALSE;
96
97         if (!modest_account_mgr_initialized) {
98                 /* signal definitions */
99                 signals[ACCOUNT_INSERTED_SIGNAL] =
100                         g_signal_new ("account_inserted",
101                                       MODEST_TYPE_ACCOUNT_MGR,
102                                       G_SIGNAL_RUN_FIRST,
103                                       G_STRUCT_OFFSET(ModestAccountMgrClass, account_inserted),
104                                       NULL, NULL,
105                                       g_cclosure_marshal_VOID__STRING,
106                                       G_TYPE_NONE, 1, G_TYPE_STRING);
107
108                 signals[ACCOUNT_REMOVED_SIGNAL] =
109                         g_signal_new ("account_removed",
110                                       MODEST_TYPE_ACCOUNT_MGR,
111                                       G_SIGNAL_RUN_FIRST,
112                                       G_STRUCT_OFFSET(ModestAccountMgrClass, account_removed),
113                                       NULL, NULL,
114                                       g_cclosure_marshal_VOID__STRING,
115                                       G_TYPE_NONE, 1, G_TYPE_STRING);
116
117                 signals[ACCOUNT_CHANGED_SIGNAL] =
118                         g_signal_new ("account_changed",
119                                       MODEST_TYPE_ACCOUNT_MGR,
120                                       G_SIGNAL_RUN_FIRST,
121                                       G_STRUCT_OFFSET(ModestAccountMgrClass, account_changed),
122                                       NULL, NULL,
123                                       modest_marshal_VOID__STRING_INT,
124                                       G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
125
126                 signals[ACCOUNT_BUSY_SIGNAL] =
127                         g_signal_new ("account_busy_changed",
128                                       MODEST_TYPE_ACCOUNT_MGR,
129                                       G_SIGNAL_RUN_FIRST,
130                                       G_STRUCT_OFFSET(ModestAccountMgrClass, account_busy_changed),
131                                       NULL, NULL,
132                                       modest_marshal_VOID__STRING_BOOLEAN,
133                                       G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN);
134
135                 signals[DEFAULT_ACCOUNT_CHANGED_SIGNAL] =
136                         g_signal_new ("default_account_changed",
137                                       MODEST_TYPE_ACCOUNT_MGR,
138                                       G_SIGNAL_RUN_FIRST,
139                                       G_STRUCT_OFFSET(ModestAccountMgrClass, default_account_changed),
140                                       NULL, NULL,
141                                       g_cclosure_marshal_VOID__VOID,
142                                       G_TYPE_NONE, 0);
143
144                 signals[DISPLAY_NAME_CHANGED_SIGNAL] =
145                         g_signal_new ("display_name_changed",
146                                       MODEST_TYPE_ACCOUNT_MGR,
147                                       G_SIGNAL_RUN_FIRST,
148                                       G_STRUCT_OFFSET(ModestAccountMgrClass, display_name_changed),
149                                       NULL, NULL,
150                                       g_cclosure_marshal_VOID__STRING,
151                                       G_TYPE_NONE, 1, G_TYPE_STRING);
152
153                 modest_account_mgr_initialized = TRUE;
154         }
155 }
156
157 static void
158 modest_account_mgr_class_init (ModestAccountMgrClass * klass)
159 {
160         GObjectClass *gobject_class;
161         gobject_class = (GObjectClass *) klass;
162
163         parent_class = g_type_class_peek_parent (klass);
164         gobject_class->finalize = modest_account_mgr_finalize;
165
166         g_type_class_add_private (gobject_class,
167                                   sizeof (ModestAccountMgrPrivate));
168 }
169
170
171 static void
172 modest_account_mgr_init (ModestAccountMgr * obj)
173 {
174         ModestAccountMgrPrivate *priv =
175                 MODEST_ACCOUNT_MGR_GET_PRIVATE (obj);
176
177         priv->modest_conf   = NULL;
178         priv->busy_accounts = NULL;
179         priv->timeout       = 0;
180         
181         priv->notification_id_accounts = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, g_free);
182
183         /* we maintain hashes for the modest-conf keys we build from account name
184          * + key. many seem to be used often, and generating them showed up high
185          * in oprofile */
186         /* both hashes are hashes to hashes;
187          * account-key => keyname ==> account-key-name
188          */     
189         priv->server_account_key_hash = g_hash_table_new_full (g_str_hash,
190                                                                g_str_equal,
191                                                                g_free,
192                                                                (GDestroyNotify)g_hash_table_destroy);
193         priv->account_key_hash        = g_hash_table_new_full (g_str_hash,
194                                                                g_str_equal,
195                                                                g_free,
196                                                                (GDestroyNotify)g_hash_table_destroy);
197
198         /* FALSE means: status is unknown */
199         priv->has_accounts = FALSE;
200         priv->has_enabled_accounts = FALSE;
201 }
202
203 static void
204 modest_account_mgr_finalize (GObject * obj)
205 {
206         ModestAccountMgrPrivate *priv = 
207                 MODEST_ACCOUNT_MGR_GET_PRIVATE (obj);
208
209         if (priv->notification_id_accounts) {
210                 /* TODO: forget dirs */
211
212                 g_hash_table_destroy (priv->notification_id_accounts);
213         }
214
215         if (priv->modest_conf) {
216                 g_object_unref (G_OBJECT(priv->modest_conf));
217                 priv->modest_conf = NULL;
218         }
219
220         if (priv->timeout)
221                 g_source_remove (priv->timeout);
222         priv->timeout = 0;
223
224         if (priv->server_account_key_hash) {
225                 g_hash_table_destroy (priv->server_account_key_hash);
226                 priv->server_account_key_hash = NULL;
227         }
228         
229         if (priv->account_key_hash) {
230                 g_hash_table_destroy (priv->account_key_hash);
231                 priv->account_key_hash = NULL;
232         }
233
234         G_OBJECT_CLASS(parent_class)->finalize (obj);
235 }
236
237
238 ModestAccountMgr *
239 modest_account_mgr_new (ModestConf *conf)
240 {
241         GObject *obj;
242         ModestAccountMgrPrivate *priv;
243
244         g_return_val_if_fail (conf, NULL);
245
246         obj = G_OBJECT (g_object_new (MODEST_TYPE_ACCOUNT_MGR, NULL));
247         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (obj);
248
249         g_object_ref (G_OBJECT(conf));
250         priv->modest_conf = conf;
251
252         return MODEST_ACCOUNT_MGR (obj);
253 }
254
255
256 static const gchar *
257 null_means_empty (const gchar * str)
258 {
259         return str ? str : "";
260 }
261
262
263 gboolean
264 modest_account_mgr_add_account (ModestAccountMgr *self,
265                                 const gchar *name,
266                                 const gchar *display_name,
267                                 const gchar *user_fullname,
268                                 const gchar *user_email,
269                                 const gchar *retrieve_type,
270                                 const gchar *store_account,
271                                 const gchar *transport_account,
272                                 gboolean enabled)
273 {
274         ModestAccountMgrPrivate *priv;
275         const gchar *key;
276         gboolean ok;
277         gchar *default_account;
278         GError *err = NULL;
279         
280         g_return_val_if_fail (MODEST_IS_ACCOUNT_MGR(self), FALSE);
281         g_return_val_if_fail (name, FALSE);
282         g_return_val_if_fail (strchr(name, '/') == NULL, FALSE);
283         
284         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
285
286         /*
287          * we create the account by adding an account 'dir', with the name <name>,
288          * and in that the 'display_name' string key
289          */
290         key = _modest_account_mgr_get_account_keyname_cached (priv, name, MODEST_ACCOUNT_DISPLAY_NAME,
291                                                               FALSE);
292         if (modest_account_mgr_account_exists (self, key, FALSE)) {
293                 g_printerr ("modest: account already exists\n");
294                 return FALSE;
295         }
296         
297         ok = modest_conf_set_string (priv->modest_conf, key, name, &err);
298         if (!ok) {
299                 g_printerr ("modest: cannot set display name\n");
300                 if (err) {
301                         g_printerr ("modest: Error adding account conf: %s\n", err->message);
302                         g_error_free (err);
303                 }
304                 return FALSE;
305         }
306         
307         if (store_account) {
308                 key = _modest_account_mgr_get_account_keyname_cached (priv, name, MODEST_ACCOUNT_STORE_ACCOUNT,
309                                                                       FALSE);
310                 ok = modest_conf_set_string (priv->modest_conf, key, store_account, &err);
311                 if (!ok) {
312                         g_printerr ("modest: failed to set store account '%s'\n",
313                                     store_account);
314                         if (err) {
315                                 g_printerr ("modest: Error adding store account conf: %s\n", err->message);
316                                 g_error_free (err);
317                         }
318                         return FALSE;
319                 }
320         }
321         
322         if (transport_account) {
323                 key = _modest_account_mgr_get_account_keyname_cached (priv, name,
324                                                                       MODEST_ACCOUNT_TRANSPORT_ACCOUNT,
325                                                                       FALSE);
326                 ok = modest_conf_set_string (priv->modest_conf, key, transport_account, &err);
327                 if (!ok) {
328                         g_printerr ("modest: failed to set transport account '%s'\n",
329                                     transport_account);
330                         if (err) {
331                                 g_printerr ("modest: Error adding transport account conf: %s\n", err->message);
332                                 g_error_free (err);
333                         }       
334                         return FALSE;
335                 }
336         }
337
338         /* Make sure that leave-messages-on-server is enabled by default, 
339          * as per the UI spec, though it is only meaningful for accounts using POP.
340          * (possibly this gconf key should be under the server account): */
341         modest_account_mgr_set_bool (self, name, MODEST_ACCOUNT_LEAVE_ON_SERVER, TRUE, FALSE);
342         modest_account_mgr_set_bool (self, name, MODEST_ACCOUNT_ENABLED, enabled,FALSE);
343
344         /* Fill other data */
345         modest_account_mgr_set_string (self, name,
346                                        MODEST_ACCOUNT_DISPLAY_NAME, 
347                                        display_name, FALSE);
348         modest_account_mgr_set_string (self, name,
349                                        MODEST_ACCOUNT_FULLNAME, 
350                                        user_fullname, FALSE);
351         modest_account_mgr_set_string (self, name,
352                                        MODEST_ACCOUNT_EMAIL, 
353                                        user_email, FALSE);
354         modest_account_mgr_set_string (self, name,
355                                        MODEST_ACCOUNT_RETRIEVE, 
356                                        retrieve_type, FALSE);
357
358         /* Notify the observers */
359         g_signal_emit (self, signals[ACCOUNT_INSERTED_SIGNAL], 0, name);
360
361         /* if no default account has been defined yet, do so now */
362         default_account = modest_account_mgr_get_default_account (self);
363         if (!default_account)
364                 modest_account_mgr_set_default_account (self, name);
365         g_free (default_account);
366         
367         /* (re)set the automatic account update */
368         modest_platform_set_update_interval
369                 (modest_conf_get_int (priv->modest_conf, MODEST_CONF_UPDATE_INTERVAL, NULL));
370         
371         return TRUE;
372 }
373
374
375 gboolean
376 modest_account_mgr_add_server_account (ModestAccountMgr * self,
377                                        const gchar *name, 
378                                        const gchar *hostname,
379                                        guint portnumber,
380                                        const gchar *username, 
381                                        const gchar *password,
382                                        ModestTransportStoreProtocol proto,
383                                        ModestConnectionProtocol security,
384                                        ModestAuthProtocol auth)
385 {
386         ModestAccountMgrPrivate *priv;
387         const gchar *key;
388         gboolean ok = TRUE;
389         GError *err = NULL;
390
391         g_return_val_if_fail (MODEST_IS_ACCOUNT_MGR(self), FALSE);
392         g_return_val_if_fail (name, FALSE);
393         g_return_val_if_fail (strchr(name, '/') == NULL, FALSE);
394                               
395         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
396
397         /* hostname */
398         key = _modest_account_mgr_get_account_keyname_cached (priv, name, MODEST_ACCOUNT_HOSTNAME, TRUE);
399         if (modest_conf_key_exists (priv->modest_conf, key, &err)) {
400                 g_printerr ("modest: server account '%s' already exists\n", name);
401                 ok =  FALSE;
402         }
403         if (!ok)
404                 goto cleanup;
405         
406         modest_conf_set_string (priv->modest_conf, key, null_means_empty(hostname), &err);
407         if (err) {
408                 g_printerr ("modest: failed to set %s: %s\n", key, err->message);
409                 g_error_free (err);
410                 ok = FALSE;
411         }
412         if (!ok)
413                 goto cleanup;
414         
415         /* username */
416         key = _modest_account_mgr_get_account_keyname_cached (priv, name, MODEST_ACCOUNT_USERNAME, TRUE);
417         ok = modest_conf_set_string (priv->modest_conf, key, null_means_empty (username), &err);
418         if (err) {
419                 g_printerr ("modest: failed to set %s: %s\n", key, err->message);
420                 g_error_free (err);
421                 ok = FALSE;
422         }
423         if (!ok)
424                 goto cleanup;
425         
426         
427         /* password */
428         key = _modest_account_mgr_get_account_keyname_cached (priv, name, MODEST_ACCOUNT_PASSWORD, TRUE);
429         ok = modest_conf_set_string (priv->modest_conf, key, null_means_empty (password), &err);
430         if (err) {
431                 g_printerr ("modest: failed to set %s: %s\n", key, err->message);
432                 g_error_free (err);
433                 ok = FALSE;
434         }
435         if (!ok)
436                 goto cleanup;
437
438         /* proto */
439         key = _modest_account_mgr_get_account_keyname_cached (priv, name, MODEST_ACCOUNT_PROTO, TRUE);
440         ok = modest_conf_set_string (priv->modest_conf, key,
441                                      modest_protocol_info_get_transport_store_protocol_name(proto),
442                                      &err);
443         if (err) {
444                 g_printerr ("modest: failed to set %s: %s\n", key, err->message);
445                 g_error_free (err);
446                 ok = FALSE;
447         }
448         if (!ok)
449                 goto cleanup;
450
451
452         /* portnumber */
453         key = _modest_account_mgr_get_account_keyname_cached (priv, name, MODEST_ACCOUNT_PORT, TRUE);
454         ok = modest_conf_set_int (priv->modest_conf, key, portnumber, &err);
455         if (err) {
456                 g_printerr ("modest: failed to set %s: %s\n", key, err->message);
457                 g_error_free (err);
458                 ok = FALSE;
459         }
460         if (!ok)
461                 goto cleanup;
462
463         
464         /* auth mechanism */
465         key = _modest_account_mgr_get_account_keyname_cached (priv, name, MODEST_ACCOUNT_AUTH_MECH, TRUE);
466         ok = modest_conf_set_string (priv->modest_conf, key,
467                                      modest_protocol_info_get_auth_protocol_name (auth),
468                                      &err);
469         if (err) {
470                 g_printerr ("modest: failed to set %s: %s\n", key, err->message);
471                 g_error_free (err);
472                 ok = FALSE;
473         }
474         if (!ok)
475                 goto cleanup;
476         
477         /* Add the security settings: */
478         modest_account_mgr_set_server_account_security (self, name, security);
479
480 cleanup:
481         if (!ok) {
482                 g_printerr ("modest: failed to add server account\n");
483                 return FALSE;
484         }
485
486         return TRUE;
487 }
488
489 /** modest_account_mgr_add_server_account_uri:
490  * Only used for mbox and maildir accounts.
491  */
492 gboolean
493 modest_account_mgr_add_server_account_uri (ModestAccountMgr * self,
494                                            const gchar *name, 
495                                            ModestTransportStoreProtocol proto,
496                                            const gchar *uri)
497 {
498         ModestAccountMgrPrivate *priv;
499         const gchar *key;
500         gboolean ok;
501         
502         g_return_val_if_fail (MODEST_IS_ACCOUNT_MGR(self), FALSE);
503         g_return_val_if_fail (name, FALSE);
504         g_return_val_if_fail (strchr(name, '/') == NULL, FALSE);
505         g_return_val_if_fail (uri, FALSE);
506         
507         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
508         
509         /* proto */
510         key = _modest_account_mgr_get_account_keyname_cached (priv, name, MODEST_ACCOUNT_PROTO, TRUE);
511         ok = modest_conf_set_string (priv->modest_conf, key,
512                                      modest_protocol_info_get_transport_store_protocol_name(proto),
513                                      NULL);
514
515         if (!ok) {
516                 g_printerr ("modest: failed to set proto\n");
517                 return FALSE;
518         }
519         
520         /* uri */
521         key = _modest_account_mgr_get_account_keyname_cached (priv, name, MODEST_ACCOUNT_URI, TRUE);
522         ok = modest_conf_set_string (priv->modest_conf, key, uri, NULL);
523
524         if (!ok) {
525                 g_printerr ("modest: failed to set uri\n");
526                 return FALSE;
527         }
528         return TRUE;
529 }
530
531 /* 
532  * Utility function used by modest_account_mgr_remove_account
533  */
534 static void
535 real_remove_account (ModestConf *conf,
536                      const gchar *acc_name,
537                      gboolean server_account)
538 {
539         GError *err = NULL;
540         gchar *key;
541         
542         key = _modest_account_mgr_get_account_keyname (acc_name, NULL, server_account);
543         modest_conf_remove_key (conf, key, &err);
544
545         if (err) {
546                 g_printerr ("modest: error removing key: %s\n", err->message);
547                 g_error_free (err);
548         }
549         g_free (key);
550 }
551
552 gboolean
553 modest_account_mgr_remove_account (ModestAccountMgr * self,
554                                    const gchar* name)
555 {
556         ModestAccountMgrPrivate *priv;
557         gchar *default_account_name, *store_acc_name, *transport_acc_name;
558         gboolean default_account_deleted;
559
560         g_return_val_if_fail (MODEST_IS_ACCOUNT_MGR(self), FALSE);
561         g_return_val_if_fail (name, FALSE);
562
563         if (!modest_account_mgr_account_exists (self, name, FALSE)) {
564                 g_printerr ("modest: %s: account '%s' does not exist\n", __FUNCTION__, name);
565                 return FALSE;
566         }
567
568         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
569         default_account_deleted = FALSE;
570
571         /* If this was the default, then remove that setting: */
572         default_account_name = modest_account_mgr_get_default_account (self);
573         if (default_account_name && (strcmp (default_account_name, name) == 0)) {
574                 modest_account_mgr_unset_default_account (self);
575                 default_account_deleted = TRUE;
576         }
577         g_free (default_account_name);
578
579         /* Delete transport and store accounts */
580         store_acc_name = modest_account_mgr_get_string (self, name, 
581                                                         MODEST_ACCOUNT_STORE_ACCOUNT, FALSE);
582         if (store_acc_name)
583                 real_remove_account (priv->modest_conf, store_acc_name, TRUE);
584
585         transport_acc_name = modest_account_mgr_get_string (self, name, 
586                                                             MODEST_ACCOUNT_TRANSPORT_ACCOUNT, FALSE);
587         if (transport_acc_name)
588                 real_remove_account (priv->modest_conf, transport_acc_name, TRUE);
589                         
590         /* Remove the modest account */
591         real_remove_account (priv->modest_conf, name, FALSE);
592
593         if (default_account_deleted) {  
594                 /* pick another one as the new default account. We do
595                    this *after* deleting the keys, because otherwise a
596                    call to account_names will retrieve also the
597                    deleted account */
598                 modest_account_mgr_set_first_account_as_default (self);
599         }
600         
601         /* Notify the observers. We do this *after* deleting
602            the keys, because otherwise a call to account_names
603            will retrieve also the deleted account */
604         g_signal_emit (G_OBJECT(self), signals[ACCOUNT_REMOVED_SIGNAL], 0, name);
605
606         /* if this was the last account, stop any auto-updating */
607         /* (re)set the automatic account update */
608         GSList *acc_names = modest_account_mgr_account_names (self, TRUE);
609         if (!acc_names) {
610                 modest_platform_set_update_interval (0);
611                 /* it was the last account, the has_account / has_enabled_account
612                  * changes
613                  */
614                 priv->has_accounts = priv->has_enabled_accounts = FALSE; 
615         } else
616                 modest_account_mgr_free_account_names (acc_names);
617         
618         return TRUE;
619 }
620
621
622
623 /* strip the first /n/ character from each element
624  * caller must make sure all elements are strings with
625  * length >= n, and also that data can be freed.
626  * change is in-place
627  */
628 static void
629 strip_prefix_from_elements (GSList * lst, guint n)
630 {
631         while (lst) {
632                 memmove (lst->data, lst->data + n,
633                          strlen(lst->data) - n + 1);
634                 lst = lst->next;
635         }
636 }
637
638
639 GSList*
640 modest_account_mgr_account_names (ModestAccountMgr * self, gboolean only_enabled)
641 {
642         GSList *accounts;
643         ModestAccountMgrPrivate *priv;
644         GError *err = NULL;
645         
646         const size_t prefix_len = strlen (MODEST_ACCOUNT_NAMESPACE "/");
647
648         g_return_val_if_fail (self, NULL);
649
650         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
651         accounts = modest_conf_list_subkeys (priv->modest_conf,
652                                              MODEST_ACCOUNT_NAMESPACE, &err);
653
654         if (err) {
655                 g_printerr ("modest: failed to get subkeys (%s): %s\n",
656                             MODEST_ACCOUNT_NAMESPACE, err->message);
657                 g_error_free (err);
658                 return NULL; /* assume accounts did not get value when err is set...*/
659         }
660         
661         strip_prefix_from_elements (accounts, prefix_len);
662                 
663         GSList *result = NULL;
664         
665         /* Unescape the keys to get the account names: */
666         GSList *iter = accounts;
667         while (iter) {
668                 if (!(iter->data))
669                         continue;
670                         
671                 const gchar* account_name_key = (const gchar*)iter->data;
672                 gchar* unescaped_name = account_name_key ? 
673                         modest_conf_key_unescape (account_name_key) 
674                         : NULL;
675                 
676                 gboolean add = TRUE;
677                 if (only_enabled) {
678                         if (unescaped_name && 
679                             !modest_account_mgr_get_bool (self, unescaped_name, 
680                                                           MODEST_ACCOUNT_ENABLED, FALSE))
681                                 add = FALSE;
682                 }
683                 
684                 /* Ignore modest accounts whose server accounts don't exist: 
685                  * (We could be getting this list while the account is being deleted, 
686                  * while the child server accounts have already been deleted, but the 
687                  * parent modest account already exists.
688                  */
689                 if (add) {
690                         gchar* server_account_name = modest_account_mgr_get_string
691                                 (self, account_name_key, MODEST_ACCOUNT_STORE_ACCOUNT,
692                                  FALSE);
693                         if (server_account_name) {
694                                 if (!modest_account_mgr_account_exists (self, server_account_name, TRUE))
695                                         add = FALSE;
696                                 g_free (server_account_name);
697                         }
698                 }
699                 
700                 if (add) {
701                         gchar* server_account_name = modest_account_mgr_get_string
702                                 (self, account_name_key, MODEST_ACCOUNT_TRANSPORT_ACCOUNT,
703                                  FALSE);
704                         if (server_account_name) {
705                                 if (!modest_account_mgr_account_exists (self, server_account_name, TRUE))
706                                         add = FALSE;
707                                 g_free (server_account_name);
708                         }
709                 }
710                 
711                 if (add)
712                         result = g_slist_append (result, unescaped_name);
713                 else 
714                         g_free (unescaped_name);
715
716                 g_free (iter->data);
717                 iter->data = NULL;
718                 
719                 iter = g_slist_next (iter);     
720         }
721         
722
723         /* we already freed the strings in the loop */
724         g_slist_free (accounts);
725         
726         accounts = NULL;
727         return result;
728 }
729
730
731 void
732 modest_account_mgr_free_account_names (GSList *account_names)
733 {
734         g_slist_foreach (account_names, (GFunc)g_free, NULL);
735         g_slist_free (account_names);
736 }
737
738
739
740 gchar *
741 modest_account_mgr_get_string (ModestAccountMgr *self, const gchar *name,
742                                const gchar *key, gboolean server_account) {
743
744         ModestAccountMgrPrivate *priv;
745
746         const gchar *keyname;
747         gchar *retval;
748         GError *err = NULL;
749
750         g_return_val_if_fail (self, NULL);
751         g_return_val_if_fail (name, NULL);
752         g_return_val_if_fail (key, NULL);
753
754         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
755         
756         keyname = _modest_account_mgr_get_account_keyname_cached (priv, name, key, server_account);
757         
758         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
759         retval = modest_conf_get_string (priv->modest_conf, keyname, &err);     
760         if (err) {
761                 g_printerr ("modest: error getting string '%s': %s\n", keyname, err->message);
762                 g_error_free (err);
763                 retval = NULL;
764         }
765
766         return retval;
767 }
768
769
770 gint
771 modest_account_mgr_get_int (ModestAccountMgr *self, const gchar *name, const gchar *key,
772                             gboolean server_account)
773 {
774         ModestAccountMgrPrivate *priv;
775
776         const gchar *keyname;
777         gint retval;
778         GError *err = NULL;
779         
780         g_return_val_if_fail (MODEST_IS_ACCOUNT_MGR(self), -1);
781         g_return_val_if_fail (name, -1);
782         g_return_val_if_fail (key, -1);
783
784         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
785
786         keyname = _modest_account_mgr_get_account_keyname_cached (priv, name, key, server_account);
787         
788         retval = modest_conf_get_int (priv->modest_conf, keyname, &err);
789         if (err) {
790                 g_printerr ("modest: error getting int '%s': %s\n", keyname, err->message);
791                 g_error_free (err);
792                 retval = -1;
793         }
794
795         return retval;
796 }
797
798
799
800 gboolean
801 modest_account_mgr_get_bool (ModestAccountMgr * self, const gchar *account,
802                              const gchar * key, gboolean server_account)
803 {
804         ModestAccountMgrPrivate *priv;
805
806         const gchar *keyname;
807         gboolean retval;
808         GError *err = NULL;
809
810         g_return_val_if_fail (MODEST_IS_ACCOUNT_MGR(self), FALSE);
811         g_return_val_if_fail (account, FALSE);
812         g_return_val_if_fail (key, FALSE);
813
814         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
815         ///keyname = _modest_account_mgr_get_account_keyname (account, key, server_account);
816
817         keyname = _modest_account_mgr_get_account_keyname_cached (priv, account, key, server_account);
818                 
819         retval = modest_conf_get_bool (priv->modest_conf, keyname, &err);               
820         if (err) {
821                 g_printerr ("modest: error getting bool '%s': %s\n", keyname, err->message);
822                 g_error_free (err);
823                 retval = FALSE;
824         }
825
826         return retval;
827 }
828
829
830
831 GSList * 
832 modest_account_mgr_get_list (ModestAccountMgr *self, const gchar *name,
833                              const gchar *key, ModestConfValueType list_type,
834                              gboolean server_account)
835 {
836         ModestAccountMgrPrivate *priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
837
838         const gchar *keyname;
839         GSList *retval;
840         GError *err = NULL;
841         
842         g_return_val_if_fail (MODEST_IS_ACCOUNT_MGR(self), NULL);
843         g_return_val_if_fail (name, NULL);
844         g_return_val_if_fail (key, NULL);
845         
846         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
847
848         keyname = _modest_account_mgr_get_account_keyname_cached (priv, name, key,
849                                                                   server_account);
850         
851         retval = modest_conf_get_list (priv->modest_conf, keyname, list_type, &err);
852         if (err) {
853                 g_printerr ("modest: error getting list '%s': %s\n", keyname,
854                             err->message);
855                 g_error_free (err);
856                 retval = FALSE;
857         }
858         return retval;
859 }
860
861
862 gboolean
863 modest_account_mgr_set_string (ModestAccountMgr * self, 
864                                const gchar * name,
865                                const gchar * key, 
866                                const gchar * val, 
867                                gboolean server_account)
868 {
869         ModestAccountMgrPrivate *priv;
870
871         const gchar *keyname;
872         gboolean retval;
873         GError *err = NULL;
874
875         g_return_val_if_fail (MODEST_IS_ACCOUNT_MGR(self), FALSE);
876         g_return_val_if_fail (name, FALSE);
877         g_return_val_if_fail (key, FALSE);
878
879         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
880
881         keyname = _modest_account_mgr_get_account_keyname_cached (priv, name, key, server_account);
882         
883         retval = modest_conf_set_string (priv->modest_conf, keyname, val, &err);
884         if (err) {
885                 g_printerr ("modest: error setting string '%s': %s\n", keyname, err->message);
886                 g_error_free (err);
887                 retval = FALSE;
888         }
889         return retval;
890 }
891
892 gboolean
893 modest_account_mgr_set_int (ModestAccountMgr * self, const gchar * name,
894                             const gchar * key, int val, gboolean server_account)
895 {
896         ModestAccountMgrPrivate *priv;
897
898         const gchar *keyname;
899         gboolean retval;
900         GError *err = NULL;
901         
902         g_return_val_if_fail (MODEST_IS_ACCOUNT_MGR(self), FALSE);
903         g_return_val_if_fail (name, FALSE);
904         g_return_val_if_fail (key, FALSE);
905
906         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
907
908         keyname = _modest_account_mgr_get_account_keyname_cached (priv, name, key, server_account);
909         
910         retval = modest_conf_set_int (priv->modest_conf, keyname, val, &err);
911         if (err) {
912                 g_printerr ("modest: error setting int '%s': %s\n", keyname, err->message);
913                 g_error_free (err);
914                 retval = FALSE;
915         }
916         return retval;
917 }
918
919
920
921 gboolean
922 modest_account_mgr_set_bool (ModestAccountMgr * self, const gchar * name,
923                              const gchar * key, gboolean val, gboolean server_account)
924 {
925         ModestAccountMgrPrivate *priv;
926
927         const gchar *keyname;
928         gboolean retval;
929         GError *err = NULL;
930
931         g_return_val_if_fail (MODEST_IS_ACCOUNT_MGR(self), FALSE);
932         g_return_val_if_fail (name, FALSE);
933         g_return_val_if_fail (key, FALSE);
934
935         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
936         keyname = _modest_account_mgr_get_account_keyname_cached (priv, name, key, server_account);
937         
938         retval = modest_conf_set_bool (priv->modest_conf, keyname, val, &err);
939         if (err) {
940                 g_printerr ("modest: error setting bool '%s': %s\n", keyname, err->message);
941                 g_error_free (err);
942                 retval = FALSE;
943         }
944
945         return retval;
946 }
947
948
949 gboolean
950 modest_account_mgr_set_list (ModestAccountMgr *self,
951                              const gchar *name,
952                              const gchar *key,
953                              GSList *val,
954                              ModestConfValueType list_type,
955                              gboolean server_account)
956 {
957         ModestAccountMgrPrivate *priv;
958         const gchar *keyname;
959         GError *err = NULL;
960         gboolean retval;
961         
962         g_return_val_if_fail (self, FALSE);
963         g_return_val_if_fail (name, FALSE);
964         g_return_val_if_fail (key,  FALSE);
965         g_return_val_if_fail (val,  FALSE);
966
967         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
968
969         keyname = _modest_account_mgr_get_account_keyname_cached (priv, name, key, server_account);
970         
971         retval = modest_conf_set_list (priv->modest_conf, keyname, val, list_type, &err);
972         if (err) {
973                 g_printerr ("modest: error setting list '%s': %s\n", keyname, err->message);
974                 g_error_free (err);
975                 retval = FALSE;
976         }
977
978         return retval;
979 }
980
981 gboolean
982 modest_account_mgr_account_exists (ModestAccountMgr * self, const gchar* name,
983                                    gboolean server_account)
984 {
985         ModestAccountMgrPrivate *priv;
986
987         const gchar *keyname;
988         gboolean retval;
989         GError *err = NULL;
990
991         g_return_val_if_fail (self, FALSE);
992         g_return_val_if_fail (name, FALSE);
993
994         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
995         keyname = _modest_account_mgr_get_account_keyname_cached (priv, name, NULL, server_account);
996         retval = modest_conf_key_exists (priv->modest_conf, keyname, &err);
997         if (err) {
998                 g_printerr ("modest: error determining existance of '%s': %s\n", keyname,
999                             err->message);
1000                 g_error_free (err);
1001                 retval = FALSE;
1002         }
1003         return retval;
1004 }
1005
1006 gboolean
1007 modest_account_mgr_account_with_display_name_exists  (ModestAccountMgr *self, 
1008                                                       const gchar *display_name)
1009 {
1010         GSList *account_names = NULL;
1011         GSList *cursor = NULL;
1012         
1013         cursor = account_names = modest_account_mgr_account_names (self, 
1014                                                                    TRUE /* enabled accounts, because disabled accounts are not user visible. */);
1015
1016         gboolean found = FALSE;
1017         
1018         /* Look at each non-server account to check their display names; */
1019         while (cursor) {
1020                 const gchar * account_name = (gchar*)cursor->data;
1021                 
1022                 ModestAccountData *account_data = modest_account_mgr_get_account_data (self, account_name);
1023                 if (!account_data) {
1024                         g_printerr ("modest: failed to get account data for %s\n", account_name);
1025                         continue;
1026                 }
1027
1028                 if(account_data->display_name && (strcmp (account_data->display_name, display_name) == 0)) {
1029                         found = TRUE;
1030                         break;
1031                 }
1032
1033                 modest_account_mgr_free_account_data (self, account_data);
1034                 cursor = cursor->next;
1035         }
1036         modest_account_mgr_free_account_names (account_names);
1037         account_names = NULL;
1038         
1039         return found;
1040 }
1041
1042
1043
1044
1045 gboolean 
1046 modest_account_mgr_unset (ModestAccountMgr *self, const gchar *name,
1047                           const gchar *key, gboolean server_account)
1048 {
1049         ModestAccountMgrPrivate *priv;
1050         
1051         const gchar *keyname;
1052         gboolean retval;
1053         GError *err = NULL;
1054         
1055         g_return_val_if_fail (MODEST_IS_ACCOUNT_MGR(self), FALSE);
1056         g_return_val_if_fail (name, FALSE);
1057         g_return_val_if_fail (key, FALSE);
1058
1059         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
1060         keyname = _modest_account_mgr_get_account_keyname_cached (priv, name, key, server_account);
1061
1062         retval = modest_conf_remove_key (priv->modest_conf, keyname, &err);
1063         if (err) {
1064                 g_printerr ("modest: error unsetting'%s': %s\n", keyname,
1065                             err->message);
1066                 g_error_free (err);
1067                 retval = FALSE;
1068         }
1069         return retval;
1070 }
1071
1072 gchar*
1073 _modest_account_mgr_account_from_key (const gchar *key, gboolean *is_account_key, gboolean *is_server_account)
1074 {
1075         /* Initialize input parameters: */
1076         if (is_account_key)
1077                 *is_account_key = FALSE;
1078
1079         if (is_server_account)
1080                 *is_server_account = FALSE;
1081
1082         const gchar* account_ns        = MODEST_ACCOUNT_NAMESPACE "/";
1083         const gchar* server_account_ns = MODEST_SERVER_ACCOUNT_NAMESPACE "/";
1084         gchar *cursor;
1085         gchar *account = NULL;
1086
1087         /* determine whether it's an account or a server account,
1088          * based on the prefix */
1089         if (g_str_has_prefix (key, account_ns)) {
1090
1091                 if (is_server_account)
1092                         *is_server_account = FALSE;
1093                 
1094                 account = g_strdup (key + strlen (account_ns));
1095
1096         } else if (g_str_has_prefix (key, server_account_ns)) {
1097
1098                 if (is_server_account)
1099                         *is_server_account = TRUE;
1100                 
1101                 account = g_strdup (key + strlen (server_account_ns));  
1102         } else
1103                 return NULL;
1104
1105         /* if there are any slashes left in the key, it's not
1106          * the toplevel entry for an account
1107          */
1108         cursor = strstr(account, "/");
1109         
1110         if (is_account_key && cursor)
1111                 *is_account_key = TRUE;
1112
1113         /* put a NULL where the first slash was */
1114         if (cursor)
1115                 *cursor = '\0';
1116
1117         if (account) {
1118                 /* The key is an escaped string, so unescape it to get the actual account name: */
1119                 gchar *unescaped_name = modest_conf_key_unescape (account);
1120                 g_free (account);
1121                 return unescaped_name;
1122         } else
1123                 return NULL;
1124 }
1125
1126
1127
1128
1129
1130 /* optimization: only with non-alphanum chars, escaping is needed */
1131 inline static gboolean
1132 is_alphanum (const gchar* str)
1133 {
1134         const gchar *cursor;
1135         for (cursor = str; cursor && *cursor; ++cursor) {
1136                 const char c = *cursor;
1137                 /* we cannot trust isalnum(3), because it might consider locales */
1138                 /*       numbers            ALPHA            alpha       */
1139                 if (!((c>=48 && c<=57)||(c>=65 && c<=90)||(c>=97 && c<=122)))
1140                         return FALSE;
1141         }
1142         return TRUE;
1143 }
1144                 
1145
1146
1147
1148 /* must be freed by caller */
1149 gchar *
1150 _modest_account_mgr_get_account_keyname (const gchar *account_name, const gchar* name,
1151                                          gboolean server_account)
1152 {
1153         gchar *retval = NULL;   
1154         gchar *namespace = server_account ? MODEST_SERVER_ACCOUNT_NAMESPACE : MODEST_ACCOUNT_NAMESPACE;
1155         gchar *escaped_account_name, *escaped_name;
1156         
1157         if (!account_name)
1158                 return g_strdup (namespace);
1159
1160         /* optimization: only escape names when need to be escaped */
1161         if (is_alphanum (account_name))
1162                 escaped_account_name = (gchar*)account_name;
1163         else
1164                 escaped_account_name = modest_conf_key_escape (account_name);
1165         
1166         if (is_alphanum (name))
1167                 escaped_name = (gchar*)name;
1168         else
1169                 escaped_name = modest_conf_key_escape (name);
1170         //////////////////////////////////////////////////////////////
1171
1172         if (escaped_account_name && escaped_name)
1173                 retval = g_strconcat (namespace, "/", escaped_account_name, "/", escaped_name, NULL);
1174         else if (escaped_account_name)
1175                 retval = g_strconcat (namespace, "/", escaped_account_name, NULL);
1176
1177         /* Sanity check: */
1178         if (!retval || !modest_conf_key_is_valid (retval)) {
1179                 g_warning ("%s: Generated conf key was invalid: %s", __FUNCTION__,
1180                            retval ? retval: "<empty>");
1181                 g_free (retval);
1182                 retval = NULL;
1183         }
1184         
1185         /* g_free is only needed if we actually allocated anything */
1186         if (name != escaped_name)
1187                 g_free (escaped_name);
1188         if (account_name != escaped_account_name)
1189                 g_free (escaped_account_name);
1190
1191         return retval;
1192 }
1193
1194 static const gchar *
1195 _modest_account_mgr_get_account_keyname_cached (ModestAccountMgrPrivate *priv, 
1196                                                 const gchar* account_name,
1197                                                 const gchar *name, 
1198                                                 gboolean is_server)
1199 {
1200         GHashTable *hash = is_server ? priv->server_account_key_hash : priv->account_key_hash;
1201         GHashTable *account_hash;
1202         gchar *key = NULL;
1203         const gchar *search_name;
1204
1205         if (!account_name)
1206                 return is_server ? MODEST_SERVER_ACCOUNT_NAMESPACE : MODEST_ACCOUNT_NAMESPACE;
1207
1208         search_name = name ? name : "<dummy>";
1209         
1210         account_hash = g_hash_table_lookup (hash, account_name);        
1211         if (!account_hash) { /* no hash for this account yet? create it */
1212                 account_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);         
1213                 key = _modest_account_mgr_get_account_keyname (account_name, name, is_server);
1214                 g_hash_table_insert (account_hash, g_strdup(search_name), key);
1215                 g_hash_table_insert (hash, g_strdup(account_name), account_hash);
1216                 return key;
1217         }
1218         
1219         /* we have a hash for this account, but do we have the key? */  
1220         key = g_hash_table_lookup (account_hash, search_name);
1221         if (!key) {
1222                 key = _modest_account_mgr_get_account_keyname (account_name, name, is_server);
1223                 g_hash_table_insert (account_hash, g_strdup(search_name), key);
1224         }
1225         
1226         return key;
1227 }
1228
1229
1230 gboolean
1231 modest_account_mgr_has_accounts (ModestAccountMgr* self, gboolean enabled)
1232 {
1233         ModestAccountMgrPrivate* priv;
1234         GSList *account_names;
1235         gboolean accounts_exist;
1236
1237         g_return_val_if_fail (MODEST_IS_ACCOUNT_MGR(self), FALSE);
1238         
1239         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
1240         
1241         if (enabled && priv->has_enabled_accounts)
1242                 return TRUE;
1243         else if (priv->has_accounts)
1244                 return TRUE;
1245                 
1246         /* Check that at least one account exists: */
1247         account_names = modest_account_mgr_account_names (self,enabled);
1248         accounts_exist = account_names != NULL;
1249         modest_account_mgr_free_account_names (account_names);
1250         account_names = NULL;
1251
1252         /* cache it. */
1253         if (enabled)
1254                 priv->has_enabled_accounts = accounts_exist;
1255         else
1256                 priv->has_accounts = accounts_exist;
1257         
1258         return accounts_exist;
1259 }
1260
1261 static int
1262 compare_account_name(gconstpointer a, gconstpointer b)
1263 {
1264         const gchar* account_name = (const gchar*) a;
1265         const gchar* account_name2 = (const gchar*) b;
1266         return strcmp(account_name, account_name2);
1267 }
1268
1269 void 
1270 modest_account_mgr_set_account_busy(ModestAccountMgr* self, 
1271                                     const gchar* account_name, 
1272                                     gboolean busy)
1273 {
1274         ModestAccountMgrPrivate* priv;
1275
1276         g_return_if_fail (MODEST_IS_ACCOUNT_MGR(self));
1277         g_return_if_fail (account_name);
1278
1279         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
1280         if (busy) {
1281                 GSList *account_names = modest_account_mgr_account_names (self, TRUE);
1282                 GSList* account = g_slist_find_custom(account_names, account_name, 
1283                                                       (GCompareFunc) compare_account_name);
1284
1285                 if (account && !modest_account_mgr_account_is_busy(self, account_name)) {
1286                         priv->busy_accounts = g_slist_append(priv->busy_accounts, g_strdup(account_name));
1287                         g_signal_emit (G_OBJECT(self), signals[ACCOUNT_BUSY_SIGNAL], 
1288                                        0, account_name, TRUE);
1289                 }
1290                 modest_account_mgr_free_account_names (account_names);
1291                 account_names = NULL;
1292         } else {
1293                 GSList* account = 
1294                         g_slist_find_custom(priv->busy_accounts, account_name, (GCompareFunc) compare_account_name);
1295
1296                 if (account) {
1297                         g_free(account->data);
1298                         priv->busy_accounts = g_slist_delete_link(priv->busy_accounts, account);
1299                         g_signal_emit (G_OBJECT(self), signals[ACCOUNT_BUSY_SIGNAL], 
1300                                        0, account_name, FALSE);
1301                 }
1302         }
1303 }
1304
1305 gboolean
1306 modest_account_mgr_account_is_busy (ModestAccountMgr* self, const gchar* account_name)
1307 {
1308         ModestAccountMgrPrivate* priv;
1309         
1310         g_return_val_if_fail (MODEST_IS_ACCOUNT_MGR(self), FALSE);
1311         g_return_val_if_fail (account_name, FALSE);
1312
1313         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
1314                 
1315         return (g_slist_find_custom(priv->busy_accounts, account_name, (GCompareFunc) compare_account_name)
1316                 != NULL);
1317 }
1318
1319 void
1320 modest_account_mgr_notify_account_update (ModestAccountMgr* self, 
1321                                           const gchar *server_account_name)
1322 {
1323         ModestTransportStoreProtocol proto;
1324         ModestAccountMgrPrivate* priv;
1325         gchar *proto_name = NULL;
1326
1327         g_return_if_fail (self);
1328         g_return_if_fail (server_account_name);
1329         
1330         priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
1331         
1332         /* Get protocol */
1333         proto_name = modest_account_mgr_get_string (self, server_account_name, 
1334                                                     MODEST_ACCOUNT_PROTO, TRUE);
1335         if (!proto_name) {
1336                 g_free (proto_name);
1337                 g_return_if_reached ();
1338         }
1339         proto = modest_protocol_info_get_transport_store_protocol (proto_name);
1340         g_free (proto_name);
1341
1342         /* there is some update in the account, so we can't
1343          * be sure about whether there are still enabled accounts...
1344          */
1345         priv->has_enabled_accounts = FALSE;
1346         priv->has_accounts         = FALSE;
1347         
1348         /* Emit "update-account" */
1349         g_signal_emit (G_OBJECT(self), 
1350                        signals[ACCOUNT_CHANGED_SIGNAL], 0, 
1351                        server_account_name, 
1352                        (modest_protocol_info_protocol_is_store (proto)) ? 
1353                        TNY_ACCOUNT_TYPE_STORE : 
1354                        TNY_ACCOUNT_TYPE_TRANSPORT);
1355 }
1356
1357
1358 gboolean
1359 modest_account_mgr_set_default_account  (ModestAccountMgr *self, const gchar* account)
1360 {
1361         ModestConf *conf;
1362         gboolean retval;
1363         
1364         g_return_val_if_fail (self,    FALSE);
1365         g_return_val_if_fail (account, FALSE);
1366         g_return_val_if_fail (modest_account_mgr_account_exists (self, account, FALSE),
1367                               FALSE);
1368         
1369         conf = MODEST_ACCOUNT_MGR_GET_PRIVATE (self)->modest_conf;
1370
1371         /* Change the default account and notify */
1372         retval = modest_conf_set_string (conf, MODEST_CONF_DEFAULT_ACCOUNT, account, NULL);
1373         if (retval)
1374                 g_signal_emit (G_OBJECT(self), signals[DEFAULT_ACCOUNT_CHANGED_SIGNAL], 0);
1375
1376         return retval;
1377 }
1378
1379
1380 gchar*
1381 modest_account_mgr_get_default_account  (ModestAccountMgr *self)
1382 {
1383         gchar *account; 
1384         ModestConf *conf;
1385         GError *err = NULL;
1386         
1387         g_return_val_if_fail (self, NULL);
1388
1389         conf = MODEST_ACCOUNT_MGR_GET_PRIVATE (self)->modest_conf;
1390         account = modest_conf_get_string (conf, MODEST_CONF_DEFAULT_ACCOUNT, &err);
1391         
1392         if (err) {
1393                 g_printerr ("modest: failed to get '%s': %s\n",
1394                             MODEST_CONF_DEFAULT_ACCOUNT, err->message);
1395                 g_error_free (err);
1396                 g_free (account);
1397                 return  NULL;
1398         }
1399         
1400         /* sanity check */
1401         if (account && !modest_account_mgr_account_exists (self, account, FALSE)) {
1402                 g_printerr ("modest: default account does not exist\n");
1403                 g_free (account);
1404                 return NULL;
1405         }
1406
1407         return account;
1408 }
1409
1410 static gboolean
1411 modest_account_mgr_unset_default_account (ModestAccountMgr *self)
1412 {
1413         ModestConf *conf;
1414         gboolean retval;
1415         
1416         g_return_val_if_fail (self,    FALSE);
1417
1418         conf = MODEST_ACCOUNT_MGR_GET_PRIVATE (self)->modest_conf;
1419                 
1420         retval = modest_conf_remove_key (conf, MODEST_CONF_DEFAULT_ACCOUNT, NULL /* err */);
1421
1422         if (retval)
1423                 g_signal_emit (G_OBJECT(self), signals[DEFAULT_ACCOUNT_CHANGED_SIGNAL], 0);
1424
1425         return retval;
1426 }
1427
1428
1429 gchar* 
1430 modest_account_mgr_get_display_name (ModestAccountMgr *self, 
1431                                      const gchar* name)
1432 {
1433         return modest_account_mgr_get_string (self, name, MODEST_ACCOUNT_DISPLAY_NAME, FALSE);
1434 }
1435
1436 void 
1437 modest_account_mgr_set_display_name (ModestAccountMgr *self, 
1438                                      const gchar *account_name,
1439                                      const gchar *display_name)
1440 {
1441         modest_account_mgr_set_string (self, 
1442                                        account_name,
1443                                        MODEST_ACCOUNT_DISPLAY_NAME, 
1444                                        display_name, 
1445                                        FALSE /* not server account */);
1446
1447         /* Notify about the change in the display name */
1448         g_signal_emit (self, signals[DISPLAY_NAME_CHANGED_SIGNAL], 0, account_name);
1449 }