diff --git a/doc/reference/libpurple/libpurple-docs.xml b/doc/reference/libpurple/libpurple-docs.xml
--- a/doc/reference/libpurple/libpurple-docs.xml
+++ b/doc/reference/libpurple/libpurple-docs.xml
@@ -46,7 +46,6 @@
       <xi:include href="xml/circularbuffer.xml" />
       <xi:include href="xml/contact.xml" />
       <xi:include href="xml/connection.xml" />
-      <xi:include href="xml/conversation.xml" />
       <xi:include href="xml/conversations.xml" />
       <xi:include href="xml/countingnode.xml" />
       <xi:include href="xml/debug.xml" />
@@ -73,6 +72,8 @@
       <xi:include href="xml/purplebuddypresence.xml" />
       <xi:include href="xml/purplechatconversation.xml" />
       <xi:include href="xml/purplechatuser.xml" />
+      <xi:include href="xml/purpleconversation.xml" />
+      <xi:include href="xml/purpleconversationuiops.xml" />
       <xi:include href="xml/purplecredentialmanager.xml" />
       <xi:include href="xml/purplecredentialprovider.xml" />
       <xi:include href="xml/purpleimconversation.xml" />
diff --git a/libpurple/buddyicon.c b/libpurple/buddyicon.c
--- a/libpurple/buddyicon.c
+++ b/libpurple/buddyicon.c
@@ -21,9 +21,9 @@
 
 #include "internal.h"
 #include "buddyicon.h"
-#include "conversation.h"
 #include "debug.h"
 #include "image.h"
+#include "purpleconversation.h"
 #include "purpleprivate.h"
 #include "purpleprotocolserver.h"
 #include "util.h"
diff --git a/libpurple/buddylist.c b/libpurple/buddylist.c
--- a/libpurple/buddylist.c
+++ b/libpurple/buddylist.c
@@ -25,7 +25,6 @@
 
 #include "internal.h"
 #include "buddylist.h"
-#include "conversation.h"
 #include "debug.h"
 #include "notify.h"
 #include "prefs.h"
@@ -33,6 +32,7 @@
 #include "purpleprivate.h"
 #include "purpleprotocolchat.h"
 #include "purpleprotocolclient.h"
+#include "purpleconversation.h"
 #include "server.h"
 #include "signals.h"
 #include "util.h"
diff --git a/libpurple/cmds.h b/libpurple/cmds.h
--- a/libpurple/cmds.h
+++ b/libpurple/cmds.h
@@ -31,7 +31,7 @@
  * @see_also: <link linkend="chapter-signals-cmd">Command signals</link>
  */
 
-#include "conversation.h"
+#include <purpleconversation.h>
 
 /******************************************************************************
  * Structures
diff --git a/libpurple/conversation.h b/libpurple/purpleconversation.h
rename from libpurple/conversation.h
rename to libpurple/purpleconversation.h
--- a/libpurple/conversation.h
+++ b/libpurple/purpleconversation.h
@@ -26,9 +26,9 @@
 #ifndef PURPLE_CONVERSATION_H
 #define PURPLE_CONVERSATION_H
 /**
- * SECTION:conversation
- * @section_id: libpurple-conversation
- * @short_description: Conversation base class <filename>conversation.h</filename>
+ * SECTION:purpleconversation
+ * @section_id: libpurple-purpleconversation
+ * @short_description: Conversation base class
  * @title: Conversation Base Class
  *
  * This is the base class for the conversation abstraction on Libpurple.
@@ -44,13 +44,6 @@
 #define PURPLE_IS_CONVERSATION_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_CONVERSATION))
 #define PURPLE_CONVERSATION_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_CONVERSATION, PurpleConversationClass))
 
-/**
- * PURPLE_TYPE_CONVERSATION_UI_OPS:
- *
- * The standard _get_type macro for #PurpleConversationUiOps.
- */
-#define PURPLE_TYPE_CONVERSATION_UI_OPS      (purple_conversation_ui_ops_get_type())
-
 /**************************************************************************/
 /* Data Structures                                                        */
 /**************************************************************************/
@@ -58,8 +51,6 @@
 typedef struct _PurpleConversation           PurpleConversation;
 typedef struct _PurpleConversationClass      PurpleConversationClass;
 
-typedef struct _PurpleConversationUiOps      PurpleConversationUiOps;
-
 /**
  * PurpleConversationUpdateType:
  * @PURPLE_CONVERSATION_UPDATE_ADD:      The buddy associated with the
@@ -112,7 +103,8 @@
 
 #include <glib.h>
 #include <glib-object.h>
-#include "purplemessage.h"
+
+#include <purplemessage.h>
 
 /**************************************************************************/
 /* PurpleConversation                                                     */
@@ -153,93 +145,12 @@
 	void (*_purple_reserved4)(void);
 };
 
+#include <purpleconversationuiops.h>
 #include "account.h"
 #include "buddyicon.h"
 #include "log.h"
 #include "smiley-list.h"
 
-/**************************************************************************/
-/* PurpleConversationUiOps                                                */
-/**************************************************************************/
-/**
- * PurpleConversationUiOps:
- * @create_conversation: Called when @conv is created (but before the
- *   <link linkend="conversations-conversation-created"><literal>"conversation-created"</literal></link>
- *                       signal is emitted).
- * @destroy_conversation: Called just before @conv is freed.
- * @write_chat: Write a message to a chat. If this field is %NULL, libpurple
- *              will fall back to using @write_conv.
- *              See purple_conversation_write_message().
- * @write_im: Write a message to an IM conversation. If this field is %NULL,
- *            libpurple will fall back to using @write_conv.
- *            See purple_conversation_write_message().
- * @write_conv: Write a message to a conversation. This is used rather than the
- *              chat- or im-specific ops for errors, system messages (such as "x
- *              is now know as y"), and as the fallback if @write_im and
- *              @write_chat are not implemented. It should be implemented, or
- *              the UI will miss conversation error messages and your users will
- *              hate you. See purple_conversation_write_message().
- * @chat_add_users: Add @cbuddies to a chat.
- *                  <sbr/>@cbuddies:     A GList of #PurpleChatUser structs.
- *                  <sbr/>@new_arrivals: Whether join notices should be shown.
- *                                       (Join notices are actually written to
- *                                       the conversation by
- *                                       purple_chat_conversation_add_users())
- * @chat_rename_user: Rename the user in this chat named @old_name to @new_name.
- *                    (The rename message is written to the conversation by
- *                    libpurple.) See purple_chat_conversation_rename_user().
- *                    <sbr/>@new_alias: @new_name's new alias, if they have one.
- * @chat_remove_users: Remove @users from a chat @chat.
- *                     See purple_chat_conversation_remove_users().
- * @chat_update_user: Called when a user's flags are changed.
- *                    See purple_chat_user_set_flags().
- * @present: Present this conversation to the user; for example, by displaying
- *           the IM dialog.
- * @has_focus: If this UI has a concept of focus (as in a windowing system) and
- *             this conversation has the focus, return %TRUE; otherwise, return
- *             %FALSE.
- * @send_confirm: Prompt the user for confirmation to send @message. This
- *                function should arrange for the message to be sent if the user
- *                accepts. If this field is %NULL, libpurple will fall back to
- *                using purple_request_action().
- *
- * Conversation operations and events.
- *
- * Any UI representing a conversation must assign a filled-out
- * #PurpleConversationUiOps structure to the #PurpleConversation.
- */
-struct _PurpleConversationUiOps
-{
-	void (*create_conversation)(PurpleConversation *conv);
-	void (*destroy_conversation)(PurpleConversation *conv);
-
-	void (*write_chat)(PurpleChatConversation *chat, PurpleMessage *msg);
-	void (*write_im)(PurpleIMConversation *im, PurpleMessage *msg);
-	void (*write_conv)(PurpleConversation *conv, PurpleMessage *msg);
-
-	void (*chat_add_users)(PurpleChatConversation *chat,
-	                       GList *cbuddies,
-	                       gboolean new_arrivals);
-
-	void (*chat_rename_user)(PurpleChatConversation *chat, const char *old_name,
-	                         const char *new_name, const char *new_alias);
-
-	void (*chat_remove_users)(PurpleChatConversation *chat, GList *users);
-
-	void (*chat_update_user)(PurpleChatUser *cb);
-
-	void (*present)(PurpleConversation *conv);
-	gboolean (*has_focus)(PurpleConversation *conv);
-
-	void (*send_confirm)(PurpleConversation *conv, const char *message);
-
-	/*< private >*/
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-};
-
 G_BEGIN_DECLS
 
 /**************************************************************************/
@@ -254,13 +165,6 @@
 GType purple_conversation_get_type(void);
 
 /**
- * purple_conversation_ui_ops_get_type:
- *
- * Returns: The #GType for the #PurpleConversationUiOps boxed structure.
- */
-GType purple_conversation_ui_ops_get_type(void);
-
-/**
  * purple_conversation_present:
  * @conv: The conversation to present
  *
diff --git a/libpurple/conversation.h b/libpurple/purpleconversationuiops.h
copy from libpurple/conversation.h
copy to libpurple/purpleconversationuiops.h
--- a/libpurple/conversation.h
+++ b/libpurple/purpleconversationuiops.h
@@ -23,144 +23,35 @@
 # error "only <purple.h> may be included directly"
 #endif
 
-#ifndef PURPLE_CONVERSATION_H
-#define PURPLE_CONVERSATION_H
+#ifndef PURPLE_CONVERSATION_UI_OPS_H
+#define PURPLE_CONVERSATION_UI_OPS_H
+
+#include <glib.h>
+#include <glib-object.h>
+
 /**
- * SECTION:conversation
- * @section_id: libpurple-conversation
- * @short_description: Conversation base class <filename>conversation.h</filename>
- * @title: Conversation Base Class
- *
- * This is the base class for the conversation abstraction on Libpurple.
+ * SECTION:purpleconversationuiops
+ * @section_id: libpurple-purpleconversationuiops
+ * @short_description: Ui Operations for Conversations
+ * @title: Ui Operations for Conversations
  *
- * The present API manages the common functionallity for both kinds of conversations
- * @PurpleIMConversation and @PurpleChatConversation.
+ * libpurple needs to tell the user interface when certain things happen in a
+ * conversation and it uses this structure to do so.
  */
 
-#define PURPLE_TYPE_CONVERSATION             (purple_conversation_get_type())
-#define PURPLE_CONVERSATION(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_CONVERSATION, PurpleConversation))
-#define PURPLE_CONVERSATION_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_CONVERSATION, PurpleConversationClass))
-#define PURPLE_IS_CONVERSATION(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_CONVERSATION))
-#define PURPLE_IS_CONVERSATION_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_CONVERSATION))
-#define PURPLE_CONVERSATION_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_CONVERSATION, PurpleConversationClass))
-
 /**
  * PURPLE_TYPE_CONVERSATION_UI_OPS:
  *
  * The standard _get_type macro for #PurpleConversationUiOps.
  */
-#define PURPLE_TYPE_CONVERSATION_UI_OPS      (purple_conversation_ui_ops_get_type())
-
-/**************************************************************************/
-/* Data Structures                                                        */
-/**************************************************************************/
-
-typedef struct _PurpleConversation           PurpleConversation;
-typedef struct _PurpleConversationClass      PurpleConversationClass;
-
-typedef struct _PurpleConversationUiOps      PurpleConversationUiOps;
-
-/**
- * PurpleConversationUpdateType:
- * @PURPLE_CONVERSATION_UPDATE_ADD:      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.
- * @PURPLE_CONVERSATION_ACCOUNT_ONLINE:  One of the user's accounts went online.
- * @PURPLE_CONVERSATION_ACCOUNT_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_NAME:     The name of the conversation was changed.
- * @PURPLE_CONVERSATION_UPDATE_TITLE:    The title of the conversation was updated.
- * @PURPLE_CONVERSATION_UPDATE_CHATLEFT: The user left a chat.
- * @PURPLE_CONVERSATION_UPDATE_FEATURES: The features for a chat have changed.
- *
- * Conversation update type.
- */
-typedef enum
-{
-	PURPLE_CONVERSATION_UPDATE_ADD = 0,
-	PURPLE_CONVERSATION_UPDATE_REMOVE,
-	PURPLE_CONVERSATION_UPDATE_ACCOUNT,
-	PURPLE_CONVERSATION_UPDATE_TYPING,
-	PURPLE_CONVERSATION_UPDATE_UNSEEN,
-	PURPLE_CONVERSATION_UPDATE_LOGGING,
-	PURPLE_CONVERSATION_UPDATE_TOPIC,
+#define PURPLE_TYPE_CONVERSATION_UI_OPS (purple_conversation_ui_ops_get_type())
+typedef struct _PurpleConversationUiOps PurpleConversationUiOps;
 
-	/*
-	 * XXX These need to go when we implement a more generic core/UI event
-	 * system.
-	 */
-	PURPLE_CONVERSATION_ACCOUNT_ONLINE,
-	PURPLE_CONVERSATION_ACCOUNT_OFFLINE,
-	PURPLE_CONVERSATION_UPDATE_AWAY,
-	PURPLE_CONVERSATION_UPDATE_ICON,
-	PURPLE_CONVERSATION_UPDATE_NAME,
-	PURPLE_CONVERSATION_UPDATE_TITLE,
-	PURPLE_CONVERSATION_UPDATE_CHATLEFT,
-
-	PURPLE_CONVERSATION_UPDATE_FEATURES
-
-} PurpleConversationUpdateType;
-
-#include <glib.h>
-#include <glib-object.h>
-#include "purplemessage.h"
+#include <purpleconversation.h>
+#include <purplechatconversation.h>
+#include <purpleimconversation.h>
+#include <purplemessage.h>
 
-/**************************************************************************/
-/* PurpleConversation                                                     */
-/**************************************************************************/
-/**
- * PurpleConversation:
- *
- * A core representation of a conversation between two or more people.
- *
- * The conversation can be an IM or a chat.
- *
- * Note: When a conversation is destroyed with the last g_object_unref(), the
- *       specified conversation is removed from the parent window. If this
- *       conversation is the only one contained in the parent window, that
- *       window is also destroyed.
- */
-struct _PurpleConversation
-{
-	GObject gparent;
-};
-
-/**
- * PurpleConversationClass:
- * @write_message: Writes a message to a chat or IM conversation. See
- *                 purple_conversation_write_message().
- *
- * Base class for all #PurpleConversation's
- */
-struct _PurpleConversationClass {
-	GObjectClass parent_class;
-
-	void (*write_message)(PurpleConversation *conv, PurpleMessage *msg);
-
-	/*< private >*/
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-};
-
-#include "account.h"
-#include "buddyicon.h"
-#include "log.h"
-#include "smiley-list.h"
-
-/**************************************************************************/
-/* PurpleConversationUiOps                                                */
-/**************************************************************************/
 /**
  * PurpleConversationUiOps:
  * @create_conversation: Called when @conv is created (but before the
@@ -242,17 +133,6 @@
 
 G_BEGIN_DECLS
 
-/**************************************************************************/
-/* Conversation API                                                       */
-/**************************************************************************/
-
-/**
- * purple_conversation_get_type:
- *
- * Returns: The #GType for the Conversation object.
- */
-GType purple_conversation_get_type(void);
-
 /**
  * purple_conversation_ui_ops_get_type:
  *
@@ -260,362 +140,6 @@
  */
 GType purple_conversation_ui_ops_get_type(void);
 
-/**
- * purple_conversation_present:
- * @conv: The conversation to present
- *
- * Present a conversation to the user. This allows core code to initiate a
- * conversation by displaying the IM dialog.
- */
-void purple_conversation_present(PurpleConversation *conv);
-
-/**
- * purple_conversation_set_ui_ops:
- * @conv: The conversation.
- * @ops:  The UI conversation operations structure.
- *
- * Sets the specified conversation's UI operations structure.
- */
-void purple_conversation_set_ui_ops(PurpleConversation *conv,
-								  PurpleConversationUiOps *ops);
-
-/**
- * purple_conversation_get_ui_ops:
- * @conv: The conversation.
- *
- * Returns the specified conversation's UI operations structure.
- *
- * Returns: The operations structure.
- */
-PurpleConversationUiOps *purple_conversation_get_ui_ops(PurpleConversation *conv);
-
-/**
- * purple_conversation_set_account:
- * @conv: The conversation.
- * @account: The purple_account.
- *
- * 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.
- */
-void purple_conversation_set_account(PurpleConversation *conv,
-                                   PurpleAccount *account);
-
-/**
- * purple_conversation_get_account:
- * @conv: The conversation.
- *
- * Returns 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.
- *
- * Returns: (transfer none): The conversation's purple_account.
- */
-PurpleAccount *purple_conversation_get_account(PurpleConversation *conv);
-
-/**
- * purple_conversation_get_connection:
- * @conv: The conversation.
- *
- * Returns the specified conversation's purple_connection.
- *
- * Returns: (transfer none): The conversation's purple_connection.
- */
-PurpleConnection *purple_conversation_get_connection(PurpleConversation *conv);
-
-/**
- * purple_conversation_set_title:
- * @conv:  The conversation.
- * @title: The title.
- *
- * Sets the specified conversation's title.
- */
-void purple_conversation_set_title(PurpleConversation *conv, const char *title);
-
-/**
- * purple_conversation_get_title:
- * @conv: The conversation.
- *
- * Returns the specified conversation's title.
- *
- * Returns: The title.
- */
-const char *purple_conversation_get_title(PurpleConversation *conv);
-
-/**
- * purple_conversation_autoset_title:
- * @conv: The conversation.
- *
- * Automatically sets the specified conversation's title.
- *
- * This function takes OPT_IM_ALIAS_TAB into account, as well as the
- * user's alias.
- */
-void purple_conversation_autoset_title(PurpleConversation *conv);
-
-/**
- * purple_conversation_set_name:
- * @conv: The conversation.
- * @name: The conversation's name.
- *
- * Sets the specified conversation's name.
- */
-void purple_conversation_set_name(PurpleConversation *conv, const char *name);
-
-/**
- * purple_conversation_get_name:
- * @conv: The conversation.
- *
- * Returns the specified conversation's name.
- *
- * Returns: The conversation's name. If the conversation is an IM with a
- *          PurpleBuddy, then it's the name of the PurpleBuddy.
- */
-const char *purple_conversation_get_name(PurpleConversation *conv);
-
-/**
- * purple_conversation_set_logging:
- * @conv: The conversation.
- * @log:  %TRUE if logging should be enabled, or %FALSE otherwise.
- *
- * Enables or disables logging for this conversation.
- */
-void purple_conversation_set_logging(PurpleConversation *conv, gboolean log);
-
-/**
- * purple_conversation_is_logging:
- * @conv: The conversation.
- *
- * Returns whether or not logging is enabled for this conversation.
- *
- * Returns: %TRUE if logging is enabled, or %FALSE otherwise.
- */
-gboolean purple_conversation_is_logging(PurpleConversation *conv);
-
-/**
- * purple_conversation_close_logs:
- * @conv: The conversation.
- *
- * Closes any open logs for this conversation.
- *
- * Note that new logs will be opened as necessary (e.g. upon receipt of a
- * message, if the conversation has logging enabled. To disable logging for
- * the remainder of the conversation, use purple_conversation_set_logging().
- */
-void purple_conversation_close_logs(PurpleConversation *conv);
-
-/**
- * purple_conversation_write_message:
- * @conv: The conversation.
- * @msg:  The message to write.
- *
- * Writes to a chat or an IM.
- */
-void purple_conversation_write_message(PurpleConversation *conv,
-	PurpleMessage *msg);
-
-/**
- * purple_conversation_write_system_message:
- * @conv:    The conversation.
- * @message: The message to write.
- * @flags:   The message flags (you don't need to set %PURPLE_MESSAGE_SYSTEM.
- *
- * Wites a system message to a chat or an IM.
- */
-void purple_conversation_write_system_message(PurpleConversation *conv,
-	const gchar *message, PurpleMessageFlags flags);
-
-/**
- * purple_conversation_send:
- * @conv:    The conversation.
- * @message: The message to send.
- *
- * Sends a message to this conversation. This function calls
- * purple_conversation_send_with_flags() with no additional flags.
- */
-void purple_conversation_send(PurpleConversation *conv, const char *message);
-
-/**
- * purple_conversation_send_with_flags:
- * @conv:    The conversation.
- * @message: The message to send.
- * @flags:   The PurpleMessageFlags flags to use in addition to
- *           PURPLE_MESSAGE_SEND.
- *
- * Sends a message to this conversation with specified flags.
- */
-void purple_conversation_send_with_flags(PurpleConversation *conv, const char *message,
-		PurpleMessageFlags flags);
-
-/**
- * purple_conversation_set_features:
- * @conv:      The conversation
- * @features:  Bitset defining supported features
- *
- * Set the features as supported for the given conversation.
- */
-void purple_conversation_set_features(PurpleConversation *conv,
-		PurpleConnectionFlags features);
-
-
-/**
- * purple_conversation_get_features:
- * @conv:  The conversation
- *
- * Get the features supported by the given conversation.
- */
-PurpleConnectionFlags purple_conversation_get_features(PurpleConversation *conv);
-
-/**
- * purple_conversation_has_focus:
- * @conv:    The conversation.
- *
- * Determines if a conversation has focus
- *
- * Returns: %TRUE if the conversation has focus, %FALSE if
- * it does not or the UI does not have a concept of conversation focus
- */
-gboolean purple_conversation_has_focus(PurpleConversation *conv);
-
-/**
- * purple_conversation_update:
- * @conv: The conversation.
- * @type: The update type.
- *
- * Updates the visual status and UI of a conversation.
- */
-void purple_conversation_update(PurpleConversation *conv, PurpleConversationUpdateType type);
-
-/**
- * purple_conversation_get_message_history:
- * @conv:   The conversation
- *
- * Retrieve the message history of a conversation.
- *
- * Returns: (element-type PurpleMessage) (transfer none):
- *          A GList of PurpleMessage's. You must not modify the
- *          list or the data within. The list contains the newest message at
- *          the beginning, and the oldest message at the end.
- */
-GList *purple_conversation_get_message_history(PurpleConversation *conv);
-
-/**
- * purple_conversation_clear_message_history:
- * @conv:  The conversation
- *
- * Clear the message history of a conversation.
- */
-void purple_conversation_clear_message_history(PurpleConversation *conv);
-
-/**
- * purple_conversation_send_confirm:
- * @conv:    The conversation.
- * @message: The message to send.
- *
- * Sends a message to a conversation after confirming with
- * the user.
- *
- * This function is intended for use in cases where the user
- * hasn't explicitly and knowingly caused a message to be sent.
- * The confirmation ensures that the user isn't sending a
- * message by mistake.
- */
-void purple_conversation_send_confirm(PurpleConversation *conv, const char *message);
-
-/**
- * purple_conversation_get_extended_menu:
- * @conv: The conversation.
- *
- * Retrieves the extended menu items for the conversation.
- *
- * Returns: (element-type PurpleActionMenu) (transfer full): The extended menu
- *          items for a conversation, as harvested by the chat-extended-menu
- *          signal.
- */
-GList * purple_conversation_get_extended_menu(PurpleConversation *conv);
-
-/**
- * purple_conversation_do_command:
- * @conv:    The conversation.
- * @cmdline: The entire command including the arguments.
- * @markup:  %NULL, or the formatted command line.
- * @error:   If the command failed errormsg is filled in with the appropriate error
- *                message, if not %NULL. It must be freed by the caller with g_free().
- *
- * Perform a command in a conversation. Similar to purple_cmd_do_command().
- *
- * Returns:  %TRUE if the command was executed successfully, %FALSE otherwise.
- */
-gboolean purple_conversation_do_command(PurpleConversation *conv,
-		const gchar *cmdline, const gchar *markup, gchar **error);
-
-/**
- * purple_conversation_get_max_message_size:
- * @conv: The conversation to query.
- *
- * Gets the maximum message size in bytes for the conversation.
- *
- * See #PurpleProtocolClientInterface's <literal>get_max_message_size</literal>.
- *
- * Returns: Maximum message size, 0 if unspecified, -1 for infinite.
- */
-gssize
-purple_conversation_get_max_message_size(PurpleConversation *conv);
-
-/**
- * purple_conversation_add_smiley:
- * @conv: The conversation that receives new smiley.
- * @smiley: The smiley.
- *
- * Adds a smiley to the list of smileys that belong to this conversation.
- */
-void purple_conversation_add_smiley(PurpleConversation *conv, PurpleSmiley *smiley);
-
-/**
- * purple_conversation_get_smiley:
- * @conv: The conversation.
- * @shortcut: The shortcut.
- *
- * Lookups for the smiley previously added to this conversation.
- *
- * Returns: (transfer none): The smiley, or %NULL if it doesn't exists.
- */
-PurpleSmiley *purple_conversation_get_smiley(PurpleConversation *conv, const gchar *shortcut);
-
-/**
- * purple_conversation_get_remote_smileys:
- * @conv: The conversation.
- *
- * Get all remote smileys previously added to this conversation.
- *
- * Returns: (transfer none): The list of remote smileys.
- */
-PurpleSmileyList *
-purple_conversation_get_remote_smileys(PurpleConversation *conv);
-
-/**************************************************************************/
-/* Conversation Helper API                                                */
-/**************************************************************************/
-
-/**
- * purple_conversation_present_error:
- * @who:     The user this error is about
- * @account: The account this error is on
- * @what:    The error
- *
- * Presents an IM-error to the user
- *
- * This is a helper function to find a conversation, write an error to it, and
- * raise the window.  If a conversation with this user doesn't already exist,
- * the function will return FALSE and the calling function can attempt to present
- * the error another way (purple_notify_error, most likely)
- *
- * Returns:        TRUE if the error was presented, else FALSE
- */
-gboolean purple_conversation_present_error(const char *who, PurpleAccount *account, const char *what);
-
 G_END_DECLS
 
-#endif /* PURPLE_CONVERSATION_H */
+#endif /* PURPLE_CONVERSATION_UI_OPS_H */
diff --git a/libpurple/conversation.c b/libpurple/purpleconversation.c
rename from libpurple/conversation.c
rename to libpurple/purpleconversation.c
--- a/libpurple/conversation.c
+++ b/libpurple/purpleconversation.c
@@ -26,12 +26,12 @@
 
 #include "buddylist.h"
 #include "cmds.h"
-#include "conversation.h"
 #include "debug.h"
 #include "enums.h"
 #include "notify.h"
 #include "prefs.h"
 #include "protocol.h"
+#include "purpleconversation.h"
 #include "purplemarkup.h"
 #include "purpleprivate.h"
 #include "purpleprotocolclient.h"
@@ -237,33 +237,6 @@
 	return priv->features;
 }
 
-static PurpleConversationUiOps *
-purple_conversation_ui_ops_copy(PurpleConversationUiOps *ops)
-{
-	PurpleConversationUiOps *ops_new;
-
-	g_return_val_if_fail(ops != NULL, NULL);
-
-	ops_new = g_new(PurpleConversationUiOps, 1);
-	*ops_new = *ops;
-
-	return ops_new;
-}
-
-GType
-purple_conversation_ui_ops_get_type(void)
-{
-	static GType type = 0;
-
-	if (type == 0) {
-		type = g_boxed_type_register_static("PurpleConversationUiOps",
-				(GBoxedCopyFunc)purple_conversation_ui_ops_copy,
-				(GBoxedFreeFunc)g_free);
-	}
-
-	return type;
-}
-
 void
 purple_conversation_set_ui_ops(PurpleConversation *conv,
 							 PurpleConversationUiOps *ops)
diff --git a/libpurple/conversation.c b/libpurple/purpleconversationuiops.c
copy from libpurple/conversation.c
copy to libpurple/purpleconversationuiops.c
--- a/libpurple/conversation.c
+++ b/libpurple/purpleconversationuiops.c
@@ -22,221 +22,11 @@
 
 #include <glib/gi18n-lib.h>
 
-#include "internal.h"
-
-#include "buddylist.h"
-#include "cmds.h"
-#include "conversation.h"
-#include "debug.h"
-#include "enums.h"
-#include "notify.h"
-#include "prefs.h"
-#include "protocol.h"
-#include "purplemarkup.h"
-#include "purpleprivate.h"
-#include "purpleprotocolclient.h"
-#include "request.h"
-#include "signals.h"
-#include "smiley-list.h"
-
-typedef struct _PurpleConversationPrivate  PurpleConversationPrivate;
-
-/* General private data for a conversation */
-struct _PurpleConversationPrivate
-{
-	PurpleAccount *account;           /* The user using this conversation. */
-
-	char *name;                       /* The name of the conversation.     */
-	char *title;                      /* The window title.                 */
-
-	gboolean logging;                 /* The status of logging.            */
-
-	GList *logs;                      /* This conversation's logs          */
-
-	PurpleConversationUiOps *ui_ops;  /* UI-specific operations.           */
-
-	PurpleConnectionFlags features;   /* The supported features            */
-	GList *message_history; /* Message history, as a GList of PurpleMessages */
-
-	/* The list of remote smileys. This should be per-buddy (PurpleBuddy),
-	 * but we don't have any class for people not on our buddy
-	 * list (PurpleDude?). So, if we have one, we should switch to it. */
-	PurpleSmileyList *remote_smileys;
-};
-
-/* GObject Property enums */
-enum
-{
-	PROP_0,
-	PROP_ACCOUNT,
-	PROP_NAME,
-	PROP_TITLE,
-	PROP_LOGGING,
-	PROP_FEATURES,
-	PROP_LAST
-};
-
-static GParamSpec *properties[PROP_LAST];
-
-G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(PurpleConversation, purple_conversation,
-		G_TYPE_OBJECT);
-
-static void
-common_send(PurpleConversation *conv, const char *message, PurpleMessageFlags msgflags)
-{
-	PurpleAccount *account;
-	PurpleConnection *gc;
-	PurpleConversationPrivate *priv =
-			purple_conversation_get_instance_private(conv);
-	char *displayed = NULL;
-	const char *sent, *me;
-	int err = 0;
-
-	if (*message == '\0')
-		return;
-
-	account = purple_conversation_get_account(conv);
-	g_return_if_fail(PURPLE_IS_ACCOUNT(account));
-
-	gc = purple_account_get_connection(account);
-	g_return_if_fail(PURPLE_IS_CONNECTION(gc));
-
-	me = purple_account_get_name_for_display(account);
-
-	/* Always linkfy the text for display, unless we're
-	 * explicitly asked to do otheriwse*/
-	if (!(msgflags & PURPLE_MESSAGE_INVISIBLE)) {
-		if(msgflags & PURPLE_MESSAGE_NO_LINKIFY)
-			displayed = g_strdup(message);
-		else
-			displayed = purple_markup_linkify(message);
-	}
-
-	if (displayed && (priv->features & PURPLE_CONNECTION_FLAG_HTML) &&
-		!(msgflags & PURPLE_MESSAGE_RAW)) {
-		sent = displayed;
-	} else
-		sent = message;
-
-	msgflags |= PURPLE_MESSAGE_SEND;
-
-	if (PURPLE_IS_IM_CONVERSATION(conv)) {
-		PurpleMessage *msg = purple_message_new_outgoing(me,
-			purple_conversation_get_name(conv), sent, msgflags);
-
-		purple_signal_emit(purple_conversations_get_handle(), "sending-im-msg",
-			account, msg);
-
-		if (!purple_message_is_empty(msg)) {
+#include <purpleconversationuiops.h>
 
-			err = purple_serv_send_im(gc, msg);
-
-			if ((err > 0) && (displayed != NULL)) {
-				/* revert the contents in case sending-im-msg changed it */
-				purple_message_set_contents(msg, displayed);
-				purple_conversation_write_message(conv, msg);
-			}
-
-			purple_signal_emit(purple_conversations_get_handle(),
-				"sent-im-msg", account, msg);
-		}
-
-		g_object_unref(G_OBJECT(msg));
-	}
-	else if (PURPLE_IS_CHAT_CONVERSATION(conv)) {
-		PurpleMessage *msg;
-		int id = purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(conv));
-
-		msg = purple_message_new_outgoing(me, NULL, sent, msgflags);
-
-		purple_signal_emit(purple_conversations_get_handle(),
-			"sending-chat-msg", account, msg, id);
-
-		if (!purple_message_is_empty(msg)) {
-			err = purple_serv_chat_send(gc, id, msg);
-
-			purple_signal_emit(purple_conversations_get_handle(),
-				"sent-chat-msg", account, msg, id);
-		}
-
-		g_object_unref(G_OBJECT(msg));
-	}
-
-	if (err < 0) {
-		const char *who;
-		const char *msg;
-
-		who = purple_conversation_get_name(conv);
-
-		if (err == -E2BIG) {
-			msg = _("Unable to send message: The message is too large.");
-
-			if (!purple_conversation_present_error(who, account, msg)) {
-				char *msg2 = g_strdup_printf(_("Unable to send message to %s."), who);
-				purple_notify_error(gc, NULL, msg2,
-					_("The message is too large."),
-					purple_request_cpar_from_connection(gc));
-				g_free(msg2);
-			}
-		}
-		else if (err == -ENOTCONN) {
-			purple_debug_error("conversation", "Not yet connected.");
-		}
-		else {
-			msg = _("Unable to send message.");
-
-			if (!purple_conversation_present_error(who, account, msg)) {
-				char *msg2 = g_strdup_printf(_("Unable to send message to %s."), who);
-				purple_notify_error(gc, NULL, msg2, NULL,
-					purple_request_cpar_from_connection(gc));
-				g_free(msg2);
-			}
-		}
-	}
-
-	g_free(displayed);
-}
-
-/**************************************************************************
- * Conversation API
- **************************************************************************/
-void
-purple_conversation_present(PurpleConversation *conv) {
-	PurpleConversationUiOps *ops;
-
-	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
-
-	ops = purple_conversation_get_ui_ops(conv);
-	if(ops && ops->present)
-		ops->present(conv);
-}
-
-void
-purple_conversation_set_features(PurpleConversation *conv, PurpleConnectionFlags features)
-{
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
-
-	priv = purple_conversation_get_instance_private(conv);
-	priv->features = features;
-
-	g_object_notify_by_pspec(G_OBJECT(conv), properties[PROP_FEATURES]);
-
-	purple_conversation_update(conv, PURPLE_CONVERSATION_UPDATE_FEATURES);
-}
-
-PurpleConnectionFlags
-purple_conversation_get_features(PurpleConversation *conv)
-{
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONVERSATION(conv), 0);
-
-	priv = purple_conversation_get_instance_private(conv);
-	return priv->features;
-}
-
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
 static PurpleConversationUiOps *
 purple_conversation_ui_ops_copy(PurpleConversationUiOps *ops)
 {
@@ -250,6 +40,9 @@
 	return ops_new;
 }
 
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
 GType
 purple_conversation_ui_ops_get_type(void)
 {
@@ -263,768 +56,3 @@
 
 	return type;
 }
-
-void
-purple_conversation_set_ui_ops(PurpleConversation *conv,
-							 PurpleConversationUiOps *ops)
-{
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
-	priv = purple_conversation_get_instance_private(conv);
-
-	if (priv->ui_ops == ops)
-		return;
-
-	if (priv->ui_ops != NULL && priv->ui_ops->destroy_conversation != NULL)
-		priv->ui_ops->destroy_conversation(conv);
-
-	priv->ui_ops = ops;
-}
-
-PurpleConversationUiOps *
-purple_conversation_get_ui_ops(PurpleConversation *conv)
-{
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONVERSATION(conv), NULL);
-
-	priv = purple_conversation_get_instance_private(conv);
-	return priv->ui_ops;
-}
-
-void
-purple_conversation_set_account(PurpleConversation *conv, PurpleAccount *account)
-{
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
-	priv = purple_conversation_get_instance_private(conv);
-
-	if (account == purple_conversation_get_account(conv))
-		return;
-
-	_purple_conversations_update_cache(conv, NULL, account);
-	priv->account = account;
-
-	g_object_notify_by_pspec(G_OBJECT(conv), properties[PROP_ACCOUNT]);
-
-	purple_conversation_update(conv, PURPLE_CONVERSATION_UPDATE_ACCOUNT);
-}
-
-PurpleAccount *
-purple_conversation_get_account(PurpleConversation *conv)
-{
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONVERSATION(conv), NULL);
-
-	priv = purple_conversation_get_instance_private(conv);
-	return priv->account;
-}
-
-PurpleConnection *
-purple_conversation_get_connection(PurpleConversation *conv)
-{
-	PurpleAccount *account;
-
-	g_return_val_if_fail(PURPLE_IS_CONVERSATION(conv), NULL);
-
-	account = purple_conversation_get_account(conv);
-
-	if (account == NULL)
-		return NULL;
-
-	return purple_account_get_connection(account);
-}
-
-void
-purple_conversation_set_title(PurpleConversation *conv, const char *title)
-{
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
-	g_return_if_fail(title != NULL);
-
-	priv = purple_conversation_get_instance_private(conv);
-	g_free(priv->title);
-	priv->title = g_strdup(title);
-
-	if (!g_object_get_data(G_OBJECT(conv), "is-finalizing"))
-		g_object_notify_by_pspec(G_OBJECT(conv), properties[PROP_TITLE]);
-
-	purple_conversation_update(conv, PURPLE_CONVERSATION_UPDATE_TITLE);
-}
-
-const char *
-purple_conversation_get_title(PurpleConversation *conv)
-{
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONVERSATION(conv), NULL);
-
-	priv = purple_conversation_get_instance_private(conv);
-	return priv->title;
-}
-
-void
-purple_conversation_autoset_title(PurpleConversation *conv)
-{
-	PurpleAccount *account;
-	PurpleBuddy *b;
-	PurpleChat *chat;
-	const char *text = NULL, *name;
-
-	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
-
-	account = purple_conversation_get_account(conv);
-	name = purple_conversation_get_name(conv);
-
-	if (PURPLE_IS_IM_CONVERSATION(conv)) {
-		if (account && ((b = purple_blist_find_buddy(account, name)) != NULL))
-			text = purple_buddy_get_contact_alias(b);
-	} else if (PURPLE_IS_CHAT_CONVERSATION(conv)) {
-		if (account && ((chat = purple_blist_find_chat(account, name)) != NULL))
-			text = purple_chat_get_name(chat);
-	}
-
-	if(text == NULL)
-		text = name;
-
-	purple_conversation_set_title(conv, text);
-}
-
-void
-purple_conversation_set_name(PurpleConversation *conv, const char *name)
-{
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
-	priv = purple_conversation_get_instance_private(conv);
-
-	_purple_conversations_update_cache(conv, name, NULL);
-
-	g_free(priv->name);
-	priv->name = g_strdup(name);
-
-	g_object_notify_by_pspec(G_OBJECT(conv), properties[PROP_NAME]);
-
-	purple_conversation_autoset_title(conv);
-	purple_conversation_update(conv, PURPLE_CONVERSATION_UPDATE_NAME);
-}
-
-const char *
-purple_conversation_get_name(PurpleConversation *conv)
-{
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONVERSATION(conv), NULL);
-
-	priv = purple_conversation_get_instance_private(conv);
-	return priv->name;
-}
-
-void
-purple_conversation_set_logging(PurpleConversation *conv, gboolean log)
-{
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
-	priv = purple_conversation_get_instance_private(conv);
-
-	if (priv->logging != log)
-	{
-		priv->logging = log;
-		if (log && priv->logs == NULL) {
-			GDateTime *dt;
-			PurpleLog *log;
-
-			dt = g_date_time_new_now_local();
-			log = purple_log_new(PURPLE_IS_CHAT_CONVERSATION(conv)
-			                             ? PURPLE_LOG_CHAT
-			                             : PURPLE_LOG_IM,
-			                     priv->name, priv->account, conv,
-			                     dt);
-			g_date_time_unref(dt);
-
-			priv->logs = g_list_append(NULL, log);
-		}
-
-		g_object_notify_by_pspec(G_OBJECT(conv), properties[PROP_LOGGING]);
-
-		purple_conversation_update(conv, PURPLE_CONVERSATION_UPDATE_LOGGING);
-	}
-}
-
-gboolean
-purple_conversation_is_logging(PurpleConversation *conv)
-{
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONVERSATION(conv), FALSE);
-
-	priv = purple_conversation_get_instance_private(conv);
-	return priv->logging;
-}
-
-void
-purple_conversation_close_logs(PurpleConversation *conv)
-{
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
-
-	priv = purple_conversation_get_instance_private(conv);
-	g_list_free_full(priv->logs, (GDestroyNotify)purple_log_free);
-	priv->logs = NULL;
-}
-
-void
-_purple_conversation_write_common(PurpleConversation *conv, PurpleMessage *pmsg)
-{
-	PurpleConversationPrivate *priv = NULL;
-	PurpleProtocol *protocol = NULL;
-	PurpleConnection *gc = NULL;
-	PurpleAccount *account;
-	PurpleConversationUiOps *ops;
-	PurpleBuddy *b;
-	int plugin_return;
-	/* int logging_font_options = 0; */
-
-	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
-	g_return_if_fail(pmsg != NULL);
-
-	priv = purple_conversation_get_instance_private(conv);
-	ops = purple_conversation_get_ui_ops(conv);
-
-	account = purple_conversation_get_account(conv);
-
-	if (account != NULL)
-		gc = purple_account_get_connection(account);
-
-	if (PURPLE_IS_CHAT_CONVERSATION(conv) &&
-		(gc != NULL && !g_slist_find(purple_connection_get_active_chats(gc), conv)))
-		return;
-
-	if (PURPLE_IS_IM_CONVERSATION(conv) &&
-		!g_list_find(purple_conversations_get_all(), conv))
-		return;
-
-	plugin_return = GPOINTER_TO_INT(purple_signal_emit_return_1(
-		purple_conversations_get_handle(),
-		(PURPLE_IS_IM_CONVERSATION(conv) ? "writing-im-msg" : "writing-chat-msg"),
-		conv, pmsg));
-
-	if (purple_message_is_empty(pmsg))
-		return;
-
-	if (plugin_return)
-		return;
-
-	if (account != NULL) {
-		protocol = purple_account_get_protocol(account);
-
-		if (PURPLE_IS_IM_CONVERSATION(conv) ||
-			!(purple_protocol_get_options(protocol) & OPT_PROTO_UNIQUE_CHATNAME)) {
-
-			if (purple_message_get_flags(pmsg) & PURPLE_MESSAGE_SEND) {
-				const gchar *alias;
-
-				b = purple_blist_find_buddy(account,
-					purple_account_get_username(account));
-
-				if (purple_account_get_private_alias(account) != NULL)
-					alias = purple_account_get_private_alias(account);
-				else if (b != NULL && !purple_strequal(purple_buddy_get_name(b),
-					purple_buddy_get_contact_alias(b)))
-				{
-					alias = purple_buddy_get_contact_alias(b);
-				} else if (purple_connection_get_display_name(gc) != NULL)
-					alias = purple_connection_get_display_name(gc);
-				else
-					alias = purple_account_get_username(account);
-
-				purple_message_set_author_alias(pmsg, alias);
-			}
-			else if (purple_message_get_flags(pmsg) & PURPLE_MESSAGE_RECV)
-			{
-				/* TODO: PurpleDude - folks not on the buddy list */
-				b = purple_blist_find_buddy(account,
-					purple_message_get_author(pmsg));
-
-				if (b != NULL) {
-					purple_message_set_author_alias(pmsg,
-						purple_buddy_get_contact_alias(b));
-				}
-			}
-		}
-	}
-
-	if (!(purple_message_get_flags(pmsg) & PURPLE_MESSAGE_NO_LOG) && purple_conversation_is_logging(conv)) {
-		GList *log;
-		GDateTime *dt;
-
-		dt = g_date_time_ref(purple_message_get_timestamp(pmsg));
-		log = priv->logs;
-		while (log != NULL) {
-			purple_log_write((PurpleLog *)log->data,
-				purple_message_get_flags(pmsg),
-				purple_message_get_author_alias(pmsg),
-				dt,
-				purple_message_get_contents(pmsg));
-			log = log->next;
-		}
-		g_date_time_unref(dt);
-	}
-
-	if (ops) {
-		if (PURPLE_IS_CHAT_CONVERSATION(conv) && ops->write_chat)
-			ops->write_chat(PURPLE_CHAT_CONVERSATION(conv), pmsg);
-		else if (PURPLE_IS_IM_CONVERSATION(conv) && ops->write_im)
-			ops->write_im(PURPLE_IM_CONVERSATION(conv), pmsg);
-		else if (ops->write_conv)
-			ops->write_conv(conv, pmsg);
-	}
-
-	g_object_ref(pmsg);
-	priv->message_history = g_list_prepend(priv->message_history, pmsg);
-
-	purple_signal_emit(purple_conversations_get_handle(),
-		(PURPLE_IS_IM_CONVERSATION(conv) ? "wrote-im-msg" : "wrote-chat-msg"),
-		conv, pmsg);
-}
-
-void
-purple_conversation_write_message(PurpleConversation *conv, PurpleMessage *msg)
-{
-	PurpleConversationClass *klass = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
-
-	klass = PURPLE_CONVERSATION_GET_CLASS(conv);
-
-	if (klass && klass->write_message)
-		klass->write_message(conv, msg);
-}
-
-void purple_conversation_write_system_message(PurpleConversation *conv,
-	const gchar *message, PurpleMessageFlags flags)
-{
-	_purple_conversation_write_common(conv,
-		purple_message_new_system(message, flags));
-}
-
-void
-purple_conversation_send(PurpleConversation *conv, const char *message)
-{
-	purple_conversation_send_with_flags(conv, message, 0);
-}
-
-void
-purple_conversation_send_with_flags(PurpleConversation *conv, const char *message,
-		PurpleMessageFlags flags)
-{
-	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
-	g_return_if_fail(message != NULL);
-
-	common_send(conv, message, flags);
-}
-
-gboolean
-purple_conversation_has_focus(PurpleConversation *conv)
-{
-	gboolean ret = FALSE;
-	PurpleConversationUiOps *ops;
-
-	g_return_val_if_fail(PURPLE_IS_CONVERSATION(conv), FALSE);
-
-	ops = purple_conversation_get_ui_ops(conv);
-
-	if (ops != NULL && ops->has_focus != NULL)
-		ret = ops->has_focus(conv);
-
-	return ret;
-}
-
-/*
- * TODO: Need to make sure calls to this function happen in the core
- * instead of the UI.  That way UIs have less work to do, and the
- * core/UI split is cleaner.  Also need to make sure this is called
- * when chats are added/removed from the blist.
- */
-void
-purple_conversation_update(PurpleConversation *conv, PurpleConversationUpdateType type)
-{
-	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
-
-	purple_signal_emit(purple_conversations_get_handle(),
-					 "conversation-updated", conv, type);
-}
-
-gboolean purple_conversation_present_error(const char *who, PurpleAccount *account, const char *what)
-{
-	PurpleConversation *conv;
-
-	g_return_val_if_fail(who != NULL, FALSE);
-	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), FALSE);
-	g_return_val_if_fail(what != NULL, FALSE);
-
-	conv = purple_conversations_find_with_account(who, account);
-	if (conv != NULL)
-		purple_conversation_write_system_message(conv, what, PURPLE_MESSAGE_ERROR);
-	else
-		return FALSE;
-
-	return TRUE;
-}
-
-static void
-purple_conversation_send_confirm_cb(gpointer *data)
-{
-	PurpleConversation *conv = data[0];
-	char *message = data[1];
-
-	g_free(data);
-
-	if (!PURPLE_IS_CONVERSATION(conv)) {
-		/* Maybe it was closed before this callback was called. */
-		return;
-	}
-
-	common_send(conv, message, 0);
-}
-
-void
-purple_conversation_send_confirm(PurpleConversation *conv, const char *message)
-{
-	PurpleConversationPrivate *priv = NULL;
-	char *text;
-	gpointer *data;
-
-	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
-	g_return_if_fail(message != NULL);
-
-	priv = purple_conversation_get_instance_private(conv);
-	if (priv->ui_ops != NULL && priv->ui_ops->send_confirm != NULL)
-	{
-		priv->ui_ops->send_confirm(conv, message);
-		return;
-	}
-
-	text = g_strdup_printf("You are about to send the following message:\n%s", message);
-	data = g_new0(gpointer, 2);
-	data[0] = conv;
-	data[1] = (gpointer)message;
-
-	purple_request_action(conv, NULL, _("Send Message"), text, 0,
-		purple_request_cpar_from_account(
-			purple_conversation_get_account(conv)),
-		data, 2, _("_Send Message"),
-		G_CALLBACK(purple_conversation_send_confirm_cb), _("Cancel"), NULL);
-}
-
-GList *
-purple_conversation_get_extended_menu(PurpleConversation *conv)
-{
-	GList *menu = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONVERSATION(conv), NULL);
-
-	purple_signal_emit(purple_conversations_get_handle(),
-			"conversation-extended-menu", conv, &menu);
-	return menu;
-}
-
-void purple_conversation_clear_message_history(PurpleConversation *conv)
-{
-	PurpleConversationPrivate *priv = NULL;
-	GList *list;
-
-	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
-
-	priv = purple_conversation_get_instance_private(conv);
-	list = priv->message_history;
-	g_list_free_full(list, g_object_unref);
-	priv->message_history = NULL;
-
-	purple_signal_emit(purple_conversations_get_handle(),
-			"cleared-message-history", conv);
-}
-
-GList *purple_conversation_get_message_history(PurpleConversation *conv)
-{
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONVERSATION(conv), NULL);
-
-	priv = purple_conversation_get_instance_private(conv);
-	return priv->message_history;
-}
-
-gboolean
-purple_conversation_do_command(PurpleConversation *conv, const gchar *cmdline,
-				const gchar *markup, gchar **error)
-{
-	char *mark = (markup && *markup) ? NULL : g_markup_escape_text(cmdline, -1), *err = NULL;
-	PurpleCmdStatus status = purple_cmd_do_command(conv, cmdline, mark ? mark : markup, error ? error : &err);
-	g_free(mark);
-	g_free(err);
-	return (status == PURPLE_CMD_STATUS_OK);
-}
-
-gssize
-purple_conversation_get_max_message_size(PurpleConversation *conv)
-{
-	PurpleProtocol *protocol;
-
-	g_return_val_if_fail(PURPLE_IS_CONVERSATION(conv), 0);
-
-	protocol = purple_connection_get_protocol(
-		purple_conversation_get_connection(conv));
-
-	g_return_val_if_fail(PURPLE_IS_PROTOCOL(protocol), 0);
-
-	return purple_protocol_client_get_max_message_size(PURPLE_PROTOCOL_CLIENT(protocol), conv);
-}
-
-void
-purple_conversation_add_smiley(PurpleConversation *conv, PurpleSmiley *smiley) {
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
-	g_return_if_fail(smiley);
-
-	priv = purple_conversation_get_instance_private(conv);
-
-	if (priv->remote_smileys == NULL) {
-		priv->remote_smileys = purple_smiley_list_new();
-		g_object_set(priv->remote_smileys,
-			"drop-failed-remotes", TRUE, NULL);
-	}
-
-	if(purple_smiley_list_get_by_shortcut(
-		priv->remote_smileys,
-		purple_smiley_get_shortcut(smiley)))
-	{
-		/* smiley was already added */
-		return;
-	}
-
-	if (!purple_smiley_list_add(priv->remote_smileys, smiley)) {
-		purple_debug_error("conversation", "failed adding remote "
-			"smiley to the list");
-	}
-}
-
-PurpleSmiley *
-purple_conversation_get_smiley(PurpleConversation *conv, const gchar *shortcut) {
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONVERSATION(conv), NULL);
-	g_return_val_if_fail(shortcut, NULL);
-
-	priv = purple_conversation_get_instance_private(conv);
-
-	if (priv->remote_smileys == NULL)
-		return NULL;
-
-	return purple_smiley_list_get_by_shortcut(priv->remote_smileys, shortcut);
-}
-
-PurpleSmileyList *
-purple_conversation_get_remote_smileys(PurpleConversation *conv)
-{
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONVERSATION(conv), NULL);
-
-	priv = purple_conversation_get_instance_private(conv);
-	return priv->remote_smileys;
-}
-
-
-/**************************************************************************
- * GObject code
- **************************************************************************/
-
-/* Set method for GObject properties */
-static void
-purple_conversation_set_property(GObject *obj, guint param_id, const GValue *value,
-		GParamSpec *pspec)
-{
-	PurpleConversation *conv = PURPLE_CONVERSATION(obj);
-	PurpleConversationPrivate *priv =
-			purple_conversation_get_instance_private(conv);
-
-	switch (param_id) {
-		case PROP_ACCOUNT:
-			priv->account = g_value_get_object(value);
-			break;
-		case PROP_NAME:
-			g_free(priv->name);
-			priv->name = g_value_dup_string(value);
-			break;
-		case PROP_TITLE:
-			g_free(priv->title);
-			priv->title = g_value_dup_string(value);
-			break;
-		case PROP_LOGGING:
-			purple_conversation_set_logging(conv, g_value_get_boolean(value));
-			break;
-		case PROP_FEATURES:
-			purple_conversation_set_features(conv, g_value_get_flags(value));
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-			break;
-	}
-}
-
-/* Get method for GObject properties */
-static void
-purple_conversation_get_property(GObject *obj, guint param_id, GValue *value,
-		GParamSpec *pspec)
-{
-	PurpleConversation *conv = PURPLE_CONVERSATION(obj);
-
-	switch (param_id) {
-		case PROP_ACCOUNT:
-			g_value_set_object(value, purple_conversation_get_account(conv));
-			break;
-		case PROP_NAME:
-			g_value_set_string(value, purple_conversation_get_name(conv));
-			break;
-		case PROP_TITLE:
-			g_value_set_string(value, purple_conversation_get_title(conv));
-			break;
-		case PROP_LOGGING:
-			g_value_set_boolean(value, purple_conversation_is_logging(conv));
-			break;
-		case PROP_FEATURES:
-			g_value_set_flags(value, purple_conversation_get_features(conv));
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_conversation_init(PurpleConversation *conv)
-{
-}
-
-/* Called when done constructing */
-static void
-purple_conversation_constructed(GObject *object)
-{
-	PurpleConversation *conv = PURPLE_CONVERSATION(object);
-	PurpleAccount *account;
-	PurpleConnection *gc;
-	PurpleConversationUiOps *ops;
-
-	G_OBJECT_CLASS(purple_conversation_parent_class)->constructed(object);
-
-	g_object_get(object, "account", &account, NULL);
-	gc = purple_account_get_connection(account);
-
-	/* copy features from the connection. */
-	purple_conversation_set_features(conv, purple_connection_get_flags(gc));
-
-	/* add the conversation to the appropriate lists */
-	purple_conversations_add(conv);
-
-	/* Auto-set the title. */
-	purple_conversation_autoset_title(conv);
-
-	/* Don't move this.. it needs to be one of the last things done otherwise
-	 * it causes mysterious crashes on my system.
-	 *  -- Gary
-	 */
-	ops  = purple_conversations_get_ui_ops();
-	purple_conversation_set_ui_ops(conv, ops);
-	if (ops != NULL && ops->create_conversation != NULL)
-		ops->create_conversation(conv);
-
-	purple_signal_emit(purple_conversations_get_handle(),
-					 "conversation-created", conv);
-
-	g_object_unref(account);
-}
-
-static void
-purple_conversation_dispose(GObject *object)
-{
-	g_object_set_data(object, "is-finalizing", GINT_TO_POINTER(TRUE));
-}
-
-/* GObject finalize function */
-static void
-purple_conversation_finalize(GObject *object)
-{
-	PurpleConversation *conv = PURPLE_CONVERSATION(object);
-	PurpleConversationPrivate *priv =
-			purple_conversation_get_instance_private(conv);
-	PurpleConversationUiOps *ops  = purple_conversation_get_ui_ops(conv);
-
-	purple_request_close_with_handle(conv);
-
- 	/* remove from conversations and im/chats lists prior to emit */
-	purple_conversations_remove(conv);
-
-	purple_signal_emit(purple_conversations_get_handle(),
-					 "deleting-conversation", conv);
-
-	purple_conversation_close_logs(conv);
-	purple_conversation_clear_message_history(conv);
-
-	if (ops != NULL && ops->destroy_conversation != NULL)
-		ops->destroy_conversation(conv);
-
-	g_free(priv->name);
-	g_free(priv->title);
-
-	priv->name = NULL;
-	priv->title = NULL;
-
-	G_OBJECT_CLASS(purple_conversation_parent_class)->finalize(object);
-}
-
-/* Class initializer function */
-static void
-purple_conversation_class_init(PurpleConversationClass *klass)
-{
-	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
-
-	obj_class->dispose = purple_conversation_dispose;
-	obj_class->finalize = purple_conversation_finalize;
-	obj_class->constructed = purple_conversation_constructed;
-
-	/* Setup properties */
-	obj_class->get_property = purple_conversation_get_property;
-	obj_class->set_property = purple_conversation_set_property;
-
-	properties[PROP_ACCOUNT] = g_param_spec_object("account", "Account",
-				"The account for the conversation.", PURPLE_TYPE_ACCOUNT,
-				G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
-
-	properties[PROP_NAME] = g_param_spec_string("name", "Name",
-				"The name of the conversation.", NULL,
-				G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
-
-	properties[PROP_TITLE] = g_param_spec_string("title", "Title",
-				"The title of the conversation.", NULL,
-				G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
-
-	properties[PROP_LOGGING] = g_param_spec_boolean("logging", "Logging status",
-				"Whether logging is enabled or not.", FALSE,
-				G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	properties[PROP_FEATURES] = g_param_spec_flags("features",
-				"Connection features",
-				"The connection features of the conversation.",
-				PURPLE_TYPE_CONNECTION_FLAGS, 0,
-				G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	g_object_class_install_properties(obj_class, PROP_LAST, properties);
-}
diff --git a/libpurple/core.c b/libpurple/core.c
--- a/libpurple/core.c
+++ b/libpurple/core.c
@@ -24,7 +24,6 @@
 #include "internal.h"
 #include "cmds.h"
 #include "connection.h"
-#include "conversation.h"
 #include "core.h"
 #include "debug.h"
 #include "xfer.h"
@@ -36,6 +35,7 @@
 #include "plugins.h"
 #include "prefs.h"
 #include "proxy.h"
+#include "purpleconversation.h"
 #include "purplecredentialmanager.h"
 #include "purplemessage.h"
 #include "purpleprivate.h"
diff --git a/libpurple/meson.build b/libpurple/meson.build
--- a/libpurple/meson.build
+++ b/libpurple/meson.build
@@ -11,7 +11,6 @@
 	'cmds.c',
 	'connection.c',
 	'contact.c',
-	'conversation.c',
 	'conversations.c',
 	'core.c',
 	'countingnode.c',
@@ -50,6 +49,8 @@
 	'purplebuddypresence.c',
 	'purplechatconversation.c',
 	'purplechatuser.c',
+	'purpleconversation.c',
+	'purpleconversationuiops.c',
 	'purplecredentialmanager.c',
 	'purplecredentialprovider.c',
 	'purpleimconversation.c',
@@ -109,7 +110,6 @@
 	'cmds.h',
 	'connection.h',
 	'contact.h',
-	'conversation.h',
 	'conversations.h',
 	'core.h',
 	'countingnode.h',
@@ -141,6 +141,8 @@
 	'purplebuddypresence.h',
 	'purplechatconversation.h',
 	'purplechatuser.h',
+	'purpleconversation.h',
+	'purpleconversationuiops.h',
 	'purplecredentialmanager.h',
 	'purplecredentialprovider.h',
 	'purpleimconversation.h',
@@ -224,7 +226,6 @@
 	'account.h',
 	'buddyicon.h',
 	'connection.h',
-	'conversation.h',
 	'debug.h',
 	'eventloop.h',
 	'notify.h',
@@ -232,6 +233,7 @@
 	'protocol.h',
 	'protocols.h',
 	'purplechatuser.h',
+	'purpleconversation.h',
 	'purpleimconversation.h',
 	'purplemessage.h',
 	'roomlist.h',
diff --git a/libpurple/protocols.c b/libpurple/protocols.c
--- a/libpurple/protocols.c
+++ b/libpurple/protocols.c
@@ -24,12 +24,12 @@
 #include <glib/gi18n-lib.h>
 
 #include "internal.h"
-#include "conversation.h"
 #include "debug.h"
 #include "network.h"
 #include "notify.h"
 #include "protocol.h"
 #include "purpleaccountoption.h"
+#include "purpleconversation.h"
 #include "purplecredentialmanager.h"
 #include "purpleprotocolattention.h"
 #include "purpleprotocolmanager.h"
diff --git a/libpurple/purplechatconversation.h b/libpurple/purplechatconversation.h
--- a/libpurple/purplechatconversation.h
+++ b/libpurple/purplechatconversation.h
@@ -45,8 +45,8 @@
 typedef struct _PurpleChatConversationClass      PurpleChatConversationClass;
 
 #include "purplechatuser.h"
+#include "purpleconversation.h"
 #include "purpleimconversation.h"
-#include "conversation.h"
 
 G_BEGIN_DECLS
 
diff --git a/libpurple/purpleimconversation.h b/libpurple/purpleimconversation.h
--- a/libpurple/purpleimconversation.h
+++ b/libpurple/purpleimconversation.h
@@ -61,7 +61,8 @@
 typedef struct _PurpleIMConversation           PurpleIMConversation;
 typedef struct _PurpleIMConversationClass      PurpleIMConversationClass;
 
-#include <conversation.h>
+#include "buddyicon.h"
+#include <purpleconversation.h>
 
 /**
  * PurpleIMConversation:
diff --git a/libpurple/request.h b/libpurple/request.h
--- a/libpurple/request.h
+++ b/libpurple/request.h
@@ -41,7 +41,7 @@
 #include <glib.h>
 #include <glib-object.h>
 
-#include "conversation.h"
+#include "purpleconversation.h"
 #include "request-datasheet.h"
 
 #define PURPLE_TYPE_REQUEST_UI_OPS (purple_request_ui_ops_get_type())
diff --git a/libpurple/server.c b/libpurple/server.c
--- a/libpurple/server.c
+++ b/libpurple/server.c
@@ -27,12 +27,12 @@
 
 #include "internal.h"
 #include "buddylist.h"
-#include "conversation.h"
 #include "debug.h"
 #include "log.h"
 #include "notify.h"
 #include "prefs.h"
 #include "protocol.h"
+#include "purpleconversation.h"
 #include "purpleprivate.h"
 #include "purpleprotocolattention.h"
 #include "purpleprotocolchat.h"
diff --git a/libpurple/smiley-parser.h b/libpurple/smiley-parser.h
--- a/libpurple/smiley-parser.h
+++ b/libpurple/smiley-parser.h
@@ -41,7 +41,7 @@
 
 #include <glib.h>
 
-#include "conversation.h"
+#include <purpleconversation.h>
 #include "smiley.h"
 #include "smiley-list.h"
 
diff --git a/libpurple/util.c b/libpurple/util.c
--- a/libpurple/util.c
+++ b/libpurple/util.c
@@ -22,12 +22,12 @@
 #include "internal.h"
 #include "purpleprivate.h"
 
-#include "conversation.h"
 #include "core.h"
 #include "debug.h"
 #include "notify.h"
 #include "protocol.h"
 #include "prefs.h"
+#include "purpleconversation.h"
 #include "purpleprotocolclient.h"
 #include "util.h"
 
diff --git a/po/POTFILES.in b/po/POTFILES.in
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -36,7 +36,6 @@
 libpurple/cmds.c
 libpurple/connection.c
 libpurple/contact.c
-libpurple/conversation.c
 libpurple/conversations.c
 libpurple/core.c
 libpurple/countingnode.c
@@ -245,6 +244,7 @@
 libpurple/purpleattentiontype.c
 libpurple/purplebuddypresence.c
 libpurple/purplechatuser.c
+libpurple/purpleconversation.c
 libpurple/purplecredentialmanager.c
 libpurple/purplecredentialprovider.c
 libpurple/purple-gio.c
