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