+
+gchar*
+_modest_account_mgr_account_from_key (const gchar *key, gboolean *is_account_key, gboolean *is_server_account)
+{
+ /* Initialize input parameters: */
+ if (is_account_key)
+ *is_account_key = FALSE;
+
+ if (is_server_account)
+ *is_server_account = FALSE;
+
+ const gchar* account_ns = MODEST_ACCOUNT_NAMESPACE "/";
+ const gchar* server_account_ns = MODEST_SERVER_ACCOUNT_NAMESPACE "/";
+ gchar *cursor;
+ gchar *account = NULL;
+
+ /* determine whether it's an account or a server account,
+ * based on the prefix */
+ if (g_str_has_prefix (key, account_ns)) {
+
+ if (is_server_account)
+ *is_server_account = FALSE;
+
+ account = g_strdup (key + strlen (account_ns));
+
+ } else if (g_str_has_prefix (key, server_account_ns)) {
+
+ if (is_server_account)
+ *is_server_account = TRUE;
+
+ account = g_strdup (key + strlen (server_account_ns));
+ } else
+ return NULL;
+
+ /* if there are any slashes left in the key, it's not
+ * the toplevel entry for an account
+ */
+ cursor = strstr(account, "/");
+
+ if (is_account_key && cursor)
+ *is_account_key = TRUE;
+
+ /* put a NULL where the first slash was */
+ if (cursor)
+ *cursor = '\0';
+
+ if (account) {
+ /* The key is an escaped string, so unescape it to get the actual account name: */
+ gchar *unescaped_name = modest_conf_key_unescape (account);
+ g_free (account);
+ return unescaped_name;
+ } else
+ return NULL;
+}
+
+
+
+
+
+/* optimization: only with non-alphanum chars, escaping is needed */
+inline static gboolean
+is_alphanum (const gchar* str)
+{
+ const gchar *cursor;
+ for (cursor = str; cursor && *cursor; ++cursor) {
+ const char c = *cursor;
+ /* we cannot trust isalnum(3), because it might consider locales */
+ /* numbers ALPHA alpha */
+ if (!((c>=48 && c<=57)||(c>=65 && c<=90)||(c>=97 && c<=122)))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+
+
+/* must be freed by caller */
+gchar *
+_modest_account_mgr_get_account_keyname (const gchar *account_name, const gchar* name,
+ gboolean server_account)
+{
+ gchar *retval = NULL;
+ gchar *namespace = server_account ? MODEST_SERVER_ACCOUNT_NAMESPACE : MODEST_ACCOUNT_NAMESPACE;
+ gchar *escaped_account_name, *escaped_name;
+
+ if (!account_name)
+ return g_strdup (namespace);
+
+ /* optimization: only escape names when need to be escaped */
+ if (is_alphanum (account_name))
+ escaped_account_name = (gchar*)account_name;
+ else
+ escaped_account_name = modest_conf_key_escape (account_name);
+
+ if (is_alphanum (name))
+ escaped_name = (gchar*)name;
+ else
+ escaped_name = modest_conf_key_escape (name);
+ //////////////////////////////////////////////////////////////
+
+ if (escaped_account_name && escaped_name)
+ retval = g_strconcat (namespace, "/", escaped_account_name, "/", escaped_name, NULL);
+ else if (escaped_account_name)
+ retval = g_strconcat (namespace, "/", escaped_account_name, NULL);
+
+ /* Sanity check: */
+ if (!retval || !modest_conf_key_is_valid (retval)) {
+ g_warning ("%s: Generated conf key was invalid: %s", __FUNCTION__,
+ retval ? retval: "<empty>");
+ g_free (retval);
+ retval = NULL;
+ }
+
+ /* g_free is only needed if we actually allocated anything */
+ if (name != escaped_name)
+ g_free (escaped_name);
+ if (account_name != escaped_account_name)
+ g_free (escaped_account_name);
+
+ return retval;
+}
+
+static const gchar *
+_modest_account_mgr_get_account_keyname_cached (ModestAccountMgrPrivate *priv,
+ const gchar* account_name,
+ const gchar *name,
+ gboolean is_server)
+{
+ GHashTable *hash = is_server ? priv->server_account_key_hash : priv->account_key_hash;
+ GHashTable *account_hash;
+ gchar *key = NULL;
+ const gchar *search_name;
+
+ if (!account_name)
+ return is_server ? MODEST_SERVER_ACCOUNT_NAMESPACE : MODEST_ACCOUNT_NAMESPACE;
+
+ search_name = name ? name : "<dummy>";
+
+ account_hash = g_hash_table_lookup (hash, account_name);
+ if (!account_hash) { /* no hash for this account yet? create it */
+ account_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+ key = _modest_account_mgr_get_account_keyname (account_name, name, is_server);
+ g_hash_table_insert (account_hash, g_strdup(search_name), key);
+ g_hash_table_insert (hash, g_strdup(account_name), account_hash);
+ return key;
+ }
+
+ /* we have a hash for this account, but do we have the key? */
+ key = g_hash_table_lookup (account_hash, search_name);
+ if (!key) {
+ key = _modest_account_mgr_get_account_keyname (account_name, name, is_server);
+ g_hash_table_insert (account_hash, g_strdup(search_name), key);
+ }
+
+ return key;
+}
+
+
+gboolean
+modest_account_mgr_has_accounts (ModestAccountMgr* self, gboolean enabled)
+{
+ ModestAccountMgrPrivate* priv;
+ GSList *account_names;
+ gboolean accounts_exist;
+
+ g_return_val_if_fail (MODEST_IS_ACCOUNT_MGR(self), FALSE);
+
+ priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
+
+ if (enabled && priv->has_enabled_accounts)
+ return TRUE;
+ else if (priv->has_accounts)
+ return TRUE;
+
+ /* Check that at least one account exists: */
+ account_names = modest_account_mgr_account_names (self,enabled);
+ accounts_exist = account_names != NULL;
+ modest_account_mgr_free_account_names (account_names);
+ account_names = NULL;
+
+ /* cache it. */
+ if (enabled)
+ priv->has_enabled_accounts = accounts_exist;
+ else
+ priv->has_accounts = accounts_exist;
+
+ return accounts_exist;
+}
+
+static int
+compare_account_name(gconstpointer a, gconstpointer b)
+{
+ const gchar* account_name = (const gchar*) a;
+ const gchar* account_name2 = (const gchar*) b;
+ return strcmp(account_name, account_name2);
+}
+
+void
+modest_account_mgr_set_account_busy(ModestAccountMgr* self,
+ const gchar* account_name,
+ gboolean busy)
+{
+ ModestAccountMgrPrivate* priv;
+
+ g_return_if_fail (MODEST_IS_ACCOUNT_MGR(self));
+ g_return_if_fail (account_name);
+
+ priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
+ if (busy) {
+ GSList *account_names = modest_account_mgr_account_names (self, TRUE);
+ GSList* account = g_slist_find_custom(account_names, account_name,
+ (GCompareFunc) compare_account_name);
+
+ if (account && !modest_account_mgr_account_is_busy(self, account_name)) {
+ priv->busy_accounts = g_slist_append(priv->busy_accounts, g_strdup(account_name));
+ g_signal_emit (G_OBJECT(self), signals[ACCOUNT_BUSY_SIGNAL],
+ 0, account_name, TRUE);
+ }
+ modest_account_mgr_free_account_names (account_names);
+ account_names = NULL;
+ } else {
+ GSList* account =
+ g_slist_find_custom(priv->busy_accounts, account_name, (GCompareFunc) compare_account_name);
+
+ if (account) {
+ g_free(account->data);
+ priv->busy_accounts = g_slist_delete_link(priv->busy_accounts, account);
+ g_signal_emit (G_OBJECT(self), signals[ACCOUNT_BUSY_SIGNAL],
+ 0, account_name, FALSE);
+ }
+ }
+}
+
+gboolean
+modest_account_mgr_account_is_busy (ModestAccountMgr* self, const gchar* account_name)
+{
+ ModestAccountMgrPrivate* priv;
+
+ g_return_val_if_fail (MODEST_IS_ACCOUNT_MGR(self), FALSE);
+ g_return_val_if_fail (account_name, FALSE);
+
+ priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
+
+ return (g_slist_find_custom(priv->busy_accounts, account_name, (GCompareFunc) compare_account_name)
+ != NULL);
+}
+
+void
+modest_account_mgr_notify_account_update (ModestAccountMgr* self,
+ const gchar *server_account_name)
+{
+ ModestTransportStoreProtocol proto;
+ ModestAccountMgrPrivate* priv;
+ gchar *proto_name = NULL;
+
+ g_return_if_fail (self);
+ g_return_if_fail (server_account_name);
+
+ priv = MODEST_ACCOUNT_MGR_GET_PRIVATE (self);
+
+ /* Get protocol */
+ proto_name = modest_account_mgr_get_string (self, server_account_name,
+ MODEST_ACCOUNT_PROTO, TRUE);
+ if (!proto_name) {
+ g_free (proto_name);
+ g_return_if_reached ();
+ }
+ proto = modest_protocol_info_get_transport_store_protocol (proto_name);
+ g_free (proto_name);
+
+ /* there is some update in the account, so we can't
+ * be sure about whether there are still enabled accounts...
+ */
+ priv->has_enabled_accounts = FALSE;
+ priv->has_accounts = FALSE;
+
+ /* Emit "update-account" */
+ g_signal_emit (G_OBJECT(self),
+ signals[ACCOUNT_CHANGED_SIGNAL], 0,
+ server_account_name,
+ (modest_protocol_info_protocol_is_store (proto)) ?
+ TNY_ACCOUNT_TYPE_STORE :
+ TNY_ACCOUNT_TYPE_TRANSPORT);
+}
+
+
+gboolean
+modest_account_mgr_set_default_account (ModestAccountMgr *self, const gchar* account)
+{
+ ModestConf *conf;
+ gboolean retval;
+
+ g_return_val_if_fail (self, FALSE);
+ g_return_val_if_fail (account, FALSE);
+ g_return_val_if_fail (modest_account_mgr_account_exists (self, account, FALSE),
+ FALSE);
+
+ conf = MODEST_ACCOUNT_MGR_GET_PRIVATE (self)->modest_conf;
+
+ /* Change the default account and notify */
+ retval = modest_conf_set_string (conf, MODEST_CONF_DEFAULT_ACCOUNT, account, NULL);
+ if (retval)
+ g_signal_emit (G_OBJECT(self), signals[DEFAULT_ACCOUNT_CHANGED_SIGNAL], 0);
+
+ return retval;
+}
+
+
+gchar*
+modest_account_mgr_get_default_account (ModestAccountMgr *self)
+{
+ gchar *account;
+ ModestConf *conf;
+ GError *err = NULL;
+
+ g_return_val_if_fail (self, NULL);
+
+ conf = MODEST_ACCOUNT_MGR_GET_PRIVATE (self)->modest_conf;
+ account = modest_conf_get_string (conf, MODEST_CONF_DEFAULT_ACCOUNT, &err);
+
+ if (err) {
+ g_printerr ("modest: failed to get '%s': %s\n",
+ MODEST_CONF_DEFAULT_ACCOUNT, err->message);
+ g_error_free (err);
+ g_free (account);
+ return NULL;
+ }
+
+ /* sanity check */
+ if (account && !modest_account_mgr_account_exists (self, account, FALSE)) {
+ g_printerr ("modest: default account does not exist\n");
+ g_free (account);
+ return NULL;
+ }
+
+ return account;
+}
+
+static gboolean
+modest_account_mgr_unset_default_account (ModestAccountMgr *self)
+{
+ ModestConf *conf;
+ gboolean retval;
+
+ g_return_val_if_fail (self, FALSE);
+
+ conf = MODEST_ACCOUNT_MGR_GET_PRIVATE (self)->modest_conf;
+
+ retval = modest_conf_remove_key (conf, MODEST_CONF_DEFAULT_ACCOUNT, NULL /* err */);
+
+ if (retval)
+ g_signal_emit (G_OBJECT(self), signals[DEFAULT_ACCOUNT_CHANGED_SIGNAL], 0);
+
+ return retval;
+}
+
+
+gchar*
+modest_account_mgr_get_display_name (ModestAccountMgr *self,
+ const gchar* name)
+{
+ return modest_account_mgr_get_string (self, name, MODEST_ACCOUNT_DISPLAY_NAME, FALSE);
+}
+
+void
+modest_account_mgr_set_display_name (ModestAccountMgr *self,
+ const gchar *account_name,
+ const gchar *display_name)
+{
+ gboolean notify = TRUE;
+
+ if (!modest_account_mgr_get_display_name (self, account_name))
+ notify = FALSE;
+
+ modest_account_mgr_set_string (self,
+ account_name,
+ MODEST_ACCOUNT_DISPLAY_NAME,
+ display_name,
+ FALSE /* not server account */);
+
+ /* Notify about the change in the display name */
+ if (notify)
+ g_signal_emit (self, signals[DISPLAY_NAME_CHANGED_SIGNAL], 0, account_name);
+}