gobjectification.conversation: 2e6c58dd: Start gobjectifying conversations.

sadrul at pidgin.im sadrul at pidgin.im
Wed Jul 21 18:01:47 EDT 2010


----------------------------------------------------------------------
Revision: 2e6c58dd973f5babefca03350dbe02fabc5d4453
Parent:   30b7bd009e86cc798927aef0729ef18e9166a96c
Author:   sadrul at pidgin.im
Date:     07/21/10 18:02:48
Branch:   im.pidgin.gobjectification.conversation
URL: http://d.pidgin.im/viewmtn/revision/info/2e6c58dd973f5babefca03350dbe02fabc5d4453

Changelog: 

Start gobjectifying conversations.

The code related to conversations is now split into several files. We
have an abstract class PurpleConversation. PurpleIM is for 1-1
conversations, and PurpleMUC for multi-user conversations. We also have
PurpleMessage for messages, which I haven't gobjectified for now, and
don't really plan to at the moment, since I don't think it'd be all that
useful. If we decide that it's something we want to do, we can surely do
it later. We will also have PurpleMUCUser to represent a user in a MUC
(previously PurpleConvChatBuddy) in the future.

libpurple, and only libpurple, compiles at the moment. There are a lot of
functions that do zilch, but those will be updated as we fix compilation
for at least some prpls and clients. The API is also likely to change, so
my current plan is to start working on one prpl at a time and see what
happens.

Suggestions/Comments/Code welcome!


Changes against parent 30b7bd009e86cc798927aef0729ef18e9166a96c

  renamed  libpurple/conversation.h
       to  libpurple/conversation/conv.h
  added    libpurple/conversation
  added    libpurple/conversation/conv-im.c
  added    libpurple/conversation/conv-im.h
  added    libpurple/conversation/conv-message.c
  added    libpurple/conversation/conv-message.h
  added    libpurple/conversation/conv-muc.c
  added    libpurple/conversation/conv-muc.h
  added    libpurple/conversation/conv.c
  added    libpurple/conversation/convs.c
  added    libpurple/conversation/convs.h
  patched  libpurple/Makefile.am
  patched  libpurple/account.c
  patched  libpurple/buddy.c
  patched  libpurple/buddyicon.c
  patched  libpurple/cmds.c
  patched  libpurple/connection.c
  patched  libpurple/contact.c
  patched  libpurple/conversation/conv.h
  patched  libpurple/dbus-define-api.h
  patched  libpurple/ft.c
  patched  libpurple/log.c
  patched  libpurple/pounce.c
  patched  libpurple/prpl.c
  patched  libpurple/server.c

-------------- next part --------------
============================================================
--- libpurple/server.c	9142906f8d23f5c07cd7653605017a798f3b2dd5
+++ libpurple/server.c	6ea4374624899ed829d393dae740e8b0e42c1c66
@@ -140,7 +140,7 @@ int serv_send_im(PurpleConnection *gc, c
 	account  = purple_connection_get_account(gc);
 	presence = purple_account_get_presence(account);
 
-	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, account);
+	conv = purple_conversations_find(PURPLE_TYPE_IM, account, name);
 
 	if (prpl_info->send_im)
 		val = prpl_info->send_im(gc, name, message, flags);
@@ -160,8 +160,8 @@ int serv_send_im(PurpleConnection *gc, c
 		lar->sent = time(NULL);
 	}
 
-	if(conv && purple_conv_im_get_send_typed_timeout(PURPLE_CONV_IM(conv)))
-		purple_conv_im_stop_send_typed_timeout(PURPLE_CONV_IM(conv));
+	if(conv && purple_conversation_get_send_typed_timeout(conv))
+		purple_conversation_stop_send_typed_timeout(conv);
 
 	return val;
 }
@@ -259,7 +259,7 @@ serv_got_alias(PurpleConnection *gc, con
 
 		purple_blist_server_alias_buddy(b, alias);
 
-		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, purple_buddy_get_name(b), account);
+		conv = purple_conversations_find(PURPLE_TYPE_IM, account, purple_buddy_get_name(b));
 		if (conv != NULL && alias != NULL && !purple_strequal(alias, who))
 		{
 			char *escaped = g_markup_escape_text(who, -1);
@@ -267,9 +267,10 @@ serv_got_alias(PurpleConnection *gc, con
 			char *tmp = g_strdup_printf(_("%s is now known as %s.\n"),
 										escaped, escaped2);
 
-			purple_conversation_write(conv, NULL, tmp,
+			purple_conversation_write(conv,
+					purple_message_new(NULL, NULL, tmp,
 					PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LINKIFY,
-					time(NULL));
+					time(NULL), conv));
 
 			g_free(tmp);
 			g_free(escaped2);
@@ -584,7 +585,7 @@ void serv_got_im(PurpleConnection *gc, c
 	 * We should update the conversation window buttons and menu,
 	 * if it exists.
 	 */
-	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, purple_connection_get_account(gc));
+	conv = purple_conversations_find(PURPLE_TYPE_IM, purple_connection_get_account(gc), who);
 
 	/*
 	 * Make copies of the message and the sender in case plugins want
@@ -612,12 +613,13 @@ void serv_got_im(PurpleConnection *gc, c
 
 	/* search for conversation again in case it was created by received-im-msg handler */
 	if (conv == NULL)
-		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, purple_connection_get_account(gc));
+		conv = purple_conversations_find(PURPLE_TYPE_IM, purple_connection_get_account(gc), name);
 
 	if (conv == NULL)
-		conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, name);
+		conv = PURPLE_CONVERSATION(purple_im_new(account, name));
 
-	purple_conv_im_write(PURPLE_CONV_IM(conv), name, message, flags, mtime);
+	purple_conversation_write(conv,
+			purple_message_new(name, NULL, message, flags, mtime, conv));
 	g_free(message);
 
 	/*
@@ -685,9 +687,10 @@ void serv_got_im(PurpleConnection *gc, c
 				{
 					serv_send_im(gc, name, away_msg, PURPLE_MESSAGE_AUTO_RESP);
 
-					purple_conv_im_write(PURPLE_CONV_IM(conv), NULL, away_msg,
+					purple_conversation_write(conv,
+							purple_message_new(NULL, NULL, away_msg,
 									   PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_AUTO_RESP,
-									   mtime);
+									   mtime, conv));
 				}
 			}
 		}
@@ -699,13 +702,10 @@ void serv_got_typing(PurpleConnection *g
 void serv_got_typing(PurpleConnection *gc, const char *name, int timeout,
 					 PurpleTypingState state) {
 	PurpleConversation *conv;
-	PurpleConvIm *im = NULL;
 
-	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, purple_connection_get_account(gc));
+	conv = purple_conversations_find(PURPLE_TYPE_IM, purple_connection_get_account(gc), name);
 	if (conv != NULL) {
-		im = PURPLE_CONV_IM(conv);
-
-		purple_conv_im_set_typing_state(im, state);
+		purple_conversation_set_typing_state(conv, state);
 	} else {
 		switch (state)
 		{
@@ -725,24 +725,21 @@ void serv_got_typing(PurpleConnection *g
 	}
 
 	if (conv != NULL && timeout > 0)
-		purple_conv_im_start_typing_timeout(im, timeout);
+		purple_conversation_start_typing_timeout(conv, timeout);
 }
 
 void serv_got_typing_stopped(PurpleConnection *gc, const char *name) {
 
 	PurpleConversation *conv;
-	PurpleConvIm *im;
 
-	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, purple_connection_get_account(gc));
+	conv = purple_conversations_find(PURPLE_TYPE_IM, purple_connection_get_account(gc), name);
 	if (conv != NULL)
 	{
-		im = PURPLE_CONV_IM(conv);
-
-		if (purple_conv_im_get_typing_state(im) == PURPLE_NOT_TYPING)
+		if (purple_conversation_get_typing_state(conv) == PURPLE_NOT_TYPING)
 			return;
 
-		purple_conv_im_stop_typing_timeout(im);
-		purple_conv_im_set_typing_state(im, PURPLE_NOT_TYPING);
+		purple_conversation_stop_typing_timeout(conv);
+		purple_conversation_set_typing_state(conv, PURPLE_NOT_TYPING);
 	}
 	else
 	{
@@ -834,8 +831,7 @@ PurpleConversation *serv_got_joined_chat
 PurpleConversation *serv_got_joined_chat(PurpleConnection *gc,
 											   int id, const char *name)
 {
-	PurpleConversation *conv;
-	PurpleConvChat *chat;
+	PurpleMUC *muc;
 	PurpleAccount *account;
 
 	account = purple_connection_get_account(gc);
@@ -843,21 +839,19 @@ PurpleConversation *serv_got_joined_chat
 	g_return_val_if_fail(account != NULL, NULL);
 	g_return_val_if_fail(name != NULL, NULL);
 
-	conv = purple_conversation_new(PURPLE_CONV_TYPE_CHAT, account, name);
-	g_return_val_if_fail(conv != NULL, NULL);
+	muc = purple_muc_new(account, name);
+	g_return_val_if_fail(muc != NULL, NULL);
 
-	chat = PURPLE_CONV_CHAT(conv);
-
 #if 0
 	if (!g_slist_find(gc->buddy_chats, conv))
 		gc->buddy_chats = g_slist_append(gc->buddy_chats, conv);
 #endif
 
-	purple_conv_chat_set_id(chat, id);
+	purple_muc_set_id(muc, id);
 
-	purple_signal_emit(purple_conversations_get_handle(), "chat-joined", conv);
+	purple_signal_emit(purple_conversations_get_handle(), "chat-joined", muc);
 
-	return conv;
+	return PURPLE_CONVERSATION(muc);
 }
 
 void serv_got_chat_left(PurpleConnection *g, int id)
@@ -887,7 +881,7 @@ void serv_got_chat_left(PurpleConnection
 	g->buddy_chats = g_slist_remove(g->buddy_chats, conv);
 #endif
 
-	purple_conv_chat_left(PURPLE_CONV_CHAT(conv));
+	purple_muc_deactivate(PURPLE_MUC(conv));
 
 	purple_signal_emit(purple_conversations_get_handle(), "chat-left", conv);
 }
@@ -905,7 +899,6 @@ void serv_got_chat_in(PurpleConnection *
 	GSList *bcs;
 #endif
 	PurpleConversation *conv = NULL;
-	PurpleConvChat *chat = NULL;
 	char *buffy, *angel;
 	int plugin_return;
 	PurpleAccount *account;
@@ -930,7 +923,7 @@ void serv_got_chat_in(PurpleConnection *
 #endif
 
 	/* Did I send the message? */
-	if (purple_strequal(purple_conv_chat_get_nick(chat),
+	if (purple_strequal(purple_muc_get_nick(PURPLE_MUC(conv)),
 				purple_normalize(purple_conversation_get_account(conv), who))) {
 		flags |= PURPLE_MESSAGE_SEND;
 		flags &= ~PURPLE_MESSAGE_RECV; /* Just in case some prpl sets it! */
@@ -963,7 +956,8 @@ void serv_got_chat_in(PurpleConnection *
 	purple_signal_emit(purple_conversations_get_handle(), "received-chat-msg", account,
 					 who, message, conv, flags);
 
-	purple_conv_chat_write(chat, who, message, flags, mtime);
+	purple_conversation_write(conv,
+			purple_message_new(who, NULL, message, flags, mtime, conv));
 
 	g_free(angel);
 	g_free(buffy);
============================================================
--- libpurple/prpl.c	2f8390a0b0b39aed1c56e91c892c90f4b6ad68d1
+++ libpurple/prpl.c	44dbd258bed13045ab0e6d184efea92e926eb841
@@ -464,8 +464,9 @@ purple_prpl_send_attention(PurpleConnect
 	if (!send_attention(gc, who, type_code))
 		return;
 
-	conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, who);
-	purple_conv_im_write(PURPLE_CONV_IM(conv), NULL, description, flags, mtime);
+	conv = PURPLE_CONVERSATION(purple_im_new(account, who));
+	purple_conversation_write(conv, purple_message_new(NULL, NULL, description,
+				flags, mtime, conv));
 	purple_prpl_attention(conv, who, type_code, PURPLE_MESSAGE_SEND, time(NULL));
 
 	g_free(description);
@@ -522,11 +523,9 @@ purple_prpl_got_attention(PurpleConnecti
 	PurpleAccount *account = purple_connection_get_account(gc);
 
 	got_attention(gc, -1, who, type_code);
-	conv = 
-		purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, who, account);
+	conv = purple_conversations_find(PURPLE_TYPE_CONVERSATION, account, who);
 	if (conv)
-		purple_prpl_attention(conv, who, type_code, PURPLE_MESSAGE_RECV,
-			time(NULL));
+		purple_prpl_attention(conv, who, type_code, PURPLE_MESSAGE_RECV, time(NULL));
 }
 
 void
============================================================
--- libpurple/ft.c	f67ecd8a7cc1b2507d7eb4480256a23fc0346ad0
+++ libpurple/ft.c	3bd08493f7eb03a1b842dc9874e234e8e6857bb4
@@ -289,8 +289,8 @@ purple_xfer_conversation_write_internal(
 
 	thumbnail_data = purple_xfer_get_thumbnail(xfer, &size);
 
-	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, xfer->who,
-											   purple_xfer_get_account(xfer));
+	conv = purple_conversations_find(PURPLE_TYPE_IM, purple_xfer_get_account(xfer),
+			xfer->who);
 
 	if (conv == NULL)
 		return;
@@ -302,17 +302,18 @@ purple_xfer_conversation_write_internal(
 
 	if (print_thumbnail && thumbnail_data) {
 		gchar *message_with_img;
-		gpointer data = g_memdup(thumbnail_data, size); 
+		gpointer data = g_memdup(thumbnail_data, size);
 		int id = purple_imgstore_add_with_id(data, size, NULL);
 
-		message_with_img = 
+		message_with_img =
 			g_strdup_printf("<img id='%d'> %s", id, escaped);
-		purple_conversation_write(conv, NULL, message_with_img, flags, 
-			time(NULL));
+		purple_conversation_write(conv,
+				purple_message_new(NULL, NULL, message_with_img, flags, time(NULL), conv));
 		purple_imgstore_unref_by_id(id);
 		g_free(message_with_img);
 	} else {
-		purple_conversation_write(conv, NULL, escaped, flags, time(NULL));
+		purple_conversation_write(conv,
+				purple_message_new(NULL, NULL, escaped, flags, time(NULL), conv));
 	}
 	g_free(escaped);
 }
@@ -896,11 +897,12 @@ purple_xfer_set_completed(PurpleXfer *xf
 		else
 			msg = g_strdup(_("File transfer complete"));
 
-		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, xfer->who,
-		                                             purple_xfer_get_account(xfer));
+		conv = purple_conversations_find(PURPLE_TYPE_IM, purple_xfer_get_account(xfer),
+				xfer->who);
 
 		if (conv != NULL)
-			purple_conversation_write(conv, NULL, msg, PURPLE_MESSAGE_SYSTEM, time(NULL));
+			purple_conversation_write(conv,
+					purple_message_new(NULL, NULL, msg, PURPLE_MESSAGE_SYSTEM, time(NULL), conv));
 		g_free(msg);
 	}
 
============================================================
--- libpurple/log.c	ce007711ac88f4eb775107bdfcb09bdc395a9209
+++ libpurple/log.c	171d990d9e401399c3ffd05112681be4a8fdb1bc
@@ -912,8 +912,9 @@ void purple_log_common_writer(PurpleLog 
 					"Could not create log file %s\n", path);
 
 			if (log->conv != NULL)
-				purple_conversation_write(log->conv, NULL, _("Logging of this conversation failed."),
-										PURPLE_MESSAGE_ERROR, time(NULL));
+				purple_conversation_write(log->conv,
+						purple_message_new(NULL, NULL, _("Logging of this conversation failed."),
+							PURPLE_MESSAGE_ERROR, time(NULL), log->conv));
 
 			g_free(path);
 			return;
============================================================
--- libpurple/conversation.h	42f30ecf7cba70fa04833f0d80445f114b5c7595
+++ libpurple/conversation/conv.h	ab68f4cdf147fc2c4308b364de044119170a8ad9
@@ -27,108 +27,42 @@
 #ifndef _PURPLE_CONVERSATION_H_
 #define _PURPLE_CONVERSATION_H_
 
-/**************************************************************************/
-/** Data Structures                                                       */
-/**************************************************************************/
+G_BEGIN_DECLS
 
+#define PURPLE_TYPE_CONVERSATION purple_conversation_get_type()
 
-/** @copydoc _PurpleConversationUiOps */
-typedef struct _PurpleConversationUiOps PurpleConversationUiOps;
-/** @copydoc _PurpleConversation */
-typedef struct _PurpleConversation      PurpleConversation;
-/** @copydoc _PurpleConvIm */
-typedef struct _PurpleConvIm            PurpleConvIm;
-/** @copydoc _PurpleConvChat */
-typedef struct _PurpleConvChat          PurpleConvChat;
-/** @copydoc _PurpleConvChatBuddy */
-typedef struct _PurpleConvChatBuddy     PurpleConvChatBuddy;
-/** @copydoc _PurpleConvMessage */
-typedef struct _PurpleConvMessage       PurpleConvMessage;
+#define PURPLE_CONVERSATION(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), PURPLE_TYPE_CONVERSATION, PurpleConversation))
 
-/**
- * A type of conversation.
- */
-typedef enum
-{
-	PURPLE_CONV_TYPE_UNKNOWN = 0, /**< Unknown conversation type. */
-	PURPLE_CONV_TYPE_IM,          /**< Instant Message.           */
-	PURPLE_CONV_TYPE_CHAT,        /**< Chat room.                 */
-	PURPLE_CONV_TYPE_MISC,        /**< A misc. conversation.      */
-	PURPLE_CONV_TYPE_ANY          /**< Any type of conversation.  */
+#define PURPLE_CONVERSATION_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), PURPLE_TYPE_CONVERSATION, PurpleConversationClass))
 
-} PurpleConversationType;
+#define PURPLE_IS_CONVERSATION(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PURPLE_TYPE_CONVERSATION))
 
-/**
- * Conversation update type.
- */
-typedef enum
-{
-	PURPLE_CONV_UPDATE_ADD = 0, /**< The buddy associated with the conversation
-	                               was added.   */
-	PURPLE_CONV_UPDATE_REMOVE,  /**< The buddy associated with the conversation
-	                               was removed. */
-	PURPLE_CONV_UPDATE_ACCOUNT, /**< The purple_account was changed. */
-	PURPLE_CONV_UPDATE_TYPING,  /**< The typing state was updated. */
-	PURPLE_CONV_UPDATE_UNSEEN,  /**< The unseen state was updated. */
-	PURPLE_CONV_UPDATE_LOGGING, /**< Logging for this conversation was
-	                               enabled or disabled. */
-	PURPLE_CONV_UPDATE_TOPIC,   /**< The topic for a chat was updated. */
-	/*
-	 * XXX These need to go when we implement a more generic core/UI event
-	 * system.
-	 */
-	PURPLE_CONV_ACCOUNT_ONLINE,  /**< One of the user's accounts went online.  */
-	PURPLE_CONV_ACCOUNT_OFFLINE, /**< One of the user's accounts went offline. */
-	PURPLE_CONV_UPDATE_AWAY,     /**< The other user went away.                */
-	PURPLE_CONV_UPDATE_ICON,     /**< The other user's buddy icon changed.     */
-	PURPLE_CONV_UPDATE_TITLE,
-	PURPLE_CONV_UPDATE_CHATLEFT,
+#define PURPLE_IS_CONVERSATION_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), PURPLE_TYPE_CONVERSATION))
 
-	PURPLE_CONV_UPDATE_FEATURES  /**< The features for a chat have changed */
+#define PURPLE_CONVERSATION_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), PURPLE_TYPE_CONVERSATION, PurpleConversationClass))
 
-} PurpleConvUpdateType;
+typedef struct _PurpleConversation PurpleConversation;
+typedef struct _PurpleConversationClass PurpleConversationClass;
 
-/**
- * The typing state of a user.
- */
-typedef enum
+#include "conversation/conv-message.h"
+
+struct _PurpleConversation
 {
-	PURPLE_NOT_TYPING = 0,  /**< Not typing.                 */
-	PURPLE_TYPING,          /**< Currently typing.           */
-	PURPLE_TYPED            /**< Stopped typing momentarily. */
+	PurpleObject parent;
+};
 
-} PurpleTypingState;
-
-/**
- * Flags applicable to a message. Most will have send, recv or system.
- */
-typedef enum
+struct _PurpleConversationClass
 {
-	PURPLE_MESSAGE_SEND        = 0x0001, /**< Outgoing message.        */
-	PURPLE_MESSAGE_RECV        = 0x0002, /**< Incoming message.        */
-	PURPLE_MESSAGE_SYSTEM      = 0x0004, /**< System message.          */
-	PURPLE_MESSAGE_AUTO_RESP   = 0x0008, /**< Auto response.           */
-	PURPLE_MESSAGE_ACTIVE_ONLY = 0x0010,  /**< Hint to the UI that this
-	                                        message should not be
-	                                        shown in conversations
-	                                        which are only open for
-	                                        internal UI purposes
-	                                        (e.g. for contact-aware
-	                                         conversations).           */
-	PURPLE_MESSAGE_NICK        = 0x0020, /**< Contains your nick.      */
-	PURPLE_MESSAGE_NO_LOG      = 0x0040, /**< Do not log.              */
-	PURPLE_MESSAGE_WHISPER     = 0x0080, /**< Whispered message.       */
-	PURPLE_MESSAGE_ERROR       = 0x0200, /**< Error message.           */
-	PURPLE_MESSAGE_DELAYED     = 0x0400, /**< Delayed message.         */
-	PURPLE_MESSAGE_RAW         = 0x0800, /**< "Raw" message - don't
-	                                        apply formatting         */
-	PURPLE_MESSAGE_IMAGES      = 0x1000, /**< Message contains images  */
-	PURPLE_MESSAGE_NOTIFY      = 0x2000, /**< Message is a notification */
-	PURPLE_MESSAGE_NO_LINKIFY  = 0x4000, /**< Message should not be auto-
-										   linkified @since 2.1.0 */
-	PURPLE_MESSAGE_INVISIBLE   = 0x8000  /**< Message should not be displayed */
-} PurpleMessageFlags;
+	PurpleObjectClass parent_class;
+};
 
+GType purple_conversation_get_type (void);
+
 /**
  * Flags applicable to users in Chats.
  */
@@ -146,7 +80,6 @@ typedef enum
 #include "account.h"
 #include "buddyicon.h"
 #include "log.h"
-#include "server.h"
 
 /**
  * Conversation operations and events.
@@ -258,21 +191,6 @@ extern "C" {
 /*@{*/
 
 /**
- * Creates a new conversation of the specified type.
- *
- * @param type    The type of conversation.
- * @param account The account opening the conversation window on the purple
- *                user's end.
- * @param name    The name of the conversation.  For PURPLE_CONV_TYPE_IM,
- *                this is the name of the buddy.
- *
- * @return The new conversation.
- */
-PurpleConversation *purple_conversation_new(PurpleConversationType type,
-										PurpleAccount *account,
-										const char *name);
-
-/**
  * Destroys the specified conversation and removes it from the parent
  * window.
  *
@@ -291,7 +209,7 @@ void purple_conversation_present(PurpleC
  */
 void purple_conversation_present(PurpleConversation *conv);
 
-
+#if 0
 /**
  * Returns the specified conversation's type.
  *
@@ -335,28 +253,9 @@ void *purple_conversation_get_ui_data(Pu
  * @return the ui_data
  */
 void *purple_conversation_get_ui_data(PurpleConversation *conv);
+#endif
 
 /**
- * Sets the ui_data for this conversation
- *
- * @param conv The conversation
- * @param data The ui_data
- */
-void purple_conversation_set_ui_data(PurpleConversation *conv, void *data);
-
-/**
- * Sets the specified conversation's purple_account.
- *
- * This purple_account represents the user using purple, not the person the user
- * is having a conversation/chat/flame with.
- *
- * @param conv The conversation.
- * @param account The purple_account.
- */
-void purple_conversation_set_account(PurpleConversation *conv,
-                                   PurpleAccount *account);
-
-/**
  * Returns the specified conversation's purple_account.
  *
  * This purple_account represents the user using purple, not the person the user
@@ -456,6 +355,7 @@ void purple_conversation_close_logs(Purp
  */
 void purple_conversation_close_logs(PurpleConversation *conv);
 
+#if 0
 /**
  * Returns the specified conversation's IM-specific data.
  *
@@ -468,7 +368,9 @@ PurpleConvIm *purple_conversation_get_im
 PurpleConvIm *purple_conversation_get_im_data(const PurpleConversation *conv);
 
 #define PURPLE_CONV_IM(c) (purple_conversation_get_im_data(c))
+#endif
 
+#if 0
 /**
  * Returns the specified conversation's chat-specific data.
  *
@@ -481,6 +383,7 @@ PurpleConvChat *purple_conversation_get_
 PurpleConvChat *purple_conversation_get_chat_data(const PurpleConversation *conv);
 
 #define PURPLE_CONV_CHAT(c) (purple_conversation_get_chat_data(c))
+#endif
 
 /**
  * Sets extra data for a conversation.
@@ -525,6 +428,7 @@ GList *purple_get_chats(void);
  */
 GList *purple_get_chats(void);
 
+#if 0
 /**
  * Finds a conversation with the specified type, name, and Purple account.
  *
@@ -537,7 +441,9 @@ PurpleConversation *purple_find_conversa
 PurpleConversation *purple_find_conversation_with_account(
 		PurpleConversationType type, const char *name,
 		const PurpleAccount *account);
+#endif
 
+#if 0
 /**
  * Writes to a conversation window.
  *
@@ -561,6 +467,7 @@ void purple_conversation_write(PurpleCon
 void purple_conversation_write(PurpleConversation *conv, const char *who,
 		const char *message, PurpleMessageFlags flags,
 		time_t mtime);
+#endif
 
 /**
 	Set the features as supported for the given conversation.
@@ -587,6 +494,7 @@ gboolean purple_conversation_has_focus(P
  */
 gboolean purple_conversation_has_focus(PurpleConversation *conv);
 
+#if 0
 /**
  * Updates the visual status and UI of a conversation.
  *
@@ -594,6 +502,7 @@ void purple_conversation_update(PurpleCo
  * @param type The update type.
  */
 void purple_conversation_update(PurpleConversation *conv, PurpleConvUpdateType type);
+#endif
 
 /**
  * Calls a function on each conversation.
@@ -624,54 +533,9 @@ void purple_conversation_clear_message_h
  */
 void purple_conversation_clear_message_history(PurpleConversation *conv);
 
-/**
- * Get the sender from a PurpleConvMessage
- *
- * @param msg   A PurpleConvMessage
- *
- * @return   The name of the sender of the message
- *
- * @since 2.2.0
- */
-const char *purple_conversation_message_get_sender(PurpleConvMessage *msg);
+#if 0
+#endif
 
-/**
- * Get the message from a PurpleConvMessage
- *
- * @param msg   A PurpleConvMessage
- *
- * @return   The name of the sender of the message
- *
- * @since 2.2.0
- */
-const char *purple_conversation_message_get_message(PurpleConvMessage *msg);
-
-/**
- * Get the message-flags of a PurpleConvMessage
- *
- * @param msg   A PurpleConvMessage
- *
- * @return   The message flags
- *
- * @since 2.2.0
- */
-PurpleMessageFlags purple_conversation_message_get_flags(PurpleConvMessage *msg);
-
-/**
- * Get the timestamp of a PurpleConvMessage
- *
- * @param msg   A PurpleConvMessage
- *
- * @return   The timestamp of the message
- *
- * @since 2.2.0
- */
-time_t purple_conversation_message_get_timestamp(PurpleConvMessage *msg);
-
-const char * purple_conversation_message_get_alias(PurpleConvMessage *msg);
-
-PurpleConversation * purple_conversation_message_get_conversation(PurpleConvMessage *msg);
-
 /*@}*/
 
 
@@ -680,6 +544,7 @@ PurpleConversation * purple_conversation
 /**************************************************************************/
 /*@{*/
 
+#if 0
 /**
  * Gets an IM's parent conversation.
  *
@@ -818,6 +683,8 @@ void purple_conv_im_write(PurpleConvIm *
 						const char *message, PurpleMessageFlags flags,
 						time_t mtime);
 
+#endif
+
 /**
  * Presents an IM-error to the user
  *
@@ -833,6 +700,7 @@ gboolean purple_conv_present_error(const
  */
 gboolean purple_conv_present_error(const char *who, PurpleAccount *account, const char *what);
 
+#if 0
 /**
  * Sends a message to this IM conversation.
  *
@@ -840,6 +708,7 @@ void purple_conv_im_send(PurpleConvIm *i
  * @param message The message to send.
  */
 void purple_conv_im_send(PurpleConvIm *im, const char *message);
+#endif
 
 /**
  * Sends a message to a conversation after confirming with
@@ -855,6 +724,7 @@ void purple_conv_send_confirm(PurpleConv
  */
 void purple_conv_send_confirm(PurpleConversation *conv, const char *message);
 
+#if 0
 /**
  * Sends a message to this IM conversation with specified flags.
  *
@@ -863,6 +733,7 @@ void purple_conv_im_send_with_flags(Purp
  * @param flags   The PurpleMessageFlags flags to use in addition to PURPLE_MESSAGE_SEND.
  */
 void purple_conv_im_send_with_flags(PurpleConvIm *im, const char *message, PurpleMessageFlags flags);
+#endif
 
 /**
  * Adds a smiley to the conversation's smiley tree. If this returns
@@ -921,6 +792,7 @@ void purple_conv_custom_smiley_close(Pur
 /**************************************************************************/
 /*@{*/
 
+#if 0
 /**
  * Gets a chat's parent conversation.
  *
@@ -929,7 +801,9 @@ PurpleConversation *purple_conv_chat_get
  * @return The parent conversation.
  */
 PurpleConversation *purple_conv_chat_get_conversation(const PurpleConvChat *chat);
+#endif
 
+#if 0
 /**
  * Sets the list of users in the chat room.
  *
@@ -1201,6 +1075,7 @@ const char *purple_conv_chat_get_nick(Pu
  * @return  The nick.
  */
 const char *purple_conv_chat_get_nick(PurpleConvChat *chat);
+#endif
 
 /**
  * Finds a chat with the specified chat ID.
@@ -1212,6 +1087,7 @@ PurpleConversation *purple_find_chat(con
  */
 PurpleConversation *purple_find_chat(const PurpleConnection *gc, int id);
 
+#if 0
 /**
  * Lets the core know we left a chat, without destroying it.
  * Called from serv_got_chat_left().
@@ -1246,7 +1122,9 @@ gboolean purple_conv_chat_has_left(Purpl
  * we're still there.
  */
 gboolean purple_conv_chat_has_left(PurpleConvChat *chat);
+#endif
 
+#if 0
 /**
  * Creates a new chat buddy
  *
@@ -1288,6 +1166,7 @@ void purple_conv_chat_cb_destroy(PurpleC
  * @param cb The chat buddy to destroy
  */
 void purple_conv_chat_cb_destroy(PurpleConvChatBuddy *cb);
+#endif
 
 /**
  * Retrieves the extended menu items for the conversation.
@@ -1343,6 +1222,67 @@ void purple_conversations_uninit(void);
 
 /*@}*/
 
+/** New API for gobjectification */
+
+/**
+ * Conversation update type.
+ */
+typedef enum
+{
+	PURPLE_CONVERSATION_UPDATE_ADD = 0, /**< The buddy associated with the conversation
+	                               was added.   */
+	PURPLE_CONVERSATION_UPDATE_REMOVE,  /**< The buddy associated with the conversation
+	                               was removed. */
+	PURPLE_CONVERSATION_UPDATE_ACCOUNT, /**< The purple_account was changed. */
+	PURPLE_CONVERSATION_UPDATE_TYPING,  /**< The typing state was updated. */
+	PURPLE_CONVERSATION_UPDATE_UNSEEN,  /**< The unseen state was updated. */
+	PURPLE_CONVERSATION_UPDATE_LOGGING, /**< Logging for this conversation was
+	                               enabled or disabled. */
+	PURPLE_CONVERSATION_UPDATE_TOPIC,   /**< The topic for a chat was updated. */
+	/*
+	 * XXX These need to go when we implement a more generic core/UI event
+	 * system.
+	 */
+	PURPLE_CONVERSATION_UCCOUNT_ONLINE,  /**< One of the user's accounts went online.  */
+	PURPLE_CONVERSATION_UCCOUNT_OFFLINE, /**< One of the user's accounts went offline. */
+	PURPLE_CONVERSATION_UPDATE_AWAY,     /**< The other user went away.                */
+	PURPLE_CONVERSATION_UPDATE_ICON,     /**< The other user's buddy icon changed.     */
+	PURPLE_CONVERSATION_UPDATE_TITLE,
+	PURPLE_CONVERSATION_UPDATE_CHATLEFT,
+
+	PURPLE_CONVERSATION_UPDATE_FEATURES  /**< The features for a chat have changed */
+} PurpleConversationUpdate;
+
+/**
+ * The typing state of a user.
+ */
+typedef enum
+{
+	PURPLE_NOT_TYPING = 0,  /**< Not typing.                 */
+	PURPLE_TYPING,          /**< Currently typing.           */
+	PURPLE_TYPED            /**< Stopped typing momentarily. */
+} PurpleTypingState;
+
+#include "server.h"
+
+void purple_conversation_set_icon(PurpleConversation *conv, PurpleBuddyIcon *icon);
+
+void purple_conversation_update(PurpleConversation *conv, PurpleConversationUpdate update);
+
+PurpleTypingState purple_conversation_get_typing_state(PurpleConversation *conv);
+
+void purple_conversation_set_typing_state(PurpleConversation *conv, PurpleTypingState state);
+
+void purple_conversation_start_typing_timeout(PurpleConversation *conv, int timeout);
+
+void purple_conversation_stop_typing_timeout(PurpleConversation *conv);
+
+guint purple_conversation_get_send_typed_timeout(PurpleConversation *conv);
+
+void purple_conversation_stop_send_typed_timeout(PurpleConversation *conv);
+
+void purple_conversation_write(PurpleConversation *conv, PurpleMessage *msg);
+
 #ifdef __cplusplus
 }
 #endif
============================================================
--- libpurple/pounce.c	ecbbe113a0a7396521042fd52835a0fc6c988a80
+++ libpurple/pounce.c	519900003d13231dc8a58aa940381f3752d6410c
@@ -1083,13 +1083,13 @@ buddy_typing_cb(PurpleAccount *account, 
 {
 	PurpleConversation *conv;
 
-	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, account);
+	conv = purple_conversations_find(PURPLE_TYPE_IM, account, name);
 	if (conv != NULL)
 	{
 		PurpleTypingState state;
 		PurplePounceEvent event;
 
-		state = purple_conv_im_get_typing_state(PURPLE_CONV_IM(conv));
+		state = purple_conversation_get_typing_state(conv);
 		if (state == PURPLE_TYPED)
 			event = PURPLE_POUNCE_TYPED;
 		else if (state == PURPLE_NOT_TYPING)
============================================================
--- libpurple/account.c	d2d7d7baddeb9a7df1992ac1cd2c9576d29e7ebf
+++ libpurple/account.c	336c42171fc8c2cfa4e35ada094d46dae57d901e
@@ -587,6 +587,7 @@ purple_account_dispose(GObject *object)
 	 */
 	purple_account_clear_current_error(account);
 
+#if 0
 	/* TODO: Remove this from here, and make the conversations subsystem update itself. */
 	for (l = purple_get_conversations(); l != NULL; l = l->next) {
 		PurpleConversation *conv = (PurpleConversation *)l->data;
@@ -594,6 +595,7 @@ purple_account_dispose(GObject *object)
 		if (purple_conversation_get_account(conv) == account)
 			purple_conversation_set_account(conv, NULL);
 	}
+#endif
 
 	purple_account_set_status_types(account, NULL);
 
============================================================
--- libpurple/connection.c	06957c17314cd959cb85243e576e3feca2e95b65
+++ libpurple/connection.c	d36fbbf98acb87d37c6ac5ff11e505d0905946b9
@@ -842,6 +842,8 @@ purple_connection_dispose(GObject *obj)
 
 	g_signal_emit(G_OBJECT(pc), signals[SIG_SIGNING_OFF], 0);
 
+#warning Mark MUCs as inactive when the account disconnects
+#if 0
 	while (priv->buddy_chats)
 	{
 		PurpleConversation *b = priv->buddy_chats->data;
@@ -849,6 +851,10 @@ purple_connection_dispose(GObject *obj)
 		priv->buddy_chats = g_slist_remove(priv->buddy_chats, b);
 		purple_conv_chat_left(PURPLE_CONV_CHAT(b));
 	}
+#else
+	g_slist_free(priv->buddy_chats);
+	priv->buddy_chats = NULL;
+#endif
 
 	update_keepalive(pc, FALSE);
 
============================================================
--- libpurple/buddyicon.c	3e6510efa5e0de81595786b28a6125343191fa6a
+++ libpurple/buddyicon.c	afaa99825c77241c01d034c1b4c9af64b9af18dc
@@ -450,10 +450,10 @@ purple_buddy_icon_update(PurpleBuddyIcon
 		buddies = g_slist_delete_link(buddies, buddies);
 	}
 
-	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, username, account);
+	conv = purple_conversations_find(PURPLE_TYPE_IM, account, username);
 
 	if (conv != NULL)
-		purple_conv_im_set_icon(PURPLE_CONV_IM(conv), icon_to_set);
+		purple_conversation_set_icon(conv, icon_to_set);
 
 	/* icon's refcount was incremented above */
 	if (icon) purple_buddy_icon_unref(icon);
@@ -902,9 +902,11 @@ purple_buddy_icons_node_set_custom_icon(
 
 			buddy = (PurpleBuddy *)child;
 
-			conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, purple_buddy_get_name(buddy), purple_buddy_get_account(buddy));
+			conv = purple_conversations_find(PURPLE_TYPE_IM,
+					purple_buddy_get_account(buddy),
+					purple_buddy_get_name(buddy));
 			if (conv)
-				purple_conversation_update(conv, PURPLE_CONV_UPDATE_ICON);
+				purple_conversation_update(conv, PURPLE_CONVERSATION_UPDATE_ICON);
 
 			/* Is this call necessary anymore? Can the buddies
 			 * themselves need updating when the custom buddy
@@ -914,9 +916,11 @@ purple_buddy_icons_node_set_custom_icon(
 	} else if (PURPLE_IS_CHAT(node)) {
 		PurpleConversation *conv = NULL;
 
-		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, purple_chat_get_name((PurpleChat*)node), purple_chat_get_account((PurpleChat*)node));
+		conv = purple_conversations_find(PURPLE_TYPE_MUC,
+				purple_chat_get_account((PurpleChat*)node),
+				purple_chat_get_name((PurpleChat*)node));
 		if (conv) {
-			purple_conversation_update(conv, PURPLE_CONV_UPDATE_ICON);
+			purple_conversation_update(conv, PURPLE_CONVERSATION_UPDATE_ICON);
 		}
 	}
 
============================================================
--- libpurple/cmds.c	f2e052a4f379bb397a19af573c691abf8b8f952b
+++ libpurple/cmds.c	511e851d6018a669ad903b593952035ec880d6c3
@@ -212,9 +212,9 @@ PurpleCmdStatus purple_cmd_do_command(Pu
 	*error = NULL;
 	prpl_id = purple_account_get_protocol_id(purple_conversation_get_account(conv));
 
-	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM)
+	if (PURPLE_IS_IM(conv))
 		is_im = TRUE;
-	else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT)
+	else if (PURPLE_IS_MUC(conv))
 		is_im = FALSE;
 	else
 		return PURPLE_CMD_STATUS_FAILED;
@@ -311,10 +311,10 @@ GList *purple_cmd_list(PurpleConversatio
 	for (l = cmds; l; l = l->next) {
 		c = l->data;
 
-		if (conv && (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM))
+		if (conv && PURPLE_IS_IM(conv))
 			if (!(c->flags & PURPLE_CMD_FLAG_IM))
 				continue;
-		if (conv && (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT))
+		if (conv && PURPLE_IS_MUC(conv))
 			if (!(c->flags & PURPLE_CMD_FLAG_CHAT))
 				continue;
 
@@ -343,10 +343,10 @@ GList *purple_cmd_help(PurpleConversatio
 		if (cmd && !purple_strequal(cmd, c->cmd))
 			continue;
 
-		if (conv && (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM))
+		if (conv && PURPLE_IS_IM(conv))
 			if (!(c->flags & PURPLE_CMD_FLAG_IM))
 				continue;
-		if (conv && (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT))
+		if (conv && PURPLE_IS_MUC(conv))
 			if (!(c->flags & PURPLE_CMD_FLAG_CHAT))
 				continue;
 
============================================================
--- libpurple/dbus-define-api.h	23b9d412fbd710505b48309c68e8e8c34fdde858
+++ libpurple/dbus-define-api.h	03ac252b0ff79ac7e3cd85f3d3d0c07ef17176d2
@@ -18,8 +18,3 @@ gboolean PURPLE_CONNECTION_IS_VALID(Purp
 gboolean PURPLE_CONNECTION_IS_CONNECTED(PurpleConnection *connection);
 gboolean PURPLE_CONNECTION_IS_VALID(PurpleConnection *connection);
 
-/* conversation.h */
-PurpleConvIm *PURPLE_CONV_IM(const PurpleConversation *conversation);
-PurpleConvIm *PURPLE_CONV_CHAT(const PurpleConversation *conversation);
-
-
============================================================
--- libpurple/Makefile.am	553a46c2b85dc706d4c98dbca191594082091583
+++ libpurple/Makefile.am	3c7ee3b46280d2e6c0e59efc29da1f09b46bad04
@@ -58,7 +58,11 @@ purple_coresources = \
 	cipher/sha256hash.c \
 	cmds.c \
 	connection.c \
-	conversation.c \
+	conversation/conv-message.c \
+	conversation/conv.c \
+	conversation/convs.c \
+	conversation/conv-im.c \
+	conversation/conv-muc.c \
 	contact.c \
 	core.c \
 	debug.c \
@@ -143,6 +147,11 @@ purple_coreheaders = \
 	cmds.h \
 	connection.h \
 	contact.h \
+	conversation/conv-message.h \
+	conversation/conv.h \
+	conversation/convs.h \
+	conversation/conv-im.h \
+	conversation/conv-muc.h \
 	conversation.h \
 	core.h \
 	dbus-maybe.h \
============================================================
--- libpurple/buddy.c	cd6d85a7b73b3d7f419e21e2265db20ee9451691
+++ libpurple/buddy.c	3e681aa8de556dc71278849d05c2f162f5791d93
@@ -178,8 +178,7 @@ void purple_buddy_set_alias(PurpleBuddy 
 	if (ops && ops->update)
 		ops->update(PURPLE_BLIST_NODE(buddy));
 
-	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, priv->name,
-											   priv->account);
+	conv = purple_conversations_find(PURPLE_TYPE_IM, priv->account, priv->name);
 	if (conv)
 		purple_conversation_autoset_title(conv);
 
@@ -234,8 +233,7 @@ void purple_blist_server_alias_buddy(Pur
 	if (ops && ops->update)
 		ops->update(PURPLE_BLIST_NODE(buddy));
 
-	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, priv->name,
-											   priv->account);
+	conv = purple_conversations_find(PURPLE_TYPE_IM, priv->account, priv->name);
 	if (conv)
 		purple_conversation_autoset_title(conv);
 
============================================================
--- libpurple/contact.c	d67426f798f84484ccea0f14bf0e75f286fe2f93
+++ libpurple/contact.c	559a7b1e1977757c75773957f47b90f76fc27edc
@@ -195,8 +195,8 @@ void purple_blist_alias_contact(PurpleCo
 	{
 		PurpleBuddy *buddy = (PurpleBuddy *)bnode;
 
-		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, purple_buddy_get_name(buddy),
-												   purple_buddy_get_account(buddy));
+		conv = purple_conversations_find(PURPLE_TYPE_IM,
+				purple_buddy_get_account(buddy), purple_buddy_get_name(buddy));
 		if (conv)
 			purple_conversation_autoset_title(conv);
 	}
============================================================
--- /dev/null	
+++ libpurple/conversation/conv-im.c	ce5c5be6f3893e2c4d15907a77cf38a1c42ea21f
@@ -0,0 +1,116 @@
+/**
+ * @file conversation.h Conversation IM API
+ * @ingroup core
+ * @see @ref conversation-signals
+ */
+
+/* purple
+ *
+ * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "internal.h"
+
+#include "conversation/conv-im.h"
+
+enum
+{
+	PROP_LAST
+};
+
+G_DEFINE_TYPE (PurpleIM, purple_im, PURPLE_TYPE_CONVERSATION)
+
+#define GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), PURPLE_TYPE_IM, PurpleIMPrivate))
+
+typedef struct _PurpleIMPrivate PurpleIMPrivate;
+
+struct _PurpleIMPrivate
+{
+};
+
+static void
+purple_im_dispose (GObject *object)
+{
+	G_OBJECT_CLASS (purple_im_parent_class)->dispose (object);
+}
+
+static void
+purple_im_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (purple_im_parent_class)->finalize (object);
+}
+
+static void
+purple_im_set_property(GObject *obj, guint param_id, const GValue *value,
+		GParamSpec *pspec)
+{
+	switch (param_id) {
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_im_get_property(GObject *obj, guint param_id, GValue *value,
+		GParamSpec *pspec)
+{
+	switch (param_id) {
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_im_class_init (PurpleIMClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (PurpleIMPrivate));
+
+	object_class->dispose = purple_im_dispose;
+	object_class->finalize = purple_im_finalize;
+
+	object_class->get_property = purple_im_get_property;
+	object_class->set_property = purple_im_set_property;
+}
+
+static void
+purple_im_init (PurpleIM *self)
+{
+}
+
+PurpleIM*
+purple_im_new (const PurpleAccount *account, const char *who)
+{
+	PurpleIM *im;
+
+	/* TODO: First, look for an existing IM */
+
+	im = g_object_new (PURPLE_TYPE_IM,
+			"account", account,
+			"name", who,
+			NULL);
+
+	g_signal_emit_by_name(G_OBJECT(im), "new");
+
+	return im;
+}
+
============================================================
--- /dev/null	
+++ libpurple/conversation/conv-im.h	ad0d567073ce0eb8df1e85488aad3f012269057f
@@ -0,0 +1,68 @@
+/**
+ * @file conversation.h Conversation IM API
+ * @ingroup core
+ * @see @ref conversation-signals
+ */
+
+/* purple
+ *
+ * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef _PURPLE_CONVERSATION_IM_H_
+#define _PURPLE_CONVERSATION_IM_H_
+
+#include "conversation/conv.h"
+
+G_BEGIN_DECLS
+
+#define PURPLE_TYPE_IM purple_im_get_type()
+
+#define PURPLE_IM(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), PURPLE_TYPE_IM, PurpleIM))
+
+#define PURPLE_IM_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), PURPLE_TYPE_IM, PurpleIMClass))
+
+#define PURPLE_IS_IM(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PURPLE_TYPE_IM))
+
+#define PURPLE_IS_IM_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), PURPLE_TYPE_IM))
+
+#define PURPLE_IM_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), PURPLE_TYPE_IM, PurpleIMClass))
+
+typedef struct
+{
+  PurpleConversation parent;
+} PurpleIM;
+
+typedef struct
+{
+  PurpleConversationClass parent_class;
+} PurpleIMClass;
+
+GType purple_im_get_type (void);
+
+PurpleIM* purple_im_new (const PurpleAccount *account, const char *who);
+
+G_END_DECLS
+
+#endif
+
============================================================
--- /dev/null	
+++ libpurple/conversation/conv-message.c	be3f9a62615ac08ab8aa1e31a2f6d23f52589920
@@ -0,0 +1,92 @@
+/*
+ * purple
+ *
+ * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "internal.h"
+
+#include "conversation/conv-message.h"
+
+/* Do we want to GObject-ify this? I don't think we lose anything if we don't. */
+struct _PurpleMessage
+{
+	char *who;
+	char *what;
+	time_t when;
+	PurpleMessageFlags flags;
+	PurpleConversation *conv;
+	char *alias;
+};
+
+PurpleMessage *purple_message_new(const char *who,
+		const char *alias, const char *message,
+		PurpleMessageFlags flags, time_t when,
+		PurpleConversation *conv)
+{
+	PurpleMessage *msg = g_new0(PurpleMessage, 1);
+	msg->who = g_strdup(who);
+	msg->alias = g_strdup(alias);
+	msg->flags = flags;
+	msg->what = g_strdup(message);
+	msg->when = when;
+	msg->conv = conv;
+
+	return msg;
+}
+
+const char *
+purple_message_get_sender(PurpleMessage *msg)
+{
+	g_return_val_if_fail(msg, NULL);
+	return msg->who;
+}
+
+const char *
+purple_message_get_message(PurpleMessage *msg)
+{
+	g_return_val_if_fail(msg, NULL);
+	return msg->what;
+}
+
+PurpleMessageFlags
+purple_message_get_flags(PurpleMessage *msg)
+{
+	g_return_val_if_fail(msg, 0);
+	return msg->flags;
+}
+
+time_t
+purple_message_get_timestamp(PurpleMessage *msg)
+{
+	g_return_val_if_fail(msg, 0);
+	return msg->when;
+}
+
+const char *
+purple_message_get_alias(PurpleMessage *msg)
+{
+	return msg->alias;
+}
+
+PurpleConversation *
+purple_message_get_conversation(PurpleMessage *msg)
+{
+	return msg->conv;
+}
+
============================================================
--- /dev/null	
+++ libpurple/conversation/conv-message.h	936e31d7320071f2dea86b32b0b43b95e22cc9a1
@@ -0,0 +1,108 @@
+/**
+ * @file conversation.h Conversation Message API
+ * @ingroup core
+ * @see @ref conversation-signals
+ */
+
+/* purple
+ *
+ * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef PURPLE_CONVERSATION_MESSAGE_H
+#define PURPLE_CONVERSATION_MESSAGE_H
+
+typedef struct _PurpleMessage PurpleMessage;
+
+/**
+ * Flags applicable to a message. Most will have send, recv or system.
+ */
+typedef enum
+{
+	PURPLE_MESSAGE_SEND        = 0x0001, /**< Outgoing message.        */
+	PURPLE_MESSAGE_RECV        = 0x0002, /**< Incoming message.        */
+	PURPLE_MESSAGE_SYSTEM      = 0x0004, /**< System message.          */
+	PURPLE_MESSAGE_AUTO_RESP   = 0x0008, /**< Auto response.           */
+	PURPLE_MESSAGE_ACTIVE_ONLY = 0x0010,  /**< Hint to the UI that this
+	                                        message should not be
+	                                        shown in conversations
+	                                        which are only open for
+	                                        internal UI purposes
+	                                        (e.g. for contact-aware
+	                                         conversations).           */
+	PURPLE_MESSAGE_NICK        = 0x0020, /**< Contains your nick.      */
+	PURPLE_MESSAGE_NO_LOG      = 0x0040, /**< Do not log.              */
+	PURPLE_MESSAGE_WHISPER     = 0x0080, /**< Whispered message.       */
+	PURPLE_MESSAGE_ERROR       = 0x0200, /**< Error message.           */
+	PURPLE_MESSAGE_DELAYED     = 0x0400, /**< Delayed message.         */
+	PURPLE_MESSAGE_RAW         = 0x0800, /**< "Raw" message - don't
+	                                        apply formatting         */
+	PURPLE_MESSAGE_IMAGES      = 0x1000, /**< Message contains images  */
+	PURPLE_MESSAGE_NOTIFY      = 0x2000, /**< Message is a notification */
+	PURPLE_MESSAGE_NO_LINKIFY  = 0x4000, /**< Message should not be auto-
+										   linkified @since 2.1.0 */
+	PURPLE_MESSAGE_INVISIBLE   = 0x8000  /**< Message should not be displayed */
+} PurpleMessageFlags;
+
+PurpleMessage *purple_message_new(const char *who,
+		const char *alias, const char *message,
+		PurpleMessageFlags flags, time_t when,
+		PurpleConversation *conv);
+
+/**
+ * Get the sender from a PurpleMessage
+ *
+ * @param msg   A PurpleMessage
+ *
+ * @return   The name of the sender of the message
+ */
+const char *purple_message_get_sender(PurpleMessage *msg);
+
+/**
+ * Get the message from a PurpleMessage
+ *
+ * @param msg   A PurpleMessage
+ *
+ * @return   The name of the sender of the message
+ */
+const char *purple_message_get_message(PurpleMessage *msg);
+
+/**
+ * Get the message-flags of a PurpleMessage
+ *
+ * @param msg   A PurpleMessage
+ *
+ * @return   The message flags
+ */
+PurpleMessageFlags purple_message_get_flags(PurpleMessage *msg);
+
+/**
+ * Get the timestamp of a PurpleMessage
+ *
+ * @param msg   A PurpleMessage
+ *
+ * @return   The timestamp of the message
+ */
+time_t purple_message_get_timestamp(PurpleMessage *msg);
+
+const char * purple_message_get_alias(PurpleMessage *msg);
+
+PurpleConversation * purple_message_get_conversation(PurpleMessage *msg);
+
+#endif
+
============================================================
--- /dev/null	
+++ libpurple/conversation/conv-muc.c	33889b3ed38777a411002aaa4496e99cc828b9a5
@@ -0,0 +1,172 @@
+/* purple
+ *
+ * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "internal.h"
+
+#include "conv-muc.h"
+
+enum
+{
+	PROP_TOPIC,
+	PROP_TOPIC_USER,
+	PROP_TOPIC_TIME,
+	PROP_LAST
+};
+
+G_DEFINE_TYPE (PurpleMUC, purple_muc, PURPLE_TYPE_CONVERSATION)
+
+#define GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), PURPLE_TYPE_MUC, PurpleMUCPrivate))
+
+typedef struct _PurpleMUCPrivate PurpleMUCPrivate;
+
+struct _PurpleMUCPrivate
+{
+	GList *users;		/* List of users in the room */
+	GList *ignored;		/* List of ignored users in the room */
+	struct {
+		char *who;		/* Who set the topic? */
+		char *text;		/* What is the topic? */
+		time_t when;	/* When was the topic set? */
+	} topic;
+
+	char *nick;			/* What's my nick in this room? */
+	gboolean active;	/* Is this an active chatroom? (i.e. am I still in this chat?) */
+};
+
+static void
+purple_muc_set_property (GObject *object, guint property_id,
+                              const GValue *value, GParamSpec *pspec)
+{
+	PurpleMUC *muc = PURPLE_MUC(object);
+	PurpleMUCPrivate *priv = GET_PRIVATE(muc);
+
+	switch (property_id) {
+		case PROP_TOPIC:
+			g_free(priv->topic.text);
+			priv->topic.text = g_strdup(g_value_get_string(value));
+			break;
+		case PROP_TOPIC_USER:
+			g_free(priv->topic.who);
+			priv->topic.who = g_strdup(g_value_get_string(value));
+			break;
+		case PROP_TOPIC_TIME:
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	}
+}
+
+static void
+purple_muc_get_property (GObject *object, guint property_id,
+                              GValue *value, GParamSpec *pspec)
+{
+	PurpleMUC *muc = PURPLE_MUC(object);
+	PurpleMUCPrivate *priv = GET_PRIVATE(muc);
+
+	switch (property_id) {
+		case PROP_TOPIC:
+			g_value_set_string(value, priv->topic.text);
+			break;
+		case PROP_TOPIC_USER:
+			g_value_set_string(value, priv->topic.who);
+			break;
+		case PROP_TOPIC_TIME:
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	}
+}
+
+static void
+purple_muc_dispose (GObject *object)
+{
+	G_OBJECT_CLASS (purple_muc_parent_class)->dispose (object);
+}
+
+static void
+purple_muc_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (purple_muc_parent_class)->finalize (object);
+}
+
+static void
+purple_muc_class_init (PurpleMUCClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (PurpleMUCPrivate));
+
+	object_class->get_property = purple_muc_get_property;
+	object_class->set_property = purple_muc_set_property;
+	object_class->dispose = purple_muc_dispose;
+	object_class->finalize = purple_muc_finalize;
+
+	g_object_class_install_property(object_class, PROP_TOPIC,
+			g_param_spec_string("topic", _("Topic"),
+				_("The topic of the chat."), NULL,
+				G_PARAM_READWRITE));
+
+	g_object_class_install_property(object_class, PROP_TOPIC_USER,
+			g_param_spec_string("topic-user", _("Topic user"),
+				_("The name of the user who set the topic."), NULL,
+				G_PARAM_READWRITE));
+}
+
+static void
+purple_muc_init (PurpleMUC *self)
+{
+}
+
+PurpleMUC*
+purple_muc_new (PurpleAccount *account, const char *name)
+{
+	return g_object_new (PURPLE_TYPE_MUC,
+			"account", account,
+			"name", name,
+			NULL);
+}
+
+void
+purple_muc_deactivate(PurpleMUC *muc)
+{
+	/* TODO */
+}
+
+void
+purple_muc_set_id(PurpleMUC *muc, int id)
+{
+	/* TODO */
+}
+
+int
+purple_muc_get_id(PurpleMUC *muc)
+{
+	/* TODO */
+	return -1;
+}
+
+const char *
+purple_muc_get_nick(PurpleMUC *muc)
+{
+	/* TODO: */
+	return NULL;
+}
+
============================================================
--- /dev/null	
+++ libpurple/conversation/conv-muc.h	fc1dede8e31464c2478b47b68fb80e202fd82d58
@@ -0,0 +1,76 @@
+/**
+ * @file conversation.h Conversation MUC API
+ * @ingroup core
+ * @see @ref conversation-signals
+ */
+
+/* purple
+ *
+ * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef _PURPLE_CONVERSATION_MUC_H_
+#define _PURPLE_CONVERSATION_MUC_H_
+
+#include "conversation/conv.h"
+
+G_BEGIN_DECLS
+
+#define PURPLE_TYPE_MUC purple_muc_get_type()
+
+#define PURPLE_MUC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), PURPLE_TYPE_MUC, PurpleMUC))
+
+#define PURPLE_MUC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), PURPLE_TYPE_MUC, PurpleMUCClass))
+
+#define PURPLE_IS_MUC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PURPLE_TYPE_MUC))
+
+#define PURPLE_IS_MUC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), PURPLE_TYPE_MUC))
+
+#define PURPLE_MUC_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), PURPLE_TYPE_MUC, PurpleMUCClass))
+
+typedef struct
+{
+	PurpleConversation parent;
+} PurpleMUC;
+
+typedef struct
+{
+	PurpleConversationClass parent_class;
+} PurpleMUCClass;
+
+GType purple_muc_get_type (void);
+
+PurpleMUC* purple_muc_new (PurpleAccount *account, const char *name);
+
+void purple_muc_deactivate(PurpleMUC *muc);
+
+void purple_muc_set_id(PurpleMUC *muc, int id);
+
+int purple_muc_get_id(PurpleMUC *muc);
+
+const char * purple_muc_get_nick(PurpleMUC *muc);
+
+G_END_DECLS
+
+#endif
+
============================================================
--- /dev/null	
+++ libpurple/conversation/conv.c	1007b49cd34e14c97458dcc0f4ebc1c90cceb45b
@@ -0,0 +1,192 @@
+/* purple
+ *
+ * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "internal.h"
+
+#include "conversation/conv.h"
+
+/** GObject stuff {{{ */
+enum
+{
+	PROP_ACCOUNT,
+	PROP_NAME
+};
+
+enum
+{
+	SIG_MSG_RECEIVE,
+	SIG_MSG_SEND,
+	SIG_LAST
+};
+
+static int signals[SIG_LAST];
+
+G_DEFINE_ABSTRACT_TYPE (PurpleConversation, purple_conversation, PURPLE_TYPE_OBJECT)
+
+#define GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), PURPLE_TYPE_CONVERSATION, PurpleConversationPrivate))
+
+typedef struct _PurpleConversationPrivate PurpleConversationPrivate;
+
+struct _PurpleConversationPrivate
+{
+    PurpleAccount *account;
+	char *name;
+};
+
+static void
+purple_conversation_get_property (GObject *object, guint property_id,
+                              GValue *value, GParamSpec *pspec)
+{
+	PurpleConversation *conv = PURPLE_CONVERSATION(object);
+	PurpleConversationPrivate *priv = GET_PRIVATE(conv);
+
+	switch (property_id) {
+		case PROP_ACCOUNT:
+			g_value_set_object(value, priv->account);
+			break;
+		case PROP_NAME:
+			g_value_set_string(value, priv->name);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	}
+}
+
+static void
+purple_conversation_set_property (GObject *object, guint property_id,
+                              const GValue *value, GParamSpec *pspec)
+{
+	PurpleConversation *conv = PURPLE_CONVERSATION(object);
+	PurpleConversationPrivate *priv = GET_PRIVATE(conv);
+
+	switch (property_id) {
+		case PROP_ACCOUNT:
+			priv->account = g_value_get_object(value);
+			break;
+		case PROP_NAME:
+			g_free(priv->name);
+			priv->name = g_strdup(g_value_get_string(value));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	}
+}
+
+static void
+purple_conversation_dispose (GObject *object)
+{
+	G_OBJECT_CLASS (purple_conversation_parent_class)->dispose (object);
+}
+
+static void
+purple_conversation_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (purple_conversation_parent_class)->finalize (object);
+}
+
+static void
+purple_conversation_class_init (PurpleConversationClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (PurpleConversationPrivate));
+
+	object_class->get_property = purple_conversation_get_property;
+	object_class->set_property = purple_conversation_set_property;
+	object_class->dispose = purple_conversation_dispose;
+	object_class->finalize = purple_conversation_finalize;
+
+	g_object_class_install_property(object_class, PROP_ACCOUNT,
+			g_param_spec_object("account", _("Account"),
+				_("The PurpleAccount for the conversation."),
+				PURPLE_TYPE_ACCOUNT,
+				G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property(object_class, PROP_NAME,
+			g_param_spec_string("name", _("Name"),
+				_("The name of the conversation."), NULL,
+				G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+		/* Should we allow changing the name once it's been created? */
+}
+
+static void
+purple_conversation_init (PurpleConversation *self)
+{
+}
+
+/* }}} */
+
+
+void
+purple_conversation_set_icon(PurpleConversation *conv, PurpleBuddyIcon *icon)
+{
+	/* TODO: */
+}
+
+void
+purple_conversation_update(PurpleConversation *conv, PurpleConversationUpdate update)
+{
+	/* TODO: */
+}
+
+PurpleTypingState
+purple_conversation_get_typing_state(PurpleConversation *conv)
+{
+	/* TODO: */
+	return PURPLE_NOT_TYPING;
+}
+
+void
+purple_conversation_set_typing_state(PurpleConversation *conv, PurpleTypingState state)
+{
+	/* TODO: */
+}
+
+void
+purple_conversation_start_typing_timeout(PurpleConversation *conv, int timeout)
+{
+	/* TODO: */
+}
+
+void
+purple_conversation_stop_typing_timeout(PurpleConversation *conv)
+{
+}
+
+guint
+purple_conversation_get_send_typed_timeout(PurpleConversation *conv)
+{
+	/* TODO: */
+	return 0;
+}
+
+void
+purple_conversation_stop_send_typed_timeout(PurpleConversation *conv)
+{
+	/* TODO: */
+}
+
+void
+purple_conversation_write(PurpleConversation *conv, PurpleMessage *msg)
+{
+	/* TODO: */
+}
+
============================================================
--- /dev/null	
+++ libpurple/conversation/convs.c	43bf9d42827c7f4f096256bcf74b32df0c8b12db
@@ -0,0 +1,220 @@
+/*
+ * purple
+ *
+ * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "internal.h"
+
+#include "gsignal.h"
+
+#include "conversation/convs.h"
+#include "conversation/conv-muc.h"
+#include "conversation/conv-im.h"
+
+static struct {
+	GHashTable *conversation_cache;
+	GList *ims;
+	GList *mucs;
+	GList *convs;
+
+	gpointer c_handler;
+	gpointer d_handler;
+} global;
+
+/** Hashtable key representing a conversation {{{ */
+
+typedef struct
+{
+	GType type;
+	char *name;
+	const PurpleAccount *account;
+} PurpleConvHash;
+
+static PurpleConvHash * conv_hash_new(GType type, const PurpleAccount *account,
+		const char *name)
+{
+	PurpleConvHash *h = g_new(PurpleConvHash, 1);
+	h->type = type;
+	h->account = account;
+	h->name = g_strdup(purple_normalize(account, name));
+	return h;
+}
+
+static guint conv_hash_value(const PurpleConvHash *hc)
+{
+	return g_str_hash(hc->name) ^ hc->type ^ g_direct_hash(hc->account);
+}
+
+static guint conv_hash_equal(const PurpleConvHash *hc1,
+	const PurpleConvHash *hc2)
+{
+	return (hc1->type == hc2->type &&
+	        hc1->account == hc2->account &&
+	        g_str_equal(hc1->name, hc2->name));
+}
+
+static void conv_hash_free(PurpleConvHash *hc)
+{
+	g_free(hc->name);
+	g_free(hc);
+}
+
+/* }}} */
+
+PurpleConversation *
+purple_conversations_find(GType type, PurpleAccount *account, const char *name)
+{
+	PurpleConversation *ret;
+	PurpleConvHash hash;
+
+	g_return_val_if_fail(type == PURPLE_TYPE_IM || type == PURPLE_TYPE_MUC ||
+			type == PURPLE_TYPE_CONVERSATION, NULL);
+
+	hash.name = (char *)purple_normalize(account, name);
+	hash.account = account;
+
+	if (type ==  PURPLE_TYPE_IM || type == PURPLE_TYPE_MUC) {
+		hash.type = type;
+		ret = g_hash_table_lookup(global.conversation_cache, &hash);
+	} else {
+		hash.type = PURPLE_TYPE_IM;
+		ret = g_hash_table_lookup(global.conversation_cache, &hash);
+		if (!ret) {
+			hash.type = PURPLE_TYPE_MUC;
+			ret = g_hash_table_lookup(global.conversation_cache, &hash);
+		}
+	}
+
+	return ret;
+}
+
+static PurpleConvHash *
+conv_hash_create(PurpleConversation *conv, PurpleConvHash *hash)
+{
+	PurpleAccount *account = NULL;
+	char *name = NULL;
+	GType type;
+
+	g_object_get(G_OBJECT(conv),
+			"account", &account,
+			"name", &name,
+			NULL);
+
+	if (PURPLE_IS_IM(conv))
+		type = PURPLE_TYPE_IM;
+	else
+		type = PURPLE_TYPE_CHAT;
+
+	if (!hash)
+		return conv_hash_new(type, account, name);
+
+	hash->name = (char *)purple_normalize(account, name);
+	hash->account = account;
+	hash->type = type;
+
+	return hash;
+}
+
+static void
+conversation_new_cb(PurpleConversation *conv)
+{
+	PurpleConvHash *hkey;
+
+	if (PURPLE_IS_IM(conv)) {
+		global.ims = g_list_prepend(global.ims, conv);
+	} else if (PURPLE_IS_MUC(conv)) {
+		global.mucs = g_list_prepend(global.mucs, conv);
+	} else {
+		g_return_if_reached();
+	}
+
+	global.convs = g_list_prepend(global.convs, conv);
+
+	hkey = conv_hash_create(conv, NULL);
+	g_hash_table_insert(global.conversation_cache, hkey, conv);
+}
+
+static void
+conversation_destroy_cb(PurpleConversation *conv)
+{
+	PurpleConvHash hash;
+
+	conv_hash_create(conv, &hash);
+	g_hash_table_remove(global.conversation_cache, &hash);
+
+	if (PURPLE_IS_IM(conv)) {
+		global.ims = g_list_remove(global.ims, conv);
+	} else if (PURPLE_IS_CHAT(conv)) {
+		global.mucs = g_list_remove(global.mucs, conv);
+	} else {
+		g_return_if_reached();
+	}
+
+	global.convs = g_list_remove(global.convs, conv);
+}
+
+void
+purple_conversations_init(void)
+{
+	global.conversation_cache = g_hash_table_new_full((GHashFunc)conv_hash_value,
+						(GEqualFunc)conv_hash_equal,
+						(GDestroyNotify)conv_hash_free, NULL);
+
+	/* We catch the 'new'/'destroying' signals to keep track of active conversations. */
+	global.c_handler = purple_g_signal_connect(PURPLE_TYPE_CONVERSATION, "new",
+			G_CALLBACK(conversation_new_cb), NULL);
+	global.d_handler = purple_g_signal_connect(PURPLE_TYPE_CONVERSATION, "destroying",
+			G_CALLBACK(conversation_destroy_cb), NULL);
+}
+
+void
+purple_conversations_uninit(void)
+{
+	g_hash_table_destroy(global.conversation_cache);
+	global.conversation_cache = NULL;
+
+	g_list_free(global.ims);
+	global.ims = NULL;
+
+	g_list_free(global.mucs);
+	global.mucs = NULL;
+
+	g_list_free(global.convs);
+	global.convs = NULL;
+
+	purple_g_signal_disconnect(global.c_handler);
+	global.c_handler = NULL;
+
+	purple_g_signal_disconnect(global.d_handler);
+	global.d_handler = NULL;
+}
+
+GList *
+purple_conversations_list(GType type)
+{
+	if (type == PURPLE_TYPE_IM)
+		return global.ims;
+	else if (type == PURPLE_TYPE_MUC)
+		return global.mucs;
+	else if (type == PURPLE_TYPE_CONVERSATION)
+		return global.convs;
+
+	g_return_val_if_reached(NULL);
+}
+
============================================================
--- /dev/null	
+++ libpurple/conversation/convs.h	e86b697f58519adbf0c94ed8cbc2324eaccf0993
@@ -0,0 +1,46 @@
+/**
+ * @file conversation.h API to manage lists of conversations
+ * @ingroup core
+ * @see @ref conversation-signals
+ */
+
+/* purple
+ *
+ * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef PURPLE_CONVERSATIONS_H
+#define PURPLE_CONVERSATIONS_H
+
+#include "conversation/conv.h"
+
+G_BEGIN_DECLS
+
+PurpleConversation * purple_conversations_find(GType type, PurpleAccount *account,
+		const char *name);
+
+void purple_conversations_init(void);
+
+void purple_conversations_uninit(void);
+
+GList * purple_conversations_list(GType type);
+
+G_END_DECLS
+
+#endif
+


More information about the Commits mailing list