2007-05-24 Murray Cumming <murrayc@murrayc.com>
[modest] / src / modest-account-mgr-helpers.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 <modest-account-mgr-helpers.h>
31 #include <modest-account-mgr-priv.h>
32 #include <tny-simple-list.h>
33 #include <modest-runtime.h>
34 #include <string.h>
35
36 gboolean
37 modest_account_mgr_set_enabled (ModestAccountMgr *self, const gchar* name,
38                                         gboolean enabled)
39 {
40         return modest_account_mgr_set_bool (self, name, MODEST_ACCOUNT_ENABLED, enabled,FALSE);
41 }
42
43
44 gboolean
45 modest_account_mgr_get_enabled (ModestAccountMgr *self, const gchar* name)
46 {
47         return modest_account_mgr_get_bool (self, name, MODEST_ACCOUNT_ENABLED, FALSE);
48 }
49
50 gboolean modest_account_mgr_set_signature (ModestAccountMgr *self, const gchar* name, 
51         const gchar* signature, gboolean use_signature)
52 {
53         gboolean result = modest_account_mgr_set_bool (self, name, MODEST_ACCOUNT_USE_SIGNATURE, 
54                 use_signature, FALSE);
55         result = result && modest_account_mgr_set_string (self, name, MODEST_ACCOUNT_SIGNATURE, 
56                 signature, FALSE);
57         return result;
58 }
59
60 gchar* modest_account_mgr_get_display_name (ModestAccountMgr *self, 
61         const gchar* name)
62 {
63         return modest_account_mgr_get_string (self, name, MODEST_ACCOUNT_DISPLAY_NAME, FALSE);
64 }
65
66
67
68 gchar* modest_account_mgr_get_signature (ModestAccountMgr *self, const gchar* name, 
69         gboolean* use_signature)
70 {
71         if (use_signature) {
72                 *use_signature = 
73                         modest_account_mgr_get_bool (self, name, MODEST_ACCOUNT_USE_SIGNATURE, FALSE);
74         }
75         
76         return modest_account_mgr_get_string (self, name, MODEST_ACCOUNT_SIGNATURE, FALSE);
77 }
78         
79
80 gboolean modest_account_mgr_set_connection_specific_smtp (ModestAccountMgr *self, 
81         const gchar* account_name,
82         const gchar* connection_name, const gchar* server_account_name)
83 {
84         modest_account_mgr_remove_connection_specific_smtp (self, account_name, connection_name);
85         
86         GSList *list = modest_account_mgr_get_list (self, account_name, 
87                                                         MODEST_ACCOUNT_CONNECTION_SPECIFIC_SMTP_LIST,
88                                                     MODEST_CONF_VALUE_STRING, TRUE);
89                 
90         /* The server account is in the item after the connection name: */
91         GSList *list_connection = g_slist_append (list, (gpointer)connection_name);
92         list_connection = g_slist_append (list_connection, (gpointer)server_account_name);
93         
94         /* Reset the changed list: */
95         modest_account_mgr_set_list (self, account_name, 
96                                                         MODEST_ACCOUNT_CONNECTION_SPECIFIC_SMTP_LIST, list,
97                                                     MODEST_CONF_VALUE_STRING, TRUE);
98                                 
99         /* TODO: Should we free the items too, or just the list? */
100         g_slist_free (list);
101         
102         return TRUE;
103 }
104
105 /**
106  * modest_account_mgr_remove_connection_specific_smtp
107  * @self: a ModestAccountMgr instance
108  * @name: the account name
109  * @connection_name: A libconic IAP connection name
110  * 
111  * Disassacoiate a server account to use with the specific connection for this account.
112  *
113  * Returns: TRUE if it worked, FALSE otherwise
114  */                              
115 gboolean modest_account_mgr_remove_connection_specific_smtp (ModestAccountMgr *self, 
116         const gchar* account_name, const gchar* connection_name)
117 {
118         GSList *list = modest_account_mgr_get_list (self, account_name, 
119                                                         MODEST_ACCOUNT_CONNECTION_SPECIFIC_SMTP_LIST,
120                                                     MODEST_CONF_VALUE_STRING, TRUE);
121         if (!list)
122                 return FALSE;
123                 
124         /* The server account is in the item after the connection name: */
125         GSList *list_connection = g_slist_find_custom (list, connection_name, (GCompareFunc)strcmp);
126         if (list_connection) {
127                 /* remove both items: */
128                 GSList *temp = g_slist_delete_link(list_connection, list_connection);
129                 temp = g_slist_delete_link(temp, g_slist_next(temp));
130         }
131         
132         /* Reset the changed list: */
133         modest_account_mgr_set_list (self, account_name, 
134                                                         MODEST_ACCOUNT_CONNECTION_SPECIFIC_SMTP_LIST, list,
135                                                     MODEST_CONF_VALUE_STRING, TRUE);
136                                 
137         /* TODO: Should we free the items too, or just the list? */
138         g_slist_free (list);
139         
140         return TRUE;
141 }
142
143 /**
144  * modest_account_mgr_get_connection_specific_smtp
145  * @self: a ModestAccountMgr instance
146  * @name: the account name
147  * @connection_name: A libconic IAP connection name
148  * 
149  * Retrieve a server account to use with this specific connection for this account.
150  *
151  * Returns: a server account name to use for this connection, or NULL if none is specified.
152  */                      
153 gchar* modest_account_mgr_get_connection_specific_smtp (ModestAccountMgr *self, const gchar* account_name,
154                                          const gchar* connection_name)
155 {
156         gchar *result = NULL;
157         
158         GSList *list = modest_account_mgr_get_list (self, account_name, 
159                                                         MODEST_ACCOUNT_CONNECTION_SPECIFIC_SMTP_LIST,
160                                                     MODEST_CONF_VALUE_STRING, TRUE);
161         if (!list)
162                 return NULL;
163                 
164         /* The server account is in the item after the connection name: */
165         GSList *list_connection = g_slist_find_custom (list, connection_name, (GCompareFunc)strcmp);
166         if (list_connection) {
167                 GSList * list_server_account = g_slist_next(list_connection);
168                 if (list_server_account)
169                         result = g_strdup ((gchar*)(list_server_account->data));
170         }
171                                 
172         /* TODO: Should we free the items too, or just the list? */
173         g_slist_free (list);
174         
175         return result;
176 }
177                                          
178 gchar*
179 modest_server_account_get_username (ModestAccountMgr *self, const gchar* account_name)
180 {
181         return modest_account_mgr_get_string (self, account_name, MODEST_ACCOUNT_USERNAME, 
182                 TRUE /* server account */);
183 }
184
185 void
186 modest_server_account_set_username (ModestAccountMgr *self, const gchar* account_name, 
187         const gchar* username)
188 {
189         /* Note that this won't work properly as long as the gconf cache is broken 
190          * in Maemo Bora: */
191         gchar *existing_username = modest_server_account_get_username(self, 
192                 account_name);
193         
194         modest_account_mgr_set_string (self, account_name, MODEST_ACCOUNT_USERNAME, 
195                 username, TRUE /* server account */);
196                 
197         /* We don't know anything about new usernames: */
198         if (strcmp (existing_username, username) != 0)
199                 modest_server_account_set_username_has_succeeded (self, 
200                 account_name, FALSE);
201                 
202         g_free (existing_username);
203 }
204
205 gboolean
206 modest_server_account_get_username_has_succeeded (ModestAccountMgr *self, const gchar* account_name)
207 {
208         return modest_account_mgr_get_bool (self, account_name, MODEST_ACCOUNT_USERNAME_HAS_SUCCEEDED, 
209                 TRUE /* server account */);
210 }
211
212 void
213 modest_server_account_set_username_has_succeeded (ModestAccountMgr *self, const gchar* account_name, 
214         gboolean succeeded)
215 {
216         modest_account_mgr_set_bool (self, account_name, MODEST_ACCOUNT_USERNAME_HAS_SUCCEEDED, 
217                 succeeded, TRUE /* server account */);
218 }
219
220 void
221 modest_server_account_set_password (ModestAccountMgr *self, const gchar* account_name, 
222         const gchar* password)
223 {
224         modest_account_mgr_set_string (self, account_name, MODEST_ACCOUNT_PASSWORD, 
225                 password, TRUE /* server account */);
226 }
227         
228 gchar*
229 modest_server_account_get_hostname (ModestAccountMgr *self, const gchar* account_name)
230 {
231         return modest_account_mgr_get_string (self, account_name, MODEST_ACCOUNT_HOSTNAME, 
232                 TRUE /* server account */);
233 }
234  
235
236 static ModestAuthProtocol
237 get_secure_auth_for_conf_string(const gchar* value)
238 {
239         ModestAuthProtocol result = MODEST_PROTOCOL_AUTH_NONE;
240         if (value) {
241                 if (strcmp(value, MODEST_ACCOUNT_AUTH_MECH_VALUE_NONE) == 0)
242                         result = MODEST_PROTOCOL_AUTH_NONE;
243                 else if (strcmp(value, MODEST_ACCOUNT_AUTH_MECH_VALUE_PASSWORD) == 0)
244                         result = MODEST_PROTOCOL_AUTH_PASSWORD;
245                 else if (strcmp(value, MODEST_ACCOUNT_AUTH_MECH_VALUE_CRAMMD5) == 0)
246                         result = MODEST_PROTOCOL_AUTH_CRAMMD5;
247         }
248         
249         return result;
250 }
251
252 ModestAuthProtocol
253 modest_server_account_get_secure_auth (ModestAccountMgr *self, 
254         const gchar* account_name)
255 {
256         ModestAuthProtocol result = MODEST_PROTOCOL_AUTH_NONE;
257         gchar* value = modest_account_mgr_get_string (self, account_name, MODEST_ACCOUNT_AUTH_MECH, 
258                 TRUE /* server account */);
259         if (value) {
260                 result = get_secure_auth_for_conf_string (value);
261                         
262                 g_free (value);
263         }
264         
265         return result;
266 }
267
268
269 void
270 modest_server_account_set_secure_auth (ModestAccountMgr *self, 
271         const gchar* account_name, ModestAuthProtocol secure_auth)
272 {
273         /* Get the conf string for the enum value: */
274         const gchar* str_value = NULL;
275         if (secure_auth == MODEST_PROTOCOL_AUTH_NONE)
276                 str_value = MODEST_ACCOUNT_AUTH_MECH_VALUE_NONE;
277         else if (secure_auth == MODEST_PROTOCOL_AUTH_PASSWORD)
278                 str_value = MODEST_ACCOUNT_AUTH_MECH_VALUE_PASSWORD;
279         else if (secure_auth == MODEST_PROTOCOL_AUTH_CRAMMD5)
280                 str_value = MODEST_ACCOUNT_AUTH_MECH_VALUE_CRAMMD5;
281         
282         /* Set it in the configuration: */
283         modest_account_mgr_set_string (self, account_name, MODEST_ACCOUNT_AUTH_MECH, str_value, TRUE);
284 }
285
286 static ModestConnectionProtocol
287 get_security_for_conf_string(const gchar* value)
288 {
289         ModestConnectionProtocol result = MODEST_PROTOCOL_CONNECTION_NORMAL;
290         if (value) {
291                 if (strcmp(value, MODEST_ACCOUNT_SECURITY_VALUE_NONE) == 0)
292                         result = MODEST_PROTOCOL_CONNECTION_NORMAL;
293                 else if (strcmp(value, MODEST_ACCOUNT_SECURITY_VALUE_NORMAL) == 0)
294                         result = MODEST_PROTOCOL_CONNECTION_TLS;
295                 else if (strcmp(value, MODEST_ACCOUNT_SECURITY_VALUE_SSL) == 0)
296                         result = MODEST_PROTOCOL_CONNECTION_SSL;
297         }
298         
299         return result;
300 }
301
302 ModestConnectionProtocol
303 modest_server_account_get_security (ModestAccountMgr *self, 
304         const gchar* account_name)
305 {
306         ModestConnectionProtocol result = MODEST_PROTOCOL_CONNECTION_NORMAL;
307         gchar* value = modest_account_mgr_get_string (self, account_name, MODEST_ACCOUNT_SECURITY, 
308                 TRUE /* server account */);
309         if (value) {
310                 result = get_security_for_conf_string (value);
311                         
312                 g_free (value);
313         }
314         
315         return result;
316 }
317
318 void
319 modest_server_account_set_security (ModestAccountMgr *self, 
320         const gchar* account_name, ModestConnectionProtocol security)
321 {
322         /* Get the conf string for the enum value: */
323         const gchar* str_value = NULL;
324         if (security == MODEST_PROTOCOL_CONNECTION_NORMAL)
325                 str_value = MODEST_ACCOUNT_SECURITY_VALUE_NONE;
326         else if (security == MODEST_PROTOCOL_CONNECTION_TLS)
327                 str_value = MODEST_ACCOUNT_SECURITY_VALUE_NORMAL;
328         else if (security == MODEST_PROTOCOL_CONNECTION_SSL)
329                 str_value = MODEST_ACCOUNT_SECURITY_VALUE_SSL;
330         
331         /* Set it in the configuration: */
332         modest_account_mgr_set_string (self, account_name, MODEST_ACCOUNT_SECURITY, str_value, TRUE);
333 }
334
335 ModestServerAccountData*
336 modest_account_mgr_get_server_account_data (ModestAccountMgr *self, const gchar* name)
337 {
338         ModestServerAccountData *data;
339         gchar *proto;
340         
341         g_return_val_if_fail (modest_account_mgr_account_exists (self, name, TRUE), NULL);      
342         data = g_slice_new0 (ModestServerAccountData);
343         
344         data->account_name = g_strdup (name);
345         data->hostname     = modest_account_mgr_get_string (self, name, MODEST_ACCOUNT_HOSTNAME,TRUE);
346         data->username     = modest_account_mgr_get_string (self, name, MODEST_ACCOUNT_USERNAME,TRUE);  
347         proto              = modest_account_mgr_get_string (self, name, MODEST_ACCOUNT_PROTO, TRUE);
348         data->proto        = modest_protocol_info_get_transport_store_protocol (proto);
349         g_free (proto);
350
351         data->port         = modest_account_mgr_get_int (self, name, MODEST_ACCOUNT_PORT, TRUE);
352         
353         gchar *secure_auth_str = modest_account_mgr_get_string (self, name, MODEST_ACCOUNT_AUTH_MECH, TRUE);
354         data->secure_auth  = get_secure_auth_for_conf_string(secure_auth_str);
355         g_free (secure_auth_str);
356                 
357         gchar *security_str = modest_account_mgr_get_string (self, name, MODEST_ACCOUNT_SECURITY, TRUE);
358         data->security     = get_security_for_conf_string(security_str);
359         g_free (security_str);
360         
361         data->last_updated = modest_account_mgr_get_int    (self, name, MODEST_ACCOUNT_LAST_UPDATED,TRUE);
362         
363         data->password     = modest_account_mgr_get_string (self, name, MODEST_ACCOUNT_PASSWORD, TRUE);            
364         
365         return data;
366 }
367
368
369 void
370 modest_account_mgr_free_server_account_data (ModestAccountMgr *self,
371                                              ModestServerAccountData* data)
372 {
373         g_return_if_fail (self);
374
375         if (!data)
376                 return; /* not an error */
377
378         g_free (data->account_name);
379         data->account_name = NULL;
380         
381         g_free (data->hostname);
382         data->hostname = NULL;
383         
384         g_free (data->username);
385         data->username = NULL;
386
387         g_free (data->password);
388         data->password = NULL;
389
390         g_slice_free (ModestServerAccountData, data);
391 }
392
393 /** You must use modest_account_mgr_free_account_data() on the result.
394  */
395 ModestAccountData*
396 modest_account_mgr_get_account_data     (ModestAccountMgr *self, const gchar* name)
397 {
398         ModestAccountData *data;
399         gchar *server_account;
400         gchar *default_account;
401         
402         g_return_val_if_fail (self, NULL);
403         g_return_val_if_fail (name, NULL);
404         
405         if (!modest_account_mgr_account_exists (self, name, FALSE)) {
406                 /* For instance, maybe you are mistakenly checking for a server account name? */
407                 g_warning ("%s: Account %s does not exist.", __FUNCTION__, name);
408                 return NULL;
409         }
410         
411         data = g_slice_new0 (ModestAccountData);
412         
413         data->account_name = g_strdup (name);
414
415         data->display_name = modest_account_mgr_get_string (self, name,
416                                                             MODEST_ACCOUNT_DISPLAY_NAME,
417                                                             FALSE);
418         data->fullname     = modest_account_mgr_get_string (self, name,
419                                                               MODEST_ACCOUNT_FULLNAME,
420                                                                FALSE);
421         data->email        = modest_account_mgr_get_string (self, name,
422                                                             MODEST_ACCOUNT_EMAIL,
423                                                             FALSE);
424         data->is_enabled   = modest_account_mgr_get_enabled (self, name);
425
426         default_account    = modest_account_mgr_get_default_account (self);
427         data->is_default   = (default_account && strcmp (default_account, name) == 0);
428         g_free (default_account);
429
430         /* store */
431         server_account     = modest_account_mgr_get_string (self, name,
432                                                             MODEST_ACCOUNT_STORE_ACCOUNT,
433                                                             FALSE);
434         if (server_account) {
435                 data->store_account =
436                         modest_account_mgr_get_server_account_data (self, server_account);
437                 g_free (server_account);
438         }
439
440         /* transport */
441         server_account = modest_account_mgr_get_string (self, name,
442                                                         MODEST_ACCOUNT_TRANSPORT_ACCOUNT,
443                                                         FALSE);
444         if (server_account) {
445                 data->transport_account =
446                         modest_account_mgr_get_server_account_data (self, server_account);
447                 g_free (server_account);
448         }
449
450         return data;
451 }
452
453
454 void
455 modest_account_mgr_free_account_data (ModestAccountMgr *self, ModestAccountData *data)
456 {
457         g_return_if_fail (self);
458
459         if (!data) /* not an error */ 
460                 return;
461
462         g_free (data->account_name);
463         g_free (data->display_name);
464         g_free (data->fullname);
465         g_free (data->email);
466
467         modest_account_mgr_free_server_account_data (self, data->store_account);
468         modest_account_mgr_free_server_account_data (self, data->transport_account);
469         
470         g_slice_free (ModestAccountData, data);
471 }
472
473
474 gchar*
475 modest_account_mgr_get_default_account  (ModestAccountMgr *self)
476 {
477         gchar *account; 
478         ModestConf *conf;
479         GError *err = NULL;
480         
481         g_return_val_if_fail (self, NULL);
482
483         conf = MODEST_ACCOUNT_MGR_GET_PRIVATE (self)->modest_conf;
484         account = modest_conf_get_string (conf, MODEST_CONF_DEFAULT_ACCOUNT, &err);
485         
486         if (err) {
487                 g_printerr ("modest: failed to get '%s': %s\n",
488                             MODEST_CONF_DEFAULT_ACCOUNT, err->message);
489                 g_error_free (err);
490                 g_free (account);
491                 return  NULL;
492         }
493         
494         /* Make sure that at least one account is always the default, if possible:
495          * (It would be meaningless to have enabled accounts but no default account. */
496         if (!account) {
497                 modest_account_mgr_set_first_account_as_default (self);
498                 account = modest_conf_get_string (conf, MODEST_CONF_DEFAULT_ACCOUNT, &err);
499         }
500
501         /* sanity check */
502         if (!modest_account_mgr_account_exists (self, account, FALSE)) {
503                 g_printerr ("modest: default account does not exist\n");
504                 g_free (account);
505                 return NULL;
506         }
507
508         return account;
509 }
510
511
512 gboolean
513 modest_account_mgr_set_default_account  (ModestAccountMgr *self, const gchar* account)
514 {
515         ModestConf *conf;
516         
517         g_return_val_if_fail (self,    FALSE);
518         g_return_val_if_fail (account, FALSE);
519         g_return_val_if_fail (modest_account_mgr_account_exists (self, account, FALSE),
520                               FALSE);
521         
522         conf = MODEST_ACCOUNT_MGR_GET_PRIVATE (self)->modest_conf;
523                 
524         return modest_conf_set_string (conf, MODEST_CONF_DEFAULT_ACCOUNT,
525                                        account, NULL);
526
527 }
528
529 gboolean
530 modest_account_mgr_unset_default_account  (ModestAccountMgr *self)
531 {
532         ModestConf *conf;
533         
534         g_return_val_if_fail (self,    FALSE);
535
536         conf = MODEST_ACCOUNT_MGR_GET_PRIVATE (self)->modest_conf;
537                 
538         return modest_conf_remove_key (conf, MODEST_CONF_DEFAULT_ACCOUNT, NULL /* err */);
539
540 }
541
542 gint on_accounts_list_sort_by_title(gconstpointer a, gconstpointer b)
543 {
544         return g_utf8_collate((const gchar*)a, (const gchar*)b);
545 }
546
547 gboolean
548 modest_account_mgr_set_first_account_as_default  (ModestAccountMgr *self)
549 {
550         gboolean result = FALSE;
551         GSList *account_names = modest_account_mgr_account_names (self, TRUE /* only enabled */);
552         
553         /* Get the first one, alphabetically, by title: */
554         GSList* list_sorted = g_slist_sort (account_names, 
555                 on_accounts_list_sort_by_title);
556         if(list_sorted)
557         {
558                 const gchar* account_name = (const gchar*)list_sorted->data;
559                 if (account_name) 
560                         result = modest_account_mgr_set_default_account (self, account_name);
561         }
562         
563         /* TODO: Free the strings too? */
564         g_slist_free (account_names);
565         
566         return result;
567 }
568
569 gchar*
570 modest_account_mgr_get_from_string (ModestAccountMgr *self, const gchar* name)
571 {
572         gchar *fullname, *email, *from;
573         
574         g_return_val_if_fail (self, NULL);
575         g_return_val_if_fail (name, NULL);
576
577         fullname      = modest_account_mgr_get_string (self, name,MODEST_ACCOUNT_FULLNAME,
578                                                        FALSE);
579         email         = modest_account_mgr_get_string (self, name, MODEST_ACCOUNT_EMAIL,
580                                                        FALSE);
581         from = g_strdup_printf ("%s <%s>",
582                                 fullname ? fullname : "",
583                                 email    ? email    : "");
584         g_free (fullname);
585         g_free (email);
586
587         return from;
588 }
589
590 /* Add a number to the end of the text, or increment a number that is already there.
591  */
592 static gchar*
593 util_increment_name (const gchar* text)
594 {
595         /* Get the end character,
596          * also doing a UTF-8 validation which is required for using g_utf8_prev_char().
597          */
598         const gchar* end = NULL;
599         if (!g_utf8_validate (text, -1, &end))
600                 return NULL;
601   
602         if (!end)
603                 return NULL;
604                 
605         --end; /* Go to before the null-termination. */
606                 
607         /* Look at each UTF-8 characer, starting at the end: */
608         const gchar* p = end;
609         const gchar* alpha_end = NULL;
610         while (p)
611         {       
612                 /* Stop when we reach the first character that is not a numeric digit: */
613                 const gunichar ch = g_utf8_get_char (p);
614                 if (!g_unichar_isdigit (ch)) {
615                         alpha_end = p;
616                         break;
617                 }
618                 
619                 p = g_utf8_prev_char (p);       
620         }
621         
622         if(!alpha_end) {
623                 /* The text must consist completely of numeric digits. */
624                 alpha_end = text;
625         }
626         else
627                 ++alpha_end;
628         
629         /* Intepret and increment the number, if any: */
630         gint num = atol (alpha_end);
631         ++num;
632         
633         /* Get the name part: */
634         gint name_len = alpha_end - text;
635         gchar *name_without_number = g_malloc(name_len + 1);
636         memcpy (name_without_number, text, name_len);
637         name_without_number[name_len] = 0;\
638         
639     /* Concatenate the text part and the new number: */ 
640         gchar *result = g_strdup_printf("%s%d", name_without_number, num);
641         g_free (name_without_number);
642         
643         return result;  
644 }
645
646 gchar*
647 modest_account_mgr_get_unused_account_name (ModestAccountMgr *self, const gchar* starting_name,
648         gboolean server_account)
649 {
650         gchar *account_name = g_strdup (starting_name);
651
652         while (modest_account_mgr_account_exists (self, 
653                 account_name, server_account /*  server_account */)) {
654                         
655                 gchar * account_name2 = util_increment_name (account_name);
656                 g_free (account_name);
657                 account_name = account_name2;
658         }
659         
660         return account_name;
661 }
662
663 gchar*
664 modest_account_mgr_get_unused_account_display_name (ModestAccountMgr *self, const gchar* starting_name)
665 {
666         gchar *account_name = g_strdup (starting_name);
667
668         while (modest_account_mgr_account_with_display_name_exists (self, account_name)) {
669                         
670                 gchar * account_name2 = util_increment_name (account_name);
671                 g_free (account_name);
672                 account_name = account_name2;
673         }
674         
675         return account_name;
676 }