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