changeset 9944:e4a27c9aec4c

[gaim-migrate @ 10838] with much rejoicing, and massive thanks to the efforts of Christian, and all who have helped him, I present to you the incomplete status rewrite! committer: Tailor Script <tailor@pidgin.im>
author Luke Schierer <lschiere@pidgin.im>
date Fri, 03 Sep 2004 21:35:52 +0000
parents f8e395a054e2
children d308de939c33
files COPYRIGHT README.CVS src/account.c src/account.h src/away.c src/blist.c src/blist.h src/connection.c src/connection.h src/core.c src/gaim.h src/gtkaccount.c src/gtkblist.c src/gtkconn.c src/gtkdialogs.c src/gtkprefs.c src/idle.c src/main.c src/protocols/gg/gg.c src/protocols/irc/irc.c src/protocols/jabber/buddy.c src/protocols/jabber/presence.h src/protocols/oscar/oscar.c src/protocols/rendezvous/mdns.c src/protocols/rendezvous/mdns_cache.c src/protocols/rendezvous/mdns_cache.h src/prpl.h src/server.c src/sound.c src/status.c src/status.h
diffstat 31 files changed, 1585 insertions(+), 193 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Fri Sep 03 21:21:25 2004 +0000
+++ b/COPYRIGHT	Fri Sep 03 21:35:52 2004 +0000
@@ -21,6 +21,7 @@
 Graham Booker
 Craig Boston
 Chris Boyle
+Matt Brenneke
 Jeremy Brooks
 Philip Brown
 Sean Burke
--- a/README.CVS	Fri Sep 03 21:21:25 2004 +0000
+++ b/README.CVS	Fri Sep 03 21:35:52 2004 +0000
@@ -1,9 +1,9 @@
 If you plan to use gaim CVS, PLEASE read this message in its entirety!
 
-Gaim is a fast-moving project with a somewhat regular release schedule.  
-Due to the rate of gaim development, CVS undergoes frequent bursts of 
-massive changes, often leaving behind brokenness and partial 
-functionality while the responsible developers rewrite some portion of 
+Gaim is a fast-moving project with a somewhat regular release schedule.
+Due to the rate of gaim development, CVS undergoes frequent bursts of
+massive changes, often leaving behind brokenness and partial
+functionality while the responsible developers rewrite some portion of
 code or seek to add new features.
 
 What this all boils down to is that CVS _WILL_ sometimes be broken.
--- a/src/account.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/account.c	Fri Sep 03 21:35:52 2004 +0000
@@ -30,8 +30,9 @@
 #include "prefs.h"
 #include "prpl.h"
 #include "request.h"
+#include "server.h"
 #include "signals.h"
-#include "server.h"
+#include "status.h"
 #include "util.h"
 
 typedef enum
@@ -126,9 +127,9 @@
 {
 	GaimAccount *account = NULL;
 
-	g_return_val_if_fail(username    != NULL, NULL);
+	g_return_val_if_fail(username != NULL, NULL);
 
-	if(protocol_id)
+	if (protocol_id != NULL)
 		account = gaim_accounts_find(username, protocol_id);
 
 	if (account != NULL)
@@ -138,7 +139,8 @@
 
 	gaim_account_set_username(account, username);
 
-	gaim_account_set_protocol_id(account, protocol_id ? protocol_id : GAIM_PROTO_DEFAULT);
+	gaim_account_set_protocol_id(account,
+		(protocol_id ? protocol_id : GAIM_PROTO_DEFAULT));
 
 	account->settings = g_hash_table_new_full(g_str_hash, g_str_equal,
 											  g_free, delete_setting);
@@ -146,6 +148,8 @@
 				g_free, (GDestroyNotify)g_hash_table_destroy);
 	account->system_log = NULL;
 
+	account->presence = gaim_presence_new_for_account(account);
+
 	return account;
 }
 
@@ -156,14 +160,12 @@
 
 	g_return_if_fail(account != NULL);
 
-	gaim_debug(GAIM_DEBUG_INFO, "account",
-			   "Destroying account %p\n", account);
+	gaim_debug_info("account", "Destroying account %p\n", account);
 
 	if (account->gc != NULL)
 		gaim_connection_destroy(account->gc);
 
-	gaim_debug(GAIM_DEBUG_INFO, "account",
-			   "Continuing to destroy account %p\n", account);
+	gaim_debug_info("account", "Continuing to destroy account %p\n", account);
 
 	for (l = gaim_get_conversations(); l != NULL; l = l->next)
 	{
@@ -182,6 +184,10 @@
 	g_hash_table_destroy(account->settings);
 	g_hash_table_destroy(account->ui_settings);
 
+	gaim_account_set_status_types(account, NULL);
+
+	gaim_presence_destroy(account->presence);
+
 	if(account->system_log)
 		gaim_log_free(account->system_log);
 
@@ -200,8 +206,8 @@
 
 	gc = gaim_connection_new(account);
 
-	gaim_debug(GAIM_DEBUG_INFO, "account",
-			"Registering account %p. gc = %p\n", account, gc);
+	gaim_debug_info("account", "Registering account %p. gc = %p\n",
+					account, gc);
 
 	gaim_connection_register(gc);
 
@@ -220,8 +226,8 @@
 
 	gc = gaim_connection_new(account);
 
-	gaim_debug(GAIM_DEBUG_INFO, "account",
-			   "Connecting to account %p. gc = %p\n", account, gc);
+	gaim_debug_info("account", "Connecting to account %p. gc = %p\n",
+					account, gc);
 
 	gaim_connection_connect(gc);
 
@@ -236,8 +242,7 @@
 	g_return_if_fail(account != NULL);
 	g_return_if_fail(gaim_account_is_connected(account));
 
-	gaim_debug(GAIM_DEBUG_INFO, "account",
-			   "Disconnecting account %p\n", account);
+	gaim_debug_info("account", "Disconnecting account %p\n", account);
 
 	gc = gaim_account_get_connection(account);
 
@@ -512,6 +517,57 @@
 }
 
 void
+gaim_account_set_status_types(GaimAccount *account, GList *status_types)
+{
+	g_return_if_fail(account != NULL);
+
+	if (account->status_types != NULL)
+	{
+		GList *l;
+
+		for (l = account->status_types; l != NULL; l = l->next)
+			gaim_status_type_destroy((GaimStatusType *)l->data);
+
+		g_list_free(account->status_types);
+	}
+
+	account->status_types = status_types;
+}
+
+void
+gaim_account_set_status(GaimAccount *account, const char *status_id,
+						gboolean active, ...)
+{
+	GaimStatus *status;
+
+	g_return_if_fail(account   != NULL);
+	g_return_if_fail(status_id != NULL);
+
+	status = gaim_account_get_status(account, status_id);
+
+	if (status == NULL)
+	{
+		gaim_debug(GAIM_DEBUG_ERROR, "accounts",
+				   "Invalid status ID %s for account %s (%s)\n",
+				   status_id, gaim_account_get_username(account),
+				   gaim_account_get_protocol_id(account));
+		return;
+	}
+
+	if (!active && gaim_status_is_independent(status))
+	{
+		gaim_debug(GAIM_DEBUG_ERROR, "accounts",
+				   "Cannot deactivate an exclusive status.\n");
+		return;
+	}
+
+	if (gaim_status_is_active(status) == active)
+		return;
+
+	gaim_status_set_active(status, active);
+}
+
+void
 gaim_account_clear_settings(GaimAccount *account)
 {
 	g_return_if_fail(account != NULL);
@@ -780,6 +836,60 @@
 	return account->proxy_info;
 }
 
+GaimStatus *
+gaim_account_get_status(const GaimAccount *account, const char *status_id)
+{
+	g_return_val_if_fail(account   != NULL, NULL);
+	g_return_val_if_fail(status_id != NULL, NULL);
+
+	return gaim_presence_get_status(account->presence, status_id);
+}
+
+GaimStatusType *
+gaim_account_get_status_type(const GaimAccount *account, const char *id)
+{
+	const GList *l;
+
+	g_return_val_if_fail(account != NULL, NULL);
+	g_return_val_if_fail(id      != NULL, NULL);
+
+	for (l = gaim_account_get_status_types(account); l != NULL; l = l->next)
+	{
+		GaimStatusType *status_type = (GaimStatusType *)l->data;
+
+		if (!strcmp(gaim_status_type_get_id(status_type), id))
+			return status_type;
+	}
+
+	return NULL;
+}
+
+GaimPresence *
+gaim_account_get_presence(const GaimAccount *account)
+{
+	g_return_val_if_fail(account != NULL, NULL);
+
+	return account->presence;
+}
+
+gboolean
+gaim_account_is_status_active(const GaimAccount *account,
+							  const char *status_id)
+{
+	g_return_val_if_fail(account   != NULL, FALSE);
+	g_return_val_if_fail(status_id != NULL, FALSE);
+
+	return gaim_presence_is_status_active(account->presence, status_id);
+}
+
+const GList *
+gaim_account_get_status_types(const GaimAccount *account)
+{
+	g_return_val_if_fail(account != NULL, NULL);
+
+	return account->status_types;
+}
+
 int
 gaim_account_get_int(const GaimAccount *account, const char *name,
 					 int default_value)
--- a/src/account.h	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/account.h	Fri Sep 03 21:35:52 2004 +0000
@@ -44,6 +44,7 @@
 	void (*notify_added)(GaimAccount *account, const char *remote_user,
 						 const char *id, const char *alias,
 						 const char *message);
+	void (*status_changed)(GaimAccount *account, GaimStatus *status);
 };
 
 struct _GaimAccount
@@ -71,6 +72,10 @@
 	GSList *permit;             /**< Permit list.                         */
 	GSList *deny;               /**< Deny list.                           */
 	int perm_deny;              /**< The permit/deny setting.             */
+
+	GList *status_types;        /**< Status types.                        */
+
+	GaimPresence *presence;     /**< Presence.                            */
 	GaimLog *system_log;        /**< The system log                       */
 
 	void *ui_data;             /**< The UI can put data here.			  */
@@ -252,6 +257,37 @@
 void gaim_account_set_proxy_info(GaimAccount *account, GaimProxyInfo *info);
 
 /**
+ * Sets the account's status types.
+ *
+ * @param account      The account.
+ * @param status_types The list of status types.
+ */
+void gaim_account_set_status_types(GaimAccount *account, GList *status_types);
+
+/**
+ * Sets the account's presence.
+ *
+ * @param account  The account.
+ * @param presence The presence.
+ */
+void gaim_account_set_presence(GaimAccount *account, GaimPresence *presence);
+
+/**
+ * Activates or deactivates a status.
+ *
+ * Only independent statuses can be deactivated with this. To deactivate
+ * an exclusive status, activate a separate status.
+ *
+ * @param account   The account.
+ * @param status_id The ID of the status.
+ * @param active    The active state.
+ * @param ...       Optional NULL-terminated attributes passed for the
+ *                  new status, in an id, value pair.
+ */
+void gaim_account_set_status(GaimAccount *account, const char *status_id,
+							 gboolean active, ...);
+
+/**
  * Clears all protocol-specific settings on an account.
  *
  * @param account The account.
@@ -441,6 +477,60 @@
 GaimProxyInfo *gaim_account_get_proxy_info(const GaimAccount *account);
 
 /**
+ * Returns the account status with the specified ID.
+ *
+ * Note that this works differently than gaim_buddy_get_status() in that
+ * it will only return NULL if the status was not registered.
+ *
+ * @param account   The account.
+ * @param status_id The status ID.
+ *
+ * @return The status, or NULL if it was never registered.
+ */
+GaimStatus *gaim_account_get_status(const GaimAccount *account,
+									const char *status_id);
+
+/**
+ * Returns the account status type with the specified ID.
+ *
+ * @param account The account.
+ * @param id      The ID of the status type.
+ *
+ * @return The status type if found, or NULL.
+ */
+GaimStatusType *gaim_account_get_status_type(const GaimAccount *account,
+											 const char *id);
+
+/**
+ * Returns the account's presence.
+ *
+ * @param account The account.
+ *
+ * @return The account's presence.
+ */
+GaimPresence *gaim_account_get_presence(const GaimAccount *account);
+
+/**
+ * Returns whether or not an account status is active.
+ *
+ * @param account   The account.
+ * @param status_id The status ID.
+ *
+ * @return TRUE if active, or FALSE if not.
+ */
+gboolean gaim_account_is_status_active(const GaimAccount *account,
+									   const char *status_id);
+
+/**
+ * Returns the account's status types.
+ *
+ * @param account The account.
+ *
+ * @return The account's status types.
+ */
+const GList *gaim_account_get_status_types(const GaimAccount *account);
+
+/**
  * Returns a protocol-specific integer setting for an account.
  *
  * @param account       The account.
--- a/src/away.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/away.c	Fri Sep 03 21:35:52 2004 +0000
@@ -33,6 +33,7 @@
 #include "util.h"
 #include "request.h"
 
+#if 0
 /* XXX CORE/UI: Until we can get rid of the message queue stuff... */
 #include "away.h"
 #include "gaim.h"
@@ -915,3 +916,4 @@
 	gtk_widget_show_all(ca->window);
 	gtk_container_set_focus_chain(GTK_CONTAINER(vbox), focus_chain);
 }
+#endif /* 0 */
--- a/src/blist.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/blist.c	Fri Sep 03 21:35:52 2004 +0000
@@ -1118,6 +1118,7 @@
 
 void gaim_blist_add_group(GaimGroup *group, GaimBlistNode *node)
 {
+#if 0
 	GaimBlistUiOps *ops;
 	GaimBlistNode *gnode = (GaimBlistNode*)group;
 
@@ -1272,6 +1273,8 @@
 	if (buddy->icon != NULL)
 		gaim_buddy_icon_unref(buddy->icon);
 	g_hash_table_destroy(buddy->node.settings);
+	gaim_presence_remove_buddy(buddy->presence, buddy);
+	gaim_presence_destroy(buddy->presence);
 	g_free(buddy->name);
 	g_free(buddy->alias);
 	g_free(buddy);
@@ -1728,8 +1731,7 @@
 						((GaimBuddy*)bnode)->present = GAIM_BUDDY_OFFLINE;
 
 						((GaimBuddy*)bnode)->uc = 0;
-						((GaimBuddy*)bnode)->idle = 0;
-						((GaimBuddy*)bnode)->evil = 0;
+						/* XXX ((GaimBuddy*)bnode)->idle = 0; */
 
 
 						if (ops && ops->remove)
--- a/src/blist.h	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/blist.h	Fri Sep 03 21:35:52 2004 +0000
@@ -42,6 +42,7 @@
 
 #include "account.h"
 #include "buddyicon.h"
+#include "status.h"
 
 /**************************************************************************/
 /* Enumerations                                                           */
@@ -56,10 +57,10 @@
 
 } GaimBlistNodeType;
 
-#define GAIM_BLIST_NODE_IS_CHAT(n) ((n)->type == GAIM_BLIST_CHAT_NODE)
-#define GAIM_BLIST_NODE_IS_BUDDY(n) ((n)->type == GAIM_BLIST_BUDDY_NODE)
+#define GAIM_BLIST_NODE_IS_CHAT(n)    ((n)->type == GAIM_BLIST_CHAT_NODE)
+#define GAIM_BLIST_NODE_IS_BUDDY(n)   ((n)->type == GAIM_BLIST_BUDDY_NODE)
 #define GAIM_BLIST_NODE_IS_CONTACT(n) ((n)->type == GAIM_BLIST_CONTACT_NODE)
-#define GAIM_BLIST_NODE_IS_GROUP(n) ((n)->type == GAIM_BLIST_GROUP_NODE)
+#define GAIM_BLIST_NODE_IS_GROUP(n)   ((n)->type == GAIM_BLIST_GROUP_NODE)
 
 typedef enum
 {
@@ -70,9 +71,9 @@
 
 } GaimBuddyPresenceState;
 
-#define GAIM_BUDDY_IS_ONLINE(b) ((b)->account->gc && \
-		((b)->present == GAIM_BUDDY_ONLINE || \
-		 (b)->present == GAIM_BUDDY_SIGNING_ON))
+#define GAIM_BUDDY_IS_ONLINE(b) \
+	((b) != NULL && gaim_account_is_connected((b)->account) && \
+	 gaim_presence_is_online(gaim_buddy_get_presence(b)))
 
 typedef enum
 {
@@ -270,29 +271,12 @@
 /**
  * Updates a buddy's signon time.
  *
- * @param buddy  The buddy whose idle time has changed.
+ * @param buddy  The buddy whose sign-on time has changed.
  * @param signon The buddy's signon time since the dawn of the UNIX epoch.
  */
 void gaim_blist_update_buddy_signon(GaimBuddy *buddy, time_t signon);
 
 /**
- * Updates a buddy's idle time.
- *
- * @param buddy  The buddy whose idle time has changed
- * @param idle   The buddy's idle time in minutes.
- */
-void gaim_blist_update_buddy_idle(GaimBuddy *buddy, int idle);
-
-
-/**
- * Updates a buddy's warning level.
- *
- * @param buddy   The buddy whose warning level has changed.
- * @param warning The warning level as an int from 0 to 100.
- */
-void gaim_blist_update_buddy_evil(GaimBuddy *buddy, int warning);
-
-/**
  * Updates a buddy's icon.
  *
  * @param buddy  The buddy whose buddy icon has changed
@@ -413,6 +397,15 @@
 GaimContact *gaim_buddy_get_contact(GaimBuddy *buddy);
 
 /**
+ * Returns a buddy's presence.
+ *
+ * @param buddy The buddy.
+ *
+ * @return The buddy's presence.
+ */
+GaimPresence *gaim_buddy_get_presence(const GaimBuddy *buddy);
+
+/**
  * Adds a new buddy to the buddy list.
  *
  * The buddy will be inserted right after node or prepended to the
@@ -513,6 +506,13 @@
 
 
 /**
+ * Re-calculates the priority buddy for a contact.
+ *
+ * @param contact The contact.
+ */
+void gaim_contact_compute_priority_buddy(GaimContact *contact);
+
+/**
  * Removes a buddy from the buddy list and frees the memory allocated to it.
  *
  * @param buddy   The buddy to be removed
--- a/src/connection.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/connection.c	Fri Sep 03 21:35:52 2004 +0000
@@ -79,12 +79,6 @@
 	if (gc->display_name != NULL)
 		g_free(gc->display_name);
 
-	if (gc->away != NULL)
-		g_free(gc->away);
-
-	if (gc->away_state != NULL)
-		g_free(gc->away_state);
-
 	if (gc->disconnect_timeout)
 		gaim_timeout_remove(gc->disconnect_timeout);
 
--- a/src/connection.h	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/connection.h	Fri Sep 03 21:35:52 2004 +0000
@@ -91,13 +91,8 @@
 	time_t last_sent_time;       /**< The time something was last sent.  */
 	int is_idle;                 /**< Idle state of the connection.      */
 
-	char *away;                  /**< The current away message, or NULL  */
-	char *away_state;            /**< The last away type.                */
 	gboolean is_auto_away;       /**< Whether or not it's auto-away.     */
 
-	int evil;                    /**< Warning level for AIM (why is
-	                                  this here?)                        */
-
 	gboolean wants_to_die;	     /**< Wants to Die state.  This is set
 	                                  when the user chooses to sign off,
 	                                  or when the protocol is
--- a/src/core.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/core.c	Fri Sep 03 21:35:52 2004 +0000
@@ -35,6 +35,7 @@
 #include "proxy.h"
 #include "signals.h"
 #include "sslconn.h"
+#include "status.h"
 #include "sound.h"
 
 struct GaimCore
@@ -74,7 +75,8 @@
 
 	gaim_prefs_init();
 
-	if (ops != NULL) {
+	if (ops != NULL)
+	{
 		if (ops->ui_prefs_init != NULL)
 			ops->ui_prefs_init();
 
@@ -82,6 +84,7 @@
 			ops->debug_ui_init();
 	}
 
+	gaim_statuses_init();
 	gaim_accounts_init();
 	gaim_connections_init();
 	gaim_conversations_init();
@@ -123,6 +126,7 @@
 	gaim_connections_uninit();
 	gaim_buddy_icons_uninit();
 	gaim_accounts_uninit();
+	gaim_statuses_uninit();
 	gaim_prefs_uninit();
 
 	gaim_debug(GAIM_DEBUG_INFO, "main", "Unloading all plugins\n");
--- a/src/gaim.h	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/gaim.h	Fri Sep 03 21:35:52 2004 +0000
@@ -32,9 +32,11 @@
 extern char *opt_away_arg;
 extern int opt_debug;
 
+/* XXX CORE/UI
 extern GSList *message_queue;
 extern GSList *unread_message_queue;
 extern GSList *away_time_queue;
+*/
 
 /* Functions in idle.c */
 extern gint check_idle(gpointer);
--- a/src/gtkaccount.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/gtkaccount.c	Fri Sep 03 21:35:52 2004 +0000
@@ -2511,7 +2511,8 @@
 
 static GaimAccountUiOps ui_ops =
 {
-	gaim_gtk_accounts_notify_added
+	gaim_gtk_accounts_notify_added,
+	NULL
 };
 
 GaimAccountUiOps *
--- a/src/gtkblist.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/gtkblist.c	Fri Sep 03 21:35:52 2004 +0000
@@ -893,7 +893,9 @@
 
 static void gtk_blist_button_away_cb(GtkWidget *w, gpointer data)
 {
-	gtk_menu_popup(GTK_MENU(awaymenu), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME);
+	/* FIXME: Status */
+	gtk_menu_popup(GTK_MENU(awaymenu), NULL, NULL, NULL, NULL,
+				   1, GDK_CURRENT_TIME);
 }
 
 static void gtk_blist_row_expanded_cb(GtkTreeView *tv, GtkTreeIter *iter, GtkTreePath *path, gpointer user_data) {
@@ -2477,6 +2479,10 @@
 	} else if(GAIM_BLIST_NODE_IS_CONTACT(node) ||
 			GAIM_BLIST_NODE_IS_BUDDY(node)) {
 		GaimBuddy *b;
+		GaimPresence *presence;
+		gboolean idle;
+		time_t idle_secs;
+		unsigned int warning_level;
 		char *statustext = NULL;
 		char *contactaliastext = NULL;
 		char *aliastext = NULL, *nicktext = NULL;
@@ -2523,8 +2529,8 @@
 		if(b->server_alias)
 			nicktext = g_markup_escape_text(b->server_alias, -1);
 
-		if (b->evil > 0)
-			warning = g_strdup_printf(_("%d%%"), b->evil);
+		if (warning_level > 0)
+			warning = g_strdup_printf(_("%d%%"), warning_level);
 
 		if(g_list_length(gaim_connections_get_all()) > 1)
 			accounttext = g_markup_escape_text(b->account->username, -1);
@@ -2578,7 +2584,8 @@
 	int y;
 };
 
-GdkPixbuf *gaim_gtk_blist_get_status_icon(GaimBlistNode *node, GaimStatusIconSize size)
+GdkPixbuf *
+gaim_gtk_blist_get_status_icon(GaimBlistNode *node, GaimStatusIconSize size)
 {
 	GdkPixbuf *scale, *status = NULL;
 	int i, scalesize = 30;
@@ -2587,7 +2594,7 @@
 	struct _gaim_gtk_blist_node *gtknode = node->ui_data;
 	struct _emblem_data emblems[4] = {{NULL, 15, 15}, {NULL, 0, 15},
 		{NULL, 0, 0}, {NULL, 15, 0}};
-
+	GaimPresence *presence = NULL;
 	GaimBuddy *buddy = NULL;
 	GaimChat *chat = NULL;
 
@@ -2690,11 +2697,15 @@
 	}
 
 	if(buddy) {
-		if(buddy->present == GAIM_BUDDY_OFFLINE)
+		presence = gaim_buddy_get_presence(buddy);
+
+		if (!GAIM_BUDDY_IS_ONLINE(buddy))
 			gdk_pixbuf_saturate_and_pixelate(scale, scale, 0.0, FALSE);
-		else if(buddy->idle &&
-				gaim_prefs_get_bool("/gaim/gtk/blist/grey_idle_buddies"))
+		else if (gaim_presence_is_idle(presence) &&
+				 gaim_prefs_get_bool("/gaim/gtk/blist/grey_idle_buddies"))
+		{
 			gdk_pixbuf_saturate_and_pixelate(scale, scale, 0.25, FALSE);
+		}
 	}
 
 	return scale;
@@ -2725,11 +2736,18 @@
 	gdk_pixbuf_loader_close(loader, NULL);
 	g_object_unref(G_OBJECT(loader));
 
-	if (buf) {
+	if (buf)
+	{
+		GaimPresence *presence = gaim_buddy_get_presence(b);
+
 		if (!GAIM_BUDDY_IS_ONLINE(b))
 			gdk_pixbuf_saturate_and_pixelate(buf, buf, 0.0, FALSE);
-		if (b->idle && gaim_prefs_get_bool("/gaim/gtk/blist/grey_idle_buddies"))
+
+		if (gaim_presence_is_idle(presence) &&
+			gaim_prefs_get_bool("/gaim/gtk/blist/grey_idle_buddies"))
+		{
 			gdk_pixbuf_saturate_and_pixelate(buf, buf, 0.25, FALSE);
+		}
 
 		ret = gdk_pixbuf_scale_simple(buf,30,30, GDK_INTERP_BILINEAR);
 		g_object_unref(G_OBJECT(buf));
@@ -2745,9 +2763,10 @@
 	GaimPlugin *prpl;
 	GaimPluginProtocolInfo *prpl_info = NULL;
 	GaimContact *contact;
+	GaimPresence *presence;
 	struct _gaim_gtk_blist_node *gtkcontactnode = NULL;
-	int ihrs, imin;
 	char *idletime = NULL, *warning = NULL, *statustext = NULL;
+	unsigned int warning_level;
 	time_t t;
 	/* XXX Clean up this crap */
 
@@ -2766,27 +2785,26 @@
 	if (prpl != NULL)
 		prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(prpl);
 
+	presence = gaim_buddy_get_presence(b);
+
 	if (!gaim_prefs_get_bool("/gaim/gtk/blist/show_buddy_icons")) {
-		if ((b->idle && !selected &&
+
+		if ((gaim_presence_is_idle(presence) && !selected &&
 			 gaim_prefs_get_bool("/gaim/gtk/blist/grey_idle_buddies")) ||
-			!GAIM_BUDDY_IS_ONLINE(b)) {
+			!GAIM_BUDDY_IS_ONLINE(b))
+		{
 			if (selected)
 				text = g_strdup(esc);
 			else
-				text =  g_strdup_printf("<span color='dim grey'>%s</span>",
-							esc);
+				text = g_strdup_printf("<span color='dim grey'>%s</span>",
+									   esc);
 			g_free(esc);
 			return text;
 		}
-		else {
+		else
 			return esc;
-		}
 	}
 
-	time(&t);
-	ihrs = (t - b->idle) / 3600;
-	imin = ((t - b->idle) / 60) % 60;
-
 	if (prpl_info && prpl_info->status_text && b->account->gc) {
 		char *tmp = prpl_info->status_text(b);
 		const char *end;
@@ -2829,22 +2847,40 @@
 		}
 	}
 
-	if (b->idle > 0 &&
-			gaim_prefs_get_bool("/gaim/gtk/blist/show_idle_time")) {
-		if (ihrs)
-			idletime = g_strdup_printf(_("Idle (%dh%02dm) "), ihrs, imin);
+	if (gaim_presence_is_idle(presence) &&
+		gaim_prefs_get_bool("/gaim/gtk/blist/show_idle_time"))
+	{
+		time_t idle_secs = gaim_presence_get_idle_time(presence);
+
+		if (idle_secs > 0)
+		{
+			int ihrs, imin;
+
+			time(&t);
+			ihrs = (t - idle_secs) / 3600;
+			imin = ((t - idle_secs) / 60) % 60;
+
+			if (ihrs)
+				idletime = g_strdup_printf(_("Idle (%dh%02dm) "), ihrs, imin);
+			else
+				idletime = g_strdup_printf(_("Idle (%dm) "), imin);
+		}
 		else
-			idletime = g_strdup_printf(_("Idle (%dm) "), imin);
+			idletime = g_strdup(_("Idle "));
 	}
 
-	if (b->evil > 0 &&
-			gaim_prefs_get_bool("/gaim/gtk/blist/show_warning_level"))
-		warning = g_strdup_printf(_("Warned (%d%%) "), b->evil);
+	warning_level = gaim_presence_get_warning_level(presence);
+
+	if (warning_level > 0 &&
+		gaim_prefs_get_bool("/gaim/gtk/blist/show_warning_level"))
+	{
+		warning = g_strdup_printf(_("Warned (%d%%) "), warning_level);
+	}
 
 	if(!GAIM_BUDDY_IS_ONLINE(b) && !statustext)
 		statustext = g_strdup(_("Offline "));
 
-	if (b->idle && !selected &&
+	if (gaim_presence_is_idle(presence) && !selected &&
 		gaim_prefs_get_bool("/gaim/gtk/blist/grey_idle_buddies")) {
 
 		text =  g_strdup_printf("<span color='dim grey'>%s</span>\n"
@@ -2917,9 +2953,14 @@
 			continue;
 		for(cnode = gnode->child; cnode; cnode = cnode->next) {
 			if(GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
-				GaimBuddy *buddy = gaim_contact_get_priority_buddy((GaimContact*)cnode);
-				if(buddy && buddy->idle)
-						gaim_gtk_blist_update(list, cnode);
+				GaimBuddy *buddy;
+				GaimPresence *presence;
+
+				buddy = gaim_contact_get_priority_buddy((GaimContact*)cnode);
+				presence = gaim_buddy_get_presence(buddy);
+
+				if (buddy && gaim_presence_is_idle(presence))
+					gaim_gtk_blist_update(list, cnode);
 			}
 		}
 	}
@@ -3117,7 +3158,11 @@
 	gtk_box_pack_start(GTK_BOX(gtkblist->vbox), gtk_item_factory_get_widget(gtkblist->ift, "<GaimMain>"), FALSE, FALSE, 0);
 
 	awaymenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Away"));
+
+	/* FIXME: Status */
+#if 0
 	do_away_menu();
+#endif
 
 	gtkblist->bpmenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Buddy Pounce"));
 	gaim_gtkpounce_menu_build(gtkblist->bpmenu);
@@ -3618,12 +3663,15 @@
 
 static void buddy_node(GaimBuddy *buddy, GtkTreeIter *iter, GaimBlistNode *node)
 {
+	GaimPresence *presence;
 	GdkPixbuf *status, *avatar;
 	char *mark;
 	char *warning = NULL, *idle = NULL;
-
+	unsigned int warning_level;
 	gboolean selected = (gtkblist->selected_node == node);
 
+	presence = gaim_buddy_get_presence(buddy);
+
 	status = gaim_gtk_blist_get_status_icon((GaimBlistNode*)buddy,
 			(gaim_prefs_get_bool("/gaim/gtk/blist/show_buddy_icons")
 			 ? GAIM_STATUS_ICON_LARGE : GAIM_STATUS_ICON_SMALL));
@@ -3631,34 +3679,43 @@
 	avatar = gaim_gtk_blist_get_buddy_icon(buddy);
 	mark = gaim_gtk_blist_get_name_markup(buddy, selected);
 
-	if (buddy->idle > 0) {
-		time_t t;
-		int ihrs, imin;
-		time(&t);
-		ihrs = (t - buddy->idle) / 3600;
-		imin = ((t - buddy->idle) / 60) % 60;
-		if(ihrs > 0)
-			idle = g_strdup_printf("(%d:%02d)", ihrs, imin);
-		else
-			idle = g_strdup_printf("(%d)", imin);
+	if (gaim_presence_is_idle(presence))
+	{
+		time_t idle_secs = gaim_presence_get_idle_time(presence);
+
+		if (idle_secs > 0)
+		{
+			time_t t;
+			int ihrs, imin;
+			time(&t);
+			ihrs = (t - idle_secs) / 3600;
+			imin = ((t - idle_secs) / 60) % 60;
+
+			if (ihrs > 0)
+				idle = g_strdup_printf("(%d:%02d)", ihrs, imin);
+			else
+				idle = g_strdup_printf("(%d)", imin);
+		}
 	}
 
-	if (buddy->evil > 0)
-		warning = g_strdup_printf("%d%%", buddy->evil);
+	warning_level = gaim_presence_get_warning_level(presence);
+
+	if (warning_level > 0)
+		warning = g_strdup_printf("%d%%", warning_level);
 
 	if (gaim_prefs_get_bool("/gaim/gtk/blist/grey_idle_buddies") &&
-			buddy->idle) {
-
-		if(warning && !selected) {
+		gaim_presence_is_idle(presence))
+	{
+		if (warning && !selected) {
 			char *w2 = g_strdup_printf("<span color='dim grey'>%s</span>",
 					warning);
 			g_free(warning);
 			warning = w2;
 		}
 
-		if(idle && !selected) {
+		if (idle && !selected) {
 			char *i2 = g_strdup_printf("<span color='dim grey'>%s</span>",
-					idle);
+									   idle);
 			g_free(idle);
 			idle = i2;
 		}
@@ -4840,7 +4897,8 @@
 	}
 
 	do {
-		int cmp;
+		gint name_cmp;
+		gint presence_cmp;
 
 		gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &more_z, NODE_COLUMN, &val);
 		n = g_value_get_pointer(&val);
@@ -4851,33 +4909,40 @@
 			this_buddy = NULL;
 		}
 
-		cmp = gaim_utf8_strcasecmp(my_buddy ?
-				gaim_contact_get_alias(gaim_buddy_get_contact(my_buddy))
-				: NULL, this_buddy ?
-				gaim_contact_get_alias(gaim_buddy_get_contact(this_buddy))
-				: NULL);
-
-		/* Hideous */
-		if(!this_buddy ||
-				((my_buddy->present > this_buddy->present) ||
-				(my_buddy->present == this_buddy->present &&
-				 (((my_buddy->uc & UC_UNAVAILABLE) < (this_buddy->uc & UC_UNAVAILABLE)) ||
-				 (((my_buddy->uc & UC_UNAVAILABLE) == (this_buddy->uc & UC_UNAVAILABLE)) &&
-				  (((my_buddy->idle == 0) && (this_buddy->idle != 0)) ||
-				   (this_buddy->idle && (my_buddy->idle > this_buddy->idle)) ||
-				   ((my_buddy->idle == this_buddy->idle) &&
-					(cmp < 0 || (cmp == 0 && node < n))))))))) {
-			if(cur) {
+		name_cmp = gaim_utf8_strcasecmp(
+			(my_buddy
+			 ? gaim_contact_get_alias(gaim_buddy_get_contact(my_buddy))
+			 : NULL),
+			(this_buddy
+			 ? gaim_contact_get_alias(gaim_buddy_get_contact(this_buddy))
+			 : NULL));
+
+		presence_cmp = gaim_presence_compare(
+			gaim_buddy_get_presence(my_buddy),
+			gaim_buddy_get_presence(this_buddy));
+
+		if (this_buddy == NULL ||
+			(presence_cmp > 0 ||
+			 (presence_cmp == 0 &&
+			  (name_cmp < 0 || (name_cmp == 0 && node < n)))))
+		{
+			if (cur != NULL)
+			{
 				gtk_tree_store_move_before(gtkblist->treemodel, cur, &more_z);
 				return *cur;
-			} else {
+			}
+			else
+			{
 				gtk_tree_store_insert_before(gtkblist->treemodel, &iter,
-						&groupiter, &more_z);
+											 &groupiter, &more_z);
 				return iter;
 			}
 		}
+
 		g_value_unset(&val);
-	} while (gtk_tree_model_iter_next (GTK_TREE_MODEL(gtkblist->treemodel), &more_z));
+	}
+	while (gtk_tree_model_iter_next(GTK_TREE_MODEL(gtkblist->treemodel),
+									&more_z));
 
 	if(cur) {
 		gtk_tree_store_move_before(gtkblist->treemodel, cur, NULL);
--- a/src/gtkconn.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/gtkconn.c	Fri Sep 03 21:35:52 2004 +0000
@@ -243,7 +243,9 @@
 
 	gaim_setup(gc);
 
+#if 0 /* XXX CORE/UI */
 	do_away_menu();
+#endif
 	gaim_gtk_blist_update_protocol_actions();
 
 	if (meter)
@@ -254,7 +256,9 @@
 {
 	struct signon_meter *meter = find_signon_meter(gc);
 
+#if 0 /* XXX CORE/UI */
 	do_away_menu();
+#endif
 	gaim_gtk_blist_update_protocol_actions();
 
 	if (meter)
@@ -682,11 +686,12 @@
 }
 
 /*
- * This function needs to be moved out of here once away messages are 
+ * This function needs to be moved out of here once away messages are
  * core/UI split.
  */
 void away_on_login(const char *mesg)
 {
+#if 0 /* XXX CORE/UI */
 	GSList *awy = away_messages;
 	struct away_message *a, *message = NULL;
 	GaimGtkBuddyList *gtkblist;
@@ -713,4 +718,5 @@
 		message = away_messages->data;
 	}
 	do_away_message(NULL, message);
+#endif
 }
--- a/src/gtkdialogs.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/gtkdialogs.c	Fri Sep 03 21:35:52 2004 +0000
@@ -861,6 +861,7 @@
 
 	g_free(text);
 }
+#endif /* 0 */
 
 static void
 gaim_gtkdialogs_remove_chat_cb(GaimChat *chat)
--- a/src/gtkprefs.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/gtkprefs.c	Fri Sep 03 21:35:52 2004 +0000
@@ -94,7 +94,9 @@
 static void delete_prefs(GtkWidget *, void *);
 static void update_plugin_list(void *data);
 
+/* XXX CORE/UI
 static void set_default_away(GtkWidget *, gpointer);
+*/
 
 static void
 update_spin_value(GtkWidget *w, GtkWidget *spin)
@@ -2241,14 +2243,24 @@
 	GValue val = { 0, };
 	gchar buffer[BUF_LONG];
 	char *tmp;
+/* XXX CORE/UI
 	struct away_message *am;
+*/
 
 	if (! gtk_tree_selection_get_selected (sel, &model, &iter))
 		return;
 	gtk_tree_model_get_value (model, &iter, 1, &val);
+
+/* XXX CORE/UI
 	am = g_value_get_pointer(&val);
+*/
+
 	gtk_imhtml_clear(GTK_IMHTML(away_text));
+
+/* XXX CORE/UI
 	strncpy(buffer, am->message, BUF_LONG);
+*/
+
 	tmp = stylize(buffer, BUF_LONG);
 	gtk_imhtml_append_text(GTK_IMHTML(away_text), tmp, GTK_IMHTML_NO_TITLE |
 			       GTK_IMHTML_NO_COMMENTS | GTK_IMHTML_NO_SCROLL);
@@ -2296,9 +2308,16 @@
 	if (! gtk_tree_selection_get_selected (sel, &model, &iter))
 		return;
 	gtk_tree_model_get_value (GTK_TREE_MODEL(prefs_away_store), &iter, 1, &val);
+
+/* XXX CORE/UI
 	am = g_value_get_pointer (&val);
+*/
+
 	gtk_imhtml_clear(GTK_IMHTML(away_text));
+
+/* XXX CORE/UI
 	rem_away_mess(NULL, am);
+*/
 }
 
 GtkWidget *away_message_page() {
@@ -2306,13 +2325,15 @@
 	GtkWidget *hbox;
 	GtkWidget *button;
 	GtkWidget *sw;
-	GtkTreeIter iter;
 	GtkWidget *event_view;
 	GtkCellRenderer *rend;
 	GtkTreeViewColumn *col;
 	GtkTreeSelection *sel;
+/* XXX CORE/UI
+	GtkTreeIter iter;
 	GSList *awy = away_messages;
 	struct away_message *a;
+*/
 	GtkSizeGroup *sg;
 
 	ret = gtk_vbox_new(FALSE, 18);
@@ -2326,6 +2347,7 @@
 	gtk_box_pack_start(GTK_BOX(ret), sw, TRUE, TRUE, 0);
 
 	prefs_away_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
+/* XXX CORE/UI
 	while (awy) {
 		a = (struct away_message *)awy->data;
 		gtk_list_store_append (prefs_away_store, &iter);
@@ -2334,6 +2356,7 @@
 				   1, a, -1);
 		awy = awy->next;
 	}
+*/
 	event_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(prefs_away_store));
 
 	rend = gtk_cell_renderer_text_new();
@@ -2634,16 +2657,20 @@
 
 void default_away_menu_init(GtkWidget *omenu)
 {
-	GtkWidget *menu, *opt;
+	GtkWidget *menu;
+/* XXX CORE/UI
+	GtkWidget *opt;
 	int index = 0, default_index = 0;
 	GSList *awy = away_messages;
 	struct away_message *a;
+*/
 	const char *default_name;
 
 	menu = gtk_menu_new();
 
 	default_name = gaim_prefs_get_string("/core/away/default_message");
 
+/* XXX CORE/UI
 	while (awy) {
 		a = (struct away_message *)awy->data;
 		opt = gtk_menu_item_new_with_label(a->name);
@@ -2658,12 +2685,18 @@
 		awy = awy->next;
 		index++;
 	}
+*/
 
 	gtk_option_menu_remove_menu(GTK_OPTION_MENU(omenu));
 	gtk_option_menu_set_menu(GTK_OPTION_MENU(omenu), menu);
+
+/* XXX CORE/UI
 	gtk_option_menu_set_history(GTK_OPTION_MENU(omenu), default_index);
+*/
 }
 
+/* XXX CORE/UI */
+#if 0
 void set_default_away(GtkWidget *w, gpointer data)
 {
 	struct away_message *default_away = NULL;
@@ -2682,6 +2715,7 @@
 	else
 		gaim_prefs_set_string("/core/away/default_message", "");
 }
+#endif
 
 static void
 smiley_theme_pref_cb(const char *name, GaimPrefType type, gpointer value,
--- a/src/idle.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/idle.c	Fri Sep 03 21:35:52 2004 +0000
@@ -108,14 +108,19 @@
 
 			if(!default_away && away_messages)
 				default_away = away_messages->data;
+*/
 
 			gaim_debug(GAIM_DEBUG_INFO, "idle",
 					   "Making %s away automatically\n",
 					   gaim_account_get_username(account));
+
+/* XXX CORE/UI
 			if (g_list_length(gaim_connections_get_all()) == 1)
 				do_away_message(NULL, default_away);
 			else if (default_away)
 				serv_set_away(gc, GAIM_AWAY_CUSTOM, default_away->message);
+*/
+
 			gc->is_auto_away = 1;
 		} else
 			gc->is_auto_away = 2;
@@ -126,6 +131,8 @@
 			return TRUE;
 		}
 		gc->is_auto_away = 0;
+
+/* XXX CORE/UI
 		if (awaymessage == NULL) {
 			gaim_debug(GAIM_DEBUG_INFO, "idle",
 					   "Removing auto-away message for %s\n", gaim_account_get_username(account));
@@ -140,6 +147,7 @@
 				serv_set_away(gc, GAIM_AWAY_CUSTOM, awaymessage->message);
 			}
 		}
+*/
 	}
 
 
--- a/src/main.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/main.c	Fri Sep 03 21:35:52 2004 +0000
@@ -861,7 +861,7 @@
 	gaim_plugins_load_saved("/gaim/gtk/plugins/loaded");
 
 	gaim_pounces_load();
-	gaim_status_load();
+	gaim_statuses_load();
 
 	ui_main();
 
--- a/src/protocols/gg/gg.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/protocols/gg/gg.c	Fri Sep 03 21:35:52 2004 +0000
@@ -1,6 +1,6 @@
 /*
  * gaim - Gadu-Gadu Protocol Plugin
- * $Id: gg.c 10835 2004-09-03 21:21:25Z faceprint $
+ * $Id: gg.c 10838 2004-09-03 21:35:52Z lschiere $
  *
  * Copyright (C) 2001 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
  *
@@ -435,6 +435,7 @@
 static void main_callback(gpointer data, gint source, GaimInputCondition cond)
 {
 	GaimConnection *gc = data;
+	GaimAccount *account = gaim_connection_get_account(gc);
 	struct agg_data *gd = gc->proto_data;
 	struct gg_event *e;
 
@@ -1557,19 +1558,19 @@
 
 static void agg_list_emblems(GaimBuddy *b, char **se, char **sw, char **nw, char **ne)
 {
-	int status;
-	if (b->present == GAIM_BUDDY_OFFLINE)
+	GaimPresence *presence = gaim_buddy_get_presence(b);
+
+	if (!GAIM_BUDDY_IS_ONLINE(b))
 		*se = "offline";
-	else if (b->uc == UC_UNAVAILABLE)
+	else if (gaim_presence_is_status_active(presence, "away") ||
+			 gaim_presence_is_status_active(presence, "away-friends"))
+	{
 		*se = "away";
-	else {
-		status = b->uc >> 5;
-		/* Drop all masks */
-		status &= ~(GG_STATUS_FRIENDS_MASK);
-		if (status == GG_STATUS_BUSY)
-			*se = "away";
-		else if (status == GG_STATUS_INVISIBLE)
-			*se = "invisiible";
+	}
+	else if (gaim_presence_is_status_active(presence, "invisible") ||
+			 gaim_presence_is_status_active(presence, "invisible-friends"))
+	{
+		*se = "invisible";
 	}
 }
 
--- a/src/protocols/irc/irc.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/protocols/irc/irc.c	Fri Sep 03 21:35:52 2004 +0000
@@ -145,9 +145,30 @@
 		*se = "offline";
 }
 
-static GList *irc_away_states(GaimConnection *gc)
+static GList *irc_status_types(GaimAccount *account)
 {
-	return g_list_append(NULL, (gpointer)GAIM_AWAY_CUSTOM);
+	GaimStatusType *type;
+	GList *types = NULL;
+
+	type = gaim_status_type_new(GAIM_STATUS_OFFLINE, "offline",
+								_("Offline"), FALSE);
+	types = g_list_append(types, type);
+
+	type = gaim_status_type_new(GAIM_STATUS_ONLINE, "online",
+								_("Online"), FALSE);
+	types = g_list_append(types, type);
+
+	type = gaim_status_type_new(GAIM_STATUS_AVAILABLE, "available",
+								_("Available"), TRUE);
+	types = g_list_append(types, type);
+
+	type = gaim_status_type_new_with_attrs(
+		GAIM_STATUS_AWAY, "away", _("Away"), TRUE, TRUE, FALSE,
+		"message", _("Message"), gaim_value_new(GAIM_TYPE_STRING));
+
+	types = g_list_append(types, type);
+
+	return types;
 }
 
 static GList *irc_actions(GaimPlugin *plugin, gpointer context)
@@ -344,20 +365,18 @@
 	irc_cmd_whois(irc, "whois", NULL, args);
 }
 
-static void irc_set_away(GaimConnection *gc, const char *state, const char *msg)
+static void irc_set_status(GaimAccount *account, GaimStatus *status)
 {
+	GaimConnection *gc = gaim_account_get_connection(account);
 	struct irc_conn *irc = gc->proto_data;
 	const char *args[1];
+	const char *status_id = gaim_status_get_id(status);
 
-	if (gc->away) {
-		g_free(gc->away);
-		gc->away = NULL;
-	}
+	if (!strcmp(status_id, "away"))
+		args[0] = gaim_status_get_attr_string(status, "message");
+	else if (!strcmp(status_id, "available"))
+		args[0] = NULL;
 
-	if (msg)
-		gc->away = g_strdup(msg);
-
-	args[0] = msg;
 	irc_cmd_away(irc, "away", NULL, args);
 }
 
--- a/src/protocols/jabber/buddy.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/protocols/jabber/buddy.c	Fri Sep 03 21:35:52 2004 +0000
@@ -818,10 +818,17 @@
 static void jabber_buddy_set_invisibility(JabberStream *js, const char *who,
 		gboolean invisible)
 {
+	GaimPresence *gpresence;
+	GaimAccount *account;
+	GaimStatus *status;
 	JabberBuddy *jb = jabber_buddy_find(js, who, TRUE);
 	xmlnode *presence;
 
-	presence = jabber_presence_create(js->gc->away_state, js->gc->away);
+	account   = gaim_connection_get_account(js->gc);
+	gpresence = gaim_account_get_presence(account);
+	status    = gaim_presence_get_active_status(gpresence);
+
+	presence = jabber_presence_create(status);
 	xmlnode_set_attrib(presence, "to", who);
 	if(invisible) {
 		xmlnode_set_attrib(presence, "type", "invisible");
--- a/src/protocols/jabber/presence.h	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/protocols/jabber/presence.h	Fri Sep 03 21:35:52 2004 +0000
@@ -33,7 +33,7 @@
 
 void jabber_presence_send(GaimConnection *gc, const char *state,
 		const char *msg);
-xmlnode *jabber_presence_create(const char *state, const char *msg);
+xmlnode *jabber_presence_create(GaimStatus *status);
 void jabber_presence_parse(JabberStream *js, xmlnode *packet);
 void jabber_presence_subscription_set(JabberStream *js, const char *who,
 		const char *type);
--- a/src/protocols/oscar/oscar.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/protocols/oscar/oscar.c	Fri Sep 03 21:35:52 2004 +0000
@@ -4985,6 +4985,16 @@
 }
 #endif
 
+static void oscar_string_append(GString *str, char *name, char *value)
+{
+	gchar *utf8;
+
+	if (value && value[0] && (utf8 = gaim_utf8_try_convert(value))) {
+		g_string_append_printf(str, "\n<br><b>%s:</b> %s", name, utf8);
+		g_free(utf8);
+	}
+}
+
 static int gaim_icqinfo(aim_session_t *sess, aim_frame_t *fr, ...)
 {
 	GaimConnection *gc = sess->aux_data;
--- a/src/protocols/rendezvous/mdns.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/protocols/rendezvous/mdns.c	Fri Sep 03 21:35:52 2004 +0000
@@ -1383,6 +1383,7 @@
 /**
  * If invalid data is encountered at any point when parsing data
  * then the entire packet is discarded and NULL is returned.
+ *
  */
 DNSPacket *
 mdns_read(int fd)
--- a/src/protocols/rendezvous/mdns_cache.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/protocols/rendezvous/mdns_cache.c	Fri Sep 03 21:35:52 2004 +0000
@@ -51,8 +51,6 @@
 void
 mdns_cache_add(const ResourceRecord *rr)
 {
-	ResourceRecord *new;
-
 	g_return_if_fail(rr != NULL);
 	g_return_if_fail((rr->type != 0) && (rr->type != RENDEZVOUS_RRTYPE_ALL));
 
@@ -78,15 +76,14 @@
 	mdns_free_rr(rr);
 }
 
-void
-mdns_cache_remove_all()
+void mdns_cache_remove_all()
 {
-	mdns_free_rrs(rrs);
+	while (resourcerecords != NULL)
+		mdns_cache_remove(resourcerecords->data);
 	rrs = NULL;
 }
 
-void
-mdns_cache_respond(int fd, const Question *q)
+void mdns_cache_respond(int fd, Question *q)
 {
 	GSList *slist;
 	ResourceRecord *cur;
--- a/src/protocols/rendezvous/mdns_cache.h	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/protocols/rendezvous/mdns_cache.h	Fri Sep 03 21:35:52 2004 +0000
@@ -31,24 +31,54 @@
 
 #include "mdns.h"
 
-/**
- *
- */
-void mdns_cache_add(const ResourceRecord *rr);
+void mdns_cache_add(ResourceRecord *rr);
 
-/**
- *
- */
 void mdns_cache_remove(gchar *name, unsigned short type);
 
-/**
- *
- */
 void mdns_cache_remove_all();
 
+void mdns_cache_respond(int fd, Question *q);
+
+#endif /* _MDNS_CACHE_H_ */
 /**
+ * @file mdns_cache.h Multicast DNS resource record caching code.
+ *
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
-void mdns_cache_respond(int fd, const Question *q);
+
+#ifndef _MDNS_CACHE_H_
+#define _MDNS_CACHE_H_
+
+#include "internal.h"
+#include "debug.h"
+
+#include "mdns.h"
+
+void mdns_cache_add(ResourceRecord *rr);
+
+void mdns_cache_remove(ResourceRecord *rr);
+
+void mdns_cache_remove_all();
+
+void mdns_cache_respond(int fd, Question *q);
 
 #endif /* _MDNS_CACHE_H_ */
--- a/src/prpl.h	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/prpl.h	Fri Sep 03 21:35:52 2004 +0000
@@ -94,6 +94,7 @@
 #include "blist.h"
 #include "proxy.h"
 #include "plugin.h"
+#include "status.h"
 
 struct proto_chat_entry {
 	char *label;
@@ -176,9 +177,6 @@
 
 } GaimProtocolOptions;
 
-/** Custom away message. */
-#define GAIM_AWAY_CUSTOM _("Custom")
-
 /** Some structs defined in roomlist.h */
 struct _GaimRoomlist;
 struct _GaimRoomlistRoom;
@@ -317,6 +315,131 @@
 extern "C" {
 #endif
 
+/**************************************************************************/
+/** @name Protocol Plugin API                                             */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Notifies Gaim that an account's idle state and time have changed.
+ *
+ * This is meant to be called from protocol plugins.
+ *
+ * @param account   The account.
+ * @param idle      The user's idle state.
+ * @param idle_time The user's idle time.
+ */
+void gaim_prpl_got_account_idle(GaimAccount *account, gboolean idle,
+								time_t idle_time);
+
+/**
+ * Notifies Gaim of an account's log-in time.
+ *
+ * This is meant to be called from protocol plugins.
+ *
+ * @param account    The account the user is on.
+ * @param login_time The user's log-in time.
+ */
+void gaim_prpl_got_account_login_time(GaimAccount *account, const char *name,
+									  time_t login_time);
+
+/**
+ * Notifies Gaim that an account's status has changed.
+ *
+ * This is meant to be called from protocol plugins.
+ *
+ * @param account   The account the user is on.
+ * @param status_id The status ID.
+ * @param attr_id   The first attribute ID, or NULL for no attribute updates.
+ * @param ...       A NULL-terminated list of attribute IDs and values,
+ *                  beginning with the value for @a attr_id.
+ */
+void gaim_prpl_got_account_status(GaimAccount *account,
+								  const char *status_id, const char *attr_id,
+								  ...);
+
+/**
+ * Notifies Gaim that an account's warning level has changed.
+ *
+ * This is meant to be called from protocol plugins.
+ *
+ * @param account  The account the user is on.
+ * @param username The user that warned the account.
+ * @param level    The new warning level.
+ */
+void gaim_prpl_got_account_warning_level(GaimAccount *account,
+										 const char *username,
+										 unsigned int level);
+
+
+/**
+ * Notifies Gaim that a user's idle state and time have changed.
+ *
+ * This is meant to be called from protocol plugins.
+ *
+ * @param account   The account the user is on.
+ * @param name      The screen name of the user.
+ * @param idle      The user's idle state.
+ * @param idle_time The user's idle time.
+ */
+void gaim_prpl_got_user_idle(GaimAccount *account, const char *name,
+							 gboolean idle, time_t idle_time);
+
+/**
+ * Notifies Gaim of a user's log-in time.
+ *
+ * This is meant to be called from protocol plugins.
+ *
+ * @param account    The account the user is on.
+ * @param name       The screen name of the user.
+ * @param login_time The user's log-in time.
+ */
+void gaim_prpl_got_user_login_time(GaimAccount *account, const char *name,
+								   time_t login_time);
+
+/**
+ * Notifies Gaim that a user's status has changed.
+ *
+ * This is meant to be called from protocol plugins.
+ *
+ * @param account   The account the user is on.
+ * @param name      The screen name of the user.
+ * @param status_id The status ID.
+ * @param attr_id   The first attribute ID, or NULL for no attribute updates.
+ * @param ...       A NULL-terminated list of attribute IDs and values,
+ *                  beginning with the value for @a attr_id.
+ */
+void gaim_prpl_got_user_status(GaimAccount *account, const char *name,
+							   const char *status_id, const char *attr_id, ...);
+
+/**
+ * Notifies Gaim that a user's warning level has changed.
+ *
+ * This is meant to be called from protocol plugins.
+ *
+ * @param account The account the user is on.
+ * @param name    The screen name of the user.
+ * @param level   The new warning level.
+ */
+void gaim_prpl_got_user_warning_level(GaimAccount *account, const char *name,
+									  unsigned int level);
+
+/**
+ * Informs the server that an account's status changed.
+ *
+ * @param account The account the user is on.
+ * @param status  The status that was activated, or deactivated
+ *                (in the case of independent statuses).
+ */
+void gaim_prpl_set_account_status(GaimAccount *account, GaimStatus *status);
+
+/*@}*/
+
+/**************************************************************************/
+/** @name Protocol Plugin Subsystem API                                   */
+/**************************************************************************/
+/*@{*/
+
 /**
  * Finds a protocol plugin structure of the specified type.
  *
@@ -324,6 +447,8 @@
  */
 GaimPlugin *gaim_find_prpl(const char *id);
 
+/*@}*/
+
 #ifdef __cplusplus
 }
 #endif
--- a/src/server.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/server.c	Fri Sep 03 21:35:52 2004 +0000
@@ -21,6 +21,7 @@
  *
  */
 #include "internal.h"
+#include "blist.h"
 #include "conversation.h"
 #include "debug.h"
 #include "log.h"
@@ -31,6 +32,7 @@
 #include "signals.h"
 #include "server.h"
 #include "sound.h"
+#include "status.h"
 #include "util.h"
 
 /* XXX UI Stuff */
@@ -791,6 +793,7 @@
 
 }
 
+#if 0
 int find_queue_row_by_name(char *name)
 {
 	gchar *temp;
@@ -829,6 +832,7 @@
 
 	return i;
 }
+#endif
 
 /*
  * woo. i'm actually going to comment this function. isn't that fun. make
@@ -837,12 +841,18 @@
 void serv_got_im(GaimConnection *gc, const char *who, const char *msg,
 				 GaimConvImFlags imflags, time_t mtime)
 {
+	GaimAccount *account;
 	GaimConversation *cnv;
+	GaimPresence *presence;
+	GaimStatus *status;
 	GaimMessageFlags msgflags;
 	char *message, *name;
 	char *angel, *buffy;
 	int plugin_return;
 
+	account  = gaim_connection_get_account(gc);
+	presence = gaim_account_get_presence(account);
+
 	/*
 	 * We should update the conversation window buttons and menu,
 	 * if it exists.
@@ -916,6 +926,7 @@
 		 * this to be queued properly, we have to make sure that the
 		 * imaway dialog actually exists, first.
 		 */
+#if 0
 		if (!cnv && awayqueue &&
 			gaim_prefs_get_bool("/gaim/gtk/away/queue_messages")) {
 			/*
@@ -961,7 +972,10 @@
 								2, _("(1 message)"),
 								-1);
 			}
-		} else {
+		}
+		else
+#endif
+		{
 			/*
 			 * Make sure the conversation
 			 * exists and is updated (partly handled above already), play
@@ -969,7 +983,7 @@
 			 * while away), and then write it to the convo window.
 			 */
 			if (cnv == NULL)
-				cnv = gaim_conversation_new(GAIM_CONV_IM, gc->account, name);
+				cnv = gaim_conversation_new(GAIM_CONV_IM, account, name);
 
 			gaim_conv_im_write(GAIM_CONV_IM(cnv), NULL, message, msgflags, mtime);
 			gaim_conv_window_flash(gaim_conversation_get_window(cnv));
@@ -1016,13 +1030,14 @@
 		lar->sent = t;
 
 		/* apply default fonts and colors */
-		tmpmsg = stylize(gc->away, MSG_LEN);
+		tmpmsg = stylize(away_msg, MSG_LEN);
 
 		/* Move this to oscar.c! */
 		buffy = gaim_str_sub_away_formatters(tmpmsg, alias);
 		serv_send_im(gc, name, buffy, GAIM_CONV_IM_AUTO_RESP);
 		g_free(buffy);
 
+#if 0
 		if (!cnv && awayqueue &&
 			gaim_prefs_get_bool("/gaim/gtk/away/queue_messages")) {
 
@@ -1035,12 +1050,20 @@
 			qm->tm = mtime;
 			qm->flags = GAIM_MESSAGE_SEND | GAIM_MESSAGE_AUTO_RESP;
 			message_queue = g_slist_append(message_queue, qm);
-		} else if (cnv != NULL)
-			gaim_conv_im_write(GAIM_CONV_IM(cnv), NULL, gaim_str_sub_away_formatters(tmpmsg, alias),
-						  GAIM_MESSAGE_SEND | GAIM_MESSAGE_AUTO_RESP, mtime);
+		}
+		else if (cnv != NULL)
+#endif
+		{
+			gaim_conv_im_write(GAIM_CONV_IM(cnv), NULL,
+							   gaim_str_sub_away_formatters(tmpmsg, alias),
+							   GAIM_MESSAGE_SEND | GAIM_MESSAGE_AUTO_RESP,
+							   mtime);
+		}
 
 		g_free(tmpmsg);
-	} else {
+	}
+	else
+	{
 		/*
 		 * We're not away. This is easy. If the convo window doesn't
 		 * exist, create and update it (if it does exist it was updated
@@ -1052,6 +1075,8 @@
 		 * Robot101 will fix this after his exams. honest.
 		 * I guess he didn't specify WHICH exams, exactly...
 		 */
+/* XXX CORE/UI */
+#if 0
 		if (docklet_count &&
 		    gaim_prefs_get_bool("/plugins/gtk/docklet/queue_messages") &&
 		    !gaim_find_conversation_with_account(name, gc->account)) {
@@ -1069,12 +1094,15 @@
 			unread_message_queue = g_slist_append(unread_message_queue, qm);
 		}
 		else {
+#endif
 			if (cnv == NULL)
 				cnv = gaim_conversation_new(GAIM_CONV_IM, gc->account, name);
 
 			gaim_conv_im_write(GAIM_CONV_IM(cnv), NULL, message, msgflags, mtime);
 			gaim_conv_window_flash(gaim_conversation_get_window(cnv));
+#if 0
 		}
+#endif
 	}
 
 	g_free(name);
@@ -1174,7 +1202,7 @@
 
 	alias = gaim_escape_html(gaim_buddy_get_alias(b));
 
-	old_idle = b->idle;
+	presence = gaim_buddy_get_presence(b);
 
 	if (loggedin) {
 		if (!GAIM_BUDDY_IS_ONLINE(b)) {
--- a/src/sound.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/sound.c	Fri Sep 03 21:35:52 2004 +0000
@@ -59,8 +59,11 @@
 
 void gaim_sound_play_file(const char *filename)
 {
+	/* FIXME */
+#if 0
 	if(awaymessage && !gaim_prefs_get_bool("/core/sound/while_away"))
 		return;
+#endif
 
 	if(sound_ui_ops && sound_ui_ops->play_file)
 		sound_ui_ops->play_file(filename);
@@ -68,8 +71,11 @@
 
 void gaim_sound_play_event(GaimSoundEventID event)
 {
+	/* FIXME */
+#if 0
 	if(awaymessage && !gaim_prefs_get_bool("/core/sound/while_away"))
 		return;
+#endif
 
 	if(sound_ui_ops && sound_ui_ops->play_event)
 		sound_ui_ops->play_event(event);
--- a/src/status.c	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/status.c	Fri Sep 03 21:35:52 2004 +0000
@@ -1,10 +1,13 @@
-/*
+/**
+ * @file status.h Status API
+ * @ingroup core
+ *
  * gaim
  *
  * Gaim is the legal property of its developers, whose names are too numerous
  * to list here.  Please refer to the COPYRIGHT file distributed with this
  * source distribution.
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
--- a/src/status.h	Fri Sep 03 21:21:25 2004 +0000
+++ b/src/status.h	Fri Sep 03 21:35:52 2004 +0000
@@ -1,10 +1,13 @@
-/*
+/**
+ * @file status.h Status API
+ * @ingroup core
+ *
  * gaim
  *
  * Gaim is the legal property of its developers, whose names are too numerous
  * to list here.  Please refer to the COPYRIGHT file distributed with this
  * source distribution.
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -19,6 +22,853 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+#ifndef _GAIM_STATUS_H_
+#define _GAIM_STATUS_H_
 
-void gaim_status_sync();
-void gaim_status_load();
+typedef struct _GaimStatusType   GaimStatusType;
+typedef struct _GaimStatusAttr   GaimStatusAttr;
+typedef struct _GaimPresence     GaimPresence;
+typedef struct _GaimStatus       GaimStatus;
+
+/**
+ * A context for a presence.
+ *
+ * The context indicates what the presence applies to.
+ */
+typedef enum
+{
+	GAIM_PRESENCE_CONTEXT_UNSET   = 0,
+	GAIM_PRESENCE_CONTEXT_ACCOUNT,
+	GAIM_PRESENCE_CONTEXT_CONV,
+	GAIM_PRESENCE_CONTEXT_BUDDY
+
+} GaimPresenceContext;
+
+/**
+ * A primitive defining the basic structure of a status type.
+ */
+typedef enum
+{
+	GAIM_STATUS_UNSET     = -1,
+	GAIM_STATUS_OFFLINE   = 0,
+	GAIM_STATUS_ONLINE,
+	GAIM_STATUS_AVAILABLE,
+	GAIM_STATUS_UNAVAILABLE,
+	GAIM_STATUS_HIDDEN,
+	GAIM_STATUS_AWAY,
+	GAIM_STATUS_EXTENDED_AWAY
+
+} GaimStatusPrimitive;
+
+#include "account.h"
+#include "blist.h"
+#include "conversation.h"
+#include "value.h"
+
+/**************************************************************************/
+/** @name GaimStatusType API                                              */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Creates a new status type.
+ *
+ * @param primitive     The primitive status type.
+ * @param id            The ID of the status type.
+ * @param name          The name presented to the user.
+ * @param saveable      TRUE if the information set for this status by the
+ *                      user can be saved for future sessions.
+ * @param user_settable TRUE if this is a status the user can manually set.
+ * @param independent   TRUE if this is an independent (non-exclusive)
+ *                      status type.
+ *
+ * @return A new status type.
+ */
+GaimStatusType *gaim_status_type_new_full(GaimStatusPrimitive primitive,
+										  const char *id, const char *name,
+										  gboolean saveable,
+										  gboolean user_settable,
+										  gboolean independent);
+
+/**
+ * Creates a new status type with some default values.
+ *
+ * @param primitive     The primitive status type.
+ * @param id            The ID of the status type.
+ * @param name          The name presented to the user.
+ * @param user_settable TRUE if this is a status the user can manually set.
+ *
+ * @return A new status type.
+ */
+GaimStatusType *gaim_status_type_new(GaimStatusPrimitive primitive,
+									 const char *id, const char *name,
+									 gboolean user_settable);
+
+/**
+ * Creates a new status type with attributes.
+ *
+ * @param primitive     The primitive status type.
+ * @param id            The ID of the status type.
+ * @param name          The name presented to the user.
+ * @param saveable      TRUE if the information set for this status by the
+ *                      user can be saved for future sessions.
+ * @param user_settable TRUE if this is a status the user can manually set.
+ * @param independent   TRUE if this is an independent (non-exclusive)
+ *                      status type.
+ * @param attr_id       The ID of the first attribute.
+ * @param attr_name     The name of the first attribute.
+ * @param attr_value    The value type of the first attribute attribute.
+ * @param ...           Additional attribute information.
+ *
+ * @return A new status type.
+ */
+GaimStatusType *gaim_status_type_new_with_attrs(GaimStatusPrimitive primitive,
+												const char *id,
+												const char *name,
+												gboolean saveable,
+												gboolean user_settable,
+												gboolean independent,
+												const char *attr_id,
+												const char *attr_name,
+												GaimValue *attr_value, ...);
+
+/**
+ * Destroys a status type.
+ *
+ * @param status_type The status type to destroy.
+ */
+void gaim_status_type_destroy(GaimStatusType *status_type);
+
+/**
+ * Sets a status type's primary attribute.
+ *
+ * The value for the primary attribute is used as the description for
+ * the particular status type. An example is an away message. The message
+ * would be the primary attribute.
+ *
+ * @param status_type The status type.
+ * @param attr_id     The ID of the primary attribute.
+ */
+void gaim_status_type_set_primary_attr(GaimStatusType *status_type,
+									   const char *attr_id);
+
+/**
+ * Adds an attribute to a status type.
+ *
+ * @param status_type The status type to add the attribute to.
+ * @param id          The ID of the attribute.
+ * @param name        The name presented to the user.
+ * @param value       The value type of this attribute.
+ */
+void gaim_status_type_add_attr(GaimStatusType *status_type, const char *id,
+							   const char *name, GaimValue *value);
+
+/**
+ * Adds multiple attributes to a status type.
+ *
+ * @param status_type The status type to add the attribute to.
+ * @param id          The ID of the first attribute.
+ * @param name        The description of the first attribute.
+ * @param value       The value type of the first attribute attribute.
+ * @param ...         Additional attribute information.
+ */
+void gaim_status_type_add_attrs(GaimStatusType *status_type, const char *id,
+								const char *name, GaimValue *value, ...);
+
+/**
+ * Adds multiple attributes to a status type using a va_list.
+ *
+ * @param status_type The status type to add the attribute to.
+ * @param args        The va_list of attributes.
+ */
+void gaim_status_type_add_attrs_vargs(GaimStatusType *status_type,
+									  va_list args);
+
+/**
+ * Returns the primitive type of a status type.
+ *
+ * @param status_type The status type.
+ *
+ * @return The primitive type of the status type.
+ */
+GaimStatusPrimitive gaim_status_type_get_primitive(
+	const GaimStatusType *status_type);
+
+/**
+ * Returns the ID of a status type.
+ *
+ * @param status_type The status type.
+ *
+ * @return The ID of the status type.
+ */
+const char *gaim_status_type_get_id(const GaimStatusType *status_type);
+
+/**
+ * Returns the name of a status type.
+ *
+ * @param status_type The status type.
+ *
+ * @return The name of the status type.
+ */
+const char *gaim_status_type_get_name(const GaimStatusType *status_type);
+
+/**
+ * Returns whether or not the status type is saveable.
+ *
+ * @param status_type The status type.
+ *
+ * @return TRUE if user-defined statuses based off this type are saveable.
+ *         FALSE otherwise.
+ */
+gboolean gaim_status_type_is_saveable(const GaimStatusType *status_type);
+
+/**
+ * Returns whether or not the status type can be set or modified by the
+ * user.
+ *
+ * @param status_type The status type.
+ *
+ * @return TRUE if the status type can be set or modified by the user.
+ *         FALSE if it's a protocol-set setting.
+ */
+gboolean gaim_status_type_is_user_settable(const GaimStatusType *status_type);
+
+/**
+ * Returns whether or not the status type is independent.
+ *
+ * Independent status types are non-exclusive. If other status types on
+ * the same hierarchy level are set, this one will not be affected.
+ *
+ * @param status_type The status type.
+ *
+ * @return TRUE if the status type is independent, or FALSE otherwise.
+ */
+gboolean gaim_status_type_is_independent(const GaimStatusType *status_type);
+
+/**
+ * Returns whether or not a status type is available.
+ *
+ * Available status types are online and possibly hidden, but not away.
+ *
+ * @param status_type The status type.
+ *
+ * @return TRUE if the status is available, or FALSE otherwise.
+ */
+gboolean gaim_status_type_is_available(const GaimStatusType *status_type);
+
+/**
+ * Returns a status type's primary attribute ID.
+ *
+ * @param type The status type.
+ *
+ * @return The primary attribute's ID.
+ */
+const char *gaim_status_type_get_primary_attr(const GaimStatusType *type);
+
+/**
+ * Returns the attribute with the specified ID.
+ *
+ * @param status_type The status type containing the attribute.
+ * @param id          The ID of the desired attribute.
+ *
+ * @return The attribute, if found. NULL otherwise.
+ */
+GaimStatusAttr *gaim_status_type_get_attr(const GaimStatusType *status_type,
+										  const char *id);
+
+/**
+ * Returns a list of all attributes in a status type.
+ *
+ * @param status_type The status type.
+ *
+ * @return The list of attributes.
+ */
+const GList *gaim_status_type_get_attrs(const GaimStatusType *status_type);
+
+/*@}*/
+
+/**************************************************************************/
+/** @name GaimStatusAttr API                                              */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Creates a new status attribute.
+ *
+ * @param id         The ID of the attribute.
+ * @param name       The name presented to the user.
+ * @param value_type The type of data contained in the attribute.
+ *
+ * @return A new status attribute.
+ */
+GaimStatusAttr *gaim_status_attr_new(const char *id, const char *name,
+									 GaimValue *value_type);
+
+/**
+ * Destroys a status attribute.
+ *
+ * @param attr The status attribute to destroy.
+ */
+void gaim_status_attr_destroy(GaimStatusAttr *attr);
+
+/**
+ * Returns the ID of a status attribute.
+ *
+ * @param attr The status attribute.
+ *
+ * @return The status attribute's ID.
+ */
+const char *gaim_status_attr_get_id(const GaimStatusAttr *attr);
+
+/**
+ * Returns the name of a status attribute.
+ *
+ * @param attr The status attribute.
+ *
+ * @return The status attribute's name.
+ */
+const char *gaim_status_attr_get_name(const GaimStatusAttr *attr);
+
+/**
+ * Returns the value type of a status attribute.
+ *
+ * @param attr The status attribute.
+ *
+ * @return The status attribute's value type.
+ */
+GaimValue *gaim_status_attr_get_value_type(const GaimStatusAttr *attr);
+
+/*@}*/
+
+/**************************************************************************/
+/** @name GaimStatus API                                                  */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Creates a new status.
+ *
+ * @param status_type The type of status.
+ * @param presence    The parent presence.
+ *
+ * @return The new status.
+ */
+GaimStatus *gaim_status_new(GaimStatusType *status_type,
+							GaimPresence *presence);
+
+/**
+ * Destroys a status.
+ *
+ * @param status The status to destroy.
+ */
+void gaim_status_destroy(GaimStatus *status);
+
+/**
+ * Sets whether or not a status is active.
+ *
+ * This should only be called by the account, conversation, and buddy APIs.
+ *
+ * @param status  The status.
+ * @param active The active state.
+ */
+void gaim_status_set_active(GaimStatus *status, gboolean active);
+
+/**
+ * Sets the boolean value of an attribute in a status with the specified ID.
+ *
+ * @param status The status.
+ * @param id     The attribute ID.
+ * @param value  The boolean value.
+ */
+void gaim_status_set_attr_boolean(GaimStatus *status, const char *id,
+								  gboolean value);
+
+/**
+ * Sets the integer value of an attribute in a status with the specified ID.
+ *
+ * @param status The status.
+ * @param id     The attribute ID.
+ * @param value  The integer value.
+ */
+void gaim_status_set_attr_int(GaimStatus *status, const char *id,
+							  int value);
+
+/**
+ * Sets the string value of an attribute in a status with the specified ID.
+ *
+ * @param status The status.
+ * @param id     The attribute ID.
+ * @param value  The string value.
+ */
+void gaim_status_set_attr_string(GaimStatus *status, const char *id,
+								 const char *value);
+
+/**
+ * Returns the status's type.
+ *
+ * @param status The status.
+ *
+ * @return The status's type.
+ */
+GaimStatusType *gaim_status_get_type(const GaimStatus *status);
+
+/**
+ * Returns the status's presence.
+ *
+ * @param status The status.
+ *
+ * @return The status's presence.
+ */
+GaimPresence *gaim_status_get_presence(const GaimStatus *status);
+
+/**
+ * Returns the status's type ID.
+ *
+ * This is a convenience method for
+ * gaim_status_type_get_id(gaim_status_get_type(status)).
+ *
+ * @param status The status.
+ *
+ * @return The status's ID.
+ */
+const char *gaim_status_get_id(const GaimStatus *status);
+
+/**
+ * Returns the status's name.
+ *
+ * This is a convenience method for
+ * gaim_status_type_get_name(gaim_status_get_type(status)).
+ *
+ * @param status The status.
+ *
+ * @return The status's name.
+ */
+const char *gaim_status_get_name(const GaimStatus *status);
+
+/**
+ * Returns whether or not a status is independent.
+ *
+ * This is a convenience method for
+ * gaim_status_type_is_independent(gaim_status_get_type(status)).
+ *
+ * @param status The status.
+ *
+ * @return TRUE if the status is independent, or FALSE otherwise.
+ */
+gboolean gaim_status_is_independent(const GaimStatus *status);
+
+/**
+ * Returns whether or not a status is available.
+ *
+ * Available statuses are online and possibly hidden, but not away or idle.
+ *
+ * This is a convenience method for
+ * gaim_status_type_is_available(gaim_status_get_type(status)).
+ *
+ * @param status The status.
+ *
+ * @return TRUE if the status is available, or FALSE otherwise.
+ */
+gboolean gaim_status_is_available(const GaimStatus *status);
+
+/**
+ * Returns the active state of a status.
+ *
+ * @param status The status.
+ *
+ * @return The active state of the status.
+ */
+gboolean gaim_status_is_active(const GaimStatus *status);
+
+/**
+ * Returns the value of an attribute in a status with the specified ID.
+ *
+ * @param status The status.
+ * @param id     The attribute ID.
+ *
+ * @return The value of the attribute.
+ */
+GaimValue *gaim_status_get_attr_value(const GaimStatus *status,
+									  const char *id);
+
+/**
+ * Returns the boolean value of an attribute in a status with the specified ID.
+ *
+ * @param status The status.
+ * @param id     The attribute ID.
+ *
+ * @return The boolean value of the attribute.
+ */
+gboolean gaim_status_get_attr_boolean(const GaimStatus *status,
+									  const char *id);
+
+/**
+ * Returns the integer value of an attribute in a status with the specified ID.
+ *
+ * @param status The status.
+ * @param id     The attribute ID.
+ *
+ * @return The integer value of the attribute.
+ */
+int gaim_status_get_attr_int(const GaimStatus *status, const char *id);
+
+/**
+ * Returns the string value of an attribute in a status with the specified ID.
+ *
+ * @param status The status.
+ * @param id     The attribute ID.
+ *
+ * @return The string value of the attribute.
+ */
+const char *gaim_status_get_attr_string(const GaimStatus *status,
+										const char *id);
+
+/**
+ * Compares two statuses for availability.
+ *
+ * @param status1 The first status.
+ * @param status2 The second status.
+ *
+ * @return -1 if @a status1 is more available than @a status2.
+ *          0 if @a status1 is equal to @a status2.
+ *          1 if @a status2 is more available than @a status1.
+ */
+gint gaim_status_compare(const GaimStatus *status1, const GaimStatus *status2);
+
+/*@}*/
+
+/**************************************************************************/
+/** @name GaimPresence API                                                */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Creates a new presence.
+ *
+ * @param context The presence context.
+ *
+ * @return A new presence.
+ */
+GaimPresence *gaim_presence_new(GaimPresenceContext context);
+
+/**
+ * Creates a presence for an account.
+ *
+ * @param account The account.
+ *
+ * @return The new presence.
+ */
+GaimPresence *gaim_presence_new_for_account(GaimAccount *account);
+
+/**
+ * Creates a presence for a conversation.
+ *
+ * @param conv The conversation.
+ *
+ * @return The new presence.
+ */
+GaimPresence *gaim_presence_new_for_conv(GaimConversation *conv);
+
+/**
+ * Creates a presence for a buddy.
+ *
+ * @param buddy The buddy.
+ *
+ * @return The new presence.
+ */
+GaimPresence *gaim_presence_new_for_buddy(GaimBuddy *buddy);
+
+/**
+ * Destroys a presence.
+ *
+ * All statuses added to this list will be destroyed along with
+ * the presence.
+ *
+ * If this presence belongs to a buddy, you must call
+ * gaim_presence_remove_buddy() first.
+ *
+ * @param presence The presence to destroy.
+ */
+void gaim_presence_destroy(GaimPresence *presence);
+
+/**
+ * Removes a buddy from a presence.
+ *
+ * This must be done before destroying a buddy in a presence.
+ *
+ * @param presence The presence.
+ * @param buddy    The buddy.
+ */
+void gaim_presence_remove_buddy(GaimPresence *presence, GaimBuddy *buddy);
+
+/**
+ * Adds a status to a presence.
+ *
+ * @param presence The presence.
+ * @param status   The status to add.
+ */
+void gaim_presence_add_status(GaimPresence *presence, GaimStatus *status);
+
+/**
+ * Adds a list of statuses to the presence.
+ *
+ * @param presence    The presence.
+ * @param source_list The source list of statuses to add.
+ */
+void gaim_presence_add_list(GaimPresence *presence, const GList *source_list);
+
+/**
+ * Sets the active state of a status in a presence.
+ *
+ * Only independent statuses can be set unactive. Normal statuses can only
+ * be set active, so if you wish to disable a status, set another
+ * non-independent status to active, or use gaim_presence_switch_status().
+ *
+ * @param presence  The presence.
+ * @param status_id The ID of the status.
+ * @param active    The active state.
+ */
+void gaim_presence_set_status_active(GaimPresence *presence,
+									 const char *status_id, gboolean active);
+
+/**
+ * Switches the active status in a presence.
+ *
+ * This is similar to gaim_presence_set_status_active(), except it won't
+ * activate independent statuses.
+ *
+ * @param presence The presence.
+ * @param status_id The status ID to switch to.
+ */
+void gaim_presence_switch_status(GaimPresence *presence,
+								 const char *status_id);
+
+/**
+ * Sets the idle state and time on a presence.
+ *
+ * @param presence  The presence.
+ * @param idle      The idle state.
+ * @param idle_time The idle time, if @a idle is TRUE.
+ */
+void gaim_presence_set_idle(GaimPresence *presence, gboolean idle,
+							time_t idle_time);
+
+/**
+ * Sets the warning level on a presence.
+ *
+ * @param presence The presence.
+ * @param level    The warning level.
+ */
+void gaim_presence_set_warning_level(GaimPresence *presence,
+									 unsigned int level);
+
+/**
+ * Returns the presence's context.
+ *
+ * @param presence The presence.
+ *
+ * @return The presence's context.
+ */
+GaimPresenceContext gaim_presence_get_context(const GaimPresence *presence);
+
+/**
+ * Returns a presence's account.
+ *
+ * @param presence The presence.
+ *
+ * @return The presence's account.
+ */
+GaimAccount *gaim_presence_get_account(const GaimPresence *presence);
+
+/**
+ * Returns a presence's conversation.
+ *
+ * @param presence The presence.
+ *
+ * @return The presence's conversation.
+ */
+GaimConversation *gaim_presence_get_conversation(const GaimPresence *presence);
+
+/**
+ * Returns a presence's chat user.
+ *
+ * @param presence The presence.
+ *
+ * @return The chat's user.
+ */
+const char *gaim_presence_get_chat_user(const GaimPresence *presence);
+
+/**
+ * Returns a presence's list of buddies.
+ *
+ * @param presence The presence.
+ *
+ * @return The presence's list of buddies.
+ */
+const GList *gaim_presence_get_buddies(const GaimPresence *presence);
+
+/**
+ * Returns all the statuses in a presence.
+ *
+ * @param presence The presence.
+ *
+ * @return The statuses.
+ */
+const GList *gaim_presence_get_statuses(const GaimPresence *presence);
+
+/**
+ * Returns the status with the specified ID from a presence.
+ *
+ * @param presence  The presence.
+ * @param status_id The ID of the status.
+ *
+ * @return The status if found, or NULL.
+ */
+GaimStatus *gaim_presence_get_status(const GaimPresence *presence,
+									 const char *status_id);
+
+/**
+ * Returns the active exclusive status from a presence.
+ *
+ * @param presence The presence.
+ *
+ * @return The active exclusive status.
+ */
+GaimStatus *gaim_presence_get_active_status(const GaimPresence *presence);
+
+/**
+ * Returns whether or not a presence is available.
+ *
+ * Available presences are online and possibly hidden, but not away or idle.
+ *
+ * @param presence The presence.
+ *
+ * @return TRUE if the presence is available, or FALSE otherwise.
+ */
+gboolean gaim_presence_is_available(const GaimPresence *presence);
+
+/**
+ * Returns whether or not a presence is online.
+ *
+ * @param presence The presence.
+ *
+ * @return TRUE if the presence is online, or FALSE otherwise.
+ */
+gboolean gaim_presence_is_online(const GaimPresence *presence);
+
+/**
+ * Returns whether or not a status in a presence is active.
+ *
+ * A status is active if itself or any of its sub-statuses are active.
+ *
+ * @param presence  The presence.
+ * @param status_id The ID of the status.
+ *
+ * @return TRUE if the status is active, or FALSE.
+ */
+gboolean gaim_presence_is_status_active(const GaimPresence *presence,
+										const char *status_id);
+
+/**
+ * Returns whether or not a status with the specified primitive type
+ * in a presence is active.
+ *
+ * A status is active if itself or any of its sub-statuses are active.
+ *
+ * @param presence  The presence.
+ * @param primitive The status primitive.
+ *
+ * @return TRUE if the status is active, or FALSE.
+ */
+gboolean gaim_presence_is_status_primitive_active(
+	const GaimPresence *presence, GaimStatusPrimitive primitive);
+
+/**
+ * Returns whether or not a presence is idle.
+ *
+ * @param presence The presence.
+ *
+ * @return TRUE if the presence is idle, or FALSE otherwise.
+ */
+gboolean gaim_presence_is_idle(const GaimPresence *presence);
+
+/**
+ * Returns the presence's idle time.
+ *
+ * @param presence The presence.
+ *
+ * @return The presence's idle time.
+ */
+time_t gaim_presence_get_idle_time(const GaimPresence *presence);
+
+/**
+ * Returns the presence's warning level.
+ *
+ * @param presence The presence.
+ *
+ * @return The presence's warning level.
+ */
+unsigned int gaim_presence_get_warning_level(const GaimPresence *presence);
+
+/**
+ * Compares two presences for availability.
+ *
+ * @param presence1 The first presence.
+ * @param presence2 The second presence.
+ *
+ * @return -1 if @a presence1 is less available than @a presence2.
+ *          0 if @a presence1 is equal to @a presence2.
+ *          1 if @a presence2 is more available than @a presence1.
+ */
+gint gaim_presence_compare(const GaimPresence *presence1,
+						   const GaimPresence *presence2);
+
+/*@}*/
+
+
+/**************************************************************************/
+/** @name Status subsystem                                                */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Returns all stored statuses.
+ *
+ * @return A list of stored statuses.
+ */
+const GList *gaim_statuses_get_stored(void);
+
+/**
+ * Finds a stored 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.
+ */
+GaimStatus *gaim_statuses_find_stored(const GaimStatusType *status_type,
+									  const char *id);
+
+/**
+ * Initializes the status subsystem.
+ */
+void gaim_statuses_init(void);
+
+/**
+ * Uninitializes the status subsystem.
+ */
+void gaim_statuses_uninit(void);
+
+/**
+ * Syncs status information to the file.
+ */
+void gaim_statuses_sync(void);
+
+/**
+ * Syncs status information from a file.
+ */
+void gaim_statuses_load(void);
+
+/*@}*/
+
+#endif /* _GAIM_STATUS_H_ */