diff src/account.c @ 5573:5e7de337a053

[gaim-migrate @ 5976] Account saving and loading _mostly_ works. committer: Tailor Script <tailor@pidgin.im>
author Christian Hammond <chipx86@chipx86.com>
date Fri, 30 May 2003 23:57:11 +0000
parents c3c4aaf69f65
children a95e872e58dc
line wrap: on
line diff
--- 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 <config.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <glib.h>
+
 #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, "   <setting name='%s' type='int'>%d</setting>\n",
+				name, setting->value.integer);
+	}
+	else if (setting->type == GAIM_PREF_STRING) {
+		fprintf(fp, "   <setting name='%s' type='string'>%s</setting>\n",
+				name, setting->value.string);
+	}
+	else if (setting->type == GAIM_PREF_BOOLEAN) {
+		fprintf(fp, "   <setting name='%s' type='bool'>%d</setting>\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, " <account>\n");
+	fprintf(fp, "  <protocol>%s</protocol>\n",
+			(plugin != NULL && plugin->info != NULL && plugin->info->id != NULL
+			 ? plugin->info->id : "unknown"));
+	fprintf(fp, "  <name>%s</name>\n", gaim_account_get_username(account));
+
+	if (gaim_account_get_remember_password(account) &&
+		(password = gaim_account_get_password(account)) != NULL) {
+
+		fprintf(fp, "  <password>%s</password>\n", password);
+	}
+
+	if ((alias = gaim_account_get_alias(account)) != NULL)
+		fprintf(fp, "  <alias>%s</alias>\n", alias);
+
+	if ((user_info = gaim_account_get_user_info(account)) != NULL)
+		fprintf(fp, "  <userinfo>%s</userinfo>\n", user_info);
+
+	if ((buddy_icon = gaim_account_get_buddy_icon(account)) != NULL)
+		fprintf(fp, "  <buddyicon>%s</buddyicon>\n", buddy_icon);
+
+	fprintf(fp, "  <settings>\n");
+	g_hash_table_foreach(account->settings, __write_setting, fp);
+	fprintf(fp, "  </settings>\n");
+
+	fprintf(fp, " </account>\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, "<?xml version='1.0' encoding='UTF-8' ?>\n\n");
+		fprintf(fp, "<accounts>\n");
+
+		for (l = gaim_accounts_get_all(); l != NULL; l = l->next)
+			gaim_accounts_write(fp, l->data);
+
+		fprintf(fp, "</accounts>\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)
 {