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