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