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
@@ -80,6 +80,7 @@
       <xi:include href="xml/purpleprotocolim.xml" />
       <xi:include href="xml/purpleprotocolmedia.xml" />
       <xi:include href="xml/purpleprotocolprivacy.xml" />
+      <xi:include href="xml/purpleprotocolserver.xml" />
       <xi:include href="xml/purplewhiteboard.xml" />
       <xi:include href="xml/purplewhiteboardops.xml" />
       <xi:include href="xml/purplewhiteboarduiops.xml" />
diff --git a/libpurple/account.c b/libpurple/account.c
--- a/libpurple/account.c
+++ b/libpurple/account.c
@@ -33,6 +33,7 @@
 #include "purplecredentialmanager.h"
 #include "purpleprivate.h"
 #include "purpleprotocolclient.h"
+#include "purpleprotocolserver.h"
 #include "request.h"
 #include "server.h"
 #include "signals.h"
@@ -1856,9 +1857,11 @@
 	gc = purple_account_get_connection(account);
 	protocol = purple_connection_get_protocol(gc);
 
-	if (PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, set_public_alias))
-		purple_protocol_server_iface_set_public_alias(protocol, gc, alias, success_cb, failure_cb);
-	else if (failure_cb) {
+	if(PURPLE_IS_PROTOCOL_SERVER(protocol)) {
+		purple_protocol_server_set_public_alias(PURPLE_PROTOCOL_SERVER(protocol),
+		                                        gc, alias, success_cb,
+		                                        failure_cb);
+	} else if(failure_cb) {
 		struct public_alias_closure *closure =
 				g_new0(struct public_alias_closure, 1);
 		closure->account = g_object_ref(account);
@@ -1881,9 +1884,10 @@
 	gc = purple_account_get_connection(account);
 	protocol = purple_connection_get_protocol(gc);
 
-	if (PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, get_public_alias))
-		purple_protocol_server_iface_get_public_alias(protocol, gc, success_cb, failure_cb);
-	else if (failure_cb) {
+	if(PURPLE_IS_PROTOCOL_SERVER(protocol)) {
+		purple_protocol_server_get_public_alias(PURPLE_PROTOCOL_SERVER(protocol),
+		                                        gc, success_cb, failure_cb);
+	} else if(failure_cb) {
 		struct public_alias_closure *closure =
 				g_new0(struct public_alias_closure, 1);
 		closure->account = g_object_ref(account);
@@ -2858,9 +2862,12 @@
 	if (gc != NULL)
 		protocol = purple_connection_get_protocol(gc);
 
-	if (protocol != NULL)
-		purple_protocol_server_iface_add_buddy(protocol, gc, buddy,
-				purple_buddy_get_group(buddy), message);
+	if(PURPLE_IS_PROTOCOL_SERVER(protocol)) {
+		PurpleGroup *group = purple_buddy_get_group(buddy);
+
+		purple_protocol_server_add_buddy(PURPLE_PROTOCOL_SERVER(protocol), gc,
+		                                 buddy, group, message);
+	}
 }
 
 void
@@ -2881,16 +2888,9 @@
 			groups = g_list_append(groups, purple_buddy_get_group(buddy));
 		}
 
-		if (PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, add_buddies))
-			purple_protocol_server_iface_add_buddies(protocol, gc, buddies, groups, message);
-		else if (PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, add_buddy)) {
-			GList *curb = buddies, *curg = groups;
-
-			while ((curb != NULL) && (curg != NULL)) {
-				purple_protocol_server_iface_add_buddy(protocol, gc, curb->data, curg->data, message);
-				curb = curb->next;
-				curg = curg->next;
-			}
+		if(PURPLE_IS_PROTOCOL_SERVER(protocol)) {
+			purple_protocol_server_add_buddies(PURPLE_PROTOCOL_SERVER(protocol),
+			                                   gc, buddies, groups, message);
 		}
 
 		g_list_free(groups);
@@ -2907,8 +2907,10 @@
 	if (gc != NULL)
 		protocol = purple_connection_get_protocol(gc);
 
-	if (protocol)
-		purple_protocol_server_iface_remove_buddy(protocol, gc, buddy, group);
+	if(PURPLE_IS_PROTOCOL_SERVER(protocol)) {
+		purple_protocol_server_remove_buddy(PURPLE_PROTOCOL_SERVER(protocol),
+		                                    gc, buddy, group);
+	}
 }
 
 void
@@ -2920,18 +2922,9 @@
 	if (gc != NULL)
 		protocol = purple_connection_get_protocol(gc);
 
-	if (protocol) {
-		if (PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, remove_buddies))
-			purple_protocol_server_iface_remove_buddies(protocol, gc, buddies, groups);
-		else {
-			GList *curb = buddies;
-			GList *curg = groups;
-			while ((curb != NULL) && (curg != NULL)) {
-				purple_account_remove_buddy(account, curb->data, curg->data);
-				curb = curb->next;
-				curg = curg->next;
-			}
-		}
+	if(PURPLE_IS_PROTOCOL_SERVER(protocol)) {
+		purple_protocol_server_remove_buddies(PURPLE_PROTOCOL_SERVER(protocol),
+		                                      gc, buddies, groups);
 	}
 }
 
@@ -2944,8 +2937,10 @@
 	if (gc != NULL)
 		protocol = purple_connection_get_protocol(gc);
 
-	if (protocol)
-		purple_protocol_server_iface_remove_group(protocol, gc, group);
+	if(PURPLE_IS_PROTOCOL_SERVER(protocol)) {
+		purple_protocol_server_remove_group(PURPLE_PROTOCOL_SERVER(protocol),
+		                                    gc, group);
+	}
 }
 
 void
@@ -2966,8 +2961,10 @@
 	if (gc != NULL)
 		protocol = purple_connection_get_protocol(gc);
 
-	if (protocol)
-		purple_protocol_server_iface_change_passwd(protocol, gc, orig_pw, new_pw);
+	if(PURPLE_IS_PROTOCOL_SERVER(protocol)) {
+		purple_protocol_server_change_passwd(PURPLE_PROTOCOL_SERVER(protocol),
+		                                     gc, orig_pw, new_pw);
+	}
 }
 
 gboolean purple_account_supports_offline_message(PurpleAccount *account, PurpleBuddy *buddy)
diff --git a/libpurple/buddyicon.c b/libpurple/buddyicon.c
--- a/libpurple/buddyicon.c
+++ b/libpurple/buddyicon.c
@@ -25,6 +25,7 @@
 #include "debug.h"
 #include "image.h"
 #include "purpleprivate.h"
+#include "purpleprotocolserver.h"
 #include "util.h"
 
 /* NOTE: Instances of this struct are allocated without zeroing the memory, so
@@ -757,8 +758,10 @@
 		gc = purple_account_get_connection(account);
 		protocol = purple_connection_get_protocol(gc);
 
-		if (protocol)
-			purple_protocol_server_iface_set_buddy_icon(protocol, gc, img);
+		if(PURPLE_IS_PROTOCOL_SERVER(protocol)) {
+			purple_protocol_server_set_buddy_icon(PURPLE_PROTOCOL_SERVER(protocol),
+			                                      gc, img);
+		}
 	}
 
 	if (old_img)
diff --git a/libpurple/connection.c b/libpurple/connection.c
--- a/libpurple/connection.c
+++ b/libpurple/connection.c
@@ -33,6 +33,7 @@
 #include "prefs.h"
 #include "proxy.h"
 #include "purpleprivate.h"
+#include "purpleprotocolserver.h"
 #include "purpleprotocolfactory.h"
 #include "request.h"
 #include "server.h"
@@ -125,7 +126,8 @@
 	PurpleConnection *gc = data;
 	PurpleConnectionPrivate *priv = purple_connection_get_instance_private(gc);
 
-	purple_protocol_server_iface_keepalive(priv->protocol, gc);
+	purple_protocol_server_keepalive(PURPLE_PROTOCOL_SERVER(priv->protocol),
+	                                 gc);
 
 	return TRUE;
 }
@@ -140,7 +142,7 @@
 
 	if (on && !priv->keepalive)
 	{
-		int interval = purple_protocol_server_iface_get_keepalive_interval(priv->protocol);
+		int interval = purple_protocol_server_get_keepalive_interval(PURPLE_PROTOCOL_SERVER(priv->protocol));
 		purple_debug_info("connection", "Activating keepalive to %d seconds.", interval);
 		priv->keepalive = g_main_context_find_source_by_id(NULL, g_timeout_add_seconds(interval, send_keepalive, gc));
 	}
@@ -677,7 +679,7 @@
 		 * it seems unlikely that the implementation will change, we just do that
 		 * for now as a workaround for this API shortcoming.
 		 */
-		gint64 seconds_from_now = purple_protocol_server_iface_get_keepalive_interval(priv->protocol);
+		gint64 seconds_from_now = purple_protocol_server_get_keepalive_interval(PURPLE_PROTOCOL_SERVER(priv->protocol));
 
 		g_source_set_ready_time(
 			priv->keepalive,
@@ -1038,7 +1040,8 @@
 		priv = purple_connection_get_instance_private(gc);
 		priv->wants_to_die = TRUE;
 
-		purple_protocol_server_iface_register_user(protocol, account);
+		purple_protocol_server_register_user(PURPLE_PROTOCOL_SERVER(protocol),
+		                                     account);
 	}
 	else
 	{
@@ -1051,7 +1054,7 @@
 
 void
 _purple_connection_new_unregister(PurpleAccount *account, const char *password,
-		PurpleAccountUnregistrationCb cb, void *user_data)
+		PurpleAccountUnregistrationCb cb, gpointer user_data)
 {
 	/* Lots of copy/pasted code to avoid API changes. You might want to integrate that into the previous function when posssible. */
 	PurpleConnection *gc;
@@ -1073,7 +1076,8 @@
 	}
 
 	if (!purple_account_is_disconnected(account)) {
-		purple_protocol_server_iface_unregister_user(protocol, account, cb, user_data);
+		purple_protocol_server_unregister_user(PURPLE_PROTOCOL_SERVER(protocol),
+		                                       account, cb, user_data);
 		return;
 	}
 
@@ -1101,7 +1105,8 @@
 
 	purple_debug_info("connection", "Unregistering.  gc = %p\n", gc);
 
-	purple_protocol_server_iface_unregister_user(protocol, account, cb, user_data);
+	purple_protocol_server_unregister_user(PURPLE_PROTOCOL_SERVER(protocol),
+	                                       account, cb, user_data);
 }
 
 /**************************************************************************
diff --git a/libpurple/group.c b/libpurple/group.c
--- a/libpurple/group.c
+++ b/libpurple/group.c
@@ -24,6 +24,7 @@
 #include "group.h"
 #include "internal.h" /* TODO: we need to kill this */
 #include "purpleprivate.h"
+#include "purpleprotocolserver.h"
 
 typedef struct _PurpleGroupPrivate      PurpleGroupPrivate;
 
@@ -212,7 +213,9 @@
 			}
 
 			if(PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, rename_group)) {
-				purple_protocol_server_iface_rename_group(protocol, gc, old_name, source, buddies);
+				purple_protocol_server_rename_group(PURPLE_PROTOCOL_SERVER(protocol),
+				                                    gc, old_name, source,
+				                                    buddies);
 			} else {
 				GList *cur, *groups = NULL;
 
diff --git a/libpurple/meson.build b/libpurple/meson.build
--- a/libpurple/meson.build
+++ b/libpurple/meson.build
@@ -65,6 +65,7 @@
 	'purpleprotocolim.c',
 	'purpleprotocolmedia.c',
 	'purpleprotocolprivacy.c',
+	'purpleprotocolserver.c',
 	'purpleuiinfo.c',
 	'purplewhiteboard.c',
 	'purplewhiteboarduiops.c',
@@ -154,6 +155,7 @@
 	'purpleprotocolim.h',
 	'purpleprotocolmedia.h',
 	'purpleprotocolprivacy.h',
+	'purpleprotocolserver.h',
 	'purpleuiinfo.h',
 	'purplewhiteboard.h',
 	'purplewhiteboardops.h',
diff --git a/libpurple/protocol.h b/libpurple/protocol.h
--- a/libpurple/protocol.h
+++ b/libpurple/protocol.h
@@ -138,144 +138,6 @@
 	void (*_purple_reserved4)(void);
 };
 
-#define PURPLE_TYPE_PROTOCOL_SERVER (purple_protocol_server_iface_get_type())
-
-typedef struct _PurpleProtocolServerInterface PurpleProtocolServerInterface;
-
-/**
- * PurpleProtocolServerInterface:
- * @register_user:   New user registration
- * @unregister_user: Remove the user from the server. The account can either be
- *                   connected or disconnected. After the removal is finished,
- *                   the connection will stay open and has to be closed!
- * @get_info:        Should arrange for purple_notify_userinfo() to be called
- *                   with @who's user info.
- * @add_buddy:       Add a buddy to a group on the server.
- *                   <sbr/>This protocol function may be called in situations in
- *                   which the buddy is already in the specified group. If the
- *                   protocol supports authorization and the user is not already
- *                   authorized to see the status of @buddy, @add_buddy should
- *                   request authorization.
- *                   <sbr/>If authorization is required, then use the supplied
- *                   invite message.
- * @keepalive:       If implemented, this will be called regularly for this
- *                   protocol's active connections. You'd want to do this if you
- *                   need to repeatedly send some kind of keepalive packet to
- *                   the server to avoid being disconnected. ("Regularly" is
- *                   defined to be 30 unless @get_keepalive_interval is
- *                   implemented to override it).
- *                   <filename>libpurple/connection.c</filename>.)
- * @get_keepalive_interval: If implemented, this will override the default
- *                          keepalive interval.
- * @alias_buddy:     Save/store buddy's alias on server list/roster
- * @group_buddy:     Change a buddy's group on a server list/roster
- * @rename_group:    Rename a group on a server list/roster
- * @set_buddy_icon:  Set the buddy icon for the given connection to @img. The
- *                   protocol does <emphasis>NOT</emphasis> own a reference to
- *                   @img; if it needs one, it must #g_object_ref(@img)
- *                   itself.
- * @send_raw:        For use in plugins that may understand the underlying
- *                   protocol
- * @set_public_alias: Set the user's "friendly name" (or alias or nickname or
- *                    whatever term you want to call it) on the server. The
- *                    protocol should call @success_cb or @failure_cb
- *                    <emphasis>asynchronously</emphasis> (if it knows
- *                    immediately that the set will fail, call one of the
- *                    callbacks from an idle/0-second timeout) depending on if
- *                    the nickname is set successfully. See
- *                    purple_account_set_public_alias().
- *                    <sbr/>@gc:    The connection for which to set an alias
- *                    <sbr/>@alias: The new server-side alias/nickname for this
- *                                  account, or %NULL to unset the
- *                                  alias/nickname (or return it to a
- *                                  protocol-specific "default").
- *                    <sbr/>@success_cb: Callback to be called if the public
- *                                       alias is set
- *                    <sbr/>@failure_cb: Callback to be called if setting the
- *                                       public alias fails
- * @get_public_alias: Retrieve the user's "friendly name" as set on the server.
- *                    The protocol should call @success_cb or @failure_cb
- *                    <emphasis>asynchronously</emphasis> (even if it knows
- *                    immediately that the get will fail, call one of the
- *                    callbacks from an idle/0-second timeout) depending on if
- *                    the nickname is retrieved. See
- *                    purple_account_get_public_alias().
- *                    <sbr/>@gc:         The connection for which to retireve
- *                                       the alias
- *                    <sbr/>@success_cb: Callback to be called with the
- *                                       retrieved alias
- *                    <sbr/>@failure_cb: Callback to be called if the protocol
- *                                       is unable to retrieve the alias
- *
- * The protocol server interface.
- *
- * This interface provides a gateway between purple and the protocol's server.
- */
-struct _PurpleProtocolServerInterface
-{
-	/*< private >*/
-	GTypeInterface parent_iface;
-
-	/*< public >*/
-	void (*register_user)(PurpleAccount *account);
-
-	void (*unregister_user)(PurpleAccount *account, PurpleAccountUnregistrationCb cb,
-							void *user_data);
-
-	void (*set_info)(PurpleConnection *connection, const char *info);
-
-	void (*get_info)(PurpleConnection *connection, const char *who);
-
-	void (*set_status)(PurpleAccount *account, PurpleStatus *status);
-
-	void (*set_idle)(PurpleConnection *connection, int idletime);
-
-	void (*change_passwd)(PurpleConnection *connection, const char *old_pass,
-						  const char *new_pass);
-
-	void (*add_buddy)(PurpleConnection *pc, PurpleBuddy *buddy,
-					  PurpleGroup *group, const char *message);
-
-	void (*add_buddies)(PurpleConnection *pc, GList *buddies, GList *groups,
-						const char *message);
-
-	void (*remove_buddy)(PurpleConnection *connection, PurpleBuddy *buddy,
-						 PurpleGroup *group);
-
-	void (*remove_buddies)(PurpleConnection *connection, GList *buddies, GList *groups);
-
-	void (*keepalive)(PurpleConnection *connection);
-
-	int (*get_keepalive_interval)(void);
-
-	void (*alias_buddy)(PurpleConnection *connection, const char *who,
-						const char *alias);
-
-	void (*group_buddy)(PurpleConnection *connection, const char *who,
-					const char *old_group, const char *new_group);
-
-	void (*rename_group)(PurpleConnection *connection, const char *old_name,
-					 PurpleGroup *group, GList *moved_buddies);
-
-	void (*set_buddy_icon)(PurpleConnection *connection, PurpleImage *img);
-
-	void (*remove_group)(PurpleConnection *gc, PurpleGroup *group);
-
-	int (*send_raw)(PurpleConnection *gc, const char *buf, int len);
-
-	void (*set_public_alias)(PurpleConnection *gc, const char *alias,
-	                         PurpleSetPublicAliasSuccessCallback success_cb,
-	                         PurpleSetPublicAliasFailureCallback failure_cb);
-
-	void (*get_public_alias)(PurpleConnection *gc,
-	                         PurpleGetPublicAliasSuccessCallback success_cb,
-	                         PurpleGetPublicAliasFailureCallback failure_cb);
-};
-
-#define PURPLE_IS_PROTOCOL_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_PROTOCOL_SERVER))
-#define PURPLE_PROTOCOL_SERVER_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE((obj), PURPLE_TYPE_PROTOCOL_SERVER, \
-                                               PurpleProtocolServerInterface))
-
 /**
  * PURPLE_PROTOCOL_IMPLEMENTS:
  * @protocol: The protocol in which to check
@@ -388,104 +250,6 @@
 const char *purple_protocol_class_list_icon(PurpleProtocol *protocol,
 		PurpleAccount *account, PurpleBuddy *buddy);
 
-/**************************************************************************/
-/* Protocol Server Interface API                                          */
-/**************************************************************************/
-
-/**
- * purple_protocol_server_iface_get_type:
- *
- * Returns: The #GType for the protocol server interface.
- */
-GType purple_protocol_server_iface_get_type(void);
-
-void purple_protocol_server_iface_register_user(PurpleProtocol *protocol,
-		PurpleAccount *account);
-
-/**
- * purple_protocol_server_iface_unregister_user:
- * @cb: (scope call):
- */
-void purple_protocol_server_iface_unregister_user(PurpleProtocol *protocol,
-		PurpleAccount *account, PurpleAccountUnregistrationCb cb, void *user_data);
-
-void purple_protocol_server_iface_set_info(PurpleProtocol *protocol, PurpleConnection *connection,
-		const char *info);
-
-void purple_protocol_server_iface_get_info(PurpleProtocol *protocol, PurpleConnection *connection,
-		const char *who);
-
-void purple_protocol_server_iface_set_status(PurpleProtocol *protocol,
-		PurpleAccount *account, PurpleStatus *status);
-
-void purple_protocol_server_iface_set_idle(PurpleProtocol *protocol, PurpleConnection *connection,
-		int idletime);
-
-void purple_protocol_server_iface_change_passwd(PurpleProtocol *protocol,
-		PurpleConnection *connection, const char *old_pass, const char *new_pass);
-
-void purple_protocol_server_iface_add_buddy(PurpleProtocol *protocol,
-		PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group,
-		const char *message);
-
-void purple_protocol_server_iface_add_buddies(PurpleProtocol *protocol,
-		PurpleConnection *pc, GList *buddies, GList *groups,
-		const char *message);
-
-void purple_protocol_server_iface_remove_buddy(PurpleProtocol *protocol,
-		PurpleConnection *connection, PurpleBuddy *buddy, PurpleGroup *group);
-
-void purple_protocol_server_iface_remove_buddies(PurpleProtocol *protocol,
-		PurpleConnection *connection, GList *buddies, GList *groups);
-
-void purple_protocol_server_iface_keepalive(PurpleProtocol *protocol,
-		PurpleConnection *connection);
-
-int purple_protocol_server_iface_get_keepalive_interval(PurpleProtocol *protocol);
-
-void purple_protocol_server_iface_alias_buddy(PurpleProtocol *protocol,
-		PurpleConnection *connection, const char *who, const char *alias);
-
-void purple_protocol_server_iface_group_buddy(PurpleProtocol *protocol,
-		PurpleConnection *connection, const char *who, const char *old_group,
-		const char *new_group);
-
-void purple_protocol_server_iface_rename_group(PurpleProtocol *protocol,
-		PurpleConnection *connection, const char *old_name, PurpleGroup *group,
-		GList *moved_buddies);
-
-void purple_protocol_server_iface_set_buddy_icon(PurpleProtocol *protocol,
-		PurpleConnection *connection, PurpleImage *img);
-
-void purple_protocol_server_iface_remove_group(PurpleProtocol *protocol,
-		PurpleConnection *gc, PurpleGroup *group);
-
-int purple_protocol_server_iface_send_raw(PurpleProtocol *protocol,
-		PurpleConnection *gc, const char *buf, int len);
-
-/**
- * purple_protocol_server_iface_set_public_alias:
- * @success_cb: (scope call):
- * @failure_cb: (scope call):
- */
-void purple_protocol_server_iface_set_public_alias(PurpleProtocol *protocol,
-		PurpleConnection *gc, const char *alias,
-		PurpleSetPublicAliasSuccessCallback success_cb,
-		PurpleSetPublicAliasFailureCallback failure_cb);
-
-/**
- * purple_protocol_server_iface_get_public_alias:
- * @success_cb: (scope call):
- * @failure_cb: (scope call):
- */
-void purple_protocol_server_iface_get_public_alias(PurpleProtocol *protocol,
-		PurpleConnection *gc, PurpleGetPublicAliasSuccessCallback success_cb,
-		PurpleGetPublicAliasFailureCallback failure_cb);
-
-/**************************************************************************/
-/* Protocol Chat Interface API                                            */
-/**************************************************************************/
-
 G_END_DECLS
 
 #endif /* PURPLE_PROTOCOL_H */
diff --git a/libpurple/protocol.c b/libpurple/protocol.c
--- a/libpurple/protocol.c
+++ b/libpurple/protocol.c
@@ -209,196 +209,3 @@
 
 #undef DEFINE_PROTOCOL_FUNC_WITH_RETURN
 #undef DEFINE_PROTOCOL_FUNC
-
-/**************************************************************************
- * Protocol Server Interface API
- **************************************************************************/
-#define DEFINE_PROTOCOL_FUNC(protocol,funcname,...) \
-	PurpleProtocolServerInterface *server_iface = \
-		PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol); \
-	if (server_iface && server_iface->funcname) \
-		server_iface->funcname(__VA_ARGS__);
-
-#define DEFINE_PROTOCOL_FUNC_WITH_RETURN(protocol,defaultreturn,funcname,...) \
-	PurpleProtocolServerInterface *server_iface = \
-		PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol); \
-	if (server_iface && server_iface->funcname) \
-		return server_iface->funcname(__VA_ARGS__); \
-	else \
-		return defaultreturn;
-
-GType
-purple_protocol_server_iface_get_type(void)
-{
-	static GType type = 0;
-
-	if (G_UNLIKELY(type == 0)) {
-		static const GTypeInfo info = {
-			.class_size = sizeof(PurpleProtocolServerInterface),
-		};
-
-		type = g_type_register_static(G_TYPE_INTERFACE,
-				"PurpleProtocolServerInterface", &info, 0);
-	}
-	return type;
-}
-
-void
-purple_protocol_server_iface_register_user(PurpleProtocol *protocol,
-		PurpleAccount *account)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, register_user, account);
-}
-
-void
-purple_protocol_server_iface_unregister_user(PurpleProtocol *protocol,
-		PurpleAccount *account, PurpleAccountUnregistrationCb cb,
-		void *user_data)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, unregister_user, account, cb, user_data);
-}
-
-void
-purple_protocol_server_iface_set_info(PurpleProtocol *protocol,
-		PurpleConnection *gc, const char *info)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, set_info, gc, info);
-}
-
-void
-purple_protocol_server_iface_get_info(PurpleProtocol *protocol,
-		PurpleConnection *gc, const char *who)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, get_info, gc, who);
-}
-
-void
-purple_protocol_server_iface_set_status(PurpleProtocol *protocol,
-		PurpleAccount *account, PurpleStatus *status)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, set_status, account, status);
-}
-
-void
-purple_protocol_server_iface_set_idle(PurpleProtocol *protocol,
-		PurpleConnection *gc, int idletime)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, set_idle, gc, idletime);
-}
-
-void
-purple_protocol_server_iface_change_passwd(PurpleProtocol *protocol,
-		PurpleConnection *gc, const char *old_pass, const char *new_pass)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, change_passwd, gc, old_pass, new_pass);
-}
-
-void
-purple_protocol_server_iface_add_buddy(PurpleProtocol *protocol,
-		PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group,
-		const char *message)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, add_buddy, gc, buddy, group, message);
-}
-
-void
-purple_protocol_server_iface_add_buddies(PurpleProtocol *protocol,
-		PurpleConnection *gc, GList *buddies, GList *groups,
-		const char *message)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, add_buddies, gc, buddies, groups, message);
-}
-
-void
-purple_protocol_server_iface_remove_buddy(PurpleProtocol *protocol,
-		PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, remove_buddy, gc, buddy, group);
-}
-
-void
-purple_protocol_server_iface_remove_buddies(PurpleProtocol *protocol,
-		PurpleConnection *gc, GList *buddies, GList *groups)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, remove_buddies, gc, buddies, groups);
-}
-
-void
-purple_protocol_server_iface_keepalive(PurpleProtocol *protocol,
-		PurpleConnection *gc)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, keepalive, gc);
-}
-
-int
-purple_protocol_server_iface_get_keepalive_interval(PurpleProtocol *protocol)
-{
-	DEFINE_PROTOCOL_FUNC_WITH_RETURN(protocol, 30, get_keepalive_interval);
-}
-
-void
-purple_protocol_server_iface_alias_buddy(PurpleProtocol *protocol,
-		PurpleConnection *gc, const char *who, const char *alias)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, alias_buddy, gc, who, alias);
-}
-
-void
-purple_protocol_server_iface_group_buddy(PurpleProtocol *protocol,
-		PurpleConnection *gc, const char *who, const char *old_group,
-		const char *new_group)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, group_buddy, gc, who, old_group, new_group);
-}
-
-void
-purple_protocol_server_iface_rename_group(PurpleProtocol *protocol,
-		PurpleConnection *gc, const char *old_name, PurpleGroup *group,
-		GList *moved_buddies)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, rename_group, gc, old_name, group,
-			moved_buddies);
-}
-
-void
-purple_protocol_server_iface_set_buddy_icon(PurpleProtocol *protocol,
-		PurpleConnection *gc, PurpleImage *img)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, set_buddy_icon, gc, img);
-}
-
-void
-purple_protocol_server_iface_remove_group(PurpleProtocol *protocol,
-		PurpleConnection *gc, PurpleGroup *group)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, remove_group, gc, group);
-}
-
-int
-purple_protocol_server_iface_send_raw(PurpleProtocol *protocol,
-		PurpleConnection *gc, const char *buf, int len)
-{
-	DEFINE_PROTOCOL_FUNC_WITH_RETURN(protocol, 0, send_raw, gc, buf, len);
-}
-
-void
-purple_protocol_server_iface_set_public_alias(PurpleProtocol *protocol,
-		PurpleConnection *gc, const char *alias,
-		PurpleSetPublicAliasSuccessCallback success_cb,
-		PurpleSetPublicAliasFailureCallback failure_cb)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, set_public_alias, gc, alias, success_cb,
-			failure_cb);
-}
-
-void
-purple_protocol_server_iface_get_public_alias(PurpleProtocol *protocol,
-		PurpleConnection *gc, PurpleGetPublicAliasSuccessCallback success_cb,
-		PurpleGetPublicAliasFailureCallback failure_cb)
-{
-	DEFINE_PROTOCOL_FUNC(protocol, get_public_alias, gc, success_cb,
-			failure_cb);
-}
-
-#undef DEFINE_PROTOCOL_FUNC_WITH_RETURN
-#undef DEFINE_PROTOCOL_FUNC
diff --git a/libpurple/protocols.c b/libpurple/protocols.c
--- a/libpurple/protocols.c
+++ b/libpurple/protocols.c
@@ -33,6 +33,7 @@
 #include "purplecredentialmanager.h"
 #include "purpleprotocolattention.h"
 #include "purpleprotocolmedia.h"
+#include "purpleprotocolserver.h"
 #include "request.h"
 #include "util.h"
 
@@ -311,8 +312,10 @@
 	if (protocol == NULL)
 		return;
 
-	if (!purple_account_is_disconnected(account))
-		purple_protocol_server_iface_set_status(protocol, account, new_status);
+	if(!purple_account_is_disconnected(account)) {
+		purple_protocol_server_set_status(PURPLE_PROTOCOL_SERVER(protocol),
+		                                  account, new_status);
+	}
 }
 
 void
diff --git a/libpurple/protocols/bonjour/bonjour.c b/libpurple/protocols/bonjour/bonjour.c
--- a/libpurple/protocols/bonjour/bonjour.c
+++ b/libpurple/protocols/bonjour/bonjour.c
@@ -216,7 +216,8 @@
 }
 
 static void
-bonjour_set_status(PurpleAccount *account, PurpleStatus *status)
+bonjour_set_status(PurpleProtocolServer *protocol_server,
+                   PurpleAccount *account, PurpleStatus *status)
 {
 	PurpleConnection *gc;
 	BonjourData *bd;
@@ -258,7 +259,10 @@
  * if there is no add_buddy callback.
  */
 static void
-bonjour_fake_add_buddy(PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group, const char *message) {
+bonjour_fake_add_buddy(PurpleProtocolServer *protocol_server,
+                       PurpleConnection *pc, PurpleBuddy *buddy,
+                       PurpleGroup *group, const gchar *message)
+{
 	purple_debug_error("bonjour", "Buddy '%s' manually added; removing.  "
 				      "Bonjour buddies must be discovered and not manually added.\n",
 			   purple_buddy_get_name(buddy));
@@ -270,7 +274,11 @@
 }
 
 
-static void bonjour_remove_buddy(PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group) {
+static void
+bonjour_remove_buddy(PurpleProtocolServer *protocol_server,
+                     PurpleConnection *pc, PurpleBuddy *buddy,
+                     PurpleGroup *group)
+{
 	BonjourBuddy *bb = purple_buddy_get_protocol_data(buddy);
 	if (bb) {
 		bonjour_buddy_delete(bb);
@@ -329,7 +337,8 @@
 }
 
 static void
-bonjour_set_buddy_icon(PurpleConnection *conn, PurpleImage *img)
+bonjour_set_buddy_icon(PurpleProtocolServer *protocol_server,
+                       PurpleConnection *conn, PurpleImage *img)
 {
 	BonjourData *bd = purple_connection_get_protocol_data(conn);
 	bonjour_dns_sd_update_buddy_icon(bd->dns_sd_data);
@@ -439,18 +448,22 @@
 }
 
 static void
-bonjour_group_buddy(PurpleConnection *connection, const char *who, const char *old_group, const char *new_group)
+bonjour_group_buddy(PurpleProtocolServer *protocol_server,
+                    PurpleConnection *connection, const gchar *who,
+                    const gchar *old_group, const gchar *new_group)
 {
 	PurpleBuddy *buddy = purple_blist_find_buddy(purple_connection_get_account(connection), who);
 
 	bonjour_do_group_change(buddy, new_group);
-
 }
 
 static void
-bonjour_rename_group(PurpleConnection *connection, const char *old_name, PurpleGroup *group, GList *moved_buddies)
+bonjour_rename_group(PurpleProtocolServer *protocol_server,
+                     PurpleConnection *connection,
+                     const gchar *old_name, PurpleGroup *group,
+                     GList *moved_buddies)
 {
-	const char *new_group;
+	const gchar *new_group;
 
 	new_group = purple_group_get_name(group);
 
diff --git a/libpurple/protocols/facebook/facebook.c b/libpurple/protocols/facebook/facebook.c
--- a/libpurple/protocols/facebook/facebook.c
+++ b/libpurple/protocols/facebook/facebook.c
@@ -1167,7 +1167,8 @@
 }
 
 static void
-fb_server_set_status(PurpleAccount *acct, PurpleStatus *status)
+fb_server_set_status(PurpleProtocolServer *protocol_server,
+                     PurpleAccount *acct, PurpleStatus *status)
 {
 	FbApi *api;
 	FbData *fata;
@@ -1584,7 +1585,7 @@
 }
 
 static void
-facebook_protocol_server_iface_init(PurpleProtocolServerInterface *iface)
+facebook_protocol_server_init(PurpleProtocolServerInterface *iface)
 {
 	iface->set_status = fb_server_set_status;
 }
@@ -1621,7 +1622,7 @@
         G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_CLIENT,
                                       facebook_protocol_client_iface_init)
         G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_SERVER,
-                                      facebook_protocol_server_iface_init)
+                                      facebook_protocol_server_init)
         G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_IM,
                                       facebook_protocol_im_iface_init)
         G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_CHAT,
diff --git a/libpurple/protocols/gg/avatar.h b/libpurple/protocols/gg/avatar.h
--- a/libpurple/protocols/gg/avatar.h
+++ b/libpurple/protocols/gg/avatar.h
@@ -41,6 +41,6 @@
 void ggp_avatar_buddy_update(PurpleConnection *gc, uin_t uin, time_t timestamp);
 void ggp_avatar_buddy_remove(PurpleConnection *gc, uin_t uin);
 
-void ggp_avatar_own_set(PurpleConnection *gc, PurpleImage *img);
+void ggp_avatar_own_set(PurpleProtocolServer *protocol_server, PurpleConnection *gc, PurpleImage *img);
 
 #endif /* PURPLE_GG_AVATAR_H */
diff --git a/libpurple/protocols/gg/avatar.c b/libpurple/protocols/gg/avatar.c
--- a/libpurple/protocols/gg/avatar.c
+++ b/libpurple/protocols/gg/avatar.c
@@ -286,7 +286,8 @@
 }
 
 void
-ggp_avatar_own_set(PurpleConnection *gc, PurpleImage *img)
+ggp_avatar_own_set(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+                   PurpleImage *img)
 {
 	ggp_avatar_session_data *avdata;
 
diff --git a/libpurple/protocols/gg/gg.c b/libpurple/protocols/gg/gg.c
--- a/libpurple/protocols/gg/gg.c
+++ b/libpurple/protocols/gg/gg.c
@@ -889,7 +889,9 @@
 	return 1; /* wait 1 second before another notification */
 }
 
-static void ggp_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group, const char *message)
+static void
+ggp_add_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+              PurpleBuddy *buddy, PurpleGroup *group, const gchar *message)
 {
 	PurpleAccount *account = purple_connection_get_account(gc);
 	GGPInfo *info = purple_connection_get_protocol_data(gc);
@@ -901,21 +903,22 @@
 	if (purple_strequal(purple_account_get_username(account), name))
 		ggp_status_fake_to_self(gc);
 
-	ggp_roster_add_buddy(gc, buddy, group, message);
+	ggp_roster_add_buddy(protocol_server, gc, buddy, group, message);
 	ggp_pubdir_request_buddy_alias(gc, buddy);
 }
 
-static void ggp_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
-	PurpleGroup *group)
+static void
+ggp_remove_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+                 PurpleBuddy *buddy, PurpleGroup *group)
 {
 	GGPInfo *info = purple_connection_get_protocol_data(gc);
 
 	gg_remove_notify(info->session, ggp_str_to_uin(purple_buddy_get_name(buddy)));
-	ggp_roster_remove_buddy(gc, buddy, group);
+	ggp_roster_remove_buddy(protocol_server, gc, buddy, group);
 }
 
-static void ggp_keepalive(PurpleConnection *gc)
-{
+static void
+ggp_keepalive(PurpleProtocolServer *protocol_server, PurpleConnection *gc) {
 	GGPInfo *info = purple_connection_get_protocol_data(gc);
 
 	/* purple_debug_info("gg", "Keeping connection alive....\n"); */
diff --git a/libpurple/protocols/gg/pubdir-prpl.h b/libpurple/protocols/gg/pubdir-prpl.h
--- a/libpurple/protocols/gg/pubdir-prpl.h
+++ b/libpurple/protocols/gg/pubdir-prpl.h
@@ -62,7 +62,7 @@
 void ggp_pubdir_get_info(PurpleConnection *gc, uin_t uin,
 	ggp_pubdir_request_cb cb, void *user_data);
 
-void ggp_pubdir_get_info_protocol(PurpleConnection *gc, const char *name);
+void ggp_pubdir_get_info_protocol(PurpleProtocolServer *protocol_server, PurpleConnection *gc, const char *name);
 void ggp_pubdir_request_buddy_alias(PurpleConnection *gc, PurpleBuddy *buddy);
 
 void ggp_pubdir_search(PurpleConnection *gc,
diff --git a/libpurple/protocols/gg/pubdir-prpl.c b/libpurple/protocols/gg/pubdir-prpl.c
--- a/libpurple/protocols/gg/pubdir-prpl.c
+++ b/libpurple/protocols/gg/pubdir-prpl.c
@@ -406,7 +406,8 @@
 }
 
 void
-ggp_pubdir_get_info_protocol(PurpleConnection *gc, const char *name)
+ggp_pubdir_get_info_protocol(PurpleProtocolServer *protocol_server,
+                             PurpleConnection *gc, const gchar *name)
 {
 	uin_t uin = ggp_str_to_uin(name);
 	uin_t *uin_p = g_new0(uin_t, 1);
@@ -606,7 +607,7 @@
 static void
 ggp_pubdir_search_results_info(PurpleConnection *gc, GList *row, gpointer _form)
 {
-	ggp_pubdir_get_info_protocol(gc, g_list_nth_data(row, 0));
+	ggp_pubdir_get_info_protocol(NULL, gc, g_list_nth_data(row, 0));
 }
 
 static void
diff --git a/libpurple/protocols/gg/roster.h b/libpurple/protocols/gg/roster.h
--- a/libpurple/protocols/gg/roster.h
+++ b/libpurple/protocols/gg/roster.h
@@ -59,15 +59,15 @@
 	struct gg_event_userlist100_version *version);
 
 /* libpurple callbacks */
-void ggp_roster_alias_buddy(PurpleConnection *gc, const char *who,
+void ggp_roster_alias_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc, const char *who,
 	const char *alias);
-void ggp_roster_group_buddy(PurpleConnection *gc, const char *who,
+void ggp_roster_group_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc, const char *who,
 	const char *old_group, const char *new_group);
-void ggp_roster_rename_group(PurpleConnection *, const char *old_name,
+void ggp_roster_rename_group(PurpleProtocolServer *protocol_server, PurpleConnection *, const char *old_name,
 	PurpleGroup *group, GList *moved_buddies);
-void ggp_roster_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
+void ggp_roster_add_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc, PurpleBuddy *buddy,
 	PurpleGroup *group, const char *message);
-void ggp_roster_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
+void ggp_roster_remove_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc, PurpleBuddy *buddy,
 	PurpleGroup *group);
 
 #endif /* PURPLE_GG_ROSTER_H */
diff --git a/libpurple/protocols/gg/roster.c b/libpurple/protocols/gg/roster.c
--- a/libpurple/protocols/gg/roster.c
+++ b/libpurple/protocols/gg/roster.c
@@ -341,8 +341,10 @@
  * Libpurple callbacks.
  ******************************************************************************/
 
-void ggp_roster_alias_buddy(PurpleConnection *gc, const char *who,
-	const char *alias)
+void
+ggp_roster_alias_buddy(PurpleProtocolServer *protocol_server,
+                       PurpleConnection *gc, const gchar *who,
+                       const gchar *alias)
 {
 	PurpleBuddy *buddy;
 
@@ -360,8 +362,10 @@
 	ggp_roster_set_synchronized(gc, buddy, FALSE);
 }
 
-void ggp_roster_group_buddy(PurpleConnection *gc, const char *who,
-	const char *old_group, const char *new_group)
+void
+ggp_roster_group_buddy(PurpleProtocolServer *protocol_server,
+                       PurpleConnection *gc, const gchar *who,
+                       const gchar *old_group, const gchar *new_group)
 {
 	ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc);
 	ggp_roster_change *change;
@@ -382,8 +386,10 @@
 	rdata->pending_updates = g_list_append(rdata->pending_updates, change);
 }
 
-void ggp_roster_rename_group(PurpleConnection *gc, const char *old_name,
-	PurpleGroup *group, GList *moved_buddies)
+void
+ggp_roster_rename_group(PurpleProtocolServer *protocol_server,
+                        PurpleConnection *gc, const gchar *old_name,
+                        PurpleGroup *group, GList *moved_buddies)
 {
 	ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc);
 	ggp_roster_change *change;
@@ -399,8 +405,10 @@
 	rdata->pending_updates = g_list_append(rdata->pending_updates, change);
 }
 
-void ggp_roster_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
-	PurpleGroup *group, const char *message)
+void
+ggp_roster_add_buddy(PurpleProtocolServer *protocol_server,
+                     PurpleConnection *gc, PurpleBuddy *buddy,
+                     PurpleGroup *group, const gchar *message)
 {
 	g_return_if_fail(gc != NULL);
 	g_return_if_fail(buddy != NULL);
@@ -411,8 +419,10 @@
 	ggp_roster_set_synchronized(gc, buddy, FALSE);
 }
 
-void ggp_roster_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
-	PurpleGroup *group)
+void
+ggp_roster_remove_buddy(PurpleProtocolServer *protocol_server,
+                        PurpleConnection *gc, PurpleBuddy *buddy,
+                        PurpleGroup *group)
 {
 	ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc);
 	ggp_roster_change *change;
diff --git a/libpurple/protocols/gg/status.h b/libpurple/protocols/gg/status.h
--- a/libpurple/protocols/gg/status.h
+++ b/libpurple/protocols/gg/status.h
@@ -48,7 +48,7 @@
 void ggp_status_set_initial(PurpleConnection *gc, struct gg_login_params *glp);
 
 gboolean ggp_status_set(PurpleAccount *account, int status, const gchar* msg);
-void ggp_status_set_purplestatus(PurpleAccount *account, PurpleStatus *status);
+void ggp_status_set_purplestatus(PurpleProtocolServer *protocol_server, PurpleAccount *account, PurpleStatus *status);
 void ggp_status_set_disconnected(PurpleAccount *account);
 void ggp_status_fake_to_self(PurpleConnection *gc);
 
diff --git a/libpurple/protocols/gg/status.c b/libpurple/protocols/gg/status.c
--- a/libpurple/protocols/gg/status.c
+++ b/libpurple/protocols/gg/status.c
@@ -249,7 +249,9 @@
 	return TRUE;
 }
 
-void ggp_status_set_purplestatus(PurpleAccount *account, PurpleStatus *status)
+void
+ggp_status_set_purplestatus(PurpleProtocolServer *protocol_server,
+                            PurpleAccount *account, PurpleStatus *status)
 {
 	int status_gg;
 	gchar *msg = NULL;
@@ -330,7 +332,7 @@
 
 	ggp_status_get_ssdata(gc)->status_broadcasting = broadcasting;
 	purple_account_set_bool(account, "status_broadcasting", broadcasting);
-	ggp_status_set_purplestatus(account,
+	ggp_status_set_purplestatus(NULL, account,
 		purple_account_get_active_status(account));
 }
 
diff --git a/libpurple/protocols/irc/irc.c b/libpurple/protocols/irc/irc.c
--- a/libpurple/protocols/irc/irc.c
+++ b/libpurple/protocols/irc/irc.c
@@ -221,7 +221,9 @@
 	g_free(body);
 }
 
-static int irc_send_raw(PurpleConnection *gc, const char *buf, int len)
+static int
+irc_send_raw(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+             const gchar *buf, gint len)
 {
 	struct irc_conn *irc = purple_connection_get_protocol_data(gc);
 	if (len == -1) {
@@ -644,7 +646,9 @@
 	return 1;
 }
 
-static void irc_get_info(PurpleConnection *gc, const char *who)
+static void
+irc_get_info(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+             const gchar *who)
 {
 	struct irc_conn *irc = purple_connection_get_protocol_data(gc);
 	const char *args[2];
@@ -653,7 +657,9 @@
 	irc_cmd_whois(irc, "whois", NULL, args);
 }
 
-static void irc_set_status(PurpleAccount *account, PurpleStatus *status)
+static void
+irc_set_status(PurpleProtocolServer *protocol_server, PurpleAccount *account,
+               PurpleStatus *status)
 {
 	PurpleConnection *gc = purple_account_get_connection(account);
 	struct irc_conn *irc;
@@ -678,7 +684,9 @@
 	}
 }
 
-static void irc_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group, const char *message)
+static void
+irc_add_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+              PurpleBuddy *buddy, PurpleGroup *group, const gchar *message)
 {
 	struct irc_conn *irc = purple_connection_get_protocol_data(gc);
 	struct irc_buddy *ib;
@@ -703,7 +711,9 @@
 		irc_ison_one(irc, ib);
 }
 
-static void irc_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
+static void
+irc_remove_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+                 PurpleBuddy *buddy, PurpleGroup *group)
 {
 	struct irc_conn *irc = purple_connection_get_protocol_data(gc);
 	struct irc_buddy *ib;
@@ -936,8 +946,8 @@
 	}
 }
 
-static void irc_keepalive(PurpleConnection *gc)
-{
+static void
+irc_keepalive(PurpleProtocolServer *protocol_server, PurpleConnection *gc) {
 	struct irc_conn *irc = purple_connection_get_protocol_data(gc);
 	if ((time(NULL) - irc->recv_time) > PING_TIMEOUT)
 		irc_cmd_ping(irc, NULL, NULL, NULL);
diff --git a/libpurple/protocols/irc/msgs.c b/libpurple/protocols/irc/msgs.c
--- a/libpurple/protocols/irc/msgs.c
+++ b/libpurple/protocols/irc/msgs.c
@@ -104,7 +104,7 @@
 	status = purple_account_get_active_status(irc->account);
 	if (purple_status_type_get_primitive(purple_status_get_status_type(status)) != PURPLE_STATUS_AVAILABLE) {
 		PurpleProtocol *protocol = purple_connection_get_protocol(gc);
-		purple_protocol_server_iface_set_status(protocol, irc->account, status);
+		purple_protocol_server_set_status(PURPLE_PROTOCOL_SERVER(protocol), irc->account, status);
 	}
 
 	/* this used to be in the core, but it's not now */
diff --git a/libpurple/protocols/jabber/buddy.h b/libpurple/protocols/jabber/buddy.h
--- a/libpurple/protocols/jabber/buddy.h
+++ b/libpurple/protocols/jabber/buddy.h
@@ -103,13 +103,13 @@
 JabberBuddyResource *jabber_buddy_track_resource(JabberBuddy *jb, const char *resource,
 		int priority, JabberBuddyState state, const char *status);
 void jabber_buddy_remove_resource(JabberBuddy *jb, const char *resource);
-void jabber_buddy_get_info(PurpleConnection *gc, const char *who);
+void jabber_buddy_get_info(PurpleProtocolServer *protocol_server, PurpleConnection *gc, const char *who);
 
 GList *jabber_blist_node_menu(PurpleProtocolClient *client, PurpleBlistNode *node);
 
-void jabber_set_info(PurpleConnection *gc, const char *info);
+void jabber_set_info(PurpleProtocolServer *protocol_server, PurpleConnection *gc, const char *info);
 void jabber_setup_set_info(PurpleProtocolAction *action);
-void jabber_set_buddy_icon(PurpleConnection *gc, PurpleImage *img);
+void jabber_set_buddy_icon(PurpleProtocolServer *protocol_server, PurpleConnection *gc, PurpleImage *img);
 
 void jabber_user_search(JabberStream *js, const char *directory);
 void jabber_user_search_begin(PurpleProtocolAction *);
diff --git a/libpurple/protocols/jabber/buddy.c b/libpurple/protocols/jabber/buddy.c
--- a/libpurple/protocols/jabber/buddy.c
+++ b/libpurple/protocols/jabber/buddy.c
@@ -449,7 +449,9 @@
 /*
  * Send vCard info to Jabber server
  */
-void jabber_set_info(PurpleConnection *gc, const char *info)
+void
+jabber_set_info(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+                const gchar *info)
 {
 	PurpleImage *img;
 	JabberIq *iq;
@@ -546,14 +548,16 @@
 	}
 }
 
-void jabber_set_buddy_icon(PurpleConnection *gc, PurpleImage *img)
+void
+jabber_set_buddy_icon(PurpleProtocolServer *protocol_server,
+                      PurpleConnection *gc, PurpleImage *img)
 {
 	PurpleAccount *account = purple_connection_get_account(gc);
 
 	/* Publish the avatar as specified in XEP-0084 */
 	jabber_avatar_set(purple_connection_get_protocol_data(gc), img);
 	/* Set the image in our vCard */
-	jabber_set_info(gc, purple_account_get_user_info(account));
+	jabber_set_info(NULL, gc, purple_account_get_user_info(account));
 
 	/* TODO: Fake image to ourselves, since a number of servers do not echo
 	 * back our presence to us. To do this without uselessly copying the data
@@ -902,7 +906,7 @@
 
 	js->vcard_timer = 0;
 
-	jabber_set_info(js->gc, purple_account_get_user_info(account));
+	jabber_set_info(NULL, js->gc, purple_account_get_user_info(account));
 
 	return FALSE;
 }
@@ -962,11 +966,12 @@
 		 * it returns an error (namespaces trimmed):
 		 * <error code="500" type="wait"><internal-server-error/></error>.
 		 */
-		if (js->googletalk)
+		if (js->googletalk) {
 			js->vcard_timer = g_timeout_add_seconds(10, set_own_vcard_cb,
 			                                             js);
-		else
-			jabber_set_info(js->gc, purple_account_get_user_info(account));
+		} else {
+			jabber_set_info(NULL, js->gc, purple_account_get_user_info(account));
+		}
 	} else if (vcard_hash) {
 		/* A photo is in the vCard. Advertise its hash */
 		js->avatar_hash = vcard_hash;
@@ -1619,7 +1624,9 @@
 	jbi->timeout_handle = g_timeout_add_seconds(30, jabber_buddy_get_info_timeout, jbi);
 }
 
-void jabber_buddy_get_info(PurpleConnection *gc, const char *who)
+void
+jabber_buddy_get_info(PurpleProtocolServer *protocol_server,
+                      PurpleConnection *gc, const char *who)
 {
 	JabberStream *js = purple_connection_get_protocol_data(gc);
 	JabberID *jid = jabber_id_new(who);
diff --git a/libpurple/protocols/jabber/jabber.h b/libpurple/protocols/jabber/jabber.h
--- a/libpurple/protocols/jabber/jabber.h
+++ b/libpurple/protocols/jabber/jabber.h
@@ -325,7 +325,7 @@
 void jabber_stream_features_parse(JabberStream *js, PurpleXmlNode *packet);
 void jabber_process_packet(JabberStream *js, PurpleXmlNode **packet);
 void jabber_send(JabberStream *js, PurpleXmlNode *data);
-void jabber_send_raw(JabberStream *js, const char *data, int len);
+void jabber_send_raw(PurpleProtocolServer *protocol_server, JabberStream *js, const char *data, int len);
 void jabber_send_signal_cb(PurpleConnection *pc, PurpleXmlNode **packet,
                            gpointer unused);
 
@@ -404,23 +404,23 @@
 GList *jabber_status_types(PurpleAccount *account);
 void jabber_login(PurpleAccount *account);
 void jabber_close(PurpleConnection *gc);
-void jabber_idle_set(PurpleConnection *gc, int idle);
+void jabber_idle_set(PurpleProtocolServer *protocol_server, PurpleConnection *gc, int idle);
 void jabber_blocklist_parse_push(JabberStream *js, const char *from,
                                  JabberIqType type, const char *id,
                                  PurpleXmlNode *child);
 void jabber_request_block_list(JabberStream *js);
 void jabber_add_deny(PurpleProtocolPrivacy *privacy, PurpleConnection *gc, const char *who);
 void jabber_remove_deny(PurpleProtocolPrivacy *privacy, PurpleConnection *gc, const char *who);
-void jabber_keepalive(PurpleConnection *gc);
+void jabber_keepalive(PurpleProtocolServer *protocol_server, PurpleConnection *gc);
 void jabber_register_gateway(JabberStream *js, const char *gateway);
-void jabber_register_account(PurpleAccount *account);
-void jabber_unregister_account(PurpleAccount *account, PurpleAccountUnregistrationCb cb, void *user_data);
+void jabber_register_account(PurpleProtocolServer *protocol_server, PurpleAccount *account);
+void jabber_unregister_account(PurpleProtocolServer *protocol_server, PurpleAccount *account, PurpleAccountUnregistrationCb cb, void *user_data);
 gboolean jabber_send_attention(PurpleProtocolAttention *attn, PurpleConnection *gc, const char *username, guint code);
 GList *jabber_attention_types(PurpleProtocolAttention *attn, PurpleAccount *account);
 void jabber_convo_closed(PurpleProtocolClient *client, PurpleConnection *gc, const char *who);
 PurpleChat *jabber_find_blist_chat(PurpleProtocolClient *client, PurpleAccount *account, const char *name);
 gboolean jabber_offline_message(PurpleProtocolClient *client, PurpleBuddy *buddy);
-int jabber_protocol_send_raw(PurpleConnection *gc, const char *buf, int len);
+int jabber_protocol_send_raw(PurpleProtocolServer *protocol_server, PurpleConnection *gc, const char *buf, int len);
 GList *jabber_get_actions(PurpleProtocolClient *client, PurpleConnection *gc);
 
 gboolean jabber_audio_enabled(JabberStream *js, const char *unused);
diff --git a/libpurple/protocols/jabber/jabber.c b/libpurple/protocols/jabber/jabber.c
--- a/libpurple/protocols/jabber/jabber.c
+++ b/libpurple/protocols/jabber/jabber.c
@@ -95,7 +95,7 @@
 						  js->user->domain);
 	/* setup the parser fresh for each stream */
 	jabber_parser_setup(js);
-	jabber_send_raw(js, open_stream, -1);
+	jabber_send_raw(NULL, js, open_stream, -1);
 	js->reinit = FALSE;
 	g_free(open_stream);
 }
@@ -225,7 +225,7 @@
 	 * We request STARTTLS for standard XMPP connections, but we do nothing for insecure
 	 * BOSH connections, per XEP-0206. */
 	if(!js->bosh) {
-		jabber_send_raw(js,
+		jabber_send_raw(NULL, js,
 				"<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>", -1);
 		return TRUE;
 	}
@@ -408,7 +408,9 @@
 	return success;
 }
 
-void jabber_send_raw(JabberStream *js, const char *data, int len)
+void
+jabber_send_raw(PurpleProtocolServer *protocol_server, JabberStream *js,
+                const gchar *data, gint len)
 {
 	PurpleConnection *gc;
 	PurpleAccount *account;
@@ -514,7 +516,9 @@
 		do_jabber_send_raw(js, data, len);
 }
 
-int jabber_protocol_send_raw(PurpleConnection *gc, const char *buf, int len)
+gint
+jabber_protocol_send_raw(PurpleProtocolServer *protocol_server,
+                         PurpleConnection *gc, const gchar *buf, gint len)
 {
 	JabberStream *js = purple_connection_get_protocol_data(gc);
 
@@ -524,7 +528,7 @@
 	 * to do things during the connection process.
 	 */
 
-	jabber_send_raw(js, buf, len);
+	jabber_send_raw(NULL, js, buf, len);
 	return (len < 0 ? (int)strlen(buf) : len);
 }
 
@@ -551,7 +555,7 @@
 				purple_strequal((*packet)->name, "presence"))
 			purple_xmlnode_set_namespace(*packet, NS_XMPP_CLIENT);
 	txt = purple_xmlnode_to_str(*packet, &len);
-	jabber_send_raw(js, txt, len);
+	jabber_send_raw(NULL, js, txt, len);
 	g_free(txt);
 }
 
@@ -569,8 +573,8 @@
 	return FALSE;
 }
 
-void jabber_keepalive(PurpleConnection *gc)
-{
+void
+jabber_keepalive(PurpleProtocolServer *protocol_server, PurpleConnection *gc) {
 	JabberStream *js = purple_connection_get_protocol_data(gc);
 
 	if (js->keepalive_timeout == 0) {
@@ -580,8 +584,8 @@
 	}
 }
 
-static int jabber_get_keepalive_interval(void)
-{
+static int
+jabber_get_keepalive_interval(PurpleProtocolServer *protocol_server) {
 	return PING_TIMEOUT;
 }
 
@@ -731,7 +735,7 @@
 	        g_io_stream_get_output_stream(js->stream));
 
 	if (js->state == JABBER_STREAM_CONNECTING) {
-		jabber_send_raw(js, "<?xml version='1.0' ?>", -1);
+		jabber_send_raw(NULL, js, "<?xml version='1.0' ?>", -1);
 	}
 
 	jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING);
@@ -1512,7 +1516,9 @@
 	jabber_iq_send(iq);
 }
 
-void jabber_register_account(PurpleAccount *account)
+void
+jabber_register_account(PurpleProtocolServer *protocol_server,
+                        PurpleAccount *account)
 {
 	JabberStream *js;
 
@@ -1566,7 +1572,11 @@
 	jabber_iq_send(iq);
 }
 
-void jabber_unregister_account(PurpleAccount *account, PurpleAccountUnregistrationCb cb, void *user_data) {
+void
+jabber_unregister_account(PurpleProtocolServer *protocol_server,
+                          PurpleAccount *account,
+                          PurpleAccountUnregistrationCb cb, gpointer user_data)
+{
 	PurpleConnection *gc = purple_account_get_connection(account);
 	JabberStream *js;
 
@@ -1771,7 +1781,9 @@
 }
 
 
-void jabber_idle_set(PurpleConnection *gc, int idle)
+void
+jabber_idle_set(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+                gint idle)
 {
 	JabberStream *js = purple_connection_get_protocol_data(gc);
 
@@ -2098,10 +2110,11 @@
 	 */
 	js->inactivity_timer = 0;
 
-	if (js->bosh)
+	if (js->bosh) {
 		jabber_bosh_connection_send_keepalive(js->bosh);
-	else
-		jabber_send_raw(js, "\t", 1);
+	} else {
+		jabber_send_raw(NULL, js, "\t", 1);
+	}
 
 	return FALSE;
 }
diff --git a/libpurple/protocols/jabber/presence.h b/libpurple/protocols/jabber/presence.h
--- a/libpurple/protocols/jabber/presence.h
+++ b/libpurple/protocols/jabber/presence.h
@@ -84,7 +84,7 @@
 void jabber_presence_init(void);
 void jabber_presence_uninit(void);
 
-void jabber_set_status(PurpleAccount *account, PurpleStatus *status);
+void jabber_set_status(PurpleProtocolServer *protocol_server, PurpleAccount *account, PurpleStatus *status);
 
 /**
  *	Send a full presence stanza.
diff --git a/libpurple/protocols/jabber/presence.c b/libpurple/protocols/jabber/presence.c
--- a/libpurple/protocols/jabber/presence.c
+++ b/libpurple/protocols/jabber/presence.c
@@ -140,7 +140,9 @@
 	g_free(msg);
 }
 
-void jabber_set_status(PurpleAccount *account, PurpleStatus *status)
+void
+jabber_set_status(PurpleProtocolServer *protocol_server,
+                  PurpleAccount *account, PurpleStatus *status)
 {
 	PurpleConnection *gc;
 	JabberStream *js;
diff --git a/libpurple/protocols/jabber/roster.h b/libpurple/protocols/jabber/roster.h
--- a/libpurple/protocols/jabber/roster.h
+++ b/libpurple/protocols/jabber/roster.h
@@ -35,15 +35,15 @@
 void jabber_roster_parse(JabberStream *js, const char *from,
                          JabberIqType type, const char *id, PurpleXmlNode *query);
 
-void jabber_roster_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
-		PurpleGroup *group, const char *message);
-void jabber_roster_alias_change(PurpleConnection *gc, const char *name,
-		const char *alias);
-void jabber_roster_group_change(PurpleConnection *gc, const char *name,
-		const char *old_group, const char *new_group);
-void jabber_roster_group_rename(PurpleConnection *gc, const char *old_name,
+void jabber_roster_add_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc, PurpleBuddy *buddy,
+		PurpleGroup *group, const gchar *message);
+void jabber_roster_alias_change(PurpleProtocolServer *protocol_server, PurpleConnection *gc, const gchar *name,
+		const gchar *alias);
+void jabber_roster_group_change(PurpleProtocolServer *protocol_server, PurpleConnection *gc, const gchar *name,
+		const gchar *old_group, const gchar *new_group);
+void jabber_roster_group_rename(PurpleProtocolServer *protocol_server, PurpleConnection *gc, const gchar *old_name,
 		PurpleGroup *group, GList *moved_buddies);
-void jabber_roster_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
+void jabber_roster_remove_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc, PurpleBuddy *buddy,
 		PurpleGroup *group);
 
 const gchar *
diff --git a/libpurple/protocols/jabber/roster.c b/libpurple/protocols/jabber/roster.c
--- a/libpurple/protocols/jabber/roster.c
+++ b/libpurple/protocols/jabber/roster.c
@@ -351,8 +351,10 @@
 	jabber_iq_send(iq);
 }
 
-void jabber_roster_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
-		PurpleGroup *group, const char *message)
+void
+jabber_roster_add_buddy(PurpleProtocolServer *protocol_server,
+                        PurpleConnection *gc, PurpleBuddy *buddy,
+                        PurpleGroup *group, const gchar *message)
 {
 	JabberStream *js = purple_connection_get_protocol_data(gc);
 	char *who;
@@ -415,7 +417,10 @@
 	g_free(who);
 }
 
-void jabber_roster_alias_change(PurpleConnection *gc, const char *name, const char *alias)
+void
+jabber_roster_alias_change(PurpleProtocolServer *protocol_server,
+                           PurpleConnection *gc, const gchar *name,
+                           const gchar *alias)
 {
 	PurpleBuddy *b = purple_blist_find_buddy(purple_connection_get_account(gc), name);
 
@@ -429,8 +434,10 @@
 	}
 }
 
-void jabber_roster_group_change(PurpleConnection *gc, const char *name,
-		const char *old_group, const char *new_group)
+void
+jabber_roster_group_change(PurpleProtocolServer *protocol_server,
+                           PurpleConnection *gc, const gchar *name,
+                           const gchar *old_group, const gchar *new_group)
 {
 	GSList *buddies, *groups = NULL;
 
@@ -449,19 +456,28 @@
 	jabber_roster_update(purple_connection_get_protocol_data(gc), name, groups);
 }
 
-void jabber_roster_group_rename(PurpleConnection *gc, const char *old_name,
-		PurpleGroup *group, GList *moved_buddies)
+void
+jabber_roster_group_rename(PurpleProtocolServer *protocol_server,
+                           PurpleConnection *gc, const gchar *old_name,
+                           PurpleGroup *group, GList *moved_buddies)
 {
 	GList *l;
 	const char *gname = jabber_roster_group_get_global_name(group);
+
 	for(l = moved_buddies; l; l = l->next) {
 		PurpleBuddy *buddy = l->data;
-		jabber_roster_group_change(gc, purple_buddy_get_name(buddy), old_name, gname);
+
+		jabber_roster_group_change(protocol_server, gc,
+		                           purple_buddy_get_name(buddy), old_name,
+		                           gname);
 	}
 }
 
-void jabber_roster_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
-		PurpleGroup *group) {
+void
+jabber_roster_remove_buddy(PurpleProtocolServer *protocol_server,
+                           PurpleConnection *gc, PurpleBuddy *buddy,
+                           PurpleGroup *group)
+{
 	const char *name = purple_buddy_get_name(buddy);
 	GSList *buddies = purple_blist_find_buddies(purple_connection_get_account(gc), name);
 
diff --git a/libpurple/protocols/novell/novell.c b/libpurple/protocols/novell/novell.c
--- a/libpurple/protocols/novell/novell.c
+++ b/libpurple/protocols/novell/novell.c
@@ -2557,7 +2557,8 @@
 }
 
 static void
-novell_add_buddy(PurpleConnection * gc, PurpleBuddy *buddy, PurpleGroup * group, const char *message)
+novell_add_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+                 PurpleBuddy *buddy, PurpleGroup * group, const gchar *message)
 {
 	NMFolder *folder = NULL;
 	NMContact *contact;
@@ -2620,7 +2621,9 @@
 }
 
 static void
-novell_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
+novell_remove_buddy(PurpleProtocolServer *protocol_server,
+                    PurpleConnection *gc, PurpleBuddy *buddy,
+                    PurpleGroup *group)
 {
 	NMContact *contact;
 	NMFolder *folder;
@@ -2655,7 +2658,8 @@
 }
 
 static void
-novell_remove_group(PurpleConnection * gc, PurpleGroup *group)
+novell_remove_group(PurpleProtocolServer *protocol_server,
+                    PurpleConnection *gc, PurpleGroup *group)
 {
 	NMUser *user;
 	NMERR_T rc = NM_OK;
@@ -2676,7 +2680,8 @@
 }
 
 static void
-novell_alias_buddy(PurpleConnection * gc, const char *name, const char *alias)
+novell_alias_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+                   const gchar *name, const gchar *alias)
 {
 	NMContact *contact;
 	NMUser *user;
@@ -2732,9 +2737,9 @@
 }
 
 static void
-novell_group_buddy(PurpleConnection * gc,
-				   const char *name, const char *old_group_name,
-				   const char *new_group_name)
+novell_group_buddy(PurpleProtocolServer *protocol_server,
+                   PurpleConnection *gc, const gchar *name,
+                   const gchar *old_group_name, const gchar *new_group_name)
 {
 	NMFolder *old_folder;
 	NMFolder *new_folder;
@@ -2794,7 +2799,8 @@
 }
 
 static void
-novell_rename_group(PurpleConnection * gc, const char *old_name,
+novell_rename_group(PurpleProtocolServer *protocol_server,
+                    PurpleConnection *gc, const gchar *old_name,
 					PurpleGroup *group, GList *moved_buddies)
 {
 	NMERR_T rc = NM_OK;
@@ -2894,7 +2900,8 @@
 }
 
 static void
-novell_set_idle(PurpleConnection * gc, int time)
+novell_set_idle(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+                gint time)
 {
 	NMUser *user;
 	NMERR_T rc = NM_OK;
@@ -2924,7 +2931,8 @@
 }
 
 static void
-novell_get_info(PurpleConnection * gc, const char *name)
+novell_get_info(PurpleProtocolServer *protocol_server, PurpleConnection * gc,
+                const gchar *name)
 {
 	NMUserRecord *user_record;
 	NMUser *user;
@@ -3020,7 +3028,8 @@
 }
 
 static void
-novell_set_status(PurpleAccount *account, PurpleStatus *status)
+novell_set_status(PurpleProtocolServer *protocol_server,
+                  PurpleAccount *account, PurpleStatus *status)
 {
 	PurpleConnection *gc;
 	gboolean connected;
@@ -3477,8 +3486,7 @@
 }
 
 static void
-novell_keepalive(PurpleConnection *gc)
-{
+novell_keepalive(PurpleProtocolServer *protocol_server, PurpleConnection *gc) {
 	NMUser *user;
 	NMERR_T rc = NM_OK;
 
diff --git a/libpurple/protocols/null/nullprpl.c b/libpurple/protocols/null/nullprpl.c
--- a/libpurple/protocols/null/nullprpl.c
+++ b/libpurple/protocols/null/nullprpl.c
@@ -458,7 +458,10 @@
    return 1;
 }
 
-static void null_set_info(PurpleConnection *gc, const char *info) {
+static void
+null_set_info(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+              const gchar *info)
+{
   purple_debug_info("nullprpl", "setting %s's user info to %s\n",
                     purple_account_get_username(purple_connection_get_account(gc)), info);
 }
@@ -496,7 +499,10 @@
   return 0;
 }
 
-static void null_get_info(PurpleConnection *gc, const char *username) {
+static void
+null_get_info(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+              const gchar *username)
+{
   const char *body;
   PurpleNotifyUserInfo *info = purple_notify_user_info_new();
   PurpleAccount *acct;
@@ -529,7 +535,10 @@
                          NULL);     /* userdata for callback */
 }
 
-static void null_set_status(PurpleAccount *acct, PurpleStatus *status) {
+static void
+null_set_status(PurpleProtocolServer *protocol_server, PurpleAccount *acct,
+                PurpleStatus *status)
+{
   const char *msg = purple_status_get_attr_string(status, "message");
   purple_debug_info("nullprpl", "setting %s's status to %s: %s\n",
                     purple_account_get_username(acct), purple_status_get_name(status), msg);
@@ -538,20 +547,26 @@
                       NULL);
 }
 
-static void null_set_idle(PurpleConnection *gc, int idletime) {
+static void
+null_set_idle(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+              gint idletime)
+{
   purple_debug_info("nullprpl",
                     "purple reports that %s has been idle for %d seconds\n",
                     purple_account_get_username(purple_connection_get_account(gc)), idletime);
 }
 
-static void null_change_passwd(PurpleConnection *gc, const char *old_pass,
-                                   const char *new_pass) {
+static void
+null_change_passwd(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+                   const gchar *old_pass, const gchar *new_pass)
+{
   purple_debug_info("nullprpl", "%s wants to change their password\n",
                     purple_account_get_username(purple_connection_get_account(gc)));
 }
 
-static void null_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
-                               PurpleGroup *group, const char *message)
+static void
+null_add_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+               PurpleBuddy *buddy, PurpleGroup *group, const gchar *message)
 {
   const char *username = purple_account_get_username(purple_connection_get_account(gc));
   PurpleConnection *buddy_gc = get_null_gc(purple_buddy_get_name(buddy));
@@ -579,38 +594,44 @@
   }
 }
 
-static void null_add_buddies(PurpleConnection *gc, GList *buddies,
-                                 GList *groups, const char *message) {
+static void
+null_add_buddies(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+                 GList *buddies, GList *groups, const gchar *message)
+{
   GList *buddy = buddies;
   GList *group = groups;
 
   purple_debug_info("nullprpl", "adding multiple buddies\n");
 
   while (buddy && group) {
-    null_add_buddy(gc, (PurpleBuddy *)buddy->data, (PurpleGroup *)group->data, message);
+    null_add_buddy(protocol_server, gc, PURPLE_BUDDY(buddy->data),
+                   PURPLE_GROUP(group->data), message);
     buddy = g_list_next(buddy);
     group = g_list_next(group);
   }
 }
 
-static void null_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
-                                  PurpleGroup *group)
+static void
+null_remove_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+                  PurpleBuddy *buddy, PurpleGroup *group)
 {
   purple_debug_info("nullprpl", "removing %s from %s's buddy list\n",
                     purple_buddy_get_name(buddy),
                     purple_account_get_username(purple_connection_get_account(gc)));
 }
 
-static void null_remove_buddies(PurpleConnection *gc, GList *buddies,
-                                    GList *groups) {
+static void
+null_remove_buddies(PurpleProtocolServer *protocol_server,
+                    PurpleConnection *gc, GList *buddies, GList *groups)
+{
   GList *buddy = buddies;
   GList *group = groups;
 
   purple_debug_info("nullprpl", "removing multiple buddies\n");
 
   while (buddy && group) {
-    null_remove_buddy(gc, (PurpleBuddy *)buddy->data,
-                          (PurpleGroup *)group->data);
+    null_remove_buddy(protocol_server, gc, PURPLE_BUDDY(buddy->data),
+                      PURPLE_GROUP(group->data));
     buddy = g_list_next(buddy);
     group = g_list_next(group);
   }
@@ -833,26 +854,35 @@
   }
 }
 
-static void null_register_user(PurpleAccount *acct) {
+static void
+null_register_user(PurpleProtocolServer *protocol_server, PurpleAccount *acct) {
  purple_debug_info("nullprpl", "registering account for %s\n",
                    purple_account_get_username(acct));
 }
 
-static void null_alias_buddy(PurpleConnection *gc, const char *who,
-                                 const char *alias) {
+static void
+null_alias_buddy(PurpleProtocolServer *protocol_server,
+                 PurpleConnection *gc, const gchar *who,
+                 const gchar *alias)
+{
  purple_debug_info("nullprpl", "%s sets %s's alias to %s\n",
                    purple_account_get_username(purple_connection_get_account(gc)), who, alias);
 }
 
-static void null_group_buddy(PurpleConnection *gc, const char *who,
-                                 const char *old_group,
-                                 const char *new_group) {
+static void
+null_group_buddy(PurpleProtocolServer *protocol_server,
+                 PurpleConnection *gc, const gchar *who,
+                 const gchar *old_group, const gchar *new_group)
+{
   purple_debug_info("nullprpl", "%s has moved %s from group %s to group %s\n",
                     purple_account_get_username(purple_connection_get_account(gc)), who, old_group, new_group);
 }
 
-static void null_rename_group(PurpleConnection *gc, const char *old_name,
-                                  PurpleGroup *group, GList *moved_buddies) {
+static void
+null_rename_group(PurpleProtocolServer *protocol_server,
+                  PurpleConnection *gc, const gchar *old_name,
+                  PurpleGroup *group, GList *moved_buddies)
+{
   purple_debug_info("nullprpl", "%s has renamed group %s to %s\n",
                     purple_account_get_username(purple_connection_get_account(gc)), old_name,
                     purple_group_get_name(group));
@@ -876,14 +906,19 @@
   return input;
 }
 
-static void null_set_buddy_icon(PurpleConnection *gc,
-                                    PurpleImage *img) {
+static void
+null_set_buddy_icon(PurpleProtocolServer *protocol_server,
+                    PurpleConnection *gc, PurpleImage *img)
+{
  purple_debug_info("nullprpl", "setting %s's buddy icon to %s\n",
                    purple_account_get_username(purple_connection_get_account(gc)),
                    img ? purple_image_get_path(img) : "(null)");
 }
 
-static void null_remove_group(PurpleConnection *gc, PurpleGroup *group) {
+static void
+null_remove_group(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+                  PurpleGroup *group)
+{
   purple_debug_info("nullprpl", "%s has removed group %s\n",
                     purple_account_get_username(purple_connection_get_account(gc)),
                     purple_group_get_name(group));
diff --git a/libpurple/protocols/sametime/sametime.c b/libpurple/protocols/sametime/sametime.c
--- a/libpurple/protocols/sametime/sametime.c
+++ b/libpurple/protocols/sametime/sametime.c
@@ -1424,7 +1424,7 @@
 }
 
 
-static void mw_protocol_set_status(PurpleAccount *acct, PurpleStatus *status);
+static void mw_protocol_set_status(PurpleProtocolServer *protocol_server, PurpleAccount *acct, PurpleStatus *status);
 
 
 /** called from mw_session_stateChange when the session's state is
@@ -1437,7 +1437,7 @@
   /* set out initial status */
   acct = purple_connection_get_account(pd->gc);
   status = purple_account_get_active_status(acct);
-  mw_protocol_set_status(acct, status);
+  mw_protocol_set_status(NULL, acct, status);
 
   /* start watching for new conversations */
   purple_signal_connect(purple_conversations_get_handle(),
@@ -3824,8 +3824,10 @@
 }
 
 
-static void mw_protocol_get_info(PurpleConnection *gc, const char *who) {
-
+static void
+mw_protocol_get_info(PurpleProtocolServer *protocol_server,
+                     PurpleConnection *gc, const gchar *who)
+{
   struct mwAwareIdBlock idb = { mwAware_USER, (char *) who, NULL };
 
   struct mwPurpleProtocolData *pd;
@@ -3898,7 +3900,10 @@
 }
 
 
-static void mw_protocol_set_status(PurpleAccount *acct, PurpleStatus *status) {
+static void
+mw_protocol_set_status(PurpleProtocolServer *protocol_server,
+                       PurpleAccount *acct, PurpleStatus *status)
+{
   PurpleConnection *gc;
   const char *state;
   char *message = NULL;
@@ -3951,7 +3956,10 @@
 }
 
 
-static void mw_protocol_set_idle(PurpleConnection *gc, int t) {
+static void
+mw_protocol_set_idle(PurpleProtocolServer *protocol_server,
+                     PurpleConnection *gc, gint t)
+{
   struct mwSession *session;
   struct mwUserStatus stat;
 
@@ -4125,11 +4133,11 @@
 }
 
 
-static void mw_protocol_add_buddy(PurpleConnection *gc,
-			      PurpleBuddy *buddy,
-			      PurpleGroup *group,
-			      const char *message) {
-
+static void
+mw_protocol_add_buddy(PurpleProtocolServer *protocol_server,
+                      PurpleConnection *gc, PurpleBuddy *buddy,
+                      PurpleGroup *group, const gchar *message)
+{
   struct mwPurpleProtocolData *pd = purple_connection_get_protocol_data(gc);
   struct mwServiceResolve *srvc;
   GList *query;
@@ -4173,7 +4181,9 @@
 }
 
 
-static void mw_protocol_add_buddies(PurpleConnection *gc,
+static void
+mw_protocol_add_buddies(PurpleProtocolServer *protocol_server,
+                        PurpleConnection *gc,
 				GList *buddies,
 				GList *groups,
 				const char *message) {
@@ -4224,9 +4234,11 @@
 }
 
 
-static void mw_protocol_remove_buddy(PurpleConnection *gc,
-				 PurpleBuddy *buddy, PurpleGroup *group) {
-
+static void
+mw_protocol_remove_buddy(PurpleProtocolServer *protocol_server,
+                         PurpleConnection *gc, PurpleBuddy *buddy,
+                         PurpleGroup *group)
+{
   struct mwPurpleProtocolData *pd;
   struct mwAwareIdBlock idb = { mwAware_USER, (char *)purple_buddy_get_name(buddy), NULL };
   struct mwAwareList *list;
@@ -4527,7 +4539,10 @@
 }
 
 
-static void mw_protocol_keepalive(PurpleConnection *gc) {
+static void
+mw_protocol_keepalive(PurpleProtocolServer *protocol_server,
+                      PurpleConnection *gc)
+{
   struct mwSession *session;
 
   g_return_if_fail(gc != NULL);
@@ -4539,10 +4554,11 @@
 }
 
 
-static void mw_protocol_alias_buddy(PurpleConnection *gc,
-				const char *who,
-				const char *alias) {
-
+static void
+mw_protocol_alias_buddy(PurpleProtocolServer *protocol_server,
+                        PurpleConnection *gc, const gchar *who,
+                        const gchar *alias)
+{
   struct mwPurpleProtocolData *pd = purple_connection_get_protocol_data(gc);
   g_return_if_fail(pd != NULL);
 
@@ -4553,11 +4569,11 @@
 }
 
 
-static void mw_protocol_group_buddy(PurpleConnection *gc,
-				const char *who,
-				const char *old_group,
-				const char *new_group) {
-
+static void
+mw_protocol_group_buddy(PurpleProtocolServer *protocol_server,
+                        PurpleConnection *gc, const gchar *who,
+                        const gchar *old_group, const gchar *new_group)
+{
   struct mwAwareIdBlock idb = { mwAware_USER, (char *) who, NULL };
   GList *gl = g_list_prepend(NULL, &idb);
 
@@ -4582,11 +4598,11 @@
 }
 
 
-static void mw_protocol_rename_group(PurpleConnection *gc,
-				 const char *old,
-				 PurpleGroup *group,
-				 GList *buddies) {
-
+static void
+mw_protocol_rename_group(PurpleProtocolServer *protocol_server,
+                         PurpleConnection *gc, const gchar *old,
+                         PurpleGroup *group, GList *buddies)
+{
   struct mwPurpleProtocolData *pd = purple_connection_get_protocol_data(gc);
   g_return_if_fail(pd != NULL);
 
@@ -4644,7 +4660,10 @@
 }
 
 
-static void mw_protocol_remove_group(PurpleConnection *gc, PurpleGroup *group) {
+static void
+mw_protocol_remove_group(PurpleProtocolServer *protocol_server,
+                         PurpleConnection *gc, PurpleGroup *group)
+{
   struct mwPurpleProtocolData *pd;
   struct mwAwareList *list;
 
diff --git a/libpurple/protocols/zephyr/zephyr.c b/libpurple/protocols/zephyr/zephyr.c
--- a/libpurple/protocols/zephyr/zephyr.c
+++ b/libpurple/protocols/zephyr/zephyr.c
@@ -1867,7 +1867,9 @@
 	return buf;
 }
 
-static void zephyr_zloc(PurpleConnection *gc, const char *who)
+static void
+zephyr_zloc(PurpleProtocolServer *protocol_server, PurpleConnection *gc,
+            const gchar *who)
 {
 	zephyr_account *zephyr = purple_connection_get_protocol_data(gc);
 	gchar* normalized_who = local_zephyr_normalize(zephyr,who);
@@ -1894,7 +1896,10 @@
 	}
 }
 
-static void zephyr_set_status(PurpleAccount *account, PurpleStatus *status) {
+static void
+zephyr_set_status(PurpleProtocolServer *protocol_server,
+                  PurpleAccount *account, PurpleStatus *status)
+{
 	PurpleConnection *gc = purple_account_get_connection(account);
 	zephyr_account *zephyr = purple_connection_get_protocol_data(gc);
 	PurpleStatusPrimitive primitive = purple_status_type_get_primitive(purple_status_get_status_type(status));
@@ -2230,7 +2235,7 @@
 static PurpleCmdRet zephyr_purple_cmd_zlocate(PurpleConversation *conv,
 					  const char *cmd, char **args, char **error, void *data)
 {
-	zephyr_zloc(purple_conversation_get_connection(conv),args[0]);
+	zephyr_zloc(NULL, purple_conversation_get_connection(conv),args[0]);
 	return PURPLE_CMD_RET_OK;
 }
 
diff --git a/libpurple/purpleaccountpresence.c b/libpurple/purpleaccountpresence.c
--- a/libpurple/purpleaccountpresence.c
+++ b/libpurple/purpleaccountpresence.c
@@ -23,6 +23,8 @@
 
 #include "purpleaccountpresence.h"
 
+#include "purpleprotocolserver.h"
+
 struct _PurpleAccountPresence {
 	PurplePresence parent;
 
@@ -94,8 +96,8 @@
 		protocol = purple_connection_get_protocol(gc);
 	}
 
-	if(protocol) {
-		purple_protocol_server_iface_set_idle(protocol, gc, (idle ? (current_time - idle_time) : 0));
+	if(PURPLE_IS_PROTOCOL_SERVER(protocol)) {
+		purple_protocol_server_set_idle(PURPLE_PROTOCOL_SERVER(protocol), gc, (idle ? (current_time - idle_time) : 0));
 	}
 }
 
diff --git a/libpurple/purpleprotocolserver.h b/libpurple/purpleprotocolserver.h
new file mode 100644
--- /dev/null
+++ b/libpurple/purpleprotocolserver.h
@@ -0,0 +1,482 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
+# error "only <purple.h> may be included directly"
+#endif
+
+#ifndef PURPLE_PROTOCOL_SERVER_H
+#define PURPLE_PROTOCOL_SERVER_H
+
+/**
+ * SECTION:purpleprotocolserver
+ * @section_id: libpurple-purpleprotocolserver
+ * @short_description: Protocol Server Interface
+ * @title: ProtocolServer Interface
+ *
+ * #PurpleProtocolServer describes the API for protocols that have a central
+ * server.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libpurple/account.h>
+#include <libpurple/buddy.h>
+#include <libpurple/connection.h>
+#include <libpurple/group.h>
+#include <libpurple/purplemessage.h>
+
+#define PURPLE_TYPE_PROTOCOL_SERVER (purple_protocol_server_get_type())
+G_DECLARE_INTERFACE(PurpleProtocolServer, purple_protocol_server, PURPLE,
+                    PROTOCOL_SERVER, GObject)
+
+G_BEGIN_DECLS
+
+/**
+ * PURPLE_TYPE_PROTOCOL_SERVER:
+ *
+ * The standard _get_type method for #PurpleProtocolServer.
+ *
+ * Since: 3.0.0
+ */
+
+/**
+ * PurpleProtocolServer:
+ *
+ * An opaque data structure used to reference a #PurpleProtocol that implements
+ * #PurpleProtocolServerInterface.
+ *
+ * Since: 3.0.0
+ */
+
+/**
+ * PurpleProtocolServerInterface:
+ * @register_user: Register a new user.
+ * @unregister_user: Remove the user from the server. The account can either be
+ *                   connected or disconnected. After the removal is finished,
+ *                   the connection will stay open and has to be closed!
+ * @set_info: Sets the user's profile.
+ * @get_info: Should arrange for purple_notify_userinfo() to be called with the
+ *            requested user's profile.
+ * @set_status: Sets the active status for the given account.
+ * @set_idle: Set the idle time for the given account.
+ * @change_passwd: Changes the users password.
+ * @add_buddy: Add a buddy to a group on the server.
+ * @add_buddies: Add multiple buddies on the server at once.
+ * @remove_buddy: Removes the given buddy from the user's buddy list.
+ * @remove_buddies: Removes multiple buddies from the user's buddy list.
+ * @keepalive: If implemented, this will be called regularly for this
+ *             protocol's active connections. You'd want to do this if you need
+ *             to repeatedly send some kind of keepalive packet to the server
+ *             to avoid being disconnected. ("Regularly" is defined to be 30
+ *             unless @get_keepalive_interval is implemented to override it).
+ * @get_keepalive_interval: If implemented, this will override the default
+ *                          keepalive interval.
+ * @alias_buddy: Save/store buddy's alias on server list/roster
+ * @group_buddy: Change a buddy's group on a server list/roster
+ * @rename_group: Rename a group on a server list/roster
+ * @set_buddy_icon: Set the buddy icon for the given connection to @img. The
+ *                  protocol does <emphasis>NOT</emphasis> own a reference to
+ *                  @img; if it needs one, it must #g_object_ref(@img) itself.
+ * @remove_group: Removes the given group from the users buddy list.
+ * @send_raw: For use in plugins that may understand the underlying protocol.
+ * @set_public_alias: Set the user's "friendly name" (or alias or nickname or
+ *                    whatever term you want to call it) on the server. The
+ *                    protocol should call @success_cb or @failure_cb
+ *                    <emphasis>asynchronously</emphasis> (if it knows
+ *                    immediately that the set will fail, call one of the
+ *                    callbacks from an idle/0-second timeout) depending on if
+ *                    the nickname is set successfully. See
+ *                    purple_account_set_public_alias().
+ *                    <sbr/>@gc:    The connection for which to set an alias
+ *                    <sbr/>@alias: The new server-side alias/nickname for this
+ *                                  account, or %NULL to unset the
+ *                                  alias/nickname (or return it to a
+ *                                  protocol-specific "default").
+ *                    <sbr/>@success_cb: Callback to be called if the public
+ *                                       alias is set
+ *                    <sbr/>@failure_cb: Callback to be called if setting the
+ *                                       public alias fails
+ * @get_public_alias: Retrieve the user's "friendly name" as set on the server.
+ *                    The protocol should call @success_cb or @failure_cb
+ *                    <emphasis>asynchronously</emphasis> (even if it knows
+ *                    immediately that the get will fail, call one of the
+ *                    callbacks from an idle/0-second timeout) depending on if
+ *                    the nickname is retrieved. See
+ *                    purple_account_get_public_alias().
+ *                    <sbr/>@gc:         The connection for which to retireve
+ *                                       the alias
+ *                    <sbr/>@success_cb: Callback to be called with the
+ *                                       retrieved alias
+ *                    <sbr/>@failure_cb: Callback to be called if the protocol
+ *                                       is unable to retrieve the alias
+ *
+ * The protocol server interface.
+ *
+ * This interface provides a gateway between purple and the protocol's server.
+ */
+struct _PurpleProtocolServerInterface {
+	/*< private >*/
+	GTypeInterface parent;
+
+	/*< public >*/
+	void (*register_user)(PurpleProtocolServer *protocol_server, PurpleAccount *account);
+	void (*unregister_user)(PurpleProtocolServer *protocol_server, PurpleAccount *account, PurpleAccountUnregistrationCb cb, gpointer data);
+
+	void (*set_info)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *info);
+	void (*get_info)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *who);
+
+	void (*set_status)(PurpleProtocolServer *protocol_server, PurpleAccount *account, PurpleStatus *status);
+	void (*set_idle)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, gint idletime);
+
+	void (*change_passwd)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *old_pass, const gchar *new_pass);
+
+	void (*add_buddy)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleBuddy *buddy, PurpleGroup *group, const gchar *message);
+	void (*add_buddies)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, GList *buddies, GList *groups, const gchar *message);
+	void (*remove_buddy)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleBuddy *buddy, PurpleGroup *group);
+	void (*remove_buddies)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, GList *buddies, GList *groups);
+
+	void (*keepalive)(PurpleProtocolServer *protocol_server, PurpleConnection *connection);
+	gint (*get_keepalive_interval)(PurpleProtocolServer *protocol_server);
+
+	void (*alias_buddy)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *who, const gchar *alias);
+
+	void (*group_buddy)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *who, const gchar *old_group, const gchar *new_group);
+
+	void (*rename_group)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *old_name, PurpleGroup *group, GList *moved_buddies);
+
+	void (*set_buddy_icon)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleImage *img);
+
+	void (*remove_group)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleGroup *group);
+
+	gint (*send_raw)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *buf, gint len);
+
+	void (*set_public_alias)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *alias, PurpleSetPublicAliasSuccessCallback success_cb, PurpleSetPublicAliasFailureCallback failure_cb);
+	void (*get_public_alias)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleGetPublicAliasSuccessCallback success_cb, PurpleGetPublicAliasFailureCallback failure_cb);
+
+	/*< private >*/
+	gpointer reserved[8];
+};
+
+/**
+ * purple_protocol_server_register_user:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @account: The #PurpleAccount to register.
+ *
+ * Tell @protocol_server to register the new account described by @account.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_register_user(PurpleProtocolServer *protocol_server, PurpleAccount *account);
+
+/**
+ * purple_protocol_server_unregister_user:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @account: The #PurpleAccount instance.
+ * @cb: A PurpleAccountUnregistrationCb function.
+ * @data: User data to pass to @cb.
+ *
+ * Unregisters @account with @protocol_server. The account can either be
+ * connected or disconnected. After the removal is finished, the connection
+ * will stay open and has to be closed.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_unregister_user(PurpleProtocolServer *protocol_server, PurpleAccount *account, PurpleAccountUnregistrationCb cb, gpointer data);
+
+/**
+ * purple_protocol_server_set_info:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @connection: The #PurpleConnection instance.
+ * @info: The user info to set.
+ *
+ * Sets the user info, sometimes referred to as a user profile to @info.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_set_info(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *info);
+
+/**
+ * purple_protocol_server_get_info:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @connection: The #PurpleConnection instance.
+ * @who: The name of the user whose information you're asking for.
+ *
+ * Gets the user info or profile for @who and displays it in a protocol specifc
+ * way.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_get_info(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *who);
+
+/**
+ * purple_protocol_server_set_status:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @account: The #PurpleAccount instance.
+ * @status: The #PurpleStatus instance.
+ *
+ * Sets the status for account @account to @status.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_set_status(PurpleProtocolServer *protocol_server, PurpleAccount *account, PurpleStatus *status);
+
+/**
+ * purple_protocol_server_set_idle:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @connection: The #PurpleConnection instance.
+ * @idletime: The number of seconds that the user has been idle.
+ *
+ * Tells @protocol_server to set the user's idle time to @idletime.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_set_idle(PurpleProtocolServer *protocol_server, PurpleConnection *connection, gint idletime);
+
+/**
+ * purple_protocol_server_change_passwd:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @connection: The #PurpleConnection instance.
+ * @old_pass: The user's old password.
+ * @new_pass: The new password for the user.
+ *
+ * Changes the user's password from @old_pass to @new_pass.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_change_passwd(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *old_pass, const gchar *new_pass);
+
+/**
+ * purple_protocol_server_add_buddy:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @connection: The #PurpleConnection instance.
+ * @buddy: The #PurpleBuddy to add.
+ * @group: The #PurpleGroup for @buddy.
+ * @message: An optional invite message.
+ *
+ * This protocol function may be called in situations in which the buddy is
+ * already in the specified group. If the protocol supports authorization and
+ * the user is not already authorized to see the status of @buddy, this
+ * function will request authorization. If authorization is required, then
+ * @message will be used as an invite message.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_add_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleBuddy *buddy, PurpleGroup *group, const gchar *message);
+
+/**
+ * purple_protocol_server_add_buddies:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @connection: The #PurpleConnection instance.
+ * @buddies: (element-type PurpleBuddy): A #GList of #PurpleBuddy's to add.
+ * @groups: (element-type PurpleGroup): A #GList of #PurpleGroup's that
+ *          correspond to the @buddies parameter.
+ * @message: An optional invite message to send.
+ *
+ * Similar to purple_protocol_server_add_buddy() but can add multiple buddies
+ * at a time. If @protocol_server does not implement this function, this will
+ * call purple_protocol_server_add_buddy() for each buddy/group pair in
+ * @buddies/@groups.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_add_buddies(PurpleProtocolServer *protocol_server, PurpleConnection *connection, GList *buddies, GList *groups, const gchar *message);
+
+/**
+ * purple_protocol_server_remove_buddy:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @connection: The #PurpleConnection instance.
+ * @buddy: The #PurpleBuddy instance.
+ * @group: The #PurpleGroup instance.
+ *
+ * Removes @buddy and potentially @group from the server side list of contacts.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_remove_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleBuddy *buddy, PurpleGroup *group);
+
+/**
+ * purple_protocol_server_remove_buddies:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @connection: The #PurpleConnection instance.
+ * @buddies: (element-type PurpleBuddy): A #GList of #PurpleBuddy's to remove.
+ * @groups: (element-type PurpleGroup): A #GList of #PurpleGroup's
+ *          corresponding to @buddies.
+ *
+ * Similiar to purple_protocol_server_remove_buddy() but allows you to remove
+ * multiple at a time.
+ *
+ * If @protocol_server doesn't implement this function directly,
+ * purple_protocol_server_remove_buddy() will be called for each buddy/group
+ * pair in @buddies/@groups.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_remove_buddies(PurpleProtocolServer *protocol_server, PurpleConnection *connection, GList *buddies, GList *groups);
+
+/**
+ * purple_protocol_server_keepalive:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @connection: The #PurpleConnection instance.
+ *
+ * Tell @protocol_server to send its keep alive to the server.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_keepalive(PurpleProtocolServer *protocol_server, PurpleConnection *connection);
+
+/**
+ * purple_protocol_server_get_keepalive_interval:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ *
+ * Returns a custom interval, in seconds, that libpurple should tell
+ * @protocol_server to send it's keepalive.
+ *
+ * Returns: The interval, in seconds, that the keep-alive function should be
+ *          called.
+ *
+ * Since: 3.0.0
+ */
+gint purple_protocol_server_get_keepalive_interval(PurpleProtocolServer *protocol_server);
+
+/**
+ * purple_protocol_server_alias_buddy:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @connection: The #PurpleConnection instance.
+ * @who: The name of the user to alias.
+ * @alias: The new alias for @who.
+ *
+ * Sets the server side alias for @who to @alias.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_alias_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *who, const gchar *alias);
+
+/**
+ * purple_protocol_server_group_buddy:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @connection: The #PurpleConnection instance.
+ * @who: The name of the user whose group to switch.
+ * @old_group: The name of @who's old group.
+ * @new_group: The name of the new group to add @who to.
+ *
+ * Moves @who from group @old_group to a new group of @new_group.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_group_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *who, const gchar *old_group, const gchar *new_group);
+
+/**
+ * purple_protocol_server_rename_group:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @connection:  The #PurpleConnection instance.
+ * @old_name: The old name of the group.
+ * @group: The new #PurpleGroup instance.
+ * @moved_buddies: (element-type PurpleBuddy): A list of #PurpleBuddy's being
+ *                 moved as part of this rename.
+ *
+ * Renames the group named @old_name to the new @group.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_rename_group(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *old_name, PurpleGroup *group, GList *moved_buddies);
+
+/**
+ * purple_protocol_server_set_buddy_icon:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @connection: The #PurpleConnection instance.
+ * @img: The #PurpleImage instance.
+ *
+ * Sets the user's buddy icon to @img.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_set_buddy_icon(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleImage *img);
+
+/**
+ * purple_protocol_server_remove_group:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @connection: The #PurpleConnection instance.
+ * @group: The #PurpleGroup instance.
+ *
+ * Removes @group from the server side contact list.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_remove_group(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleGroup *group);
+
+/**
+ * purple_protocol_server_send_raw:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @connection: The #PurpleConnection instance.
+ * @buf: The raw protocol data to send.
+ * @len: The length of @buf in bytes.
+ *
+ * Sends raw data over the protocol. This should only be called when you know
+ * the exact underlying protocol.
+ *
+ * Returns: The number of bytes that was sent.
+ *
+ * Since: 3.0.0
+ */
+gint purple_protocol_server_send_raw(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *buf, gint len);
+
+/**
+ * purple_protocol_server_set_public_alias:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @connection: The #PurpleConnection instance.
+ * @alias: The new alias.
+ * @success_cb: (scope async): The #PurpleSetPublicAliasSuccessCallback to call
+ *              if setting the alias was successful.
+ * @failure_cb: (scope async): The #PurpleSetPublicAliasFailureCallback to call
+ *              if setting the alias was unsuccessful.
+ *
+ * Sets the server side alias or display name for the user.  @success_cb will
+ * be called if the alias was set successfully otherwise @failure_cb will be
+ * called.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_set_public_alias(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *alias, PurpleSetPublicAliasSuccessCallback success_cb, PurpleSetPublicAliasFailureCallback failure_cb);
+
+/**
+ * purple_protocol_server_get_public_alias:
+ * @protocol_server: The #PurpleProtocolServer instance.
+ * @connection: The #PurpleConnection instance.
+ * @success_cb: (scope async): The #PurpleGetPublicAliasSuccessCallback to call
+ *              if setting the alias was successful.
+ * @failure_cb: (scope async): The #PurpleGetPublicAliasFailureCallback to call
+ *              if setting the alias was unsuccessful.
+ *
+ * Gets the server side alias or display name for the user.  @success_cb will
+ * be called if the alias was successfully retrieved otherwise @failure_cb will
+ * be called.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_server_get_public_alias(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleGetPublicAliasSuccessCallback success_cb, PurpleGetPublicAliasFailureCallback failure_cb);
+
+G_END_DECLS
+
+#endif /* PURPLE_PROTOCOL_SERVER_H */
+
diff --git a/libpurple/purpleprotocolserver.c b/libpurple/purpleprotocolserver.c
new file mode 100644
--- /dev/null
+++ b/libpurple/purpleprotocolserver.c
@@ -0,0 +1,414 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "purpleprotocolserver.h"
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+G_DEFINE_INTERFACE(PurpleProtocolServer, purple_protocol_server, G_TYPE_INVALID)
+
+static void
+purple_protocol_server_default_init(PurpleProtocolServerInterface *iface) {
+}
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+void
+purple_protocol_server_register_user(PurpleProtocolServer *protocol_server,
+                                     PurpleAccount *account)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_ACCOUNT(account));
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->register_user != NULL) {
+		iface->register_user(protocol_server, account);
+	}
+}
+
+void
+purple_protocol_server_unregister_user(PurpleProtocolServer *protocol_server,
+                                       PurpleAccount *account,
+                                       PurpleAccountUnregistrationCb cb,
+                                       gpointer data)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_ACCOUNT(account));
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->unregister_user != NULL) {
+		iface->unregister_user(protocol_server, account, cb, data);
+	}
+}
+
+void
+purple_protocol_server_set_info(PurpleProtocolServer *protocol_server,
+                                PurpleConnection *connection,
+                                const gchar *info)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->set_info != NULL) {
+		iface->set_info(protocol_server, connection, info);
+	}
+}
+
+void
+purple_protocol_server_get_info(PurpleProtocolServer *protocol_server,
+                                PurpleConnection *connection, const gchar *who)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
+	g_return_if_fail(who != NULL);
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->get_info != NULL) {
+		iface->get_info(protocol_server, connection, who);
+	}
+}
+
+void
+purple_protocol_server_set_status(PurpleProtocolServer *protocol_server,
+                                  PurpleAccount *account, PurpleStatus *status)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_ACCOUNT(account));
+	g_return_if_fail(PURPLE_IS_STATUS(status));
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->set_status != NULL) {
+		iface->set_status(protocol_server, account, status);
+	}
+}
+
+void
+purple_protocol_server_set_idle(PurpleProtocolServer *protocol_server,
+                                PurpleConnection *connection, gint idletime)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->set_idle != NULL) {
+		iface->set_idle(protocol_server, connection, idletime);
+	}
+}
+
+void
+purple_protocol_server_change_passwd(PurpleProtocolServer *protocol_server,
+                                     PurpleConnection *connection,
+                                     const gchar *old_pass,
+                                     const gchar *new_pass)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
+	g_return_if_fail(old_pass != NULL);
+	g_return_if_fail(new_pass != NULL);
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->change_passwd != NULL) {
+		iface->change_passwd(protocol_server, connection, old_pass, new_pass);
+	}
+}
+
+void
+purple_protocol_server_add_buddy(PurpleProtocolServer *protocol_server,
+                                 PurpleConnection *connection,
+                                 PurpleBuddy *buddy, PurpleGroup *group,
+                                 const gchar *message)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
+	g_return_if_fail(PURPLE_IS_BUDDY(buddy));
+	g_return_if_fail(PURPLE_IS_GROUP(group));
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->add_buddy != NULL) {
+		iface->add_buddy(protocol_server, connection, buddy, group, message);
+	}
+}
+
+void
+purple_protocol_server_add_buddies(PurpleProtocolServer *protocol_server,
+                                   PurpleConnection *connection,
+                                   GList *buddies, GList *groups,
+                                   const gchar *message)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
+	g_return_if_fail(g_list_length(buddies) != g_list_length(groups));
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->add_buddies != NULL) {
+		iface->add_buddies(protocol_server, connection, buddies, groups,
+		                   message);
+	} else {
+		while(buddies != NULL && groups != NULL) {
+			purple_protocol_server_add_buddy(protocol_server, connection,
+			                                 PURPLE_BUDDY(buddies->data),
+			                                 PURPLE_GROUP(groups->data),
+			                                 message);
+
+			buddies = g_list_next(buddies);
+			groups = g_list_next(groups);
+		}
+	}
+}
+
+void
+purple_protocol_server_remove_buddy(PurpleProtocolServer *protocol_server,
+                                    PurpleConnection *connection,
+                                    PurpleBuddy *buddy, PurpleGroup *group)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
+	g_return_if_fail(PURPLE_IS_BUDDY(buddy));
+	g_return_if_fail(PURPLE_IS_GROUP(group));
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->remove_buddy != NULL) {
+		iface->remove_buddy(protocol_server, connection, buddy, group);
+	}
+}
+
+void
+purple_protocol_server_remove_buddies(PurpleProtocolServer *protocol_server,
+                                      PurpleConnection *connection,
+                                      GList *buddies, GList *groups)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->remove_buddies != NULL) {
+		iface->remove_buddies(protocol_server, connection, buddies, groups);
+	} else {
+		while(buddies != NULL && groups != NULL) {
+			purple_protocol_server_remove_buddy(protocol_server, connection,
+			                                    PURPLE_BUDDY(buddies->data),
+			                                    PURPLE_GROUP(groups->data));
+
+			buddies = g_list_next(buddies);
+			groups = g_list_next(groups);
+		}
+	}
+}
+
+void
+purple_protocol_server_keepalive(PurpleProtocolServer *protocol_server,
+                                 PurpleConnection *connection)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->keepalive != NULL) {
+		iface->keepalive(protocol_server, connection);
+	}
+}
+
+gint
+purple_protocol_server_get_keepalive_interval(PurpleProtocolServer *protocol_server)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server), -1);
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->get_keepalive_interval != NULL) {
+		return iface->get_keepalive_interval(protocol_server);
+	}
+
+	return -1;
+}
+
+void
+purple_protocol_server_alias_buddy(PurpleProtocolServer *protocol_server,
+                                   PurpleConnection *connection,
+                                   const gchar *who, const gchar *alias)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
+	g_return_if_fail(who != NULL);
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->alias_buddy != NULL) {
+		iface->alias_buddy(protocol_server, connection, who, alias);
+	}
+}
+
+void
+purple_protocol_server_group_buddy(PurpleProtocolServer *protocol_server,
+                                   PurpleConnection *connection,
+                                   const gchar *who, const gchar *old_group,
+                                   const gchar *new_group)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
+	g_return_if_fail(who != NULL);
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->group_buddy != NULL) {
+		iface->group_buddy(protocol_server, connection, who, old_group,
+		                   new_group);
+	}
+}
+
+void
+purple_protocol_server_rename_group(PurpleProtocolServer *protocol_server,
+                                    PurpleConnection *connection,
+                                    const gchar *old_name, PurpleGroup *group,
+                                    GList *moved_buddies)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
+	g_return_if_fail(PURPLE_IS_GROUP(group));
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->rename_group != NULL) {
+		iface->rename_group(protocol_server, connection, old_name, group,
+		                    moved_buddies);
+	}
+}
+
+void
+purple_protocol_server_set_buddy_icon(PurpleProtocolServer *protocol_server,
+                                      PurpleConnection *connection,
+                                      PurpleImage *img)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
+	g_return_if_fail(PURPLE_IS_IMAGE(img));
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->set_buddy_icon != NULL) {
+		iface->set_buddy_icon(protocol_server, connection, img);
+	}
+}
+
+void
+purple_protocol_server_remove_group(PurpleProtocolServer *protocol_server,
+                                    PurpleConnection *connection,
+                                    PurpleGroup *group)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
+	g_return_if_fail(PURPLE_IS_GROUP(group));
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->remove_group != NULL) {
+		iface->remove_group(protocol_server, connection, group);
+	}
+}
+
+gint
+purple_protocol_server_send_raw(PurpleProtocolServer *protocol_server,
+                                PurpleConnection *connection,
+                                const gchar *buf, gint len)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server), -1);
+	g_return_val_if_fail(PURPLE_IS_CONNECTION(connection), -1);
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->send_raw != NULL) {
+		return iface->send_raw(protocol_server, connection, buf, len);
+	}
+
+	return -1;
+}
+
+void
+purple_protocol_server_set_public_alias(PurpleProtocolServer *protocol_server,
+                                        PurpleConnection *connection,
+                                        const gchar *alias,
+                                        PurpleSetPublicAliasSuccessCallback success_cb,
+                                        PurpleSetPublicAliasFailureCallback failure_cb)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->set_public_alias != NULL) {
+		iface->set_public_alias(protocol_server, connection, alias, success_cb,
+		                        failure_cb);
+	}
+}
+
+void
+purple_protocol_server_get_public_alias(PurpleProtocolServer *protocol_server,
+                                        PurpleConnection *connection,
+                                        PurpleGetPublicAliasSuccessCallback success_cb,
+                                        PurpleGetPublicAliasFailureCallback failure_cb)
+{
+	PurpleProtocolServerInterface *iface = NULL;
+
+	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
+	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
+
+	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
+	if(iface != NULL && iface->get_public_alias != NULL) {
+		iface->get_public_alias(protocol_server, connection, success_cb,
+		                        failure_cb);
+	}
+}
diff --git a/libpurple/server.c b/libpurple/server.c
--- a/libpurple/server.c
+++ b/libpurple/server.c
@@ -38,6 +38,7 @@
 #include "purpleprotocolchat.h"
 #include "purpleprotocolim.h"
 #include "purpleprotocolprivacy.h"
+#include "purpleprotocolserver.h"
 #include "request.h"
 #include "signals.h"
 #include "server.h"
@@ -179,7 +180,8 @@
 
 	if (gc) {
 		protocol = purple_connection_get_protocol(gc);
-		purple_protocol_server_iface_get_info(protocol, gc, name);
+		purple_protocol_server_get_info(PURPLE_PROTOCOL_SERVER(protocol), gc,
+		                                name);
 	}
 }
 
@@ -197,7 +199,8 @@
 			purple_signal_emit(purple_accounts_get_handle(),
 					"account-setting-info", account, info);
 
-			purple_protocol_server_iface_set_info(protocol, gc, info);
+			purple_protocol_server_set_info(PURPLE_PROTOCOL_SERVER(protocol),
+			                                gc, info);
 
 			purple_signal_emit(purple_accounts_get_handle(),
 					"account-set-info", account, info);
@@ -220,11 +223,12 @@
 		if (account) {
 			gc = purple_account_get_connection(account);
 
-			if (gc) {
+			if(gc) {
 				protocol = purple_connection_get_protocol(gc);
-				purple_protocol_server_iface_alias_buddy(protocol, gc,
-						purple_buddy_get_name(b),
-						purple_buddy_get_local_alias(b));
+				purple_protocol_server_alias_buddy(PURPLE_PROTOCOL_SERVER(protocol),
+				                                   gc,
+				                                   purple_buddy_get_name(b),
+				                                   purple_buddy_get_local_alias(b));
 			}
 		}
 	}
@@ -345,9 +349,10 @@
 
 	if (gc) {
 		protocol = purple_connection_get_protocol(gc);
-		purple_protocol_server_iface_group_buddy(protocol, gc, purple_buddy_get_name(buddy),
-				purple_group_get_name(orig),
-				purple_group_get_name(dest));
+		purple_protocol_server_group_buddy(PURPLE_PROTOCOL_SERVER(protocol),
+		                                   gc, purple_buddy_get_name(buddy),
+		                                   purple_group_get_name(orig),
+		                                   purple_group_get_name(dest));
 	}
 }
 
diff --git a/pidgin/plugins/xmppconsole/xmppconsole.c b/pidgin/plugins/xmppconsole/xmppconsole.c
--- a/pidgin/plugins/xmppconsole/xmppconsole.c
+++ b/pidgin/plugins/xmppconsole/xmppconsole.c
@@ -252,8 +252,10 @@
 	gtk_text_buffer_get_bounds(console->entry_buffer, &start, &end);
 	text = gtk_text_buffer_get_text(console->entry_buffer, &start, &end, FALSE);
 
-	if (protocol)
-		purple_protocol_server_iface_send_raw(protocol, gc, text, strlen(text));
+	if(PURPLE_IS_PROTOCOL_SERVER(protocol)) {
+		purple_protocol_server_send_raw(PURPLE_PROTOCOL_SERVER(protocol), gc,
+		                                text, strlen(text));
+	}
 
 	g_free(text);
 	gtk_text_buffer_set_text(console->entry_buffer, "", 0);
diff --git a/po/POTFILES.in b/po/POTFILES.in
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -261,6 +261,7 @@
 libpurple/purpleprotocolim.c
 libpurple/purpleprotocolmedia.c
 libpurple/purpleprotocolprivacy.c
+libpurple/purpleprotocolserver.c
 libpurple/purplewhiteboard.c
 libpurple/purplewhiteboarduiops.c
 libpurple/queuedoutputstream.c
