changeset 10337:682201b69107

[gaim-migrate @ 11545] * Preliminary reading of status.xml using xmlnode.[h|c] * I made a few changes the blist.xml readering code that I think makes it cleaner * "gaim_statuses_find_saved" makes more sense to me than "gaim_statuses_find_stored" * struct GaimStatus isn't really supposed to be used for keeping the saved statuses, is it? I don't see how that would work. It seems to make more sense to have a separate data structure for it. Maybe I'm not seeing things clearly. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Thu, 09 Dec 2004 03:55:19 +0000
parents 114d3ac8ff5a
children 67db2cbc0294
files src/blist.c src/gtkstatus.c src/status.c src/status.h src/xmlnode.h
diffstat 5 files changed, 212 insertions(+), 67 deletions(-) [+]
line wrap: on
line diff
--- a/src/blist.c	Thu Dec 09 03:10:30 2004 +0000
+++ b/src/blist.c	Thu Dec 09 03:55:19 2004 +0000
@@ -1956,43 +1956,40 @@
 	gsize length;
 	xmlnode *gaim, *blist, *privacy;
 
-	gaim_debug(GAIM_DEBUG_INFO, "blist import",
-			   "Reading %s\n", filename);
+	gaim_debug_info("blist", "Reading %s\n", filename);
+
 	if (!g_file_get_contents(filename, &contents, &length, &error)) {
-		gaim_debug(GAIM_DEBUG_ERROR, "blist import",
-				   "Error reading blist: %s\n", error->message);
+		gaim_debug_error("blist", "Error reading blist.xml: %s\n",
+						 error->message);
 		g_error_free(error);
 		return FALSE;
 	}
 
 	gaim = xmlnode_from_str(contents, length);
-	
-	if (!gaim) {
+
+	if (gaim == NULL) {
 		FILE *backup;
 		char *name;
-		gaim_debug(GAIM_DEBUG_ERROR, "blist import", "Error parsing %s\n",
-				filename);
+		gaim_debug_error("blist", "Error parsing blist.xml\n");
 		name = g_build_filename(gaim_user_dir(), "blist.xml~", NULL);
-
 		if ((backup = fopen(name, "w"))) {
 			fwrite(contents, length, 1, backup);
 			fclose(backup);
 			chmod(name, S_IRUSR | S_IWUSR);
 		} else {
-			gaim_debug(GAIM_DEBUG_ERROR, "blist load", "Unable to write backup %s\n",
-				   name);
+			gaim_debug_error("blist", "Unable to write backup %s\n", name);
 		}
 		g_free(name);
 		g_free(contents);
 		return FALSE;
 	}
-	
+
 	g_free(contents);
-	
+
 	blist = xmlnode_get_child(gaim, "blist");
 	if (blist) {
 		xmlnode *groupnode;
-		for (groupnode = xmlnode_get_child(blist, "group"); groupnode;
+		for (groupnode = xmlnode_get_child(blist, "group"); groupnode != NULL;
 				groupnode = xmlnode_get_next_twin(groupnode)) {
 			parse_group(groupnode);
 		}
@@ -2039,31 +2036,32 @@
 		}
 	}
 
-	gaim_debug(GAIM_DEBUG_INFO, "blist import", "Finished reading %s\n",
-			   filename);
+	gaim_debug_info("blist", "Finished reading blist.xml\n");
 
 	xmlnode_free(gaim);
+
 	return TRUE;
 }
 
 void gaim_blist_load()
 {
 	const char *user_dir = gaim_user_dir();
-	char *filename;
-	char *msg;
+	gchar *filename;
+	gchar *msg;
 
 	blist_safe_to_write = TRUE;
 
-	if (!user_dir)
+	if (user_dir == NULL)
 		return;
 
 	filename = g_build_filename(user_dir, "blist.xml", NULL);
 
 	if (g_file_test(filename, G_FILE_TEST_EXISTS)) {
 		if (!gaim_blist_read(filename)) {
-			msg = g_strdup_printf(_("An error was encountered parsing your "
-						"buddy list.  It has not been loaded, "
-						"and the old file has moved to blist.xml~."));
+			msg = g_strdup_printf(_("An error was encountered parsing the "
+						"file containing your buddy list (%s).  It has not "
+						"been loaded, and the old file has been renamed "
+						"to blist.xml~."), filename);
 			gaim_notify_error(NULL, NULL, _("Buddy List Error"), msg);
 			g_free(msg);
 		}
--- a/src/gtkstatus.c	Thu Dec 09 03:10:30 2004 +0000
+++ b/src/gtkstatus.c	Thu Dec 09 03:55:19 2004 +0000
@@ -421,20 +421,19 @@
 populate_saved_status_list(StatusWindow *dialog)
 {
 	GtkTreeIter iter;
+	const GList *saved_statuses;
+	GaimStatusSaved *saved_status;
 
 	gtk_list_store_clear(dialog->model);
 
-	gtk_list_store_append(dialog->model, &iter);
-	gtk_list_store_set(dialog->model, &iter, 0, "Dinner time!", -1);
-
-	gtk_list_store_append(dialog->model, &iter);
-	gtk_list_store_set(dialog->model, &iter, 0, "I am not here because I am cow tipping with Jimmy.", -1);
-
-	gtk_list_store_append(dialog->model, &iter);
-	gtk_list_store_set(dialog->model, &iter, 0, "Picking up the kids from the zoo.", -1);
-
-	gtk_list_store_append(dialog->model, &iter);
-	gtk_list_store_set(dialog->model, &iter, 0, "In a meeting discussing what to do when King Kong gets here.", -1);
+	for (saved_statuses = gaim_statuses_get_saved(); saved_statuses != NULL;
+			saved_statuses = g_list_next(saved_statuses))
+	{
+		saved_status = (GaimStatusSaved *)saved_statuses->data;
+		gtk_list_store_append(dialog->model, &iter);
+		gtk_list_store_set(dialog->model, &iter, 0,
+						   gaim_statuses_saved_get_name(saved_status), -1);
+	}
 }
 
 static GtkWidget *
--- a/src/status.c	Thu Dec 09 03:10:30 2004 +0000
+++ b/src/status.c	Thu Dec 09 03:55:19 2004 +0000
@@ -26,9 +26,11 @@
 
 #include "blist.h"
 #include "debug.h"
+#include "notify.h"
 #include "prefs.h"
 #include "status.h"
 #include "util.h"
+#include "xmlnode.h"
 
 /**
  * A type of status.
@@ -120,30 +122,32 @@
 	char *name;
 } GaimStatusBuddyKey;
 
-
-#if 0
-static GList *stored_statuses = NULL;
-
-/*
- * XXX This stuff should be removed in a few versions. It stores the
- *     old v1 status stuff so we can write it later. We don't write out
- *     the new status stuff, though. These should all die soon, as the
- *     old status.xml was created before the new status system's design
- *     was created.
+/**
+ * The information of a snap-shot of the statuses of all
+ * your accounts.  Basically these are your saved away messages.
+ * There is an overall status and message that applies to
+ * all your accounts, and then each individual account can
+ * optionally have a different custom status and message.
  *
- *       -- ChipX86
+ * The changes to status.xml caused by the new status API
+ * are fully backward compatible.  The new status API just
+ * adds the optional sub-statuses to the XML file.
  */
-typedef struct
+struct _GaimStatusSaved
 {
 	char *name;
-	char *state;
+	GaimStatusType *type;
 	char *message;
 
-} GaimStatusV1Info;
+	GList *individual;      /**< A list of GaimStatusSavedSub's. */
+};
 
-static GList *v1_statuses = NULL;
-#endif
-
+struct _GaimStatusSavedSub
+{
+	GaimAccount *account;
+	GaimStatusType *type;
+	char *message;
+};
 
 static int primitive_scores[] =
 {
@@ -160,6 +164,7 @@
 };
 
 static GHashTable *buddy_presences = NULL;
+static GList *saved_statuses = NULL;
 
 #define SCORE_IDLE      5
 #define SCORE_IDLE_TIME 6
@@ -1645,15 +1650,21 @@
 }
 
 const GList *
-gaim_statuses_get_stored(void)
+gaim_statuses_get_saved(void)
+{
+	return saved_statuses;
+}
+
+GaimStatusSaved *
+gaim_statuses_find_saved(const GaimStatusType *status_type, const char *id)
 {
 	return NULL;
 }
 
-GaimStatus *
-gaim_statuses_find_stored(const GaimStatusType *status_type, const char *id)
+const char *
+gaim_statuses_saved_get_name(const GaimStatusSaved *saved_status)
 {
-	return NULL;
+	return saved_status->name;
 }
 
 void *
@@ -1723,7 +1734,132 @@
 {
 }
 
+/**
+ * Parse a saved status and add it to the saved_statuses linked list.
+ *
+ * Here's an example of the XML for a saved status:
+ *   <status name="Girls">
+ *       <state>away</state>
+ *       <message>I like the way that they walk
+ *   And it's chill to hear them talk
+ *   And I can always make them smile
+ *   From White Castle to the Nile</message>
+ *   </status>
+ *
+ * I know.  Moving, huh?
+ *
+ * TODO: Make sure the name is unique before adding it to the linked list.
+ */
+static void
+gaim_statuses_read_parse_status(xmlnode *status)
+{
+	xmlnode *node;
+	const char *name, *state, *message;
+	GaimStatusSaved *new;
+
+	name = xmlnode_get_attrib(status, "name");
+	if (name == NULL)
+		name = "TODO: Make up something unique";
+
+	node = xmlnode_get_child(status, "state");
+	if (node != NULL) {
+		state = xmlnode_get_data(node);
+	}
+
+	node = xmlnode_get_child(status, "message");
+	if (node != NULL) {
+		message = xmlnode_get_data(node);
+	}
+
+	/* TODO: Need to read in substatuses here */
+
+	new = g_new0(GaimStatusSaved, 1);
+
+	new->name = g_strdup(name);
+	/* TODO: Need to set type based on "state" */
+	new->type = NULL;
+	if (message != NULL)
+		new->message = g_strdup(message);
+
+	saved_statuses = g_list_append(saved_statuses, new);
+}
+
+/**
+ * @return TRUE on success, FALSE on failure (if the file can not
+ *         be opened, or if it contains invalid XML).
+ */
+gboolean
+gaim_statuses_read(const char *filename)
+{
+	GError *error;
+	gchar *contents = NULL;
+	gsize length;
+	xmlnode *statuses, *status;
+
+	gaim_debug_info("status", "Reading %s\n", filename);
+
+	if (!g_file_get_contents(filename, &contents, &length, &error)) {
+		gaim_debug_error("status", "Error reading status.xml: %s\n",
+						 error->message);
+		g_error_free(error);
+		return FALSE;
+	}
+
+	statuses = xmlnode_from_str(contents, length);
+
+	if (statuses == NULL) {
+		FILE *backup;
+		gchar *name;
+		gaim_debug_error("status", "Error parsing status.xml\n");
+		name = g_build_filename(gaim_user_dir(), "status.xml~", NULL);
+		if ((backup = fopen(name, "w"))) {
+			fwrite(contents, length, 1, backup);
+			fclose(backup);
+			chmod(name, S_IRUSR | S_IWUSR);
+		} else {
+			gaim_debug_error("status", "Unable to write backup %s\n", name);
+		}
+		g_free(name);
+		g_free(contents);
+		return FALSE;
+	}
+
+	g_free(contents);
+
+	for (status = xmlnode_get_child(statuses, "status"); status != NULL;
+			status = xmlnode_get_next_twin(status)) {
+		gaim_statuses_read_parse_status(status);
+	}
+
+	gaim_debug_info("status", "Finished reading status.xml\n");
+
+	xmlnode_free(statuses);
+
+	return TRUE;
+}
+
 void
 gaim_statuses_load(void)
 {
+	const char *user_dir = gaim_user_dir();
+	gchar *filename;
+	gchar *msg;
+
+	if (user_dir == NULL)
+		return;
+
+	filename = g_build_filename(user_dir, "status.xml", NULL);
+
+	if (g_file_test(filename, G_FILE_TEST_EXISTS)) {
+		if (!gaim_statuses_read(filename)) {
+			msg = g_strdup_printf(_("An error was encountered parsing the "
+						"file containing your saved statuses (%s).  They "
+						"have not been loaded, and the old file has been "
+						"renamed to status.xml~."), filename);
+			gaim_notify_error(NULL, NULL, _("Saved Statuses Error"), msg);
+			g_free(msg);
+		}
+	}
+
+	g_free(filename);
 }
--- a/src/status.h	Thu Dec 09 03:10:30 2004 +0000
+++ b/src/status.h	Thu Dec 09 03:55:19 2004 +0000
@@ -25,10 +25,12 @@
 #ifndef _GAIM_STATUS_H_
 #define _GAIM_STATUS_H_
 
-typedef struct _GaimStatusType   GaimStatusType;
-typedef struct _GaimStatusAttr   GaimStatusAttr;
-typedef struct _GaimPresence     GaimPresence;
-typedef struct _GaimStatus       GaimStatus;
+typedef struct _GaimStatusType      GaimStatusType;
+typedef struct _GaimStatusAttr      GaimStatusAttr;
+typedef struct _GaimPresence        GaimPresence;
+typedef struct _GaimStatus          GaimStatus;
+typedef struct _GaimStatusSavedSub  GaimStatusSavedSub;
+typedef struct _GaimStatusSaved     GaimStatusSaved;
 
 /**
  * A context for a presence.
@@ -879,29 +881,37 @@
 
 /*@}*/
 
-
 /**************************************************************************/
 /** @name Status subsystem                                                */
 /**************************************************************************/
 /*@{*/
 
 /**
- * Returns all stored statuses.
+ * Returns all saved statuses.
  *
- * @return A list of stored statuses.
+ * @return A list of saved statuses.
  */
-const GList *gaim_statuses_get_stored(void);
+const GList *gaim_statuses_get_saved(void);
 
 /**
- * Finds a stored status with the specified status type and primary ID.
+ * Finds a saved status with the specified status type and primary ID.
  *
  * @param status_type The status type of the status.
  * @param id          The primary attribute ID.
  *
- * @return The stored status if found, or NULL.
+ * @return The saved status if found, or NULL.
  */
-GaimStatus *gaim_statuses_find_stored(const GaimStatusType *status_type,
-									  const char *id);
+GaimStatusSaved *gaim_statuses_find_saved(const GaimStatusType *status_type,
+										  const char *id);
+
+/**
+ * Return the name of a given saved status.
+ *
+ * @param saved_status The saved status.
+ *
+ * @return The name.
+ */
+const char *gaim_statuses_saved_get_name(const GaimStatusSaved *saved_status);
 
 /**
  * Get the handle for the status subsystem.
--- a/src/xmlnode.h	Thu Dec 09 03:10:30 2004 +0000
+++ b/src/xmlnode.h	Thu Dec 09 03:55:19 2004 +0000
@@ -173,7 +173,9 @@
 char *xmlnode_to_formatted_str(xmlnode *node, int *len);
 
 /**
- * Creates a node from a string of xml.
+ * Creates a node from a string of XML.  Calling this on the
+ * root node of an XML document will parse the entire document
+ * into a tree of nodes, and return the xmlnode of the root.
  *
  * @param str  The string of xml.
  * @param size The size of the string.