# HG changeset patch
# Node ID a52b2b3c7d56
# Parent  3a58ef28ee44
diff --git a/libpurple/protocols/silc/buddy.c b/libpurple/protocols/silc/buddy.c
--- a/libpurple/protocols/silc/buddy.c
+++ b/libpurple/protocols/silc/buddy.c
@@ -17,11 +17,9 @@
 
 */
 
-#include "internal.h"
-PURPLE_BEGIN_IGNORE_CAST_ALIGN
-#include "silc.h"
-PURPLE_END_IGNORE_CAST_ALIGN
-#include "silcclient.h"
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+
 #include "silcpurple.h"
 #include "wb.h"
 
@@ -676,7 +674,7 @@
 			      SilcDList clients,
 			      void *context);
 
-void silcpurple_get_info(PurpleConnection *gc, const char *who)
+void silcpurple_get_info(PurpleProtocolServer *protocol_server, PurpleConnection *gc, const char *who)
 {
 	SilcPurple sg = purple_connection_get_protocol_data(gc);
 	SilcClient client = sg->client;
@@ -1405,7 +1403,7 @@
 	silc_buffer_free(attrs);
 }
 
-void silcpurple_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group, const char *message)
+void silcpurple_add_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group, const char *message)
 {
 	/* Don't add if the buddy is already on the list.
 	 *
@@ -1430,13 +1428,13 @@
 	}
 }
 
-void silcpurple_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
+void silcpurple_remove_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc, PurpleBuddy *buddy,
 			   PurpleGroup *group)
 {
 	silc_free(purple_buddy_get_protocol_data(buddy));
 }
 
-void silcpurple_idle_set(PurpleConnection *gc, int idle)
+void silcpurple_idle_set(PurpleProtocolServer *protocol_server, PurpleConnection *gc, int idle)
 
 {
 	SilcPurple sg;
@@ -1472,7 +1470,7 @@
 				  &service, sizeof(service));
 }
 
-char *silcpurple_status_text(PurpleBuddy *b)
+char *silcpurple_status_text(PurpleProtocolClient *ppclient, PurpleBuddy *b)
 {
 	PurpleAccount *account = purple_buddy_get_account(b);
 	PurpleConnection *gc = purple_account_get_connection(account);
@@ -1538,7 +1536,7 @@
 	return NULL;
 }
 
-void silcpurple_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full)
+void silcpurple_tooltip_text(PurpleProtocolClient *ppclient, PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full)
 {
 	PurpleAccount *account = purple_buddy_get_account(b);
 	PurpleConnection *gc = purple_account_get_connection(account);
@@ -1722,7 +1720,7 @@
 	return m;
 }
 
-void silcpurple_buddy_set_icon(PurpleConnection *gc, PurpleImage *img)
+void silcpurple_buddy_set_icon(PurpleProtocolServer *protocol_server, PurpleConnection *gc, PurpleImage *img)
 {
 	SilcPurple sg = purple_connection_get_protocol_data(gc);
 	SilcClient client = sg->client;
diff --git a/libpurple/protocols/silc/chat.c b/libpurple/protocols/silc/chat.c
--- a/libpurple/protocols/silc/chat.c
+++ b/libpurple/protocols/silc/chat.c
@@ -17,17 +17,14 @@
 
 */
 
-#include "internal.h"
-PURPLE_BEGIN_IGNORE_CAST_ALIGN
-#include "silc.h"
-PURPLE_END_IGNORE_CAST_ALIGN
-#include "silcclient.h"
+#include <glib/gi18n-lib.h>
+
 #include "silcpurple.h"
 #include "wb.h"
 
 /***************************** Channel Routines ******************************/
 
-GList *silcpurple_chat_info(PurpleConnection *gc)
+GList *silcpurple_chat_info(PurpleProtocolChat *protocol_chat, PurpleConnection *gc)
 {
 	GList *ci = NULL;
 	PurpleProtocolChatEntry *pce;
@@ -47,7 +44,7 @@
 	return ci;
 }
 
-GHashTable *silcpurple_chat_info_defaults(PurpleConnection *gc, const char *chat_name)
+GHashTable *silcpurple_chat_info_defaults(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, const char *chat_name)
 {
 	GHashTable *defaults;
 
@@ -541,7 +538,7 @@
 	purple_blist_node_set_string((PurpleBlistNode *)cn, "parentch", p->channel);
 
 	/* Join the group */
-	silcpurple_chat_join(sg->gc, comp);
+	silcpurple_chat_join(NULL, sg->gc, comp);
 
 	silc_free(p);
 }
@@ -980,12 +977,12 @@
 
 /******************************* Joining Etc. ********************************/
 
-char *silcpurple_get_chat_name(GHashTable *data)
+char *silcpurple_get_chat_name(PurpleProtocolChat *protocol_chat, GHashTable *data)
 {
 	return g_strdup(g_hash_table_lookup(data, "channel"));
 }
 
-void silcpurple_chat_join(PurpleConnection *gc, GHashTable *data)
+void silcpurple_chat_join(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, GHashTable *data)
 {
 	SilcPurple sg = purple_connection_get_protocol_data(gc);
 	SilcClient client = sg->client;
@@ -1068,7 +1065,7 @@
 					 channel, "-auth", "-founder", NULL);
 }
 
-void silcpurple_chat_invite(PurpleConnection *gc, int id, const char *msg,
+void silcpurple_chat_invite(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int id, const char *msg,
 			    const char *name)
 {
 	SilcPurple sg = purple_connection_get_protocol_data(gc);
@@ -1114,7 +1111,7 @@
 				 name, NULL);
 }
 
-void silcpurple_chat_leave(PurpleConnection *gc, int id)
+void silcpurple_chat_leave(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int id)
 {
 	SilcPurple sg = purple_connection_get_protocol_data(gc);
 	SilcClient client = sg->client;
@@ -1183,7 +1180,7 @@
 		}
 }
 
-int silcpurple_chat_send(PurpleConnection *gc, int id, PurpleMessage *pmsg)
+int silcpurple_chat_send(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int id, PurpleMessage *pmsg)
 {
 	SilcPurple sg = purple_connection_get_protocol_data(gc);
 	SilcClient client = sg->client;
@@ -1309,7 +1306,7 @@
 	return ret;
 }
 
-void silcpurple_chat_set_topic(PurpleConnection *gc, int id, const char *topic)
+void silcpurple_chat_set_topic(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int id, const char *topic)
 {
 	SilcPurple sg = purple_connection_get_protocol_data(gc);
 	SilcClient client = sg->client;
diff --git a/libpurple/protocols/silc/ft.h b/libpurple/protocols/silc/ft.h
new file mode 100644
--- /dev/null
+++ b/libpurple/protocols/silc/ft.h
@@ -0,0 +1,37 @@
+/*
+ * 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/>.
+ */
+
+#ifndef PURPLE_SILC_FT_H
+#define PURPLE_SILC_FT_H
+
+#include <purple.h>
+
+G_BEGIN_DECLS
+
+#define SILCPURPLE_TYPE_XFER (silcpurple_xfer_get_type())
+G_DECLARE_FINAL_TYPE(SilcPurpleXfer, silcpurple_xfer, SILCPURPLE, XFER, PurpleXfer);
+
+void silcpurple_xfer_register(GTypeModule *module);
+
+G_END_DECLS
+
+#endif /* PURPLE_SILC_FT_H */
diff --git a/libpurple/protocols/silc/ft.c b/libpurple/protocols/silc/ft.c
--- a/libpurple/protocols/silc/ft.c
+++ b/libpurple/protocols/silc/ft.c
@@ -17,12 +17,11 @@
 
 */
 
-#include "internal.h"
-PURPLE_BEGIN_IGNORE_CAST_ALIGN
-#include "silc.h"
-PURPLE_END_IGNORE_CAST_ALIGN
-#include "silcclient.h"
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+
 #include "silcpurple.h"
+#include "ft.h"
 
 /****************************** File Transfer ********************************/
 
@@ -48,17 +47,20 @@
    FT API gets better this is the way to go.  Good thing that FT API allowed
    us to do this. */
 
-typedef struct {
+struct _SilcPurpleXfer {
+	PurpleXfer parent;
+
 	SilcPurple sg;
 	SilcClientEntry client_entry;
 	SilcUInt32 session_id;
 	char *hostname;
 	SilcUInt16 port;
-	PurpleXfer *xfer;
 
 	SilcClientFileName completion;
 	void *completion_context;
-} *SilcPurpleXfer;
+};
+
+G_DEFINE_DYNAMIC_TYPE(SilcPurpleXfer, silcpurple_xfer, PURPLE_TYPE_XFER);
 
 static void
 silcpurple_ftp_monitor(SilcClient client,
@@ -72,15 +74,15 @@
 		     const char *filepath,
 		     void *context)
 {
-	SilcPurpleXfer xfer = context;
-	PurpleConnection *gc = xfer->sg->gc;
+	PurpleXfer *xfer = context;
+	SilcPurpleXfer *spx = SILCPURPLE_XFER(xfer);
+	PurpleConnection *gc = spx->sg->gc;
 	char tmp[256];
 
 	if (status == SILC_CLIENT_FILE_MONITOR_CLOSED) {
 		/* All started sessions terminate here */
-		purple_xfer_set_protocol_data(xfer->xfer, NULL);
-		g_object_unref(xfer->xfer);
-		silc_free(xfer);
+		g_object_unref(xfer);
+		silc_free(spx);
 		return;
 	}
 
@@ -88,7 +90,7 @@
 		purple_notify_error(gc, _("Secure File Transfer"), _("Error "
 			"during file transfer"), _("Remote disconnected"),
 			purple_request_cpar_from_connection(gc));
-		purple_xfer_set_status(xfer->xfer, PURPLE_XFER_STATUS_CANCEL_REMOTE);
+		purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_CANCEL_REMOTE);
 		silc_client_file_close(client, conn, session_id);
 		return;
 	}
@@ -129,66 +131,55 @@
 				_("File transfer session does not exist"),
 				purple_request_cpar_from_connection(gc));
 		}
-		purple_xfer_set_status(xfer->xfer, PURPLE_XFER_STATUS_CANCEL_REMOTE);
+		purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_CANCEL_REMOTE);
 		silc_client_file_close(client, conn, session_id);
 		return;
 	}
 
 	/* Update file transfer UI */
-	if (!offset && filesize)
-		purple_xfer_set_size(xfer->xfer, filesize);
+	if (!offset && filesize) {
+		purple_xfer_set_size(xfer, filesize);
+	}
 	if (offset && filesize) {
-		purple_xfer_set_bytes_sent(xfer->xfer, offset);
+		purple_xfer_set_bytes_sent(xfer, offset);
 	}
 
 	if (status == SILC_CLIENT_FILE_MONITOR_SEND ||
 	    status == SILC_CLIENT_FILE_MONITOR_RECEIVE) {
 		if (offset == filesize) {
 			/* Download finished */
-			purple_xfer_set_completed(xfer->xfer, TRUE);
+			purple_xfer_set_completed(xfer, TRUE);
 			silc_client_file_close(client, conn, session_id);
 		}
 	}
 }
 
 static void
-silcpurple_ftp_cancel(PurpleXfer *x)
+silcpurple_ftp_cancel(PurpleXfer *xfer)
 {
-	SilcPurpleXfer xfer = purple_xfer_get_protocol_data(x);
+	SilcPurpleXfer *spx = SILCPURPLE_XFER(xfer);
 
-	if (!xfer)
+	if (!spx) {
 		return;
+	}
 
-	purple_xfer_set_status(xfer->xfer, PURPLE_XFER_STATUS_CANCEL_LOCAL);
-	purple_xfer_update_progress(xfer->xfer);
-	silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id);
+	purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_CANCEL_LOCAL);
+	silc_client_file_close(spx->sg->client, spx->sg->conn, spx->session_id);
 }
 
 static void
-silcpurple_ftp_ask_name_cancel(PurpleXfer *x)
+silcpurple_ftp_ask_name_ok(PurpleXfer *xfer)
 {
-	SilcPurpleXfer xfer = purple_xfer_get_protocol_data(x);
-
-	if (!xfer)
-		return;
-
-	/* Cancel the transmission */
-	xfer->completion(NULL, xfer->completion_context);
-	silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id);
-}
-
-static void
-silcpurple_ftp_ask_name_ok(PurpleXfer *x)
-{
-	SilcPurpleXfer xfer = purple_xfer_get_protocol_data(x);
+	SilcPurpleXfer *spx = SILCPURPLE_XFER(xfer);
 	const char *name;
 
-	if (!xfer)
+	if (!spx) {
 		return;
+	}
 
-	name = purple_xfer_get_local_filename(x);
+	name = purple_xfer_get_local_filename(xfer);
 	g_unlink(name);
-	xfer->completion(name, xfer->completion_context);
+	spx->completion(name, spx->completion_context);
 }
 
 static void
@@ -200,34 +191,33 @@
 		      void *completion_context,
 		      void *context)
 {
-	SilcPurpleXfer xfer = context;
+	PurpleXfer *xfer = context;
+	SilcPurpleXfer *spx = SILCPURPLE_XFER(xfer);
 
-	xfer->completion = completion;
-	xfer->completion_context = completion_context;
-
-	purple_xfer_set_init_fnc(xfer->xfer, silcpurple_ftp_ask_name_ok);
-	purple_xfer_set_request_denied_fnc(xfer->xfer, silcpurple_ftp_ask_name_cancel);
+	spx->completion = completion;
+	spx->completion_context = completion_context;
 
 	/* Request to save the file */
-	purple_xfer_set_filename(xfer->xfer, remote_filename);
-	purple_xfer_request(xfer->xfer);
+	purple_xfer_set_filename(xfer, remote_filename);
+	purple_xfer_request(xfer);
 }
 
 static void
-silcpurple_ftp_request_result(PurpleXfer *x)
+silcpurple_ftp_request_result(PurpleXfer *xfer)
 {
-	SilcPurpleXfer xfer = purple_xfer_get_protocol_data(x);
+	SilcPurpleXfer *spx = SILCPURPLE_XFER(xfer);
 	SilcClientFileError status;
-	PurpleConnection *gc = xfer->sg->gc;
+	PurpleConnection *gc = spx->sg->gc;
 	SilcClientConnectionParams params;
-	gboolean local = xfer->hostname ? FALSE : TRUE;
+	gboolean local = spx->hostname ? FALSE : TRUE;
 	char *local_ip = NULL, *remote_ip = NULL;
 	SilcSocket sock;
 
-	if (purple_xfer_get_status(x) != PURPLE_XFER_STATUS_ACCEPTED)
+	if (purple_xfer_get_status(xfer) != PURPLE_XFER_STATUS_ACCEPTED) {
 		return;
+	}
 
-	silc_socket_stream_get_info(silc_packet_stream_get_stream(xfer->sg->conn->stream),
+	silc_socket_stream_get_info(silc_packet_stream_get_stream(spx->sg->conn->stream),
 				    &sock, NULL, NULL, NULL);
 
 	if (local) {
@@ -258,12 +248,12 @@
 	  params.local_ip = local_ip;
 
 	/* Start the file transfer */
-	status = silc_client_file_receive(xfer->sg->client, xfer->sg->conn,
-					  &params, xfer->sg->public_key,
-					  xfer->sg->private_key,
-					  silcpurple_ftp_monitor, xfer,
-					  NULL, xfer->session_id,
-					  silcpurple_ftp_ask_name, xfer);
+	status = silc_client_file_receive(spx->sg->client, spx->sg->conn,
+	                                  &params, spx->sg->public_key,
+	                                  spx->sg->private_key,
+	                                  silcpurple_ftp_monitor, xfer,
+	                                  NULL, spx->session_id,
+	                                  silcpurple_ftp_ask_name, xfer);
 	switch (status) {
 	case SILC_CLIENT_FILE_OK:
 		silc_free(local_ip);
@@ -297,17 +287,39 @@
 	}
 
 	/* Error */
-	g_object_unref(xfer->xfer);
-	g_free(xfer->hostname);
-	silc_free(xfer);
+	g_object_unref(xfer);
+	g_free(spx->hostname);
+	silc_free(spx);
 	silc_free(local_ip);
 	silc_free(remote_ip);
 }
 
 static void
-silcpurple_ftp_request_denied(PurpleXfer *x)
+silcpurple_ftp_request_init(PurpleXfer *xfer)
 {
+	SilcPurpleXfer *spx = SILCPURPLE_XFER(xfer);
 
+	if (spx->completion) {
+		silcpurple_ftp_ask_name_ok(xfer);
+	} else {
+		silcpurple_ftp_request_result(xfer);
+	}
+}
+
+static void
+silcpurple_ftp_request_denied(PurpleXfer *xfer)
+{
+	SilcPurpleXfer *spx = SILCPURPLE_XFER(xfer);
+
+	if (!spx) {
+		return;
+	}
+
+	/* Cancel the transmission */
+	if (spx->completion) {
+		spx->completion(NULL, spx->completion_context);
+	}
+	silc_client_file_close(spx->sg->client, spx->sg->conn, spx->session_id);
 }
 
 void silcpurple_ftp_request(SilcClient client, SilcClientConnection conn,
@@ -316,65 +328,56 @@
 {
 	PurpleConnection *gc = client->application;
 	SilcPurple sg = purple_connection_get_protocol_data(gc);
-	SilcPurpleXfer xfer;
+	SilcPurpleXfer *spx;
+
+	spx = g_object_new(SILCPURPLE_TYPE_XFER,
+	                   "account", sg->account,
+	                   "type", PURPLE_XFER_TYPE_RECEIVE,
+	                   "remote-user", client_entry->nickname,
+	                   NULL);
 
-	xfer = silc_calloc(1, sizeof(*xfer));
-	if (!xfer) {
-		silc_client_file_close(sg->client, sg->conn, session_id);
+	spx->sg = sg;
+	spx->client_entry = client_entry;
+	spx->session_id = session_id;
+	spx->hostname = g_strdup(hostname);
+	spx->port = port;
+
+	purple_xfer_start(PURPLE_XFER(spx), -1, hostname, port);
+
+	/* File transfer request */
+	purple_xfer_request(PURPLE_XFER(spx));
+}
+
+static void
+silcpurple_ftp_send_cancel(PurpleXfer *xfer)
+{
+	SilcPurpleXfer *spx = SILCPURPLE_XFER(xfer);
+
+	if (!spx) {
 		return;
 	}
 
-	xfer->sg = sg;
-	xfer->client_entry = client_entry;
-	xfer->session_id = session_id;
-	xfer->hostname = g_strdup(hostname);
-	xfer->port = port;
-	xfer->xfer = purple_xfer_new(xfer->sg->account, PURPLE_XFER_TYPE_RECEIVE,
-				     xfer->client_entry->nickname);
-	if (!xfer->xfer) {
-		silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id);
-		g_free(xfer->hostname);
-		silc_free(xfer);
-		return;
-	}
-	purple_xfer_set_init_fnc(xfer->xfer, silcpurple_ftp_request_result);
-	purple_xfer_set_request_denied_fnc(xfer->xfer, silcpurple_ftp_request_denied);
-	purple_xfer_set_cancel_recv_fnc(xfer->xfer, silcpurple_ftp_cancel);
-	purple_xfer_start(xfer->xfer, -1, hostname, port);
-	purple_xfer_set_protocol_data(xfer->xfer, xfer);
-
-	/* File transfer request */
-	purple_xfer_request(xfer->xfer);
+	/* This call will free all resources */
+	silc_client_file_close(spx->sg->client, spx->sg->conn, spx->session_id);
 }
 
 static void
-silcpurple_ftp_send_cancel(PurpleXfer *x)
+silcpurple_ftp_send(PurpleXfer *xfer)
 {
-	SilcPurpleXfer xfer = purple_xfer_get_protocol_data(x);
-
-	if (!xfer)
-		return;
-
-	/* This call will free all resources */
-	silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id);
-}
-
-static void
-silcpurple_ftp_send(PurpleXfer *x)
-{
-	SilcPurpleXfer xfer = purple_xfer_get_protocol_data(x);
+	SilcPurpleXfer *spx = SILCPURPLE_XFER(xfer);
 	const char *name;
 	char *local_ip = NULL, *remote_ip = NULL;
 	gboolean local = TRUE;
 	SilcClientConnectionParams params;
 	SilcSocket sock;
 
-	if (!xfer)
+	if (!spx) {
 		return;
+	}
 
-	name = purple_xfer_get_local_filename(x);
+	name = purple_xfer_get_local_filename(xfer);
 
-	silc_socket_stream_get_info(silc_packet_stream_get_stream(xfer->sg->conn->stream),
+	silc_socket_stream_get_info(silc_packet_stream_get_stream(spx->sg->conn->stream),
 				    &sock, NULL, NULL, NULL);
 
 	/* Do the same magic what we do with key agreement (see silcpurple_buddy.c)
@@ -403,11 +406,11 @@
 	  params.local_ip = local_ip;
 
 	/* Send the file */
-	silc_client_file_send(xfer->sg->client, xfer->sg->conn,
-			      xfer->client_entry, &params,
-			      xfer->sg->public_key, xfer->sg->private_key,
-			      silcpurple_ftp_monitor, xfer,
-			      name, &xfer->session_id);
+	silc_client_file_send(spx->sg->client, spx->sg->conn,
+	                      spx->client_entry, &params,
+	                      spx->sg->public_key, spx->sg->private_key,
+	                      silcpurple_ftp_monitor, xfer,
+	                      name, &spx->session_id);
 
 	silc_free(local_ip);
 	silc_free(remote_ip);
@@ -434,7 +437,7 @@
 		return;
 	}
 
-	silcpurple_ftp_send_file(client->application, (const char *)context, NULL);
+	silcpurple_ftp_send_file(NULL, client->application, (const char *)context, NULL);
 	g_free(context);
 }
 
@@ -444,7 +447,8 @@
 	SilcClient client = sg->client;
 	SilcClientConnection conn = sg->conn;
 	SilcDList clients;
-	SilcPurpleXfer xfer;
+	SilcClientEntry client_entry;
+	SilcPurpleXfer *spx;
 
 	g_return_val_if_fail(name != NULL, NULL);
 
@@ -458,30 +462,24 @@
 	}
 	silc_dlist_start(clients);
 
-	xfer = silc_calloc(1, sizeof(*xfer));
-	g_return_val_if_fail(xfer != NULL, NULL);
-
-	xfer->sg = sg;
-	xfer->client_entry = silc_dlist_get(clients);
-	xfer->xfer = purple_xfer_new(xfer->sg->account, PURPLE_XFER_TYPE_SEND,
-				     xfer->client_entry->nickname);
-	if (!xfer->xfer) {
-		silc_free(xfer);
-		return NULL;
-	}
-	purple_xfer_set_init_fnc(xfer->xfer, silcpurple_ftp_send);
-	purple_xfer_set_request_denied_fnc(xfer->xfer, silcpurple_ftp_request_denied);
-	purple_xfer_set_cancel_send_fnc(xfer->xfer, silcpurple_ftp_send_cancel);
-	purple_xfer_set_protocol_data(xfer->xfer, xfer);
-
+	client_entry = silc_dlist_get(clients);
 	silc_free(clients);
 
-	return xfer->xfer;
+	spx = g_object_new(SILCPURPLE_TYPE_XFER,
+	                   "account", sg->account,
+	                   "type", PURPLE_XFER_TYPE_SEND,
+	                   "remote-user", client_entry->nickname,
+	                   NULL);
+
+	spx->sg = sg;
+	spx->client_entry = client_entry;
+
+	return PURPLE_XFER(spx);
 }
 
 void silcpurple_ftp_send_file(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, const char *name, const char *file)
 {
-	PurpleXfer *xfer = silcpurple_ftp_new_xfer(gc, name);
+	PurpleXfer *xfer = silcpurple_ftp_new_xfer(prplxfer, gc, name);
 
 	g_return_if_fail(xfer != NULL);
 
@@ -491,3 +489,61 @@
 	else
 		purple_xfer_request(xfer);
 }
+
+static void
+silcpurple_ftp_init(PurpleXfer *xfer)
+{
+	switch(purple_xfer_get_xfer_type(xfer)) {
+	case PURPLE_XFER_TYPE_SEND:
+		silcpurple_ftp_send(xfer);
+		break;
+	case PURPLE_XFER_TYPE_RECEIVE:
+		silcpurple_ftp_request_init(xfer);
+		break;
+	case PURPLE_XFER_TYPE_UNKNOWN:
+		g_return_if_reached();
+		break;
+	}
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+static void
+silcpurple_xfer_init(SilcPurpleXfer *spx)
+{
+}
+
+static void
+silcpurple_xfer_finalize(GObject *obj) {
+	SilcPurpleXfer *spx = SILCPURPLE_XFER(obj);
+
+	g_free(spx->hostname);
+
+	G_OBJECT_CLASS(silcpurple_xfer_parent_class)->finalize(obj);
+}
+
+static void
+silcpurple_xfer_class_init(SilcPurpleXferClass *klass) {
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	PurpleXferClass *xfer_class = PURPLE_XFER_CLASS(klass);
+
+	obj_class->finalize = silcpurple_xfer_finalize;
+
+	xfer_class->init = silcpurple_ftp_init;
+	xfer_class->request_denied = silcpurple_ftp_request_denied;
+	xfer_class->cancel_send = silcpurple_ftp_send_cancel;
+	xfer_class->cancel_recv = silcpurple_ftp_cancel;
+}
+
+static void
+silcpurple_xfer_class_finalize(SilcPurpleXferClass *klass) {
+}
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+void
+silcpurple_xfer_register(GTypeModule *module) {
+	silcpurple_xfer_register_type(module);
+}
diff --git a/libpurple/protocols/silc/meson.build b/libpurple/protocols/silc/meson.build
--- a/libpurple/protocols/silc/meson.build
+++ b/libpurple/protocols/silc/meson.build
@@ -2,6 +2,7 @@
 	'buddy.c',
 	'chat.c',
 	'ft.c',
+	'ft.h',
 	'ops.c',
 	'pk.c',
 	'silc.c',
diff --git a/libpurple/protocols/silc/ops.c b/libpurple/protocols/silc/ops.c
--- a/libpurple/protocols/silc/ops.c
+++ b/libpurple/protocols/silc/ops.c
@@ -17,11 +17,9 @@
 
 */
 
-#include "internal.h"
-PURPLE_BEGIN_IGNORE_CAST_ALIGN
-#include "silc.h"
-PURPLE_END_IGNORE_CAST_ALIGN
-#include "silcclient.h"
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+
 #include "silcpurple.h"
 #include "wb.h"
 
diff --git a/libpurple/protocols/silc/pk.c b/libpurple/protocols/silc/pk.c
--- a/libpurple/protocols/silc/pk.c
+++ b/libpurple/protocols/silc/pk.c
@@ -17,12 +17,10 @@
 
 */
 
-#include "internal.h"
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+
 #include "glibcompat.h" /* for purple_g_stat on win32 */
-PURPLE_BEGIN_IGNORE_CAST_ALIGN
-#include "silc.h"
-PURPLE_END_IGNORE_CAST_ALIGN
-#include "silcclient.h"
 #include "silcpurple.h"
 
 /************************* Public Key Verification ***************************/
diff --git a/libpurple/protocols/silc/silc.c b/libpurple/protocols/silc/silc.c
--- a/libpurple/protocols/silc/silc.c
+++ b/libpurple/protocols/silc/silc.c
@@ -17,14 +17,11 @@
 
 */
 
-#include "internal.h"
-#include <purple.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
 
-PURPLE_BEGIN_IGNORE_CAST_ALIGN
-#include "silc.h"
-PURPLE_END_IGNORE_CAST_ALIGN
-#include "silcclient.h"
 #include "silcpurple.h"
+#include "ft.h"
 #include "wb.h"
 
 extern SilcClientOperations ops;
@@ -91,7 +88,7 @@
 }
 
 static void
-silcpurple_set_status(PurpleAccount *account, PurpleStatus *status)
+silcpurple_set_status(PurpleProtocolServer *protocol_server, PurpleAccount *account, PurpleStatus *status)
 {
 	PurpleConnection *gc = purple_account_get_connection(account);
 	SilcPurple sg = NULL;
@@ -146,7 +143,7 @@
 /*************************** Connection Routines *****************************/
 
 static void
-silcpurple_keepalive(PurpleConnection *gc)
+silcpurple_keepalive(PurpleProtocolServer *protocol_server, PurpleConnection *gc)
 {
 	SilcPurple sg = purple_connection_get_protocol_data(gc);
 	silc_packet_send(sg->conn->stream, SILC_PACKET_HEARTBEAT, 0,
@@ -316,7 +313,7 @@
 
 		/* Set our buddy icon */
 		img = purple_buddy_icons_find_account_icon(sg->account);
-		silcpurple_buddy_set_icon(gc, img);
+		silcpurple_buddy_set_icon(NULL, gc, img);
 		g_object_unref(img);
 
 		return;
@@ -465,6 +462,7 @@
 	PurpleConnection *gc = sg->gc;
 	PurpleAccount *account = purple_connection_get_account(gc);
 	GSocketClient *client;
+	GError *error;
 
 	client = purple_gio_socket_client_new(account, &error);
 	if (client == NULL) {
@@ -494,6 +492,7 @@
 	char pkd[256], prd[256];
 	const char *password;
 	gboolean remember;
+	PurpleCredentialManager *manager;
 
 	/* TODO: the password prompt dialog doesn't get disposed if the account disconnects */
 	PURPLE_ASSERT_CONNECTION_IS_VALID(gc);
@@ -514,7 +513,9 @@
 	if (remember)
 		purple_account_set_remember_password(account, TRUE);
 
-	purple_account_set_password(account, password, NULL, NULL);
+	manager = purple_credential_manager_get_default();
+	purple_credential_manager_write_password_async(manager, account, password,
+	                                               NULL, NULL, NULL);
 
 	/* Load SILC key pair */
 	g_snprintf(pkd, sizeof(pkd), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir());
@@ -1305,7 +1306,7 @@
 }
 
 static void
-silcpurple_change_passwd(PurpleConnection *gc, const char *old, const char *new)
+silcpurple_change_passwd(PurpleProtocolServer *protocol_server, PurpleConnection *gc, const char *old, const char *new)
 {
 	char prd[256];
 	g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.pub", silcpurple_silcdir());
@@ -1322,12 +1323,12 @@
 }
 
 static void
-silcpurple_set_info(PurpleConnection *gc, const char *text)
+silcpurple_set_info(PurpleProtocolServer *protocol_server, PurpleConnection *gc, const char *text)
 {
 }
 
 static GList *
-silcpurple_get_actions(PurpleConnection *gc)
+silcpurple_get_actions(PurpleProtocolClient *client, PurpleConnection *gc)
 {
 	GList *list = NULL;
 	PurpleProtocolAction *act;
@@ -1385,6 +1386,8 @@
 	SilcClientEntry client_entry;
 	SilcDList list;
 	gboolean free_list = FALSE;
+	const gchar *me;
+	PurpleMessage *msg;
 
 	convo = purple_conversations_find_im_with_account(im->nick,
 						      sg->account);
@@ -1408,6 +1411,8 @@
 	silc_dlist_start(clients);
 	client_entry = silc_dlist_get(clients);
 
+	me = purple_account_get_name_for_display(sg->account);
+
 	/* Check for images */
 	if (im->gflags & PURPLE_MESSAGE_IMAGES) {
 		list = silcpurple_image_message(im->message, &im->flags);
@@ -1423,9 +1428,9 @@
 								 buf->data,
 								 silc_buffer_len(buf));
 			silc_mime_partial_free(list);
-			purple_conversation_write_message(PURPLE_CONVERSATION(convo),
-				purple_message_new_outgoing(
-					conn->local_entry->nickname, im->message, 0));
+			msg = purple_message_new_outgoing(me, conn->local_entry->nickname, im->message, 0);
+			purple_conversation_write_message(PURPLE_CONVERSATION(convo), msg);
+			g_object_unref(G_OBJECT(msg));
 			goto out;
 		}
 	}
@@ -1433,8 +1438,9 @@
 	/* Send the message */
 	silc_client_send_private_message(client, conn, client_entry, im->flags,
 					 sg->sha1hash, (unsigned char *)im->message, im->message_len);
-	purple_conversation_write_message(PURPLE_CONVERSATION(convo),
-		purple_message_new_outgoing(conn->local_entry->nickname, im->message, 0));
+	msg = purple_message_new_outgoing(me, conn->local_entry->nickname, im->message, 0);
+	purple_conversation_write_message(PURPLE_CONVERSATION(convo), msg);
+	g_object_unref(G_OBJECT(msg));
 	goto out;
 
  err:
@@ -1553,7 +1559,7 @@
 }
 
 
-static GList *silcpurple_blist_node_menu(PurpleBlistNode *node) {
+static GList *silcpurple_blist_node_menu(PurpleProtocolClient *client, PurpleBlistNode *node) {
 	/* split this single menu building function back into the two
 	   original: one for buddies and one for chats */
 	if(PURPLE_IS_CHAT(node)) {
@@ -1589,7 +1595,7 @@
 	if (id == 0)
 		return PURPLE_CMD_RET_FAILED;
 
-	silcpurple_chat_leave(gc, id);
+	silcpurple_chat_leave(NULL, gc, id);
 
 	return PURPLE_CMD_RET_OK;
 
@@ -1630,7 +1636,7 @@
 		return PURPLE_CMD_RET_FAILED;
 	}
 
-	silcpurple_chat_set_topic(gc, id, args ? args[0] : NULL);
+	silcpurple_chat_set_topic(NULL, gc, id, args ? args[0] : NULL);
 
 	return PURPLE_CMD_RET_OK;
 }
@@ -1649,7 +1655,7 @@
 	if(args[1])
 		g_hash_table_replace(comp, "passphrase", args[1]);
 
-	silcpurple_chat_join(purple_conversation_get_connection(conv), comp);
+	silcpurple_chat_join(NULL, purple_conversation_get_connection(conv), comp);
 
 	g_hash_table_destroy(comp);
 	return PURPLE_CMD_RET_OK;
@@ -1674,7 +1680,7 @@
 	if (gc == NULL)
 		return PURPLE_CMD_RET_FAILED;
 
-	silcpurple_get_info(gc, args[0]);
+	silcpurple_get_info(NULL, gc, args[0]);
 
 	return PURPLE_CMD_RET_OK;
 }
@@ -1684,14 +1690,20 @@
 {
 	int ret;
 	PurpleConnection *gc;
+	PurpleAccount *account;
+	const gchar *me;
+	PurpleMessage *msg;
 
 	gc = purple_conversation_get_connection(conv);
 
 	if (gc == NULL)
 		return PURPLE_CMD_RET_FAILED;
 
-	ret = silcpurple_send_im(gc,
-		purple_message_new_outgoing(args[0], args[1], 0));
+	account = purple_connection_get_account(gc);
+	me = purple_account_get_name_for_display(account);
+	msg = purple_message_new_outgoing(me, args[0], args[1], 0);
+	ret = silcpurple_send_im(NULL, gc, msg);
+	g_object_unref(G_OBJECT(msg));
 
 	if (ret)
 		return PURPLE_CMD_RET_OK;
@@ -1722,11 +1734,13 @@
 	im = purple_im_conversation_new(account, args[0]);
 
 	if (args[1]) {
+		const gchar *me = purple_account_get_name_for_display(account);
 		PurpleMessage *msg = purple_message_new_outgoing(
-			args[0], args[1], 0);
+		        me, args[0], args[1], 0);
 
-		ret = silcpurple_send_im(gc, msg);
+		ret = silcpurple_send_im(NULL, gc, msg);
 		purple_conversation_write_message(PURPLE_CONVERSATION(im), msg);
+		g_object_unref(G_OBJECT(msg));
 	}
 
 	if (ret)
@@ -2328,6 +2342,8 @@
 {
 	silcpurple_protocol_register_type(G_TYPE_MODULE(plugin));
 
+	silcpurple_xfer_register(G_TYPE_MODULE(plugin));
+
 	my_protocol = purple_protocols_add(SILCPURPLE_TYPE_PROTOCOL, error);
 	if (!my_protocol)
 		return FALSE;
diff --git a/libpurple/protocols/silc/silcpurple.h b/libpurple/protocols/silc/silcpurple.h
--- a/libpurple/protocols/silc/silcpurple.h
+++ b/libpurple/protocols/silc/silcpurple.h
@@ -22,8 +22,10 @@
 
 #include <gmodule.h>
 
+#include <silc.h>
+#include <silcclient.h>
+
 /* Purple includes */
-#include "internal.h"
 #include <purple.h>
 
 #define SILCPURPLE_TYPE_PROTOCOL             (silcpurple_protocol_get_type())
@@ -115,27 +117,27 @@
 				  SilcVerifyPublicKey completion,
 				  void *context);
 GList *silcpurple_buddy_menu(PurpleBuddy *buddy);
-void silcpurple_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group, const char *message);
+void silcpurple_add_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group, const char *message);
 void silcpurple_send_buddylist(PurpleConnection *gc);
-void silcpurple_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
+void silcpurple_remove_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
 void silcpurple_buddy_keyagr_request(SilcClient client,
 				     SilcClientConnection conn,
 				     SilcClientEntry client_entry,
 				     const char *hostname, SilcUInt16 port,
 				     SilcUInt16 protocol);
-void silcpurple_idle_set(PurpleConnection *gc, int idle);
-void silcpurple_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full);
-char *silcpurple_status_text(PurpleBuddy *b);
+void silcpurple_idle_set(PurpleProtocolServer *protocol_server, PurpleConnection *gc, int idle);
+void silcpurple_tooltip_text(PurpleProtocolClient *ppclient, PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full);
+char *silcpurple_status_text(PurpleProtocolClient *ppclient, PurpleBuddy *b);
 gboolean silcpurple_ip_is_private(const char *ip);
-void silcpurple_ftp_send_file(PurpleConnection *gc, const char *name, const char *file);
-PurpleXfer *silcpurple_ftp_new_xfer(PurpleConnection *gc, const char *name);
+void silcpurple_ftp_send_file(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, const char *name, const char *file);
+PurpleXfer *silcpurple_ftp_new_xfer(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, const char *name);
 void silcpurple_ftp_request(SilcClient client, SilcClientConnection conn,
 			  SilcClientEntry client_entry, SilcUInt32 session_id,
 			  const char *hostname, SilcUInt16 port);
 void silcpurple_show_public_key(SilcPurple sg,
 			      const char *name, SilcPublicKey public_key,
 			      GCallback callback, void *context);
-void silcpurple_get_info(PurpleConnection *gc, const char *who);
+void silcpurple_get_info(PurpleProtocolServer *protocol_server, PurpleConnection *gc, const char *who);
 SilcAttributePayload
 silcpurple_get_attr(SilcDList attrs, SilcAttribute attribute);
 void silcpurple_get_umode_string(SilcUInt32 mode, char *buf,
@@ -144,16 +146,16 @@
 				SilcUInt32 buf_size);
 void silcpurple_get_chumode_string(SilcUInt32 mode, char *buf,
 				 SilcUInt32 buf_size);
-GList *silcpurple_chat_info(PurpleConnection *gc);
-GHashTable *silcpurple_chat_info_defaults(PurpleConnection *gc, const char *chat_name);
+GList *silcpurple_chat_info(PurpleProtocolChat *protocol_chat, PurpleConnection *gc);
+GHashTable *silcpurple_chat_info_defaults(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, const char *chat_name);
 GList *silcpurple_chat_menu(PurpleChat *);
-void silcpurple_chat_join(PurpleConnection *gc, GHashTable *data);
-char *silcpurple_get_chat_name(GHashTable *data);
-void silcpurple_chat_invite(PurpleConnection *gc, int id, const char *msg,
+void silcpurple_chat_join(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, GHashTable *data);
+char *silcpurple_get_chat_name(PurpleProtocolChat *protocol_chat, GHashTable *data);
+void silcpurple_chat_invite(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int id, const char *msg,
 			  const char *name);
-void silcpurple_chat_leave(PurpleConnection *gc, int id);
-int silcpurple_chat_send(PurpleConnection *gc, int id, PurpleMessage *msg);
-void silcpurple_chat_set_topic(PurpleConnection *gc, int id, const char *topic);
+void silcpurple_chat_leave(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int id);
+int silcpurple_chat_send(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int id, PurpleMessage *msg);
+void silcpurple_chat_set_topic(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int id, const char *topic);
 PurpleRoomlist *silcpurple_roomlist_get_list(PurpleConnection *gc);
 void silcpurple_roomlist_cancel(PurpleRoomlist *list);
 void silcpurple_chat_chauth_show(SilcPurple sg, SilcChannelEntry channel,
@@ -161,7 +163,7 @@
 void silcpurple_parse_attrs(SilcDList attrs, char **moodstr, char **statusstr,
 					 char **contactstr, char **langstr, char **devicestr,
 					 char **tzstr, char **geostr);
-void silcpurple_buddy_set_icon(PurpleConnection *gc, PurpleImage *img);
+void silcpurple_buddy_set_icon(PurpleProtocolServer *protocol_server, PurpleConnection *gc, PurpleImage *img);
 SilcDList silcpurple_image_message(const char *msg, SilcMessageFlags *mflags);
 
 #ifdef _WIN32
diff --git a/libpurple/protocols/silc/util.c b/libpurple/protocols/silc/util.c
--- a/libpurple/protocols/silc/util.c
+++ b/libpurple/protocols/silc/util.c
@@ -17,13 +17,17 @@
 
 */
 
-#include "internal.h"
-#include <purple.h>
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
 
-PURPLE_BEGIN_IGNORE_CAST_ALIGN
-#include "silc.h"
-PURPLE_END_IGNORE_CAST_ALIGN
-#include "silcclient.h"
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+
 #include "silcpurple.h"
 
 /**************************** Utility Routines *******************************/
@@ -246,7 +250,7 @@
 	if ((st.st_mode & 0777) != 0600) {
 		purple_debug_warning("silc", "Wrong permissions in your private key file `%s'!\n"
 			"Trying to change them ...\n", file_private_key);
-		if ((fd == -1) || (g_fchmod(fd, S_IRUSR | S_IWUSR)) == -1) {
+		if ((fd == -1) || (fchmod(fd, S_IRUSR | S_IWUSR) == -1)) {
 			purple_debug_error("silc",
 				"Failed to change permissions for private key file!\n"
 				"Permissions for your private key file must be 0600.\n");
diff --git a/libpurple/protocols/silc/wb.c b/libpurple/protocols/silc/wb.c
--- a/libpurple/protocols/silc/wb.c
+++ b/libpurple/protocols/silc/wb.c
@@ -17,11 +17,8 @@
 
 */
 
-#include "internal.h"
-PURPLE_BEGIN_IGNORE_CAST_ALIGN
-#include "silc.h"
-PURPLE_END_IGNORE_CAST_ALIGN
-#include "silcclient.h"
+#include <glib/gi18n-lib.h>
+
 #include "silcpurple.h"
 #include "wb.h"
 
diff --git a/libpurple/purpleprivate.h b/libpurple/purpleprivate.h
--- a/libpurple/purpleprivate.h
+++ b/libpurple/purpleprivate.h
@@ -178,17 +178,6 @@
 int *_purple_statuses_get_primitive_scores(void);
 
 /**
- * A fstat alternative, like g_stat for stat.
- *
- * @param fd The file descriptor.
- * @param st The stat buffer.
- *
- * @return the result just like for fstat.
- */
-int
-_purple_fstat(int fd, GStatBuf *st);
-
-/**
  * _purple_conversation_write_common:
  * @conv:    The conversation.
  * @msg:     The message.
diff --git a/libpurple/util.h b/libpurple/util.h
--- a/libpurple/util.h
+++ b/libpurple/util.h
@@ -38,6 +38,8 @@
 
 #include <stdio.h>
 
+#include <glib/gstdio.h>
+
 #include "account.h"
 #include "signals.h"
 #include "xmlnode.h"
@@ -968,6 +970,17 @@
  */
 void purple_value_free(GValue *value);
 
+/**
+ * A fstat alternative, like g_stat for stat.
+ *
+ * @param fd The file descriptor.
+ * @param st The stat buffer.
+ *
+ * @return the result just like for fstat.
+ */
+int
+_purple_fstat(int fd, GStatBuf *st);
+
 G_END_DECLS
 
 #endif /* PURPLE_UTIL_H */
