Clean merge.

Thu, 29 Aug 2013 23:01:58 -0700

author
Mark Doliner <mark@kingant.net>
date
Thu, 29 Aug 2013 23:01:58 -0700
changeset 34320
6c217475a114
parent 34319
c0d0b7137c8a (current diff)
parent 34317
4de5b4193f32 (diff)
child 34321
f60fcab02bd4
child 34902
658670a20905

Clean merge.

--- a/libpurple/Makefile.am	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/Makefile.am	Thu Aug 29 23:01:58 2013 -0700
@@ -76,6 +76,7 @@
 	privacy.c \
 	proxy.c \
 	prpl.c \
+	purple-socket.c \
 	request.c \
 	roomlist.c \
 	savedstatuses.c \
@@ -141,6 +142,7 @@
 	privacy.h \
 	proxy.h \
 	prpl.h \
+	purple-socket.h \
 	request.h \
 	roomlist.h \
 	savedstatuses.h \
--- a/libpurple/Makefile.mingw	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/Makefile.mingw	Thu Aug 29 23:01:58 2013 -0700
@@ -104,6 +104,7 @@
 			privacy.c \
 			proxy.c \
 			prpl.c \
+			purple-socket.c \
 			request.c \
 			roomlist.c \
 			savedstatuses.c \
--- a/libpurple/connection.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/connection.c	Thu Aug 29 23:01:58 2013 -0700
@@ -631,6 +631,26 @@
 	gc->last_received = time(NULL);
 }
 
+gsize
+purple_connection_get_max_message_size(PurpleConnection *gc)
+{
+	PurplePlugin *prpl;
+	PurplePluginProtocolInfo *prpl_info;
+
+	g_return_val_if_fail(gc != NULL, 0);
+
+	prpl = purple_connection_get_prpl(gc);
+	g_return_val_if_fail(prpl != NULL, 0);
+
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+	g_return_val_if_fail(prpl_info != NULL, 0);
+
+	if (!PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, get_max_message_size))
+		return 0;
+
+	return prpl_info->get_max_message_size(gc);
+}
+
 void
 purple_connections_disconnect_all(void)
 {
--- a/libpurple/connection.h	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/connection.h	Thu Aug 29 23:01:58 2013 -0700
@@ -452,6 +452,18 @@
  */
 void purple_connection_update_last_received(PurpleConnection *gc);
 
+/**
+ * Gets the maximum message size in bytes for the protocol. It may depend on
+ * connection-specific variables (like protocol version).
+ *
+ * @see PurplePluginProtocolInfo#get_max_message_size
+ *
+ * @param gc The connection to query.
+ * @return   Maximum message size, or 0 if unspecified or infinite.
+ */
+gsize
+purple_connection_get_max_message_size(PurpleConnection *gc);
+
 /*@}*/
 
 /**************************************************************************/
--- a/libpurple/http.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/http.c	Thu Aug 29 23:01:58 2013 -0700
@@ -31,6 +31,7 @@
 
 #include "debug.h"
 #include "ntlm.h"
+#include "purple-socket.h"
 
 #include <zlib.h>
 
@@ -56,23 +57,13 @@
 
 typedef struct _PurpleHttpGzStream PurpleHttpGzStream;
 
-typedef void (*PurpleHttpSocketConnectCb)(PurpleHttpSocket *hs,
-	const gchar *error, gpointer user_data);
-
 struct _PurpleHttpSocket
 {
-	gboolean is_ssl;
+	PurpleSocket *ps;
+
 	gboolean is_busy;
 	guint use_count;
 	PurpleHttpKeepaliveHost *host;
-
-	PurpleSslConnection *ssl_connection;
-	PurpleProxyConnectData *raw_connection;
-	int fd;
-	guint inpa;
-	PurpleInputFunction watch_cb;
-	PurpleHttpSocketConnectCb connect_cb;
-	gpointer cb_data;
 };
 
 struct _PurpleHttpRequest
@@ -184,7 +175,7 @@
 struct _PurpleHttpKeepaliveRequest
 {
 	PurpleConnection *gc;
-	PurpleHttpSocketConnectCb cb;
+	PurpleSocketConnectCb cb;
 	gpointer user_data;
 
 	PurpleHttpKeepaliveHost *host;
@@ -256,7 +247,7 @@
 static PurpleHttpKeepaliveRequest *
 purple_http_keepalive_pool_request(PurpleHttpKeepalivePool *pool,
 	PurpleConnection *gc, const gchar *host, int port, gboolean is_ssl,
-	PurpleHttpSocketConnectCb cb, gpointer user_data);
+	PurpleSocketConnectCb cb, gpointer user_data);
 static void
 purple_http_keepalive_pool_request_cancel(PurpleHttpKeepaliveRequest *req);
 static void
@@ -464,43 +455,6 @@
 
 /*** HTTP Sockets *************************************************************/
 
-static void _purple_http_socket_connected_raw(gpointer _hs, gint fd,
-	const gchar *error_message)
-{
-	PurpleHttpSocket *hs = _hs;
-
-	hs->raw_connection = NULL;
-
-	if (fd == -1 || error_message != NULL) {
-		if (error_message == NULL)
-			error_message = _("Unknown error");
-		hs->connect_cb(hs, error_message, hs->cb_data);
-		return;
-	}
-
-	hs->fd = fd;
-	hs->connect_cb(hs, NULL, hs->cb_data);
-}
-
-static void _purple_http_socket_connected_ssl(gpointer _hs,
-	PurpleSslConnection *ssl_connection, PurpleInputCondition cond)
-{
-	PurpleHttpSocket *hs = _hs;
-
-	hs->fd = hs->ssl_connection->fd;
-	hs->connect_cb(hs, NULL, hs->cb_data);
-}
-
-static void _purple_http_socket_connected_ssl_error(
-	PurpleSslConnection *ssl_connection, PurpleSslErrorType error,
-	gpointer _hs)
-{
-	PurpleHttpSocket *hs = _hs;
-
-	hs->ssl_connection = NULL;
-	hs->connect_cb(hs, purple_ssl_strerror(error), hs->cb_data);
-}
-
 static gchar *
 purple_http_socket_hash(const gchar *host, int port, gboolean is_ssl)
 {
@@ -508,41 +462,18 @@
 }
 
 static PurpleHttpSocket *
-purple_http_socket_connect_new(PurpleConnection *gc, const gchar *host, int port, gboolean is_ssl, PurpleHttpSocketConnectCb cb, gpointer user_data)
+purple_http_socket_connect_new(PurpleConnection *gc, const gchar *host,
+	int port, gboolean is_ssl, PurpleSocketConnectCb cb, gpointer user_data)
 {
 	PurpleHttpSocket *hs = g_new0(PurpleHttpSocket, 1);
-	PurpleAccount *account = NULL;
-
-	if (gc != NULL)
-		account = purple_connection_get_account(gc);
-
-	hs->is_ssl = is_ssl;
-	hs->connect_cb = cb;
-	hs->cb_data = user_data;
-	hs->fd = -1;
-
-	if (is_ssl) {
-		if (!purple_ssl_is_supported()) {
-			g_free(hs);
-			return NULL;
-		}
-
-		hs->ssl_connection = purple_ssl_connect(account,
-			host, port,
-			_purple_http_socket_connected_ssl,
-			_purple_http_socket_connected_ssl_error, hs);
-/* TODO
-		purple_ssl_set_compatibility_level(hs->ssl_connection,
-			PURPLE_SSL_COMPATIBILITY_SECURE);
-*/
-	} else {
-		hs->raw_connection = purple_proxy_connect(gc, account,
-			host, port,
-			_purple_http_socket_connected_raw, hs);
-	}
-
-	if (hs->ssl_connection == NULL &&
-		hs->raw_connection == NULL) {
+
+	hs->ps = purple_socket_new(gc);
+	purple_socket_set_data(hs->ps, "hs", hs);
+	purple_socket_set_tls(hs->ps, is_ssl);
+	purple_socket_set_host(hs->ps, host);
+	purple_socket_set_port(hs->ps, port);
+	if (!purple_socket_connect(hs->ps, cb, user_data)) {
+		purple_socket_destroy(hs->ps);
 		g_free(hs);
 		return NULL;
 	}
@@ -553,72 +484,6 @@
 	return hs;
 }
 
-static int
-purple_http_socket_read(PurpleHttpSocket *hs, gchar *buf, size_t len)
-{
-	g_return_val_if_fail(hs != NULL, -1);
-	g_return_val_if_fail(buf != NULL, -1);
-
-	if (hs->is_ssl)
-		return purple_ssl_read(hs->ssl_connection, buf, sizeof(buf));
-	else
-		return read(hs->fd, buf, sizeof(buf));
-}
-
-static int
-purple_http_socket_write(PurpleHttpSocket *hs, const gchar *buf, size_t len)
-{
-	g_return_val_if_fail(hs != NULL, -1);
-	g_return_val_if_fail(buf != NULL, -1);
-
-	if (hs->is_ssl)
-		return purple_ssl_write(hs->ssl_connection, buf, len);
-	else
-		return write(hs->fd, buf, len);
-}
-
-static void _purple_http_socket_watch_recv_ssl(gpointer _hs,
-	PurpleSslConnection *ssl_connection, PurpleInputCondition cond)
-{
-	PurpleHttpSocket *hs = _hs;
-
-	g_return_if_fail(hs != NULL);
-
-	hs->watch_cb(hs->cb_data, hs->fd, cond);
-}
-
-static void
-purple_http_socket_watch(PurpleHttpSocket *hs, PurpleInputCondition cond,
-	PurpleInputFunction func, gpointer user_data)
-{
-	g_return_if_fail(hs != NULL);
-
-	if (hs->inpa > 0)
-		purple_input_remove(hs->inpa);
-	hs->inpa = 0;
-
-	if (cond == PURPLE_INPUT_READ && hs->is_ssl) {
-		hs->watch_cb = func;
-		hs->cb_data = user_data;
-		purple_ssl_input_add(hs->ssl_connection,
-			_purple_http_socket_watch_recv_ssl, hs);
-	}
-	else
-		hs->inpa = purple_input_add(hs->fd, cond, func, user_data);
-}
-
-static void
-purple_http_socket_dontwatch(PurpleHttpSocket *hs)
-{
-	g_return_if_fail(hs != NULL);
-
-	if (hs->inpa > 0)
-		purple_input_remove(hs->inpa);
-	hs->inpa = 0;
-	if (hs->ssl_connection)
-		purple_ssl_input_remove(hs->ssl_connection);
-}
-
 static void
 purple_http_socket_close_free(PurpleHttpSocket *hs)
 {
@@ -628,19 +493,7 @@
 	if (purple_debug_is_verbose())
 		purple_debug_misc("http", "destroying socket: %p\n", hs);
 
-	if (hs->inpa != 0)
-		purple_input_remove(hs->inpa);
-
-	if (hs->is_ssl) {
-		if (hs->ssl_connection != NULL)
-			purple_ssl_close(hs->ssl_connection);
-	} else {
-		if (hs->raw_connection != NULL)
-			purple_proxy_connect_cancel(hs->raw_connection);
-		if (hs->fd > 0)
-			close(hs->fd);
-	}
-
+	purple_socket_destroy(hs->ps);
 	g_free(hs);
 }
 
@@ -1226,7 +1079,7 @@
 	gchar buf[4096];
 	gboolean got_anything;
 
-	len = purple_http_socket_read(hc->socket, buf, sizeof(buf));
+	len = purple_socket_read(hc->socket->ps, (guchar*)buf, sizeof(buf));
 	got_anything = (len > 0);
 
 	if (len < 0 && errno == EAGAIN)
@@ -1489,8 +1342,8 @@
 		purple_debug_warning("http", "Nothing to write\n");
 		written = 0;
 	} else {
-		written = purple_http_socket_write(hc->socket, write_from,
-			write_len);
+		written = purple_socket_write(hc->socket->ps,
+			(const guchar*)write_from, write_len);
 	}
 
 	if (written < 0 && errno == EAGAIN)
@@ -1533,7 +1386,7 @@
 
 	/* request is completely written, let's read the response */
 	hc->is_reading = TRUE;
-	purple_http_socket_watch(hc->socket, PURPLE_INPUT_READ,
+	purple_socket_watch(hc->socket->ps, PURPLE_INPUT_READ,
 		_purple_http_recv, hc);
 }
 
@@ -1558,10 +1411,15 @@
 	}
 }
 
-static void  _purple_http_connected(PurpleHttpSocket *hs, const gchar *error, gpointer _hc)
+static void
+_purple_http_connected(PurpleSocket *ps, const gchar *error, gpointer _hc)
 {
+	PurpleHttpSocket *hs = NULL;
 	PurpleHttpConnection *hc = _hc;
 
+	if (ps != NULL)
+		hs = purple_socket_get_data(ps, "hs");
+
 	hc->socket_request = NULL;
 	hc->socket = hs;
 
@@ -1571,7 +1429,7 @@
 		return;
 	}
 
-	purple_http_socket_watch(hs, PURPLE_INPUT_WRITE, _purple_http_send, hc);
+	purple_socket_watch(hs->ps, PURPLE_INPUT_WRITE, _purple_http_send, hc);
 }
 
 static gboolean _purple_http_reconnect(PurpleHttpConnection *hc)
@@ -2273,7 +2131,7 @@
 static PurpleHttpKeepaliveRequest *
 purple_http_keepalive_pool_request(PurpleHttpKeepalivePool *pool,
 	PurpleConnection *gc, const gchar *host, int port, gboolean is_ssl,
-	PurpleHttpSocketConnectCb cb, gpointer user_data)
+	PurpleSocketConnectCb cb, gpointer user_data)
 {
 	PurpleHttpKeepaliveRequest *req;
 	PurpleHttpKeepaliveHost *kahost;
@@ -2316,15 +2174,19 @@
 }
 
 static void
-_purple_http_keepalive_socket_connected(PurpleHttpSocket *hs,
+_purple_http_keepalive_socket_connected(PurpleSocket *ps,
 	const gchar *error, gpointer _req)
 {
+	PurpleHttpSocket *hs = NULL;
 	PurpleHttpKeepaliveRequest *req = _req;
 
+	if (ps != NULL)
+		hs = purple_socket_get_data(ps, "hs");
+
 	if (hs != NULL)
 		hs->use_count++;
 
-	req->cb(hs, error, req->user_data);
+	req->cb(hs->ps, error, req->user_data);
 	g_free(req);
 }
 
@@ -2380,7 +2242,7 @@
 
 		purple_http_keepalive_host_process_queue(host);
 
-		req->cb(hs, NULL, req->user_data);
+		req->cb(hs->ps, NULL, req->user_data);
 		g_free(req);
 
 		return FALSE;
@@ -2428,7 +2290,7 @@
 		purple_http_socket_close_free(req->hs);
 		/* req should already be free'd here */
 	} else {
-		req->cb(req->hs, _("Cancelled"), req->user_data);
+		req->cb(NULL, _("Cancelled"), req->user_data);
 		g_free(req);
 	}
 }
@@ -2444,7 +2306,7 @@
 	if (purple_debug_is_verbose())
 		purple_debug_misc("http", "releasing a socket: %p\n", hs);
 
-	purple_http_socket_dontwatch(hs);
+	purple_socket_watch(hs->ps, 0, NULL, NULL);
 	hs->is_busy = FALSE;
 	host = hs->host;
 
--- a/libpurple/protocols/bonjour/bonjour.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/bonjour/bonjour.c	Thu Aug 29 23:01:58 2013 -0700
@@ -470,6 +470,14 @@
 	return (buddy != NULL && purple_buddy_get_protocol_data(buddy) != NULL);
 }
 
+static gsize
+bonjour_get_max_message_size(PurpleConnection *gc)
+{
+	/* It looks, like the message length is practically unlimited (I've
+	 * tried 5MB). */
+	return 0;
+}
+
 static gboolean
 plugin_unload(PurplePlugin *plugin)
 {
@@ -555,7 +563,8 @@
 	NULL,                                                    /* get_media_caps */
 	NULL,                                                    /* get_moods */
 	NULL,                                                    /* set_public_alias */
-	NULL                                                     /* get_public_alias */
+	NULL,                                                    /* get_public_alias */
+	bonjour_get_max_message_size                             /* get_max_message_size */
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/gg/gg.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/gg/gg.c	Thu Aug 29 23:01:58 2013 -0700
@@ -1369,6 +1369,13 @@
 	return table;
 }
 
+static gsize
+ggp_get_max_message_size(PurpleConnection *gc)
+{
+	/* it may depend on protocol version or other factors - check it */
+	return 1232;
+}
+
 static PurplePluginProtocolInfo prpl_info =
 {
 	sizeof(PurplePluginProtocolInfo),       /* struct_size */
@@ -1441,7 +1448,8 @@
 	NULL,				/* can_do_media */
 	NULL,				/* get_moods */
 	NULL,				/* set_public_alias */
-	NULL				/* get_public_alias */
+	NULL,				/* get_public_alias */
+	ggp_get_max_message_size	/* get_max_message_size */
 };
 
 static gboolean ggp_load(PurplePlugin *plugin);
--- a/libpurple/protocols/irc/irc.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/irc/irc.c	Thu Aug 29 23:01:58 2013 -0700
@@ -911,6 +911,13 @@
 		irc_cmd_ping(irc, NULL, NULL, NULL);
 }
 
+static gsize
+irc_get_max_message_size(PurpleConnection *gc)
+{
+	/* got from pidgin-otr */
+	return 417;
+}
+
 static PurplePluginProtocolInfo prpl_info =
 {
 	sizeof(PurplePluginProtocolInfo),    /* struct_size */
@@ -984,7 +991,8 @@
 	NULL,					 /* get_media_caps */
 	NULL,					 /* get_moods */
 	NULL,					 /* set_public_alias */
-	NULL					 /* get_public_alias */
+	NULL,					 /* get_public_alias */
+	irc_get_max_message_size		/* get_max_message_size */
 };
 
 static gboolean load_plugin (PurplePlugin *plugin) {
--- a/libpurple/protocols/jabber/libfacebook.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/jabber/libfacebook.c	Thu Aug 29 23:01:58 2013 -0700
@@ -133,7 +133,8 @@
 	NULL,							/* get_media_caps */
 	NULL,							/* get_moods */
 	NULL, /* set_public_alias */
-	NULL  /* get_public_alias */
+	NULL, /* get_public_alias */
+	NULL  /* get_max_message_size */
 };
 
 static gboolean load_plugin(PurplePlugin *plugin)
--- a/libpurple/protocols/jabber/libgtalk.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/jabber/libgtalk.c	Thu Aug 29 23:01:58 2013 -0700
@@ -133,7 +133,8 @@
 	jabber_get_media_caps,                  /* get_media_caps */
 	jabber_get_moods,  							/* get_moods */
 	NULL, /* set_public_alias */
-	NULL  /* get_public_alias */
+	NULL, /* get_public_alias */
+	NULL  /* get_max_message_size */
 };
 
 static gboolean load_plugin(PurplePlugin *plugin)
--- a/libpurple/protocols/jabber/libxmpp.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/jabber/libxmpp.c	Thu Aug 29 23:01:58 2013 -0700
@@ -127,7 +127,8 @@
 	jabber_get_media_caps,                  /* get_media_caps */
 	jabber_get_moods,  							/* get_moods */
 	NULL, /* set_public_alias */
-	NULL  /* get_public_alias */
+	NULL, /* get_public_alias */
+	NULL  /* get_max_message_size */
 };
 
 static gboolean load_plugin(PurplePlugin *plugin)
--- a/libpurple/protocols/msn/msn.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/msn/msn.c	Thu Aug 29 23:01:58 2013 -0700
@@ -2882,6 +2882,12 @@
 	return FALSE;
 }
 
+static gsize
+msn_get_max_message_size(PurpleConnection *gc)
+{
+	/* pidgin-otr says: 1409 */
+	return 1525 - strlen(VERSION);
+}
 
 static PurplePluginProtocolInfo prpl_info =
 {
@@ -2955,7 +2961,8 @@
 	NULL,                               /* get_media_caps */
 	NULL,                               /* get_moods */
 	msn_set_public_alias,               /* set_public_alias */
-	msn_get_public_alias                /* get_public_alias */
+	msn_get_public_alias,               /* get_public_alias */
+	msn_get_max_message_size            /* get_max_message_size */
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/mxit/mxit.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/mxit/mxit.c	Thu Aug 29 23:01:58 2013 -0700
@@ -793,7 +793,8 @@
 	mxit_media_caps,		/* get_media_caps */
 	mxit_get_moods,			/* get_moods */
 	NULL,					/* set_public_alias */
-	NULL					/* get_public_alias */
+	NULL,					/* get_public_alias */
+	NULL					/* get_max_message_size */
 };
 
 
--- a/libpurple/protocols/myspace/myspace.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/myspace/myspace.c	Thu Aug 29 23:01:58 2013 -0700
@@ -3080,7 +3080,8 @@
 	NULL,                   /* get_media_caps */
 	NULL,                   /* get_moods */
 	NULL,                   /* set_public_alias */
-	NULL                    /* get_public_alias */
+	NULL,                   /* get_public_alias */
+	NULL                    /* get_max_message_size */
 };
 
 /**
--- a/libpurple/protocols/novell/novell.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/novell/novell.c	Thu Aug 29 23:01:58 2013 -0700
@@ -3465,6 +3465,13 @@
 	_check_for_disconnect(user, rc);
 }
 
+static gsize
+novell_get_max_message_size(PurpleConnection *gc)
+{
+	/* got from pidgin-otr */
+	return 1792;
+}
+
 static PurplePluginProtocolInfo prpl_info = {
 	sizeof(PurplePluginProtocolInfo),       /* struct_size */
 	0,
@@ -3536,7 +3543,8 @@
 	NULL,						/* get_media_caps */
 	NULL,						/* get_moods */
 	NULL,						/* set_public_alias */
-	NULL						/* get_public_alias */
+	NULL,						/* get_public_alias */
+	novell_get_max_message_size			/* get_max_message_size */
 };
 
 static PurplePluginInfo info = {
--- a/libpurple/protocols/null/nullprpl.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/null/nullprpl.c	Thu Aug 29 23:01:58 2013 -0700
@@ -1130,7 +1130,8 @@
   NULL,                                /* get_media_caps */
   NULL,                                /* get_moods */
   NULL,                                /* set_public_alias */
-  NULL                                 /* get_public_alias */
+  NULL,                                /* get_public_alias */
+  NULL                                 /* get_max_message_size */
 };
 
 static void nullprpl_init(PurplePlugin *plugin)
--- a/libpurple/protocols/oscar/libaim.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/oscar/libaim.c	Thu Aug 29 23:01:58 2013 -0700
@@ -99,7 +99,8 @@
 	NULL,					/* get_media_caps */
 	NULL,					/* get_moods */
 	NULL,					/* set_public_alias */
-	NULL					/* get_public_alias */
+	NULL,					/* get_public_alias */
+	oscar_get_max_message_size		/* get_max_message_size */
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/oscar/libicq.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/oscar/libicq.c	Thu Aug 29 23:01:58 2013 -0700
@@ -36,6 +36,13 @@
 	return table;
 }
 
+static gsize
+icq_get_max_message_size(PurpleConnection *gc)
+{
+	/* got from pidgin-otr */
+	return 2346;
+}
+
 static PurplePluginProtocolInfo prpl_info =
 {
 	sizeof(PurplePluginProtocolInfo),       /* struct_size */
@@ -108,7 +115,8 @@
 	NULL,					/* can_do_media */
 	oscar_get_purple_moods, /* get_moods */
 	NULL,					/* set_public_alias */
-	NULL					/* get_public_alias */
+	NULL,					/* get_public_alias */
+	icq_get_max_message_size		/* get_max_message_size */
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/oscar/oscar.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/oscar/oscar.c	Thu Aug 29 23:01:58 2013 -0700
@@ -5433,6 +5433,13 @@
 	return TRUE;
 }
 
+gsize
+oscar_get_max_message_size(PurpleConnection *gc)
+{
+	/* got from pidgin-otr */
+	return 2343;
+}
+
 /* TODO: Find somewhere to put this instead of including it in a bunch of places.
  * Maybe just change purple_accounts_find() to return anything for the prpl if there is no acct_id.
  */
--- a/libpurple/protocols/oscar/oscarcommon.h	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/oscar/oscarcommon.h	Thu Aug 29 23:01:58 2013 -0700
@@ -102,5 +102,6 @@
 void oscar_send_file(PurpleConnection *gc, const char *who, const char *file);
 PurpleXfer *oscar_new_xfer(PurpleConnection *gc, const char *who);
 gboolean oscar_offline_message(const PurpleBuddy *buddy);
+gsize oscar_get_max_message_size(PurpleConnection *gc);
 GList *oscar_actions(PurplePlugin *plugin, gpointer context);
 void oscar_init(PurplePlugin *plugin, gboolean is_icq);
--- a/libpurple/protocols/sametime/sametime.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/sametime/sametime.c	Thu Aug 29 23:01:58 2013 -0700
@@ -5160,6 +5160,7 @@
   NULL,
   NULL,
   NULL,
+  NULL,
   NULL
 };
 
--- a/libpurple/protocols/silc/silc.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/silc/silc.c	Thu Aug 29 23:01:58 2013 -0700
@@ -2125,7 +2125,8 @@
 	NULL,				        /* get_media_caps */
 	NULL,				        /* get_moods */
 	NULL,				        /* set_public_alias */
-	NULL				        /* get_public_alias */
+	NULL,				        /* get_public_alias */
+	NULL					/* get_max_message_size */
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/simple/simple.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/simple/simple.c	Thu Aug 29 23:01:58 2013 -0700
@@ -2116,7 +2116,8 @@
 	NULL,					/* get_media_caps */
 	NULL,					/* get_moods */
 	NULL,					/* set_public_alias */
-	NULL					/* get_public_alias */
+	NULL,					/* get_public_alias */
+	NULL					/* get_max_message_size */
 };
 
 
--- a/libpurple/protocols/yahoo/libyahoo.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/yahoo/libyahoo.c	Thu Aug 29 23:01:58 2013 -0700
@@ -264,7 +264,8 @@
 	NULL,  /* get_media_caps */
 	NULL,  /* get_moods */
 	NULL,  /* set_public_alias */
-	NULL   /* get_public_alias */
+	NULL,  /* get_public_alias */
+	yahoo_get_max_message_size
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/yahoo/libyahoojp.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/yahoo/libyahoojp.c	Thu Aug 29 23:01:58 2013 -0700
@@ -162,7 +162,8 @@
 	NULL, /* get_media_caps */
 	NULL, /* get_moods */
 	NULL, /* set_public_alias */
-	NULL  /* get_public_alias */
+	NULL, /* get_public_alias */
+	yahoo_get_max_message_size
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/yahoo/libymsg.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/yahoo/libymsg.c	Thu Aug 29 23:01:58 2013 -0700
@@ -5134,3 +5134,9 @@
 	return list;
 }
 
+gsize
+yahoo_get_max_message_size(PurpleConnection *gc)
+{
+	/* got from pidgin-otr */
+	return 799;
+}
--- a/libpurple/protocols/yahoo/libymsg.h	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/yahoo/libymsg.h	Thu Aug 29 23:01:58 2013 -0700
@@ -384,6 +384,7 @@
 
 GList *yahoo_actions(PurplePlugin *plugin, gpointer context);
 void yahoopurple_register_commands(void);
+gsize yahoo_get_max_message_size(PurpleConnection *gc);
 
 PurpleCmdRet yahoopurple_cmd_buzz(PurpleConversation *c, const gchar *cmd, gchar **args, gchar **error, void *data);
 PurpleCmdRet yahoopurple_cmd_chat_join(PurpleConversation *conv, const char *cmd, char **args, char **error, void *data);
--- a/libpurple/protocols/zephyr/zephyr.c	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/protocols/zephyr/zephyr.c	Thu Aug 29 23:01:58 2013 -0700
@@ -2943,7 +2943,8 @@
 	NULL,					/* get_media_caps */
 	NULL,					/* get_moods */
 	NULL,					/* set_public_alias */
-	NULL					/* get_public_alias */
+	NULL,					/* get_public_alias */
+	NULL					/* get_max_message_size */
 };
 
 static PurplePluginInfo info = {
--- a/libpurple/prpl.h	Thu Aug 29 22:59:30 2013 -0700
+++ b/libpurple/prpl.h	Thu Aug 29 23:01:58 2013 -0700
@@ -628,6 +628,21 @@
 	void (*get_public_alias)(PurpleConnection *gc,
 	                         PurpleGetPublicAliasSuccessCallback success_cb,
 	                         PurpleGetPublicAliasFailureCallback failure_cb);
+
+	/**
+	 * Gets the maximum message size in bytes for the protocol. It may
+	 * depend on connection-specific variables (like protocol version).
+	 *
+	 * This value is intended for plaintext message, the exact value may be
+	 * lower because of:
+	 *  - used newlines (some protocols count them as more than one byte),
+	 *  - formatting,
+	 *  - used special characters.
+	 *
+	 * @param gc The connection to query, or NULL to get safe minimum.
+	 * @return   Maximum message size, or 0 if unspecified or infinite.
+	 */
+	gsize (*get_max_message_size)(PurpleConnection *gc);
 };
 
 #define PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl, member) \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purple-socket.c	Thu Aug 29 23:01:58 2013 -0700
@@ -0,0 +1,354 @@
+/**
+ * @file purple-socket.c Generic sockets
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "purple-socket.h"
+
+#include "internal.h"
+
+#include "debug.h"
+#include "proxy.h"
+#include "sslconn.h"
+
+typedef enum {
+	PURPLE_SOCKET_STATE_DISCONNECTED = 0,
+	PURPLE_SOCKET_STATE_CONNECTING,
+	PURPLE_SOCKET_STATE_CONNECTED,
+	PURPLE_SOCKET_STATE_ERROR
+} PurpleSocketState;
+
+struct _PurpleSocket
+{
+	PurpleConnection *gc;
+	gchar *host;
+	int port;
+	gboolean is_tls;
+	GHashTable *data;
+
+	PurpleSocketState state;
+
+	PurpleSslConnection *tls_connection;
+	PurpleProxyConnectData *raw_connection;
+	int fd;
+	guint inpa;
+
+	PurpleSocketConnectCb cb;
+	gpointer cb_data;
+};
+
+PurpleSocket *
+purple_socket_new(PurpleConnection *gc)
+{
+	PurpleSocket *ps = g_new0(PurpleSocket, 1);
+
+	ps->gc = gc;
+	ps->fd = -1;
+	ps->port = -1;
+	ps->data = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+
+	return ps;
+}
+
+PurpleConnection *
+purple_socket_get_connection(PurpleSocket *ps)
+{
+	g_return_val_if_fail(ps != NULL, NULL);
+
+	return ps->gc;
+}
+
+static gboolean
+purple_socket_check_state(PurpleSocket *ps, PurpleSocketState wanted_state)
+{
+	g_return_val_if_fail(ps != NULL, FALSE);
+
+	if (ps->state == wanted_state)
+		return TRUE;
+
+	purple_debug_error("socket", "invalid state: %d (should be: %d)",
+		ps->state, wanted_state);
+	ps->state = PURPLE_SOCKET_STATE_ERROR;
+	return FALSE;
+}
+
+void
+purple_socket_set_tls(PurpleSocket *ps, gboolean is_tls)
+{
+	g_return_if_fail(ps != NULL);
+
+	if (!purple_socket_check_state(ps, PURPLE_SOCKET_STATE_DISCONNECTED))
+		return;
+
+	ps->is_tls = is_tls;
+}
+
+void
+purple_socket_set_host(PurpleSocket *ps, const gchar *host)
+{
+	g_return_if_fail(ps != NULL);
+
+	if (!purple_socket_check_state(ps, PURPLE_SOCKET_STATE_DISCONNECTED))
+		return;
+
+	g_free(ps->host);
+	ps->host = g_strdup(host);
+}
+
+void
+purple_socket_set_port(PurpleSocket *ps, int port)
+{
+	g_return_if_fail(ps != NULL);
+	g_return_if_fail(port >= 0);
+	g_return_if_fail(port <= 65535);
+
+	if (!purple_socket_check_state(ps, PURPLE_SOCKET_STATE_DISCONNECTED))
+		return;
+
+	ps->port = port;
+}
+
+static void
+_purple_socket_connected_raw(gpointer _ps, gint fd, const gchar *error_message)
+{
+	PurpleSocket *ps = _ps;
+
+	ps->raw_connection = NULL;
+
+	if (!purple_socket_check_state(ps, PURPLE_SOCKET_STATE_CONNECTING)) {
+		if (fd > 0)
+			close(fd);
+		ps->cb(ps, _("Invalid socket state"), ps->cb_data);
+		return;
+	}
+
+	if (fd <= 0 || error_message != NULL) {
+		if (error_message == NULL)
+			error_message = _("Unknown error");
+		ps->fd = -1;
+		ps->state = PURPLE_SOCKET_STATE_ERROR;
+		ps->cb(ps, error_message, ps->cb_data);
+		return;
+	}
+
+	ps->state = PURPLE_SOCKET_STATE_CONNECTED;
+	ps->fd = fd;
+	ps->cb(ps, NULL, ps->cb_data);
+}
+
+static void
+_purple_socket_connected_tls(gpointer _ps, PurpleSslConnection *tls_connection,
+	PurpleInputCondition cond)
+{
+	PurpleSocket *ps = _ps;
+
+	if (!purple_socket_check_state(ps, PURPLE_SOCKET_STATE_CONNECTING)) {
+		purple_ssl_close(tls_connection);
+		ps->tls_connection = NULL;
+		ps->cb(ps, _("Invalid socket state"), ps->cb_data);
+		return;
+	}
+
+	if (ps->tls_connection->fd <= 0) {
+		ps->state = PURPLE_SOCKET_STATE_ERROR;
+		purple_ssl_close(tls_connection);
+		ps->tls_connection = NULL;
+		ps->cb(ps, _("Invalid file descriptor"), ps->cb_data);
+		return;
+	}
+
+	ps->state = PURPLE_SOCKET_STATE_CONNECTED;
+	ps->fd = ps->tls_connection->fd;
+	ps->cb(ps, NULL, ps->cb_data);
+}
+
+static void
+_purple_socket_connected_tls_error(PurpleSslConnection *ssl_connection,
+	PurpleSslErrorType error, gpointer _ps)
+{
+	PurpleSocket *ps = _ps;
+
+	ps->state = PURPLE_SOCKET_STATE_ERROR;
+	ps->tls_connection = NULL;
+	ps->cb(ps, purple_ssl_strerror(error), ps->cb_data);
+}
+
+gboolean
+purple_socket_connect(PurpleSocket *ps, PurpleSocketConnectCb cb,
+	gpointer user_data)
+{
+	PurpleAccount *account = NULL;
+
+	g_return_val_if_fail(ps != NULL, FALSE);
+
+	if (!purple_socket_check_state(ps, PURPLE_SOCKET_STATE_DISCONNECTED))
+		return FALSE;
+	ps->state = PURPLE_SOCKET_STATE_CONNECTING;
+
+	if (ps->host == NULL || ps->port < 0) {
+		purple_debug_error("socket", "Host or port is not specified");
+		ps->state = PURPLE_SOCKET_STATE_ERROR;
+		return FALSE;
+	}
+
+	if (ps->gc != NULL)
+		account = purple_connection_get_account(ps->gc);
+
+	ps->cb = cb;
+	ps->cb_data = user_data;
+
+	if (ps->is_tls) {
+		if (!purple_ssl_is_supported()) {
+			purple_debug_error("socket", "TLS is not supported");
+			ps->state = PURPLE_SOCKET_STATE_ERROR;
+			return FALSE;
+		}
+
+		ps->tls_connection = purple_ssl_connect(account, ps->host,
+			ps->port, _purple_socket_connected_tls,
+			_purple_socket_connected_tls_error, ps);
+	} else {
+		ps->raw_connection = purple_proxy_connect(ps->gc, account,
+			ps->host, ps->port, _purple_socket_connected_raw, ps);
+	}
+
+	if (ps->tls_connection == NULL &&
+		ps->raw_connection == NULL)
+	{
+		ps->state = PURPLE_SOCKET_STATE_ERROR;
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+gssize
+purple_socket_read(PurpleSocket *ps, guchar *buf, size_t len)
+{
+	g_return_val_if_fail(ps != NULL, -1);
+	g_return_val_if_fail(buf != NULL, -1);
+
+	if (!purple_socket_check_state(ps, PURPLE_SOCKET_STATE_CONNECTED))
+		return -1;
+
+	if (ps->is_tls)
+		return purple_ssl_read(ps->tls_connection, buf, len);
+	else
+		return read(ps->fd, buf, len);
+}
+
+gssize
+purple_socket_write(PurpleSocket *ps, const guchar *buf, size_t len)
+{
+	g_return_val_if_fail(ps != NULL, -1);
+	g_return_val_if_fail(buf != NULL, -1);
+
+	if (!purple_socket_check_state(ps, PURPLE_SOCKET_STATE_CONNECTED))
+		return -1;
+
+	if (ps->is_tls)
+		return purple_ssl_write(ps->tls_connection, buf, len);
+	else
+		return write(ps->fd, buf, len);
+}
+
+void
+purple_socket_watch(PurpleSocket *ps, PurpleInputCondition cond,
+	PurpleInputFunction func, gpointer user_data)
+{
+	g_return_if_fail(ps != NULL);
+
+	if (!purple_socket_check_state(ps, PURPLE_SOCKET_STATE_CONNECTED))
+		return;
+
+	if (ps->inpa > 0)
+		purple_input_remove(ps->inpa);
+	ps->inpa = 0;
+
+	g_return_if_fail(ps->fd > 0);
+
+	if (func != NULL)
+		ps->inpa = purple_input_add(ps->fd, cond, func, user_data);
+}
+
+int
+purple_socket_get_fd(PurpleSocket *ps)
+{
+	g_return_val_if_fail(ps != NULL, -1);
+
+	if (!purple_socket_check_state(ps, PURPLE_SOCKET_STATE_CONNECTED))
+		return -1;
+
+	g_return_val_if_fail(ps->fd > 0, -1);
+
+	return ps->fd;
+}
+
+void
+purple_socket_set_data(PurpleSocket *ps, const gchar *key, gpointer data)
+{
+	g_return_if_fail(ps != NULL);
+	g_return_if_fail(key != NULL);
+
+	if (data == NULL)
+		g_hash_table_remove(ps->data, key);
+	else
+		g_hash_table_insert(ps->data, g_strdup(key), data);
+}
+
+gpointer
+purple_socket_get_data(PurpleSocket *ps, const gchar *key)
+{
+	g_return_val_if_fail(ps != NULL, NULL);
+	g_return_val_if_fail(key != NULL, NULL);
+
+	return g_hash_table_lookup(ps->data, key);
+}
+
+void
+purple_socket_destroy(PurpleSocket *ps)
+{
+	if (ps == NULL)
+		return;
+
+	g_free(ps->host);
+
+	if (ps->inpa > 0)
+		purple_input_remove(ps->inpa);
+	ps->inpa = 0;
+
+	if (ps->tls_connection != NULL) {
+		purple_ssl_close(ps->tls_connection);
+		ps->fd = -1;
+	}
+
+	if (ps->raw_connection != NULL)
+		purple_proxy_connect_cancel(ps->raw_connection);
+
+	if (ps->fd > 0)
+		close(ps->fd);
+
+	g_hash_table_destroy(ps->data);
+	g_free(ps);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purple-socket.h	Thu Aug 29 23:01:58 2013 -0700
@@ -0,0 +1,200 @@
+/**
+ * @file purple-socket.h Generic sockets
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#ifndef _PURPLE_SOCKET_H_
+#define _PURPLE_SOCKET_H_
+
+#include "connection.h"
+
+/**
+ * A structure holding all resources needed for the TCP connection.
+ */
+typedef struct _PurpleSocket PurpleSocket;
+
+/**
+ * A callback fired after (successfully or not) establishing a connection.
+ *
+ * @param ps        The socket.
+ * @param error     Error message, or NULL if connection was successful.
+ * @param user_data The user data passed with callback function.
+ */
+typedef void (*PurpleSocketConnectCb)(PurpleSocket *ps, const gchar *error,
+	gpointer user_data);
+
+/**
+ * Creates new, disconnected socket.
+ *
+ * Passing a PurpleConnection allows for proper proxy handling.
+ *
+ * @param gs The connection for which the socket is needed, or NULL.
+ *
+ * @return   The new socket struct.
+ */
+PurpleSocket *
+purple_socket_new(PurpleConnection *gc);
+
+/**
+ * Gets PurpleConnection tied with specified socket.
+ *
+ * @param ps The socket.
+ *
+ * @return   The PurpleConnection object.
+ */
+PurpleConnection *
+purple_socket_get_connection(PurpleSocket *ps);
+
+/**
+ * Determines, if socket should handle TLS.
+ *
+ * @param ps     The socket.
+ * @param is_tls TRUE, if TLS should be handled transparently, FALSE otherwise.
+ */
+void
+purple_socket_set_tls(PurpleSocket *ps, gboolean is_tls);
+
+/**
+ * Sets connection host.
+ *
+ * @param ps   The socket.
+ * @param host The connection host.
+ */
+void
+purple_socket_set_host(PurpleSocket *ps, const gchar *host);
+
+/**
+ * Sets connection port.
+ *
+ * @param ps   The socket.
+ * @param port The connection port.
+ */
+void
+purple_socket_set_port(PurpleSocket *ps, int port);
+
+/**
+ * Establishes a connection.
+ *
+ * @param ps        The socket.
+ * @param cb        The function to call after establishing a connection, or on
+ *                  error.
+ * @param user_data The user data to be passed to callback function.
+ *
+ * @return TRUE on success (this doesn't mean it's connected yet), FALSE
+ *         otherwise.
+ */
+gboolean
+purple_socket_connect(PurpleSocket *ps, PurpleSocketConnectCb cb,
+	gpointer user_data);
+
+/**
+ * Reads incoming data from socket.
+ *
+ * This function deals with TLS, if the socket is configured to do it.
+ *
+ * @param ps  The socket.
+ * @param buf The buffer to write data to.
+ * @param len The buffer size.
+ *
+ * @return Amount of data written, or -1 on error (errno will be also be set).
+ */
+gssize
+purple_socket_read(PurpleSocket *ps, guchar *buf, size_t len);
+
+/**
+ * Sends data through socket.
+ *
+ * This function deals with TLS, if the socket is configured to do it.
+ *
+ * @param ps  The socket.
+ * @param buf The buffer to read data from.
+ * @param len The amount of data to read and send.
+ *
+ * @param Amount of data sent, or -1 on error (errno will albo be set).
+ */
+gssize
+purple_socket_write(PurpleSocket *ps, const guchar *buf, size_t len);
+
+/**
+ * Adds an input handler for the socket.
+ *
+ * If the specified socket had input handler already registered, it will be
+ * removed. To remove any input handlers, pass an NULL handler function.
+ *
+ * @param ps        The socket.
+ * @param cond      The condition type.
+ * @param func      The callback function for data, or NULL to remove any
+ *                  existing callbacks.
+ * @param user_data The user data to be passed to callback function.
+ */
+void
+purple_socket_watch(PurpleSocket *ps, PurpleInputCondition cond,
+	PurpleInputFunction func, gpointer user_data);
+
+/**
+ * Gets underlying file descriptor for socket.
+ *
+ * It's not meant to read/write data (use purple_socket_read/
+ * purple_socket_write), rather for watching for changes with select().
+ *
+ * @param ps The socket
+ *
+ * @return The file descriptor, or -1 on error.
+ */
+int
+purple_socket_get_fd(PurpleSocket *ps);
+
+/**
+ * Sets extra data for a socket.
+ *
+ * @param ps   The socket.
+ * @param key  The unique key.
+ * @param data The data to assign, or NULL to remove.
+ */
+void
+purple_socket_set_data(PurpleSocket *ps, const gchar *key, gpointer data);
+
+/**
+ * Returns extra data in a socket.
+ *
+ * @param ps  The socket.
+ * @param key The unqiue key.
+ *
+ * @return The data associated with the key.
+ */
+gpointer
+purple_socket_get_data(PurpleSocket *ps, const gchar *key);
+
+/**
+ * Destroys the socket, closes connection and frees all resources.
+ *
+ * If file descriptor for the socket was extracted with purple_socket_get_fd and
+ * added to event loop, it have to be removed prior this.
+ *
+ * @param ps The socket.
+ */
+void
+purple_socket_destroy(PurpleSocket *ps);
+
+#endif /* _PURPLE_SOCKET_H_ */

mercurial