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