From 4bff1463869934e1b2ea83d166746bea08045714 Mon Sep 17 00:00:00 2001 From: dequis Date: Mon, 21 Nov 2016 10:16:25 -0300 Subject: VERSION: update to c9b74a765767 Relevant changes: https://bitbucket.org/pidgin/main/pull-requests/167 * fb_api_cb_contacts: Make all the other fields optional too * fb_http_urlcmp: more loose comparison, to avoid showing urls twice * Prevent disconnections on 509 errors, "Invalid attachment id" * Make $.hugePictureUrl.uri optional * Store sent message id in lastmid, to deduplicate echoed messages --- MANIFEST_PIDGIN | 1 - VERSION | 2 +- patches/02-glibcompat.patch | 28 +- patches/05-revert-http-callbacks.patch | 42 +++ patches/06-revert-purple-socket.patch | 637 +++++++++++++++++++++++++++++++++ patches/07-revert-http-gio.patch | 430 ++++++++++++++++++++++ 6 files changed, 1122 insertions(+), 18 deletions(-) create mode 100644 patches/05-revert-http-callbacks.patch create mode 100644 patches/06-revert-purple-socket.patch create mode 100644 patches/07-revert-http-gio.patch diff --git a/MANIFEST_PIDGIN b/MANIFEST_PIDGIN index 391033b..dd29b52 100644 --- a/MANIFEST_PIDGIN +++ b/MANIFEST_PIDGIN @@ -26,4 +26,3 @@ libpurple/protocols/facebook/util.c libpurple/protocols/facebook/util.h libpurple/purple-socket.c libpurple/purple-socket.h -share/ca-certs/GTE_CyberTrust_Global_Root.pem diff --git a/VERSION b/VERSION index 714caa5..a76e224 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -56d191003b34 +c9b74a765767 diff --git a/patches/02-glibcompat.patch b/patches/02-glibcompat.patch index 4669b77..663ab0c 100644 --- a/patches/02-glibcompat.patch +++ b/patches/02-glibcompat.patch @@ -1,12 +1,11 @@ -diff -r 1852eb9052a0 libpurple/glibcompat.h ---- a/libpurple/glibcompat.h Fri Dec 25 15:20:41 2015 -0500 -+++ b/libpurple/glibcompat.h Fri Dec 25 15:49:07 2015 -0500 -@@ -61,6 +61,33 @@ - return FALSE; - } - -+#if !GLIB_CHECK_VERSION(2, 32, 0) +--- a/libpurple/glibcompat.h 2016-11-21 09:38:39.250858177 -0300 ++++ b/libpurple/glibcompat.h 2016-11-21 09:39:44.789845560 -0300 +@@ -66,6 +66,30 @@ + /****************************************************************************** + * g_assert_* macros + *****************************************************************************/ + ++#if !GLIB_CHECK_VERSION(2, 32, 0) +static inline GByteArray * g_byte_array_new_take(guint8 *data, gsize len) +{ + GByteArray *array; @@ -23,15 +22,12 @@ diff -r 1852eb9052a0 libpurple/glibcompat.h + g_queue_foreach(queue, (GFunc)free_func, NULL); + g_queue_free(queue); +} ++#endif + +#if !GLIB_CHECK_VERSION(2, 30, 0) -+ +#define G_VALUE_INIT {0, {{0}}} ++#endif + -+#endif /* < 2.30.0 */ -+ -+#endif /* < 2.32.0 */ -+ - #endif /* < 2.36.0 */ - - + #if !GLIB_CHECK_VERSION(2, 38, 0) + #define g_assert_true(expr) G_STMT_START { \ + if G_LIKELY (expr) ; else \ diff --git a/patches/05-revert-http-callbacks.patch b/patches/05-revert-http-callbacks.patch new file mode 100644 index 0000000..36d1d17 --- /dev/null +++ b/patches/05-revert-http-callbacks.patch @@ -0,0 +1,42 @@ +diff --git a/libpurple/http.c b/libpurple/http.c +--- a/libpurple/http.c ++++ b/libpurple/http.c +@@ -486,11 +486,7 @@ purple_http_socket_connect_new_cb(GObjec + cb_data = g_object_steal_data(source, "cb_data"); + + if (conn == NULL) { +- if (!g_error_matches(error, +- G_IO_ERROR, G_IO_ERROR_CANCELLED)) { +- cb(hs, error->message, cb_data); +- } +- ++ cb(hs, error->message, cb_data); + g_clear_error(&error); + return; + } +@@ -1162,10 +1158,8 @@ static gboolean _purple_http_recv_loopbo + &error); + got_anything = (len > 0); + +- if (len < 0 && (g_error_matches(error, +- G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) || +- g_error_matches(error, +- G_IO_ERROR, G_IO_ERROR_CANCELLED))) { ++ if (len < 0 && g_error_matches(error, ++ G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { + g_clear_error(&error); + return FALSE; + } +@@ -1450,10 +1444,8 @@ static gboolean _purple_http_send(GObjec + &error); + } + +- if (written < 0 && (g_error_matches(error, +- G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) || +- g_error_matches(error, +- G_IO_ERROR, G_IO_ERROR_CANCELLED))) { ++ if (written < 0 && g_error_matches(error, ++ G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { + g_clear_error(&error); + return G_SOURCE_CONTINUE; + } diff --git a/patches/06-revert-purple-socket.patch b/patches/06-revert-purple-socket.patch new file mode 100644 index 0000000..230ccd0 --- /dev/null +++ b/patches/06-revert-purple-socket.patch @@ -0,0 +1,637 @@ +diff --git a/libpurple/purple-socket.c b/libpurple/purple-socket.c +new file mode 100644 +--- /dev/null ++++ b/libpurple/purple-socket.c +@@ -0,0 +1,410 @@ ++/* 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; ++}; ++ ++static GHashTable *handles = NULL; ++ ++static void ++handle_add(PurpleSocket *ps) ++{ ++ PurpleConnection *gc = ps->gc; ++ GSList *l; ++ ++ l = g_hash_table_lookup(handles, gc); ++ l = g_slist_prepend(l, ps); ++ g_hash_table_insert(handles, gc, l); ++} ++ ++static void ++handle_remove(PurpleSocket *ps) ++{ ++ PurpleConnection *gc = ps->gc; ++ GSList *l; ++ ++ l = g_hash_table_lookup(handles, gc); ++ l = g_slist_remove(l, ps); ++ g_hash_table_insert(handles, gc, l); ++} ++ ++void ++_purple_socket_init(void) ++{ ++ handles = g_hash_table_new(g_direct_hash, g_direct_equal); ++} ++ ++void ++_purple_socket_uninit(void) ++{ ++ g_hash_table_destroy(handles); ++ handles = NULL; ++} ++ ++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); ++ ++ handle_add(ps); ++ ++ 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 (ps->gc && purple_connection_is_disconnecting(ps->gc)) { ++ purple_debug_error("socket", "connection is being destroyed"); ++ ps->state = PURPLE_SOCKET_STATE_ERROR; ++ return 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) { ++ 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); ++} ++ ++static void ++purple_socket_cancel(PurpleSocket *ps) ++{ ++ 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; ++ } ++ ps->tls_connection = NULL; ++ ++ if (ps->raw_connection != NULL) ++ purple_proxy_connect_cancel(ps->raw_connection); ++ ps->raw_connection = NULL; ++ ++ if (ps->fd > 0) ++ close(ps->fd); ++ ps->fd = 0; ++} ++ ++void ++purple_socket_destroy(PurpleSocket *ps) ++{ ++ if (ps == NULL) ++ return; ++ ++ handle_remove(ps); ++ ++ purple_socket_cancel(ps); ++ ++ g_free(ps->host); ++ g_hash_table_destroy(ps->data); ++ g_free(ps); ++} ++ ++void ++_purple_socket_cancel_with_connection(PurpleConnection *gc) ++{ ++ GSList *it; ++ ++ it = g_hash_table_lookup(handles, gc); ++ for (; it; it = g_slist_next(it)) { ++ PurpleSocket *ps = it->data; ++ purple_socket_cancel(ps); ++ } ++} +diff --git a/libpurple/purple-socket.h b/libpurple/purple-socket.h +new file mode 100644 +--- /dev/null ++++ b/libpurple/purple-socket.h +@@ -0,0 +1,217 @@ ++/* 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_ ++/** ++ * SECTION:purple-socket ++ * @section_id: libpurple-purple-socket ++ * @short_description: purple-socket.h ++ * @title: Generic Sockets ++ */ ++ ++#include "connection.h" ++ ++/** ++ * PurpleSocket: ++ * ++ * A structure holding all resources needed for the TCP connection. ++ */ ++typedef struct _PurpleSocket PurpleSocket; ++ ++/** ++ * PurpleSocketConnectCb: ++ * @ps: The socket. ++ * @error: Error message, or NULL if connection was successful. ++ * @user_data: The user data passed with callback function. ++ * ++ * A callback fired after (successfully or not) establishing a connection. ++ */ ++typedef void (*PurpleSocketConnectCb)(PurpleSocket *ps, const gchar *error, ++ gpointer user_data); ++ ++/** ++ * purple_socket_new: ++ * @gc: The connection for which the socket is needed, or NULL. ++ * ++ * Creates new, disconnected socket. ++ * ++ * Passing a PurpleConnection allows for proper proxy handling. ++ * ++ * Returns: The new socket struct. ++ */ ++PurpleSocket * ++purple_socket_new(PurpleConnection *gc); ++ ++/** ++ * purple_socket_get_connection: ++ * @ps: The socket. ++ * ++ * Gets PurpleConnection tied with specified socket. ++ * ++ * Returns: The PurpleConnection object. ++ */ ++PurpleConnection * ++purple_socket_get_connection(PurpleSocket *ps); ++ ++/** ++ * purple_socket_set_tls: ++ * @ps: The socket. ++ * @is_tls: TRUE, if TLS should be handled transparently, FALSE otherwise. ++ * ++ * Determines, if socket should handle TLS. ++ */ ++void ++purple_socket_set_tls(PurpleSocket *ps, gboolean is_tls); ++ ++/** ++ * purple_socket_set_host: ++ * @ps: The socket. ++ * @host: The connection host. ++ * ++ * Sets connection host. ++ */ ++void ++purple_socket_set_host(PurpleSocket *ps, const gchar *host); ++ ++/** ++ * purple_socket_set_port: ++ * @ps: The socket. ++ * @port: The connection port. ++ * ++ * Sets connection port. ++ */ ++void ++purple_socket_set_port(PurpleSocket *ps, int port); ++ ++/** ++ * purple_socket_connect: ++ * @ps: The socket. ++ * @cb: The function to call after establishing a connection, or on ++ * error. ++ * @user_data: The user data to be passed to callback function. ++ * ++ * Establishes a connection. ++ * ++ * Returns: TRUE on success (this doesn't mean it's connected yet), FALSE ++ * otherwise. ++ */ ++gboolean ++purple_socket_connect(PurpleSocket *ps, PurpleSocketConnectCb cb, ++ gpointer user_data); ++ ++/** ++ * purple_socket_read: ++ * @ps: The socket. ++ * @buf: The buffer to write data to. ++ * @len: The buffer size. ++ * ++ * Reads incoming data from socket. ++ * ++ * This function deals with TLS, if the socket is configured to do it. ++ * ++ * Returns: 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); ++ ++/** ++ * purple_socket_write: ++ * @ps: The socket. ++ * @buf: The buffer to read data from. ++ * @len: The amount of data to read and send. ++ * ++ * Sends data through socket. ++ * ++ * This function deals with TLS, if the socket is configured to do it. ++ * ++ * Returns: 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); ++ ++/** ++ * purple_socket_watch: ++ * @ps: The socket. ++ * @cond: The condition type. ++ * @func: The callback function for data, or NULL to remove any ++ * existing callbacks. ++ * @user_data: The user data to be passed to callback function. ++ * ++ * 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. ++ */ ++void ++purple_socket_watch(PurpleSocket *ps, PurpleInputCondition cond, ++ PurpleInputFunction func, gpointer user_data); ++ ++/** ++ * purple_socket_get_fd: ++ * @ps: The socket ++ * ++ * 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(). ++ * ++ * Returns: The file descriptor, or -1 on error. ++ */ ++int ++purple_socket_get_fd(PurpleSocket *ps); ++ ++/** ++ * purple_socket_set_data: ++ * @ps: The socket. ++ * @key: The unique key. ++ * @data: The data to assign, or NULL to remove. ++ * ++ * Sets extra data for a socket. ++ */ ++void ++purple_socket_set_data(PurpleSocket *ps, const gchar *key, gpointer data); ++ ++/** ++ * purple_socket_get_data: ++ * @ps: The socket. ++ * @key: The unqiue key. ++ * ++ * Returns extra data in a socket. ++ * ++ * Returns: The data associated with the key. ++ */ ++gpointer ++purple_socket_get_data(PurpleSocket *ps, const gchar *key); ++ ++/** ++ * purple_socket_destroy: ++ * @ps: The socket. ++ * ++ * 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. ++ */ ++void ++purple_socket_destroy(PurpleSocket *ps); ++ ++#endif /* _PURPLE_SOCKET_H_ */ diff --git a/patches/07-revert-http-gio.patch b/patches/07-revert-http-gio.patch new file mode 100644 index 0000000..9bfb0d8 --- /dev/null +++ b/patches/07-revert-http-gio.patch @@ -0,0 +1,430 @@ +diff --git a/libpurple/http.c b/libpurple/http.c +--- a/libpurple/http.c ++++ b/libpurple/http.c +@@ -28,7 +28,7 @@ + #include "debug.h" + #include "ntlm.h" + #include "proxy.h" +-#include "purple-gio.h" ++#include "purple-socket.h" + + #include + #ifndef z_const +@@ -57,15 +57,9 @@ typedef struct _PurpleHttpKeepaliveReque + + typedef struct _PurpleHttpGzStream PurpleHttpGzStream; + +-typedef void (*PurpleHttpSocketConnectCb)(PurpleHttpSocket *hs, +- const gchar *error, gpointer _hc); +- + struct _PurpleHttpSocket + { +- GSocketConnection *conn; +- GCancellable *cancellable; +- guint input_source; +- guint output_source; ++ PurpleSocket *ps; + + gboolean is_busy; + guint use_count; +@@ -181,7 +175,7 @@ struct _PurpleHttpCookieJar + struct _PurpleHttpKeepaliveRequest + { + PurpleConnection *gc; +- PurpleHttpSocketConnectCb cb; ++ PurpleSocketConnectCb cb; + gpointer user_data; + + PurpleHttpKeepaliveHost *host; +@@ -253,7 +247,7 @@ gchar * purple_http_cookie_jar_dump(Purp + 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 +@@ -469,65 +463,23 @@ purple_http_socket_hash(const gchar *hos + return g_strdup_printf("%c:%s:%d", (is_ssl ? 'S' : 'R'), host, port); + } + +-static void +-purple_http_socket_connect_new_cb(GObject *source, GAsyncResult *res, +- gpointer user_data) +-{ +- PurpleHttpSocket *hs = user_data; +- GSocketConnection *conn; +- PurpleHttpSocketConnectCb cb; +- gpointer cb_data; +- GError *error = NULL; +- +- conn = g_socket_client_connect_to_host_finish(G_SOCKET_CLIENT(source), +- res, &error); +- +- cb = g_object_steal_data(source, "cb"); +- cb_data = g_object_steal_data(source, "cb_data"); +- +- if (conn == NULL) { +- cb(hs, error->message, cb_data); +- g_clear_error(&error); +- return; +- } +- +- hs->conn = conn; +- +- cb(hs, NULL, cb_data); +-} +- + static PurpleHttpSocket * + purple_http_socket_connect_new(PurpleConnection *gc, const gchar *host, +- int port, gboolean is_ssl, +- PurpleHttpSocketConnectCb cb, gpointer user_data) ++ int port, gboolean is_ssl, PurpleSocketConnectCb cb, gpointer user_data) + { +- PurpleHttpSocket *hs; +- GSocketClient *client; +- GError *error = NULL; +- +- client = purple_gio_socket_client_new( +- purple_connection_get_account(gc), &error); +- +- if (client == NULL) { +- purple_debug_error("http", "Error connecting to '%s:%d': %s", +- host, port, error->message); +- g_clear_error(&error); ++ PurpleHttpSocket *hs = g_new0(PurpleHttpSocket, 1); ++ ++ 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; + } + +- hs = g_new0(PurpleHttpSocket, 1); +- hs->cancellable = g_cancellable_new(); +- +- g_socket_client_set_tls(client, is_ssl); +- g_object_set_data(G_OBJECT(client), "cb", cb); +- g_object_set_data(G_OBJECT(client), "cb_data", user_data); +- +- g_socket_client_connect_to_host_async(client, +- host, port, hs->cancellable, +- purple_http_socket_connect_new_cb, hs); +- +- g_object_unref(client); +- + if (purple_debug_is_verbose()) + purple_debug_misc("http", "new socket created: %p\n", hs); + +@@ -543,26 +495,7 @@ purple_http_socket_close_free(PurpleHttp + if (purple_debug_is_verbose()) + purple_debug_misc("http", "destroying socket: %p\n", hs); + +- if (hs->input_source > 0) { +- g_source_remove(hs->input_source); +- hs->input_source = 0; +- } +- +- if (hs->output_source > 0) { +- g_source_remove(hs->output_source); +- hs->output_source = 0; +- } +- +- if (hs->cancellable != NULL) { +- g_cancellable_cancel(hs->cancellable); +- g_clear_object(&hs->cancellable); +- } +- +- if (hs->conn != NULL) { +- purple_gio_graceful_close(G_IO_STREAM(hs->conn), NULL, NULL); +- g_clear_object(&hs->conn); +- } +- ++ purple_socket_destroy(hs->ps); + g_free(hs); + } + +@@ -749,9 +682,10 @@ static void _purple_http_disconnect(Purp + gboolean is_graceful); + + static void _purple_http_gen_headers(PurpleHttpConnection *hc); +-static gboolean _purple_http_recv_loopbody(PurpleHttpConnection *hc); +-static gboolean _purple_http_recv(GObject *source, gpointer _hc); +-static gboolean _purple_http_send(GObject *source, gpointer _hc); ++static gboolean _purple_http_recv_loopbody(PurpleHttpConnection *hc, gint fd); ++static void _purple_http_recv(gpointer _hc, gint fd, ++ PurpleInputCondition cond); ++static void _purple_http_send(gpointer _hc, gint fd, PurpleInputCondition cond); + + /* closes current connection (if exists), estabilishes one and proceeds with + * request */ +@@ -1143,31 +1077,21 @@ static gboolean _purple_http_recv_body(P + return _purple_http_recv_body_data(hc, buf, len); + } + +-static gboolean _purple_http_recv_loopbody(PurpleHttpConnection *hc) ++static gboolean _purple_http_recv_loopbody(PurpleHttpConnection *hc, gint fd) + { + int len; + gchar buf[4096]; + gboolean got_anything; +- GError *error = NULL; +- +- len = g_pollable_input_stream_read_nonblocking( +- G_POLLABLE_INPUT_STREAM( +- g_io_stream_get_input_stream( +- G_IO_STREAM(hc->socket->conn))), +- buf, sizeof(buf), hc->socket->cancellable, +- &error); ++ ++ len = purple_socket_read(hc->socket->ps, (guchar*)buf, sizeof(buf)); + got_anything = (len > 0); + +- if (len < 0 && g_error_matches(error, +- G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { +- g_clear_error(&error); ++ if (len < 0 && errno == EAGAIN) + return FALSE; +- } + + if (len < 0) { + _purple_http_error(hc, _("Error reading from %s: %s"), +- hc->url->host, error->message); +- g_clear_error(&error); ++ hc->url->host, g_strerror(errno)); + return FALSE; + } + +@@ -1346,13 +1270,11 @@ static gboolean _purple_http_recv_loopbo + return got_anything; + } + +-static gboolean _purple_http_recv(GObject *source, gpointer _hc) ++static void _purple_http_recv(gpointer _hc, gint fd, PurpleInputCondition cond) + { + PurpleHttpConnection *hc = _hc; + +- while (_purple_http_recv_loopbody(hc)); +- +- return G_SOURCE_CONTINUE; ++ while (_purple_http_recv_loopbody(hc, fd)); + } + + static void _purple_http_send_got_data(PurpleHttpConnection *hc, +@@ -1383,19 +1305,17 @@ static void _purple_http_send_got_data(P + hc->request->contents_length = estimated_length; + } + +-static gboolean _purple_http_send(GObject *source, gpointer _hc) ++static void _purple_http_send(gpointer _hc, gint fd, PurpleInputCondition cond) + { + PurpleHttpConnection *hc = _hc; + int written, write_len; + const gchar *write_from; + gboolean writing_headers; +- GError *error = NULL; +- GSource *gsource; + + /* Waiting for data. This could be written more efficiently, by removing + * (and later, adding) hs->inpa. */ + if (hc->contents_reader_requested) +- return G_SOURCE_CONTINUE; ++ return; + + _purple_http_gen_headers(hc); + +@@ -1408,7 +1328,7 @@ static gboolean _purple_http_send(GObjec + hc->request_header_written; + } else if (hc->request->contents_reader) { + if (hc->contents_reader_requested) +- return G_SOURCE_CONTINUE; /* waiting for data */ ++ return; /* waiting for data */ + if (!hc->contents_reader_buffer) + hc->contents_reader_buffer = g_string_new(""); + if (hc->contents_reader_buffer->len == 0) { +@@ -1421,7 +1341,7 @@ static gboolean _purple_http_send(GObjec + PURPLE_HTTP_MAX_READ_BUFFER_LEN, + hc->request->contents_reader_data, + _purple_http_send_got_data); +- return G_SOURCE_CONTINUE; ++ return; + } + write_from = hc->contents_reader_buffer->str; + write_len = hc->contents_reader_buffer->len; +@@ -1436,19 +1356,12 @@ static gboolean _purple_http_send(GObjec + purple_debug_warning("http", "Nothing to write\n"); + written = 0; + } else { +- written = g_pollable_output_stream_write_nonblocking( +- G_POLLABLE_OUTPUT_STREAM( +- g_io_stream_get_output_stream( +- G_IO_STREAM(hc->socket->conn))), +- write_from, write_len, hc->socket->cancellable, +- &error); ++ written = purple_socket_write(hc->socket->ps, ++ (const guchar*)write_from, write_len); + } + +- if (written < 0 && g_error_matches(error, +- G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { +- g_clear_error(&error); +- return G_SOURCE_CONTINUE; +- } ++ if (written < 0 && errno == EAGAIN) ++ return; + + if (written < 0) { + if (hc->request_header_written == 0 && +@@ -1457,22 +1370,21 @@ static gboolean _purple_http_send(GObjec + purple_debug_info("http", "Keep-alive connection " + "expired (when writing), retrying...\n"); + purple_http_conn_retry(hc); +- } else { +- _purple_http_error(hc, _("Error writing to %s: %s"), +- hc->url->host, error->message); ++ return; + } + +- g_clear_error(&error); +- return G_SOURCE_CONTINUE; ++ _purple_http_error(hc, _("Error writing to %s: %s"), ++ hc->url->host, g_strerror(errno)); ++ return; + } + + if (writing_headers) { + hc->request_header_written += written; + purple_http_conn_notify_progress_watcher(hc); + if (hc->request_header_written < hc->request_header->len) +- return G_SOURCE_CONTINUE; ++ return; + if (hc->request->contents_length > 0) +- return G_SOURCE_CONTINUE; ++ return; + } else { + hc->request_contents_written += written; + purple_http_conn_notify_progress_watcher(hc); +@@ -1482,24 +1394,14 @@ static gboolean _purple_http_send(GObjec + hc->request_contents_written < + (guint)hc->request->contents_length) + { +- return G_SOURCE_CONTINUE; ++ return; + } + } + + /* request is completely written, let's read the response */ + hc->is_reading = TRUE; +- gsource = g_pollable_input_stream_create_source( +- G_POLLABLE_INPUT_STREAM( +- g_io_stream_get_input_stream( +- G_IO_STREAM(hc->socket->conn))), +- NULL); +- g_source_set_callback(gsource, +- (GSourceFunc)_purple_http_recv, hc, NULL); +- hc->socket->input_source = g_source_attach(gsource, NULL); +- g_source_unref(gsource); +- +- hc->socket->output_source = 0; +- return G_SOURCE_REMOVE; ++ purple_socket_watch(hc->socket->ps, PURPLE_INPUT_READ, ++ _purple_http_recv, hc); + } + + static void _purple_http_disconnect(PurpleHttpConnection *hc, +@@ -1524,10 +1426,13 @@ static void _purple_http_disconnect(Purp + } + + static void +-_purple_http_connected(PurpleHttpSocket *hs, const gchar *error, gpointer _hc) ++_purple_http_connected(PurpleSocket *ps, const gchar *error, gpointer _hc) + { ++ PurpleHttpSocket *hs = NULL; + PurpleHttpConnection *hc = _hc; +- GSource *source; ++ ++ if (ps != NULL) ++ hs = purple_socket_get_data(ps, "hs"); + + hc->socket_request = NULL; + hc->socket = hs; +@@ -1538,14 +1443,7 @@ static void + return; + } + +- source = g_pollable_output_stream_create_source( +- G_POLLABLE_OUTPUT_STREAM( +- g_io_stream_get_output_stream(G_IO_STREAM(hs->conn))), +- NULL); +- g_source_set_callback(source, +- (GSourceFunc)_purple_http_send, hc, NULL); +- hc->socket->output_source = g_source_attach(source, NULL); +- g_source_unref(source); ++ purple_socket_watch(ps, PURPLE_INPUT_WRITE, _purple_http_send, hc); + } + + static gboolean _purple_http_reconnect(PurpleHttpConnection *hc) +@@ -2257,7 +2155,7 @@ purple_http_keepalive_pool_unref(PurpleH + 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; +@@ -2300,15 +2198,19 @@ purple_http_keepalive_pool_request(Purpl + } + + 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(ps, error, req->user_data); + g_free(req); + } + +@@ -2364,7 +2266,7 @@ static gboolean + + 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; +@@ -2435,16 +2337,7 @@ purple_http_keepalive_pool_release(Purpl + if (purple_debug_is_verbose()) + purple_debug_misc("http", "releasing a socket: %p\n", hs); + +- if (hs->input_source > 0) { +- g_source_remove(hs->input_source); +- hs->input_source = 0; +- } +- +- if (hs->output_source > 0) { +- g_source_remove(hs->output_source); +- hs->output_source = 0; +- } +- ++ purple_socket_watch(hs->ps, 0, NULL, NULL); + hs->is_busy = FALSE; + host = hs->host; + -- cgit v1.2.3