# HG changeset patch # User Christian Hammond # Date 1054339031 0 # Node ID 5e7de337a05385d0c4ec9d1dd4e94619c04901e7 # Parent dfdea22a71532eacaf487d83369fa7da90c39251 [gaim-migrate @ 5976] Account saving and loading _mostly_ works. committer: Tailor Script diff -r dfdea22a7153 -r 5e7de337a053 src/account.c --- a/src/account.c Fri May 30 23:05:01 2003 +0000 +++ b/src/account.c Fri May 30 23:57:11 2003 +0000 @@ -1,4 +1,4 @@ -/** +/*if* * @file account.c Account API * @ingroup core * @@ -20,9 +20,32 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + #include "account.h" #include "prefs.h" +typedef enum +{ + TAG_PROTOCOL, + TAG_NAME, + TAG_PASSWORD, + TAG_ALIAS, + TAG_USERINFO, + TAG_BUDDYICON, + TAG_SETTING + +} AccountParserTag; + typedef struct { GaimPrefType type; @@ -37,7 +60,23 @@ } GaimAccountSetting; -static GList *accounts = NULL; +typedef struct +{ + AccountParserTag tag; + + GaimAccount *account; + GaimProtocol protocol; + + GString *buffer; + + GaimPrefType setting_type; + char *setting_name; + +} AccountParserData; + +static GList *accounts = NULL; +static guint accounts_save_timer = 0; +static gboolean accounts_loaded = FALSE; static void __delete_setting(void *data) @@ -50,6 +89,22 @@ g_free(setting); } +static gboolean +__accounts_save_cb(gpointer unused) +{ + gaim_accounts_sync(); + accounts_save_timer = 0; + + return FALSE; +} + +static void +schedule_accounts_save() +{ + if (!accounts_save_timer) + accounts_save_timer = g_timeout_add(5000, __accounts_save_cb, NULL); +} + GaimAccount * gaim_account_new(const char *username, GaimProtocol protocol) { @@ -127,6 +182,8 @@ g_free(account->username); account->username = (username == NULL ? NULL : g_strdup(username)); + + schedule_accounts_save(); } void @@ -139,6 +196,8 @@ g_free(account->password); account->password = (password == NULL ? NULL : g_strdup(password)); + + schedule_accounts_save(); } void @@ -151,6 +210,8 @@ g_free(account->alias); account->alias = (alias == NULL ? NULL : g_strdup(alias)); + + schedule_accounts_save(); } void @@ -163,6 +224,8 @@ g_free(account->user_info); account->user_info = (user_info == NULL ? NULL : g_strdup(user_info)); + + schedule_accounts_save(); } void @@ -175,6 +238,8 @@ g_free(account->buddy_icon); account->buddy_icon = (icon == NULL ? NULL : g_strdup(icon)); + + schedule_accounts_save(); } void @@ -183,6 +248,8 @@ g_return_if_fail(account != NULL); account->protocol = protocol; + + schedule_accounts_save(); } void @@ -192,6 +259,8 @@ g_return_if_fail(gc != NULL); account->gc = gc; + + schedule_accounts_save(); } void @@ -200,6 +269,8 @@ g_return_if_fail(account != NULL); account->remember_pass = value; + + schedule_accounts_save(); } void @@ -216,6 +287,8 @@ setting->value.integer = value; g_hash_table_insert(account->settings, g_strdup(name), setting); + + schedule_accounts_save(); } void @@ -233,6 +306,8 @@ setting->value.string = g_strdup(value); g_hash_table_insert(account->settings, g_strdup(name), setting); + + schedule_accounts_save(); } void @@ -249,6 +324,8 @@ setting->value.bool = value; g_hash_table_insert(account->settings, g_strdup(name), setting); + + schedule_accounts_save(); } gboolean @@ -389,6 +466,334 @@ return setting->value.bool; } +/* XML Stuff */ +static void +__free_parser_data(gpointer user_data) +{ + AccountParserData *data = user_data; + + if (data->buffer != NULL) + g_free(data->buffer); + + if (data->setting_name != NULL) + g_free(data->setting_name); + + g_free(data); +} + +static void +__start_element_handler(GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, GError **error) +{ + AccountParserData *data = user_data; + int i; + + if (data->buffer != NULL) { + g_string_free(data->buffer, TRUE); + data->buffer = NULL; + } + + if (!strcmp(element_name, "protocol")) + data->tag = TAG_PROTOCOL; + else if (!strcmp(element_name, "name")) + data->tag = TAG_NAME; + else if (!strcmp(element_name, "password")) + data->tag = TAG_PASSWORD; + else if (!strcmp(element_name, "alias")) + data->tag = TAG_ALIAS; + else if (!strcmp(element_name, "userinfo")) + data->tag = TAG_USERINFO; + else if (!strcmp(element_name, "buddyicon")) + data->tag = TAG_BUDDYICON; + else if (!strcmp(element_name, "setting")) { + data->tag = TAG_SETTING; + + for (i = 0; attribute_names[i] != NULL; i++) { + + if (!strcmp(attribute_names[i], "name")) + data->setting_name = g_strdup(attribute_values[i]); + else if (!strcmp(attribute_names[i], "type")) { + + if (!strcmp(attribute_values[i], "string")) + data->setting_type = GAIM_PREF_STRING; + else if (!strcmp(attribute_values[i], "int")) + data->setting_type = GAIM_PREF_INT; + else if (!strcmp(attribute_values[i], "bool")) + data->setting_type = GAIM_PREF_BOOLEAN; + } + } + } +} + +static void +__end_element_handler(GMarkupParseContext *context, const gchar *element_name, + gpointer user_data, GError **error) +{ + AccountParserData *data = user_data; + gchar *buffer; + + if (data->buffer == NULL) + return; + + buffer = g_string_free(data->buffer, FALSE); + data->buffer = NULL; + + if (data->tag == TAG_PROTOCOL) { + GList *l; + GaimPlugin *plugin; + + data->protocol = -1; + + for (l = gaim_plugins_get_protocols(); l != NULL; l = l->next) { + plugin = (GaimPlugin *)l->data; + + if (GAIM_IS_PROTOCOL_PLUGIN(plugin)) { + if (!strcmp(plugin->info->name, buffer)) { + data->protocol = + GAIM_PLUGIN_PROTOCOL_INFO(plugin)->protocol; + + break; + } + } + } + } + else if (data->tag == TAG_NAME) + data->account = gaim_account_new(buffer, data->protocol); + else if (data->tag == TAG_PASSWORD) + gaim_account_set_password(data->account, buffer); + else if (data->tag == TAG_ALIAS) + gaim_account_set_alias(data->account, buffer); + else if (data->tag == TAG_USERINFO) + gaim_account_set_user_info(data->account, buffer); + else if (data->tag == TAG_BUDDYICON) + gaim_account_set_buddy_icon(data->account, buffer); + else if (data->tag == TAG_SETTING) { + if (data->setting_type == GAIM_PREF_STRING) + gaim_account_set_string(data->account, data->setting_name, + buffer); + else if (data->setting_type == GAIM_PREF_INT) + gaim_account_set_int(data->account, data->setting_name, + atoi(buffer)); + else if (data->setting_type == GAIM_PREF_BOOLEAN) + gaim_account_set_bool(data->account, data->setting_name, + (*buffer == '0' ? FALSE : TRUE)); + + g_free(data->setting_name); + data->setting_name = NULL; + } + + g_free(buffer); +} + +static void +__text_handler(GMarkupParseContext *context, const gchar *text, + gsize text_len, gpointer user_data, GError **error) +{ + AccountParserData *data = user_data; + + if (data->buffer == NULL) + data->buffer = g_string_new_len(text, text_len); + else + g_string_append_len(data->buffer, text, text_len); +} + +static GMarkupParser accounts_parser = +{ + __start_element_handler, + __end_element_handler, + __text_handler, + NULL, + NULL +}; + +gboolean +gaim_accounts_load() +{ + gchar *filename = g_build_filename(gaim_user_dir(), "accounts.xml", NULL); + gchar *contents = NULL; + gsize length; + GMarkupParseContext *context; + GError *error = NULL; + AccountParserData *parser_data; + + if (filename == NULL) { + accounts_loaded = TRUE; + return FALSE; + } + + gaim_debug(GAIM_DEBUG_INFO, "accounts", "Reading %s\n", filename); + + if (!g_file_get_contents(filename, &contents, &length, &error)) { + gaim_debug(GAIM_DEBUG_ERROR, "accounts", + "Error reading accounts: %s\n", error->message); + + g_error_free(error); + + accounts_loaded = TRUE; + return FALSE; + } + + parser_data = g_new0(AccountParserData, 1); + + context = g_markup_parse_context_new(&accounts_parser, 0, + parser_data, __free_parser_data); + + if (!g_markup_parse_context_parse(context, contents, length, NULL)) { + g_markup_parse_context_free(context); + g_free(contents); + + accounts_loaded = TRUE; + + return FALSE; + } + + if (!g_markup_parse_context_end_parse(context, NULL)) { + gaim_debug(GAIM_DEBUG_ERROR, "accounts", "Error parsing %s\n", + filename); + + g_markup_parse_context_free(context); + g_free(contents); + accounts_loaded = TRUE; + + return FALSE; + } + + g_markup_parse_context_free(context); + g_free(contents); + + gaim_debug(GAIM_DEBUG_INFO, "accounts", "Finished reading %s\n", + filename); + g_free(filename); + + accounts_loaded = TRUE; + + return TRUE; +} + +static void +__write_setting(gpointer key, gpointer value, gpointer user_data) +{ + GaimAccountSetting *setting; + const char *name; + FILE *fp; + + setting = (GaimAccountSetting *)value; + name = (const char *)key; + fp = (FILE *)user_data; + + if (setting->type == GAIM_PREF_INT) { + fprintf(fp, " %d\n", + name, setting->value.integer); + } + else if (setting->type == GAIM_PREF_STRING) { + fprintf(fp, " %s\n", + name, setting->value.string); + } + else if (setting->type == GAIM_PREF_BOOLEAN) { + fprintf(fp, " %d\n", + name, setting->value.bool); + } +} + +static void +gaim_accounts_write(FILE *fp, GaimAccount *account) +{ + GaimPlugin *plugin; + const char *password, *alias, *user_info, *buddy_icon; + + plugin = gaim_find_prpl(gaim_account_get_protocol(account)); + + fprintf(fp, " \n"); + fprintf(fp, " %s\n", + (plugin != NULL && plugin->info != NULL && plugin->info->id != NULL + ? plugin->info->id : "unknown")); + fprintf(fp, " %s\n", gaim_account_get_username(account)); + + if (gaim_account_get_remember_password(account) && + (password = gaim_account_get_password(account)) != NULL) { + + fprintf(fp, " %s\n", password); + } + + if ((alias = gaim_account_get_alias(account)) != NULL) + fprintf(fp, " %s\n", alias); + + if ((user_info = gaim_account_get_user_info(account)) != NULL) + fprintf(fp, " %s\n", user_info); + + if ((buddy_icon = gaim_account_get_buddy_icon(account)) != NULL) + fprintf(fp, " %s\n", buddy_icon); + + fprintf(fp, " \n"); + g_hash_table_foreach(account->settings, __write_setting, fp); + fprintf(fp, " \n"); + + fprintf(fp, " \n"); +} + +void +gaim_accounts_sync(void) +{ + FILE *fp; + const char *user_dir = gaim_user_dir(); + char *filename; + char *filename_real; + + if (!accounts_loaded) { + gaim_debug(GAIM_DEBUG_WARNING, "accounts", + "Writing accounts to disk.\n"); + schedule_accounts_save(); + return; + } + + if (user_dir == NULL) + return; + + gaim_debug(GAIM_DEBUG_INFO, "accounts", "Writing accounts to disk.\n"); + + fp = fopen(user_dir, "r"); + + if (fp == NULL) + mkdir(user_dir, S_IRUSR | S_IWUSR | S_IXUSR); + else + fclose(fp); + + filename = g_build_filename(user_dir, "accounts.xml.save", NULL); + + if ((fp = fopen(filename, "w")) != NULL) { + GList *l; + + fprintf(fp, "\n\n"); + fprintf(fp, "\n"); + + for (l = gaim_accounts_get_all(); l != NULL; l = l->next) + gaim_accounts_write(fp, l->data); + + fprintf(fp, "\n"); + + fclose(fp); + chmod(filename, S_IRUSR | S_IWUSR); + } + else { + gaim_debug(GAIM_DEBUG_ERROR, "accounts", "Unable to write %s\n", + filename); + } + + filename_real = g_build_filename(user_dir, "accounts.xml", NULL); + + if (rename(filename, filename_real) < 0) { + gaim_debug(GAIM_DEBUG_ERROR, "accounts", "Error renaming %s to %s\n", + filename, filename_real); + } + + g_free(filename); + g_free(filename_real); +} + + GList * gaim_accounts_get_all(void) { diff -r dfdea22a7153 -r 5e7de337a053 src/account.h --- a/src/account.h Fri May 30 23:05:01 2003 +0000 +++ b/src/account.h Fri May 30 23:57:11 2003 +0000 @@ -316,6 +316,16 @@ gboolean default_value); /** + * Loads the accounts. + */ +gboolean gaim_accounts_load(); + +/** + * Force an immediate write of accounts. + */ +void gaim_accounts_sync(); + +/** * Returns a list of all accounts. * * @return A list of all accounts. diff -r dfdea22a7153 -r 5e7de337a053 src/away.c --- a/src/away.c Fri May 30 23:05:01 2003 +0000 +++ b/src/away.c Fri May 30 23:57:11 2003 +0000 @@ -161,7 +161,7 @@ if (!awayqueue || !awayqueuesw) return; - if (gaim_prefs_get_bool("/core/away/queue_messages")) { + if (gaim_prefs_get_bool("/gaim/gtk/away/queue_messages")) { gtk_widget_show(awayqueue); gtk_widget_show(awayqueuesw); } else { @@ -274,7 +274,7 @@ g_signal_connect(G_OBJECT(awayqueue), "button_press_event", G_CALLBACK(dequeue_cb), NULL); - if (gaim_prefs_get_bool("/core/away/queue_messages")) { + if (gaim_prefs_get_bool("/gaim/gtk/away/queue_messages")) { gtk_widget_show(awayqueuesw); gtk_widget_show(awayqueue); } diff -r dfdea22a7153 -r 5e7de337a053 src/gaimrc.c --- a/src/gaimrc.c Fri May 30 23:05:01 2003 +0000 +++ b/src/gaimrc.c Fri May 30 23:57:11 2003 +0000 @@ -544,7 +544,8 @@ if ((i = strlen(user_info))) user_info[i - 1] = '\0'; - gaim_account_set_user_info(account, user_info); + if (*user_info != '.') + gaim_account_set_user_info(account, user_info); if (!fgets(buf, sizeof(buf), f)) { return account; @@ -599,7 +600,8 @@ if (strcmp(p->option, "iconfile")) return account; - gaim_account_set_buddy_icon(account, p->value[0]); + if (*p->value[0] != '\n' && *p->value[0] != '\0') + gaim_account_set_buddy_icon(account, p->value[0]); if (!fgets(buf, sizeof(buf), f)) return account; @@ -612,7 +614,8 @@ if (strcmp(p->option, "alias")) return account; - gaim_account_set_alias(account, p->value[0]); + if (*p->value[0] != '\n' && *p->value[0] != '\0') + gaim_account_set_alias(account, p->value[0]); if (!fgets(buf, sizeof(buf), f)) return account; diff -r dfdea22a7153 -r 5e7de337a053 src/gtkaccount.c --- a/src/gtkaccount.c Fri May 30 23:05:01 2003 +0000 +++ b/src/gtkaccount.c Fri May 30 23:57:11 2003 +0000 @@ -142,7 +142,7 @@ gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), -1, _("Online"), renderer, - "text", COLUMN_ONLINE, + "active", COLUMN_ONLINE, NULL); @@ -155,7 +155,7 @@ gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), -1, _("Auto-login"), renderer, - "text", COLUMN_AUTOLOGIN, + "active", COLUMN_AUTOLOGIN, NULL); @@ -182,8 +182,13 @@ for (l = gaim_accounts_get_all(); l != NULL; l = l->next) { account = l->data; + scale = NULL; + pixbuf = create_prpl_icon(account); - scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, GDK_INTERP_BILINEAR); + + if (pixbuf != NULL) + scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, + GDK_INTERP_BILINEAR); gtk_list_store_append(dialog->model, &iter); gtk_list_store_set(dialog->model, &iter, @@ -195,8 +200,8 @@ COLUMN_DATA, account, -1); - g_object_unref(G_OBJECT(pixbuf)); - g_object_unref(G_OBJECT(scale)); + if (pixbuf != NULL) g_object_unref(G_OBJECT(pixbuf)); + if (scale != NULL) g_object_unref(G_OBJECT(scale)); } } @@ -216,7 +221,7 @@ gtk_widget_show(sw); /* Create the list model. */ - dialog->model = gtk_list_store_new(NUM_COLUMNS, G_TYPE_POINTER, + dialog->model = gtk_list_store_new(NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER); diff -r dfdea22a7153 -r 5e7de337a053 src/gtkprefs.c --- a/src/gtkprefs.c Fri May 30 23:05:01 2003 +0000 +++ b/src/gtkprefs.c Fri May 30 23:57:11 2003 +0000 @@ -1442,7 +1442,7 @@ prefs_checkbox(_("_Sending messages removes away status"), "/core/conversations/away_back_on_send", vbox); prefs_checkbox(_("_Queue new messages when away"), - "/plugins/gtk/docklet/queue_messages", vbox); + "/gaim/gtk/away/queue_messages", vbox); vbox = gaim_gtk_make_frame (ret, _("Auto-response")); hbox = gtk_hbox_new(FALSE, 0); @@ -2699,6 +2699,10 @@ gaim_prefs_add_int("/gaim/gtk/accounts/dialog/width", 550); gaim_prefs_add_int("/gaim/gtk/accounts/dialog/height", 250); + /* Away Queueing */ + gaim_prefs_add_none("/gaim/gtk/away"); + gaim_prefs_add_bool("/gaim/gtk/away/queue_messages", FALSE); + /* Browsers */ gaim_prefs_add_none("/gaim/gtk/browsers"); gaim_prefs_add_bool("/gaim/gtk/browsers/new_window", FALSE); diff -r dfdea22a7153 -r 5e7de337a053 src/main.c --- a/src/main.c Fri May 30 23:05:01 2003 +0000 +++ b/src/main.c Fri May 30 23:57:11 2003 +0000 @@ -124,8 +124,8 @@ gaim_connections_disconnect_all(); /* record what we have before we blow it away... */ - save_prefs(); gaim_prefs_sync(); + gaim_accounts_sync(); gaim_debug(GAIM_DEBUG_INFO, "main", "Unloading all plugins\n"); gaim_plugins_destroy_all(); @@ -891,6 +891,7 @@ gaim_prefs_init(); gaim_gtk_prefs_init(); + gaim_accounts_load(); if (!gaim_prefs_load()) load_prefs(); diff -r dfdea22a7153 -r 5e7de337a053 src/plugin.c --- a/src/plugin.c Fri May 30 23:05:01 2003 +0000 +++ b/src/plugin.c Fri May 30 23:57:11 2003 +0000 @@ -66,6 +66,7 @@ static GList *loaded_plugins = NULL; static GList *plugins = NULL; static GList *plugin_loaders = NULL; +static GList *protocol_plugins = NULL; static size_t search_path_count = 0; static char **search_paths = NULL; @@ -618,8 +619,8 @@ return FALSE; } - protocols = g_slist_insert_sorted(protocols, plugin, - (GCompareFunc)compare_prpl); + protocol_plugins = g_list_insert_sorted(protocol_plugins, plugin, + (GCompareFunc)compare_prpl); } plugins = g_list_append(plugins, plugin); @@ -744,6 +745,12 @@ } GList * +gaim_plugins_get_protocols(void) +{ + return protocol_plugins; +} + +GList * gaim_plugins_get_all(void) { return plugins; diff -r dfdea22a7153 -r 5e7de337a053 src/plugin.h --- a/src/plugin.h Fri May 30 23:05:01 2003 +0000 +++ b/src/plugin.h Fri May 30 23:57:11 2003 +0000 @@ -343,11 +343,18 @@ /** * Returns a list of all loaded plugins. * - * @return A list of all plugins. + * @return A list of all loaded plugins. */ GList *gaim_plugins_get_loaded(void); /** + * Returns a list of all protocol plugins. + * + * @return A list of all protocol plugins. + */ +GList *gaim_plugins_get_protocols(void); + +/** * Returns a list of all plugins, whether loaded or not. * * @return A list of all plugins. diff -r dfdea22a7153 -r 5e7de337a053 src/prpl.c --- a/src/prpl.c Fri May 30 23:05:01 2003 +0000 +++ b/src/prpl.c Fri May 30 23:57:11 2003 +0000 @@ -34,8 +34,6 @@ #include "win32dep.h" #endif -GSList *protocols = NULL; - GtkWidget *protomenu = NULL; struct _prompt { @@ -49,10 +47,10 @@ GaimPlugin * gaim_find_prpl(GaimProtocol type) { - GSList *l; + GList *l; GaimPlugin *plugin; - for (l = protocols; l != NULL; l = l->next) { + for (l = gaim_plugins_get_protocols(); l != NULL; l = l->next) { plugin = (GaimPlugin *)l->data; /* Just In Case (TM) */ @@ -432,7 +430,7 @@ static void reset_reg_dlg() { - GSList *P = protocols; + GList *P = gaim_plugins_get_protocols(); if (!regdlg) return; diff -r dfdea22a7153 -r 5e7de337a053 src/prpl.h --- a/src/prpl.h Fri May 30 23:05:01 2003 +0000 +++ b/src/prpl.h Fri May 30 23:57:11 2003 +0000 @@ -301,9 +301,6 @@ #define GAIM_PLUGIN_PROTOCOL_INFO(plugin) \ ((GaimPluginProtocolInfo *)(plugin)->info->extra_info) -/** A list of all loaded protocol plugins. */ -extern GSList *protocols; - /** * Compares two protocol plugins, based off their protocol plugin number. * diff -r dfdea22a7153 -r 5e7de337a053 src/server.c --- a/src/server.c Fri May 30 23:05:01 2003 +0000 +++ b/src/server.c Fri May 30 23:57:11 2003 +0000 @@ -857,7 +857,7 @@ * imaway dialog actually exists, first. */ if (!cnv && awayqueue && - gaim_prefs_get_bool("/core/away/queue_messages")) { + gaim_prefs_get_bool("/gaim/gtk/away/queue_messages")) { /* * Alright, so we're going to queue it. Neat, eh? :) * So first we create something to store the message, and add @@ -963,7 +963,7 @@ tmpmsg = stylize(gc->away, MSG_LEN); serv_send_im(gc, name, away_subs(tmpmsg, alias), -1, IM_FLAG_AWAY); if (!cnv && awayqueue && - gaim_prefs_get_bool("/core/away/queue_messages")) { + gaim_prefs_get_bool("/gaim/gtk/away/queue_messages")) { struct queued_message *qm; @@ -992,7 +992,7 @@ * Robot101 will fix this after his exams. honest. */ if (docklet_count && - gaim_prefs_get_bool("/plugins/gtk/docklet/queue_unread") && + gaim_prefs_get_bool("/plugins/gtk/docklet/queue_messages") && !gaim_find_conversation(name)) { /* * We're gonna queue it up and wait for the user to ask for