Thu, 29 Aug 2013 23:01:58 -0700
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_ */