Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating to the latest hg #523

Open
wants to merge 1 commit into
base: libpurple-integration
Choose a base branch
from

Conversation

1ay1
Copy link

@1ay1 1ay1 commented Jun 13, 2021

No description provided.

@av1934413
Copy link

``From 63f48e9 Mon Sep 17 00:00:00 2001
From: Ayush tfeayush@gmail.com
Date: Sun, 13 Jun 2021 16:55:21 +0530
Subject: [PATCH] Updating to the latest hg


.gitignore | 1 +
pidgin/libpurple/glibcompat.h | 27 ++
pidgin/libpurple/http.c | 305 +++++----------
.../libpurple/protocols/facebook/Makefile.am | 30 +-
.../protocols/facebook/Makefile.mingw | 20 +-
pidgin/libpurple/protocols/facebook/api.c | 80 ++--
pidgin/libpurple/protocols/facebook/api.h | 4 +-
pidgin/libpurple/protocols/facebook/data.c | 4 +-
.../libpurple/protocols/facebook/facebook.c | 250 ++++++-------
.../libpurple/protocols/facebook/facebook.h | 50 ---
pidgin/libpurple/protocols/facebook/http.c | 2 +-
pidgin/libpurple/protocols/facebook/json.c | 3 +-
pidgin/libpurple/protocols/facebook/mqtt.c | 346 ++++++++----------
pidgin/libpurple/protocols/facebook/mqtt.h | 17 +
pidgin/libpurple/protocols/facebook/thrift.c | 3 +-
15 files changed, 515 insertions(+), 627 deletions(-)

diff --git a/.gitignore b/.gitignore
index a632a291..db0c607c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,4 @@ Makefile
Makefile.in
pidgin
win32-install-dir
+.idea
\ No newline at end of file
diff --git a/pidgin/libpurple/glibcompat.h b/pidgin/libpurple/glibcompat.h
index ccc303d4..03826511 100644
--- a/pidgin/libpurple/glibcompat.h
+++ b/pidgin/libpurple/glibcompat.h
@@ -71,6 +71,30 @@ purple_g_stat(const gchar filename, GStatBufW32 buf)
/
****************************************************************************

  • g_assert_* macros
    *****************************************************************************/

+#if !GLIB_CHECK_VERSION(2, 32, 0)
+static inline GByteArray * g_byte_array_new_take(guint8 *data, gsize len)
+{

  • GByteArray *array;
  • array = g_byte_array_new();
  • g_byte_array_append(array, data, len);
  • g_free(data);
  • return array;
    +}

+static inline void g_queue_free_full(GQueue *queue, GDestroyNotify free_func)
+{

  • 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
+
#if !GLIB_CHECK_VERSION(2, 38, 0)
#define g_assert_true(expr) G_STMT_START {
if G_LIKELY (expr) ; else
@@ -86,6 +110,9 @@ purple_g_stat(const gchar *filename, GStatBufW32 *buf)
g_assertion_message (G_LOG_DOMAIN, FILE, LINE, G_STRFUNC,
"'" #expr "' should be NULL");
} G_STMT_END
+#define G_ADD_PRIVATE(TypeName) G_STMT_START { } G_STMT_END
+#else
+#define g_type_class_add_private(k,s) G_STMT_START { } G_STMT_END
#endif

#if !GLIB_CHECK_VERSION(2, 40, 0)
diff --git a/pidgin/libpurple/http.c b/pidgin/libpurple/http.c
index fd882947..75e390ab 100644
--- a/pidgin/libpurple/http.c
+++ b/pidgin/libpurple/http.c
@@ -27,7 +27,12 @@

#include "debug.h"
#include "proxy.h"
-#include "purple-gio.h"
+#include "purple-socket.h"
+
+#include <zlib.h>
+#ifndef z_const
+#define z_const
+#endif

#define PURPLE_HTTP_URL_CREDENTIALS_CHARS "a-z0-9.,~_/*!&%?=+\^-"
#define PURPLE_HTTP_MAX_RECV_BUFFER_LEN 10240
@@ -51,15 +56,9 @@ typedef struct _PurpleHttpKeepaliveRequest PurpleHttpKeepaliveRequest;

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;
    @@ -175,7 +174,7 @@ struct _PurpleHttpCookieJar
    struct _PurpleHttpKeepaliveRequest
    {
    PurpleConnection *gc;

  • PurpleHttpSocketConnectCb cb;
  • PurpleSocketConnectCb cb;
    gpointer user_data;

    PurpleHttpKeepaliveHost *host;
    @@ -218,7 +217,7 @@ struct _PurpleHttpConnectionSet
    struct _PurpleHttpGzStream
    {
    gboolean failed;

  • GZlibDecompressor *decompressor;
  • z_stream zs;
    gsize max_output;
    gsize decompressed;
    GString *pending;
    @@ -266,7 +265,7 @@ gchar * purple_http_cookie_jar_dump(PurpleHttpCookieJar *cjar);
    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
    @@ -366,14 +365,19 @@ static PurpleHttpGzStream *
    purple_http_gz_new(gsize max_output, gboolean is_deflate)
    {
    PurpleHttpGzStream *gzs = g_new0(PurpleHttpGzStream, 1);
  • GZlibCompressorFormat format;
  • int windowBits;

    if (is_deflate)

  •   format = G_ZLIB_COMPRESSOR_FORMAT_RAW;
    
  •   windowBits = -MAX_WBITS;
    
    else /* is gzip */
  •   format = G_ZLIB_COMPRESSOR_FORMAT_GZIP;
    
  •   windowBits = MAX_WBITS + 32;
    
  • if (inflateInit2(&gzs->zs, windowBits) != Z_OK) {
  •   purple_debug_error("http", "Cannot initialize zlib stream\n");
    
  •   g_free(gzs);
    
  •   return NULL;
    
  • }
  • gzs->decompressor = g_zlib_decompressor_new(format);
    gzs->max_output = max_output;

    return gzs;
    @@ -385,6 +389,7 @@ purple_http_gz_put(PurpleHttpGzStream *gzs, const gchar *buf, gsize len)
    const gchar *compressed_buff;
    gsize compressed_len;
    GString *ret;

  • z_stream *zs;

    g_return_val_if_fail(gzs != NULL, NULL);
    g_return_val_if_fail(buf != NULL, NULL);
    @@ -392,6 +397,8 @@ purple_http_gz_put(PurpleHttpGzStream *gzs, const gchar *buf, gsize len)
    if (gzs->failed)
    return NULL;

  • zs = &gzs->zs;

  • if (gzs->pending) {
    g_string_append_len(gzs->pending, buf, len);
    compressed_buff = gzs->pending->str;
    @@ -401,26 +408,22 @@ purple_http_gz_put(PurpleHttpGzStream *gzs, const gchar *buf, gsize len)
    compressed_len = len;
    }

  • zs->next_in = (z_const Bytef*)compressed_buff;

  • zs->avail_in = compressed_len;

  • ret = g_string_new(NULL);

  • while (compressed_len > 0) {
  •   GConverterResult gzres;
    
  • while (zs->avail_in > 0) {
  •   int gzres;
      gchar decompressed_buff[PURPLE_HTTP_GZ_BUFF_LEN];
    
  •   gsize decompressed_len = 0;
    
  •   gsize bytes_read = 0;
    
  •   GError *error = NULL;
    
  •   gzres = g_converter_convert(G_CONVERTER(gzs->decompressor),
    
  •   	       compressed_buff, compressed_len,
    
  •          	       decompressed_buff, sizeof(decompressed_buff),
    
  •   	       G_CONVERTER_NO_FLAGS,
    
  •   	       &bytes_read,
    
  •   	       &decompressed_len,
    
  •   	       &error);
    
  •   compressed_buff += bytes_read;
    
  •   compressed_len -= bytes_read;
    
  •   if (gzres == G_CONVERTER_CONVERTED || G_CONVERTER_FINISHED) {
    
  •   gsize decompressed_len;
    
  •   zs->next_out = (Bytef*)decompressed_buff;
    
  •   zs->avail_out = sizeof(decompressed_buff);
    
  •   decompressed_len = zs->avail_out = sizeof(decompressed_buff);
    
  •   gzres = inflate(zs, Z_FULL_FLUSH);
    
  •   decompressed_len -= zs->avail_out;
    
  •   if (gzres == Z_OK || gzres == Z_STREAM_END) {
      	if (decompressed_len == 0)
      		break;
      	if (gzs->decompressed + decompressed_len >=
    

@@ -430,18 +433,17 @@ purple_http_gz_put(PurpleHttpGzStream *gzs, const gchar *buf, gsize len)
" decompressed data is reached\n");
decompressed_len = gzs->max_output -
gzs->decompressed;

  •   		gzres = G_CONVERTER_FINISHED;
    
  •   		gzres = Z_STREAM_END;
      	}
      	gzs->decompressed += decompressed_len;
      	g_string_append_len(ret, decompressed_buff,
      		decompressed_len);
    
  •   	if (gzres == G_CONVERTER_FINISHED)
    
  •   	if (gzres == Z_STREAM_END)
      		break;
      } else {
      	purple_debug_error("http",
      		"Decompression failed (%d): %s\n", gzres,
    
  •   		error->message);
    
  •   	g_clear_error(&error);
    
  •   		zs->msg);
      	gzs->failed = TRUE;
      	return NULL;
      }
    

@@ -452,9 +454,9 @@ purple_http_gz_put(PurpleHttpGzStream *gzs, const gchar *buf, gsize len)
gzs->pending = NULL;
}

  • if (compressed_len > 0) {
  •   gzs->pending = g_string_new_len(compressed_buff,
    
  •   	compressed_len);
    
  • if (zs->avail_in > 0) {

  •   gzs->pending = g_string_new_len((gchar*)zs->next_in,
    
  •   	zs->avail_in);
    

    }

    return ret;
    @@ -465,7 +467,7 @@ purple_http_gz_free(PurpleHttpGzStream *gzs)
    {
    if (gzs == NULL)
    return;

  • g_object_unref(gzs->decompressor);
  • inflateEnd(&gzs->zs);
    if (gzs->pending)
    g_string_free(gzs->pending, TRUE);
    g_free(gzs);
    @@ -529,69 +531,23 @@ purple_http_socket_hash(const gchar *host, int port, gboolean is_ssl)
    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) {
  •   if (!g_error_matches(error,
    
  •   		G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
    
  •   	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)
    

-{

  • 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);
    
  • int port, gboolean is_ssl, PurpleSocketConnectCb cb, gpointer user_data)
    +{
  • 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);

@@ -607,26 +563,7 @@ purple_http_socket_close_free(PurpleHttpSocket *hs)
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);
    }

@@ -813,9 +750,10 @@ static void _purple_http_disconnect(PurpleHttpConnection *hc,
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 */
    @@ -1208,33 +1146,21 @@ static gboolean _purple_http_recv_body(PurpleHttpConnection *hc,
    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_error_matches(error,
    
  •   	G_IO_ERROR, G_IO_ERROR_CANCELLED))) {
    
  •   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;
    
    }

@@ -1413,13 +1339,11 @@ static gboolean _purple_http_recv_loopbody(PurpleHttpConnection *hc)
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,
@@ -1450,19 +1374,17 @@ static void _purple_http_send_got_data(PurpleHttpConnection *hc,
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);

@@ -1475,7 +1397,7 @@ static gboolean _purple_http_send(GObject *source, gpointer _hc)
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) {
    

@@ -1488,7 +1410,7 @@ static gboolean _purple_http_send(GObject *source, gpointer _hc)
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;
    

@@ -1503,21 +1425,12 @@ static gboolean _purple_http_send(GObject *source, gpointer _hc)
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_error_matches(error,
    
  •   	G_IO_ERROR, G_IO_ERROR_CANCELLED))) {
    
  •   g_clear_error(&error);
    
  •   return G_SOURCE_CONTINUE;
    
  • }
  • if (written < 0 && errno == EAGAIN)

  •   return;
    

    if (written < 0) {
    if (hc->request_header_written == 0 &&
    @@ -1526,22 +1439,21 @@ static gboolean _purple_http_send(GObject *source, gpointer _hc)
    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);
    @@ -1551,24 +1463,14 @@ static gboolean _purple_http_send(GObject *source, gpointer _hc)
    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,
@@ -1593,10 +1495,13 @@ static void _purple_http_disconnect(PurpleHttpConnection *hc,
}

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;
    @@ -1607,14 +1512,7 @@ _purple_http_connected(PurpleHttpSocket *hs, const gchar *error, gpointer _hc)
    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)
@@ -2326,7 +2224,7 @@ purple_http_keepalive_pool_unref(PurpleHttpKeepalivePool *pool)
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;
    @@ -2369,15 +2267,19 @@ purple_http_keepalive_pool_request(PurpleHttpKeepalivePool *pool,
    }

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);
    }

@@ -2433,7 +2335,7 @@ _purple_http_keepalive_host_process_queue_cb(gpointer _host)

	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;
    

@@ -2504,16 +2406,7 @@ purple_http_keepalive_pool_release(PurpleHttpSocket *hs, gboolean invalidate)
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;

diff --git a/pidgin/libpurple/protocols/facebook/Makefile.am b/pidgin/libpurple/protocols/facebook/Makefile.am
index 268e8efc..87dd0825 100644
--- a/pidgin/libpurple/protocols/facebook/Makefile.am
+++ b/pidgin/libpurple/protocols/facebook/Makefile.am
@@ -1,9 +1,12 @@
EXTRA_DIST = \

  • Makefile.mingw
  • Makefile.mingw \
  • marshaller.list

pkgdir = @PURPLE_PLUGINDIR@

FACEBOOKSOURCES = \

  • marshal.c \
  • marshal.h
    api.c
    api.h
    data.c
    @@ -20,7 +23,23 @@ FACEBOOKSOURCES =
    thrift.c
    thrift.h
    util.c \
  • util.h
  • util.h \
  • ../../glibcompat.h \
  • ../../http.c \
  • ../../http.h \
  • ../../purple-socket.h \
  • ../../purple-socket.c

+CLEANFILES = \

  • marshal.c \
  • marshal.h

+marshal.c: $(srcdir)/marshaller.list marshal.h

  • $(AM_V_GEN)echo "#include "marshal.h"" &gt; $@
  • $(AM_V_at)$(GLIB_GENMARSHAL) --prefix=fb_marshal --body $(srcdir)/marshaller.list &gt;&gt; $@

+marshal.h: $(srcdir)/marshaller.list

  • $(AM_V_GEN)$(GLIB_GENMARSHAL) --prefix=fb_marshal --header $(srcdir)/marshaller.list &gt; $@

AM_CFLAGS = $(st)

@@ -43,10 +62,9 @@ libfacebook_la_LIBADD = @PURPLE_LIBS@ $(JSON_LIBS)
endif

AM_CPPFLAGS = \

  • -I$(top_srcdir)/libpurple \
  • -I$(top_builddir)/libpurple \
  • -I$(top_srcdir)
    $(GLIB_CFLAGS)
    $(JSON_CFLAGS) \
  • $(GPLUGIN_CFLAGS) \
  • $(PURPLE_CFLAGS) \
  • $(ZLIB_CFLAGS) \
  • $(PLUGIN_CFLAGS)
    $(DEBUG_CFLAGS)
    diff --git a/pidgin/libpurple/protocols/facebook/Makefile.mingw b/pidgin/libpurple/protocols/facebook/Makefile.mingw
    index c2aaad84..181937ff 100644
    --- a/pidgin/libpurple/protocols/facebook/Makefile.mingw
    +++ b/pidgin/libpurple/protocols/facebook/Makefile.mingw
    @@ -42,6 +42,7 @@ LIB_PATHS += -L$(GTK_TOP)/lib \

SOURCES, OBJECTS

C_SRC = \

  •   	marshal.c \
      	api.c \
      	data.c \
      	facebook.c \
    

@@ -49,7 +50,9 @@ C_SRC =
json.c
mqtt.c
thrift.c \

  •   	util.c
    
  •   	util.c \
    
  •   	../../http.c \
    
  •   	../../purple-socket.c
    

OBJECTS = $(C_SRC:%.c=%.o)

@@ -62,7 +65,6 @@ LIBS =
-lgobject-2.0
-lws2_32
-lintl \

  •   	-lgplugin \
      	-ljson-glib-1.0 \
      	-lz \
      	-lpurple
    

@@ -76,19 +78,27 @@ include $(PIDGIN_COMMON_RULES)

all: $(TARGET).dll

-install: all $(DLL_INSTALL_DIR)
+install: all
cp $(TARGET).dll $(DLL_INSTALL_DIR)

$(OBJECTS): $(PURPLE_CONFIG_H)

-$(TARGET).dll: $(PURPLE_DLL).a $(OBJECTS)
+$(TARGET).dll: $(OBJECTS)
$(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -o $(TARGET).dll

+marshal.c: marshaller.list marshal.h

  • @echo "#include "marshal.h"" > $@
  • @$(GLIB_GENMARSHAL) --prefix=fb_marshal --body marshaller.list >> $@

+marshal.h: marshaller.list

  • @$(GLIB_GENMARSHAL) --prefix=fb_marshal --header marshaller.list > $@

CLEAN RULES

clean:

  • rm -f $(OBJECTS)
  • rm -f $(OBJECTS) marshal.c marshal.h
    rm -f $(TARGET).dll

include $(PIDGIN_COMMON_TARGETS)
diff --git a/pidgin/libpurple/protocols/facebook/api.c b/pidgin/libpurple/protocols/facebook/api.c
index 163a4884..445714bb 100644
--- a/pidgin/libpurple/protocols/facebook/api.c
+++ b/pidgin/libpurple/protocols/facebook/api.c
@@ -28,6 +28,7 @@
#include "api.h"
#include "http.h"
#include "json.h"
+#include "marshal.h"
#include "thrift.h"
#include "util.h"

@@ -91,7 +92,7 @@ fb_api_sticker(FbApi *api, FbId sid, FbApiMessage *msg);
void
fb_api_contacts_delta(FbApi *api, const gchar *delta_cursor);

-G_DEFINE_TYPE(FbApi, fb_api, G_TYPE_OBJECT);
+G_DEFINE_TYPE_WITH_CODE(FbApi, fb_api, G_TYPE_OBJECT, G_ADD_PRIVATE(FbApi));

static void
fb_api_set_property(GObject *obj, guint prop, const GValue *val,
@@ -291,7 +292,8 @@ fb_api_class_init(FbApiClass *klass)
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_ACTION,
0,

  •            NULL, NULL, NULL,
    
  •            NULL, NULL,
    
  •            fb_marshal_VOID__VOID,
               G_TYPE_NONE,
               0);
    

@@ -306,7 +308,8 @@ fb_api_class_init(FbApiClass *klass)
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_ACTION,
0,

  •            NULL, NULL, NULL,
    
  •            NULL, NULL,
    
  •            fb_marshal_VOID__VOID,
               G_TYPE_NONE,
               0);
    

@@ -322,7 +325,8 @@ fb_api_class_init(FbApiClass *klass)
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_ACTION,
0,

  •            NULL, NULL, NULL,
    
  •            NULL, NULL,
    
  •            fb_marshal_VOID__POINTER,
               G_TYPE_NONE,
               1, G_TYPE_POINTER);
    

@@ -342,7 +346,8 @@ fb_api_class_init(FbApiClass *klass)
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_ACTION,
0,

  •            NULL, NULL, NULL,
    
  •            NULL, NULL,
    
  •            fb_marshal_VOID__POINTER_BOOLEAN,
               G_TYPE_NONE,
               2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
    

@@ -358,7 +363,8 @@ fb_api_class_init(FbApiClass *klass)
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_ACTION,
0,

  •            NULL, NULL, NULL,
    
  •            NULL, NULL,
    
  •            fb_marshal_VOID__POINTER_POINTER,
               G_TYPE_NONE,
               2, G_TYPE_POINTER, G_TYPE_POINTER);
    

@@ -374,7 +380,8 @@ fb_api_class_init(FbApiClass *klass)
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_ACTION,
0,

  •            NULL, NULL, NULL,
    
  •            NULL, NULL,
    
  •            fb_marshal_VOID__POINTER,
               G_TYPE_NONE,
               1, G_TYPE_POINTER);
    

@@ -389,7 +396,8 @@ fb_api_class_init(FbApiClass *klass)
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_ACTION,
0,

  •            NULL, NULL, NULL,
    
  •            NULL, NULL,
    
  •            fb_marshal_VOID__POINTER,
               G_TYPE_NONE,
               1, G_TYPE_POINTER);
    

@@ -404,7 +412,8 @@ fb_api_class_init(FbApiClass *klass)
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_ACTION,
0,

  •            NULL, NULL, NULL,
    
  •            NULL, NULL,
    
  •            fb_marshal_VOID__POINTER,
               G_TYPE_NONE,
               1, G_TYPE_POINTER);
    

@@ -419,7 +428,8 @@ fb_api_class_init(FbApiClass *klass)
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_ACTION,
0,

  •            NULL, NULL, NULL,
    
  •            NULL, NULL,
    
  •            fb_marshal_VOID__POINTER,
               G_TYPE_NONE,
               1, G_TYPE_POINTER);
    

@@ -435,7 +445,8 @@ fb_api_class_init(FbApiClass *klass)
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_ACTION,
0,

  •            NULL, NULL, NULL,
    
  •            NULL, NULL,
    
  •            fb_marshal_VOID__POINTER,
               G_TYPE_NONE,
               1, G_TYPE_POINTER);
    

@@ -452,7 +463,8 @@ fb_api_class_init(FbApiClass *klass)
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_ACTION,
0,

  •            NULL, NULL, NULL,
    
  •            NULL, NULL,
    
  •            fb_marshal_VOID__INT64,
               G_TYPE_NONE,
               1, FB_TYPE_ID);
    

@@ -468,7 +480,8 @@ fb_api_class_init(FbApiClass *klass)
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_ACTION,
0,

  •            NULL, NULL, NULL,
    
  •            NULL, NULL,
    
  •            fb_marshal_VOID__POINTER,
               G_TYPE_NONE,
               1, G_TYPE_POINTER);
    

@@ -484,7 +497,8 @@ fb_api_class_init(FbApiClass *klass)
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_ACTION,
0,

  •            NULL, NULL, NULL,
    
  •            NULL, NULL,
    
  •            fb_marshal_VOID__POINTER,
               G_TYPE_NONE,
               1, G_TYPE_POINTER);
    

@@ -499,7 +513,8 @@ fb_api_class_init(FbApiClass *klass)
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_ACTION,
0,

  •            NULL, NULL, NULL,
    
  •            NULL, NULL,
    
  •            fb_marshal_VOID__POINTER,
               G_TYPE_NONE,
               1, G_TYPE_POINTER);
    

}
@@ -1486,6 +1501,23 @@ fb_api_cb_publish_ms_new_message(FbApi *api, JsonNode *root, GSList *msgs, GErro
static GSList *
fb_api_cb_publish_ms_event(FbApi *api, JsonNode *root, GSList *events, FbApiEventType type, GError **error);

+static void
+fb_api_cb_publish_mst(FbThrift *thft, GError **error)
+{

  • if (fb_thrift_read_isstop(thft)) {
  •   FB_API_TCHK(fb_thrift_read_stop(thft));
    
  • } else {
  •   FbThriftType type;
    
  •   gint16 id;
    
  •   FB_API_TCHK(fb_thrift_read_field(thft, &type, &id, 0));
    
  •   FB_API_TCHK(type == FB_THRIFT_TYPE_STRING);
    
  •   // FB_API_TCHK(id == 2);
    
  •   FB_API_TCHK(fb_thrift_read_str(thft, NULL));
    
  •   FB_API_TCHK(fb_thrift_read_stop(thft));
    
  • }
    +}

static void
fb_api_cb_publish_ms(FbApi *api, GByteArray *pload)
{
@@ -1516,10 +1548,14 @@ fb_api_cb_publish_ms(FbApi *api, GByteArray *pload)

/* Read identifier string (for Facebook employees) */
thft = fb_thrift_new(pload, 0);
  • fb_thrift_read_str(thft, NULL);
  • fb_api_cb_publish_mst(thft, &err);
    size = fb_thrift_get_pos(thft);
    g_object_unref(thft);

  • FB_API_ERROR_EMIT(api, err,

  •   return;
    
  • );

  • g_return_if_fail(size < pload->len);
    data = (gchar *) pload->data + size;
    size = pload->len - size;
    @@ -1829,10 +1865,10 @@ fb_api_cb_publish_pt(FbThrift *thft, GSList **press, GError **error)
    pres->active = i32 != 0;
    *press = g_slist_prepend(*press, pres);

  •   fb_util_debug_info("Presence: %" FB_ID_FORMAT " (%d)",
    
  •                      i64, i32 != 0);
    
  •   fb_util_debug_info("Presence: %" FB_ID_FORMAT " (%d) id: %d",
    
  •                      i64, i32 != 0, id);
    
  •   while (id <= 5) {
    
  •   while (id <= 6) {
      	if (fb_thrift_read_isstop(thft)) {
      		break;
      	}
    

@@ -1879,7 +1915,9 @@ fb_api_cb_publish_pt(FbThrift *thft, GSList **press, GError **error)
}

/* Read the field stop */
  • FB_API_TCHK(fb_thrift_read_stop(thft));
  • if (fb_thrift_read_isstop(thft)) {
  •   FB_API_TCHK(fb_thrift_read_stop(thft));
    
  • }
    }

static void
@@ -2409,7 +2447,7 @@ fb_api_cb_contacts(PurpleHttpConnection *con, PurpleHttpResponse *res,
priv->contacts_delta = g_strdup(is_delta ? cursor : delta_cursor);
}

  •   if (users) {
    
  •   if (users || (complete && !is_delta)) {
      	g_signal_emit_by_name(api, "contacts", users, complete);
      }
    

diff --git a/pidgin/libpurple/protocols/facebook/api.h b/pidgin/libpurple/protocols/facebook/api.h
index 111788ea..63c9a1b9 100644
--- a/pidgin/libpurple/protocols/facebook/api.h
+++ b/pidgin/libpurple/protocols/facebook/api.h
@@ -104,14 +104,14 @@

  • server started checking this.
    */

-#define FB_ORCA_AGENT "[FBAN/Orca-Android;FBAV/109.0.0.17.70;FBPN/com.facebook.orca;FBLC/en_US;FBBV/52182662]"
+#define FB_ORCA_AGENT "[FBAN/Orca-Android;FBAV/537.0.0.31.101;FBPN/com.facebook.orca;FBLC/en_US;FBBV/52182662]"

/**

  • FB_API_AGENT:
  • The HTTP User-Agent header.
    */
    -#define FB_API_AGENT "Facebook plugin / Purple / 0.9.5 " FB_ORCA_AGENT
    +#define FB_API_AGENT "Facebook plugin / Purple / " PACKAGE_VERSION " " FB_ORCA_AGENT

/**

  • FB_API_MQTT_AGENT
    diff --git a/pidgin/libpurple/protocols/facebook/data.c b/pidgin/libpurple/protocols/facebook/data.c
    index fe32404f..81e32581 100644
    --- a/pidgin/libpurple/protocols/facebook/data.c
    +++ b/pidgin/libpurple/protocols/facebook/data.c
    @@ -59,8 +59,8 @@ static const gchar *fb_props_strs[] = {
    "token"
    };

-G_DEFINE_TYPE(FbData, fb_data, G_TYPE_OBJECT);
-G_DEFINE_TYPE(FbDataImage, fb_data_image, G_TYPE_OBJECT);
+G_DEFINE_TYPE_WITH_CODE(FbData, fb_data, G_TYPE_OBJECT, G_ADD_PRIVATE(FbData));
+G_DEFINE_TYPE_WITH_CODE(FbDataImage, fb_data_image, G_TYPE_OBJECT, G_ADD_PRIVATE(FbDataImage));

static void
fb_data_dispose(GObject *obj)
diff --git a/pidgin/libpurple/protocols/facebook/facebook.c b/pidgin/libpurple/protocols/facebook/facebook.c
index 9554adc7..7a6ed818 100644
--- a/pidgin/libpurple/protocols/facebook/facebook.c
+++ b/pidgin/libpurple/protocols/facebook/facebook.c
@@ -373,8 +373,8 @@ fb_cb_api_error(FbApi *api, GError *error, gpointer data)

gc = fb_data_get_connection(fata);
  • if (error->domain == G_IO_ERROR) {
  •   purple_connection_g_error(gc, error);
    
  • if (error->domain == FB_MQTT_SSL_ERROR) {
  •   purple_connection_ssl_error(gc, error->code);
      return;
    
    }

@@ -500,7 +500,7 @@ fb_cb_image(FbDataImage *img, GError *error)
id = purple_image_store_add_weak(pimg);

g_free(msg->text);
  • msg->text = g_strdup_printf("<img src=""
  • msg->text = g_strdup_printf("<img id=""
    PURPLE_IMAGE_STORE_PROTOCOL
    "%u">", id);
    msg->flags |= FB_API_MESSAGE_FLAG_DONE;
    @@ -966,7 +966,7 @@ fb_blist_chat_init(PurpleBlistNode *node, gpointer data)
    GSList *select = NULL;
    PurpleConnection *gc;
  • if (!PURPLE_IS_BUDDY(node)) {
  • if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) {
    return;
    }

@@ -1160,7 +1160,7 @@ fb_client_blist_node_menu(PurpleBlistNode *node)
PurpleConnection *gc;
PurpleMenuAction *act;

  • if (!PURPLE_IS_BUDDY(node)) {
  • if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) {
    return NULL;
    }

@@ -1208,7 +1208,8 @@ fb_server_set_status(PurpleAccount *acct, PurpleStatus *status)
}

static gint
-fb_im_send(PurpleConnection *gc, PurpleMessage *msg)
+fb_im_send(PurpleConnection *gc, const gchar *who, const gchar *tmsg,

  •       PurpleMessageFlags flags)
    

{
const gchar *name;
const gchar *text;
@@ -1217,6 +1218,8 @@ fb_im_send(PurpleConnection *gc, PurpleMessage *msg)
FbId uid;
gchar *sext;

  • PurpleMessage *msg = purple_message_new_outgoing(who, tmsg, flags);
  • fata = purple_connection_get_protocol_data(gc);
    api = fb_data_get_api(fata);

@@ -1355,7 +1358,8 @@ fb_chat_invite(PurpleConnection *gc, gint id, const gchar *msg,
}

static gint
-fb_chat_send(PurpleConnection *gc, gint id, PurpleMessage *msg)
+fb_chat_send(PurpleConnection *gc, gint id, const gchar *tmsg,

  •         PurpleMessageFlags flags)
    

{
const gchar *name;
const gchar *text;
@@ -1366,6 +1370,8 @@ fb_chat_send(PurpleConnection *gc, gint id, PurpleMessage *msg)
PurpleAccount *acct;
PurpleChatConversation *chat;

  • PurpleMessage *msg = purple_message_new_outgoing(NULL, tmsg, flags);
  • acct = purple_connection_get_account(gc);
    fata = purple_connection_get_protocol_data(gc);
    api = fb_data_get_api(fata);
    @@ -1533,107 +1539,6 @@ fb_cmd_leave(PurpleConversation *conv, const gchar *cmd, gchar **args,
    return PURPLE_CMD_RET_OK;
    }

-static void
-facebook_protocol_init(PurpleProtocol *protocol)
-{

  • GList *opts = NULL;
  • PurpleAccountOption *opt;
  • protocol->id = FB_PROTOCOL_ID;
  • protocol->name = "Facebook";
  • protocol->options = OPT_PROTO_CHAT_TOPIC;
  • opt = purple_account_option_int_new(_("Buddy list sync interval"),
  •                                   "sync-interval", 5);
    
  • opts = g_list_prepend(opts, opt);
  • opt = purple_account_option_bool_new(_("Mark messages as read on focus"),
  •                                    "mark-read", TRUE);
    
  • opts = g_list_prepend(opts, opt);
  • opt = purple_account_option_bool_new(_("Mark messages as read only when available"),
  •                                    "mark-read-available", FALSE);
    
  • opts = g_list_prepend(opts, opt);
  • opt = purple_account_option_bool_new(_("Show self messages"),
  •                                    "show-self", TRUE);
    
  • opts = g_list_prepend(opts, opt);
  • opt = purple_account_option_bool_new(_("Show unread messages"),
  •                                    "show-unread", TRUE);
    
  • opts = g_list_prepend(opts, opt);
  • opt = purple_account_option_bool_new(_("Open new group chats with "
  •                                      "incoming messages"),
    
  •                                    "group-chat-open", TRUE);
    
  • opts = g_list_prepend(opts, opt);
  • protocol->account_options = g_list_reverse(opts);
    -}

-static void
-facebook_protocol_class_init(PurpleProtocolClass *klass)
-{

  • klass->login = fb_login;
  • klass->close = fb_close;
  • klass->status_types = fb_status_types;
  • klass->list_icon = fb_list_icon;
    -}

-static void
-facebook_protocol_client_iface_init(PurpleProtocolClientIface *iface)
-{

  • iface->tooltip_text = fb_client_tooltip_text;
  • iface->blist_node_menu = fb_client_blist_node_menu;
  • iface->offline_message = fb_client_offline_message;
    -}

-static void
-facebook_protocol_server_iface_init(PurpleProtocolServerIface *iface)
-{

  • iface->set_status = fb_server_set_status;
    -}

-static void
-facebook_protocol_im_iface_init(PurpleProtocolIMIface *iface)
-{

  • iface->send = fb_im_send;
  • iface->send_typing = fb_im_send_typing;
    -}

-static void
-facebook_protocol_chat_iface_init(PurpleProtocolChatIface *iface)
-{

  • iface->info = fb_chat_info;
  • iface->info_defaults = fb_chat_info_defaults;
  • iface->join = fb_chat_join;
  • iface->get_name = fb_chat_get_name;
  • iface->invite = fb_chat_invite;
  • iface->send = fb_chat_send;
  • iface->set_topic = fb_chat_set_topic;
    -}

-static void
-facebook_protocol_roomlist_iface_init(PurpleProtocolRoomlistIface *iface)
-{

  • iface->get_list = fb_roomlist_get_list;
  • iface->cancel = fb_roomlist_cancel;
    -}

-PURPLE_DEFINE_TYPE_EXTENDED(

  • FacebookProtocol, facebook_protocol, PURPLE_TYPE_PROTOCOL, 0,
  • PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_CLIENT_IFACE,
  •                                 facebook_protocol_client_iface_init)
    
  • PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_SERVER_IFACE,
  •                                 facebook_protocol_server_iface_init)
    
  • PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_IM_IFACE,
  •                                 facebook_protocol_im_iface_init)
    
  • PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_CHAT_IFACE,
  •                                 facebook_protocol_chat_iface_init)
    
  • PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_ROOMLIST_IFACE,
  •                                 facebook_protocol_roomlist_iface_init)
    

-);

static void
fb_cmds_register(void)
{
@@ -1646,13 +1551,13 @@ fb_cmds_register(void)
g_return_if_fail(fb_cmds == NULL);

id = purple_cmd_register("kick", "s", PURPLE_CMD_P_PROTOCOL, cflags,
  •   		 fb_protocol->id, fb_cmd_kick,
    
  •   		 "prpl-facebook", fb_cmd_kick,
      		 _("kick: Kick someone from the chat"),
      		 NULL);
    

    fb_cmds = g_slist_prepend(fb_cmds, GUINT_TO_POINTER(id));

    id = purple_cmd_register("leave", "", PURPLE_CMD_P_PROTOCOL, cflags,

  •   		 fb_protocol->id, fb_cmd_leave,
    
  •   		 "prpl-facebook", fb_cmd_leave,
      		 _("leave: Leave the chat"),
      		 NULL);
    
    fb_cmds = g_slist_prepend(fb_cmds, GUINT_TO_POINTER(id));
    @@ -1671,43 +1576,110 @@ fb_cmds_unregister(void)
    g_slist_free_full(fb_cmds, fb_cmds_unregister_free);
    }

-static PurplePluginInfo *
-plugin_query(GError **error)
-{

  • return purple_plugin_info_new(
  •   "id",          FB_PROTOCOL_ID,
    
  •   "name",        "Facebook Protocol",
    
  •   "version",     DISPLAY_VERSION,
    
  •   "category",    N_("Protocol"),
    
  •   "summary",     N_("Facebook Protocol Plugin"),
    
  •   "description", N_("Facebook Protocol Plugin"),
    
  •   "website",     PURPLE_WEBSITE,
    
  •   "abi-version", PURPLE_ABI_VERSION,
    
  •   "flags",       PURPLE_PLUGIN_INFO_FLAGS_INTERNAL |
    
  •                  PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD,
    
  •   NULL
    
  • );
    -}

static gboolean
-plugin_load(PurplePlugin *plugin, GError **error)
+plugin_load(PurplePlugin *plugin)
{

  • facebook_protocol_register_type(plugin);
  • fb_protocol = purple_protocols_add(FACEBOOK_TYPE_PROTOCOL, error);
  • if (fb_protocol == NULL) {
  •   return FALSE;
    
  • }
  • fb_cmds_register();
  • _purple_socket_init();
  • purple_http_init();
    return TRUE;
    }

static gboolean
-plugin_unload(PurplePlugin *plugin, GError **error)
+plugin_unload(PurplePlugin *plugin)
{
fb_cmds_unregister();

  • return purple_protocols_remove(fb_protocol, error);
  • purple_http_uninit();
  • _purple_socket_uninit();
  • return TRUE;
    }

-PURPLE_PLUGIN_INIT(facebook, plugin_query, plugin_load, plugin_unload);
+G_MODULE_EXPORT gboolean
+purple_init_plugin(PurplePlugin *plugin);
+
+G_MODULE_EXPORT gboolean
+purple_init_plugin(PurplePlugin *plugin)
+{

  • GList *opts = NULL;
  • PurpleAccountOption *opt;
  • static gboolean inited = FALSE;
  • static PurplePluginInfo info;
  • static PurplePluginProtocolInfo pinfo;
  • (void) fb_protocol;
  • plugin->info = &info;
  • if (G_LIKELY(inited)) {
  •   return purple_plugin_register(plugin);
    
  • }
  • memset(&info, 0, sizeof info);
  • memset(&pinfo, 0, sizeof pinfo);
  • info.magic = PURPLE_PLUGIN_MAGIC;
  • info.major_version = PURPLE_MAJOR_VERSION;
  • info.minor_version = PURPLE_MINOR_VERSION;
  • info.type = PURPLE_PLUGIN_PROTOCOL;
  • info.priority = PURPLE_PRIORITY_DEFAULT;
  • info.id = FB_PROTOCOL_ID;
  • info.name = "Facebook";
  • info.version = PACKAGE_VERSION;
  • info.summary = N_("Facebook Protocol Plugin");
  • info.description = N_("Facebook Protocol Plugin");
  • info.homepage = PACKAGE_URL;
  • info.load = plugin_load;
  • info.unload = plugin_unload;
  • info.extra_info = &pinfo;
  • pinfo.options = OPT_PROTO_CHAT_TOPIC;
  • pinfo.list_icon = fb_list_icon;
  • pinfo.tooltip_text = fb_client_tooltip_text;
  • pinfo.status_types = fb_status_types;
  • pinfo.blist_node_menu = fb_client_blist_node_menu;
  • pinfo.chat_info = fb_chat_info;
  • pinfo.chat_info_defaults = fb_chat_info_defaults;
  • pinfo.login = fb_login;
  • pinfo.close = fb_close;
  • pinfo.send_im = fb_im_send;
  • pinfo.send_typing = fb_im_send_typing;
  • pinfo.set_status = fb_server_set_status;
  • pinfo.join_chat = fb_chat_join;
  • pinfo.get_chat_name = fb_chat_get_name;
  • pinfo.chat_invite = fb_chat_invite;
  • pinfo.chat_send = fb_chat_send;
  • pinfo.set_chat_topic = fb_chat_set_topic;
  • pinfo.roomlist_get_list = fb_roomlist_get_list;
  • pinfo.roomlist_cancel = fb_roomlist_cancel;
  • pinfo.offline_message = fb_client_offline_message;
  • pinfo.struct_size = sizeof pinfo;
  • opt = purple_account_option_int_new(_("Buddy list sync interval"),
  •                                   "sync-interval", 5);
    
  • opts = g_list_prepend(opts, opt);
  • opt = purple_account_option_bool_new(_("Mark messages as read on focus"),
  •                                    "mark-read", TRUE);
    
  • opts = g_list_prepend(opts, opt);
  • opt = purple_account_option_bool_new(_("Mark messages as read only when available"),
  •                                    "mark-read-available", FALSE);
    
  • opts = g_list_prepend(opts, opt);
  • opt = purple_account_option_bool_new(_("Show self messages"),
  •                                    "show-self", TRUE);
    
  • opts = g_list_prepend(opts, opt);
  • opt = purple_account_option_bool_new(_("Show unread messages"),
  •                                    "show-unread", TRUE);
    
  • opts = g_list_prepend(opts, opt);
  • opt = purple_account_option_bool_new(_("Open new group chats with "
  •                                      "incoming messages"),
    
  •                                    "group-chat-open", TRUE);
    
  • opts = g_list_prepend(opts, opt);
  • pinfo.protocol_options = g_list_reverse(opts);
  • inited = TRUE;
  • return purple_plugin_register(plugin);
    +}
    diff --git a/pidgin/libpurple/protocols/facebook/facebook.h b/pidgin/libpurple/protocols/facebook/facebook.h
    index edc8b262..aa8b3c34 100644
    --- a/pidgin/libpurple/protocols/facebook/facebook.h
    +++ b/pidgin/libpurple/protocols/facebook/facebook.h
    @@ -22,24 +22,7 @@
    #ifndef FACEBOOK_H
    #define FACEBOOK_H

-/**

    • SECTION:facebook
    • @section_id: facebook-plugin
    • @short_description: facebook.h
    • The Facebook Messenger #PurpleProtocol.
  • */

#include <glib.h>
-#include <gmodule.h>

-#define FACEBOOK_TYPE_PROTOCOL (facebook_protocol_get_type())
-#define FACEBOOK_PROTOCOL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), FACEBOOK_TYPE_PROTOCOL, FacebookProtocol))
-#define FACEBOOK_PROTOCOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), FACEBOOK_TYPE_PROTOCOL, FacebookProtocolClass))
-#define FACEBOOK_IS_PROTOCOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), FACEBOOK_TYPE_PROTOCOL))
-#define FACEBOOK_IS_PROTOCOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), FACEBOOK_TYPE_PROTOCOL))
-#define FACEBOOK_PROTOCOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), FACEBOOK_TYPE_PROTOCOL, FacebookProtocolClass))

/**

  • FB_PROTOCOL_ID:
    @@ -48,37 +31,4 @@
    */
    #define FB_PROTOCOL_ID "prpl-facebook"

-typedef struct _FacebookProtocol FacebookProtocol;
-typedef struct _FacebookProtocolClass FacebookProtocolClass;

-/**

    • FacebookProtocol:
    • Represents the Facebook #PurpleProtocol.
  • */
    -struct _FacebookProtocol
    -{
  • /< private >/
  • PurpleProtocol parent;
    -};

-/**

    • FacebookProtocolClass:
    • The base class for all #FacebookProtocol's.
  • */
    -struct _FacebookProtocolClass
    -{
  • /< private >/
  • PurpleProtocolClass parent_class;
    -};

-/**

    • facebook_protocol_get_type:
    • Returns: The #GType for a #FacebookProtocol.
  • */
    -G_MODULE_EXPORT GType
    -facebook_protocol_get_type(void);

#endif /* FACEBOOK_H */
diff --git a/pidgin/libpurple/protocols/facebook/http.c b/pidgin/libpurple/protocols/facebook/http.c
index 148c9c26..cd9876cf 100644
--- a/pidgin/libpurple/protocols/facebook/http.c
+++ b/pidgin/libpurple/protocols/facebook/http.c
@@ -381,7 +381,7 @@ fb_http_urlcmp(const gchar *url1, const gchar *url2, gboolean protocol)
PurpleHttpURL *purl1;
PurpleHttpURL *purl2;

  • static const const gchar * (*funcs[]) (const PurpleHttpURL *url) = {
  • static const gchar * (*funcs[]) (const PurpleHttpURL url) = {
    /
    Always first so it can be skipped */
    purple_http_url_get_protocol,

diff --git a/pidgin/libpurple/protocols/facebook/json.c b/pidgin/libpurple/protocols/facebook/json.c
index f36839c5..448c5b2e 100644
--- a/pidgin/libpurple/protocols/facebook/json.c
+++ b/pidgin/libpurple/protocols/facebook/json.c
@@ -25,6 +25,7 @@
#include <string.h>

#include "json.h"
+#include "glibcompat.h"
#include "util.h"

typedef struct _FbJsonValue FbJsonValue;
@@ -50,7 +51,7 @@ struct _FbJsonValuesPrivate
GError *error;
};

-G_DEFINE_TYPE(FbJsonValues, fb_json_values, G_TYPE_OBJECT);
+G_DEFINE_TYPE_WITH_CODE(FbJsonValues, fb_json_values, G_TYPE_OBJECT, G_ADD_PRIVATE(FbJsonValues));

static void
fb_json_values_dispose(GObject *obj)
diff --git a/pidgin/libpurple/protocols/facebook/mqtt.c b/pidgin/libpurple/protocols/facebook/mqtt.c
index da279cbe..ec87b0f7 100644
--- a/pidgin/libpurple/protocols/facebook/mqtt.c
+++ b/pidgin/libpurple/protocols/facebook/mqtt.c
@@ -28,26 +28,26 @@
#include "account.h"
#include "eventloop.h"
#include "glibcompat.h"
-#include "purple-gio.h"
-#include "queuedoutputstream.h"
+#include "sslconn.h"

+#include "marshal.h"
#include "mqtt.h"
#include "util.h"

struct _FbMqttPrivate
{
PurpleConnection *gc;

  • GIOStream *conn;
  • GBufferedInputStream *input;
  • PurpleQueuedOutputStream *output;
  • GCancellable *cancellable;
  • PurpleSslConnection *gsc;
    gboolean connected;
    guint16 mid;

    GByteArray *rbuf;

  • GByteArray *wbuf;
    gsize remz;

    gint tev;

  • gint rev;

  • gint wev;
    };

struct _FbMqttMessagePrivate
@@ -62,10 +62,8 @@ struct _FbMqttMessagePrivate
gboolean local;
};

-G_DEFINE_TYPE(FbMqtt, fb_mqtt, G_TYPE_OBJECT);
-G_DEFINE_TYPE(FbMqttMessage, fb_mqtt_message, G_TYPE_OBJECT);

-static void fb_mqtt_read_packet(FbMqtt *mqtt);
+G_DEFINE_TYPE_WITH_CODE(FbMqtt, fb_mqtt, G_TYPE_OBJECT, G_ADD_PRIVATE(FbMqtt));
+G_DEFINE_TYPE_WITH_CODE(FbMqttMessage, fb_mqtt_message, G_TYPE_OBJECT, G_ADD_PRIVATE(FbMqttMessage));

static void
fb_mqtt_dispose(GObject *obj)
@@ -75,6 +73,7 @@ fb_mqtt_dispose(GObject *obj)

fb_mqtt_close(mqtt);
g_byte_array_free(priv->rbuf, TRUE);
  • g_byte_array_free(priv->wbuf, TRUE);
    }

static void
@@ -96,7 +95,8 @@ fb_mqtt_class_init(FbMqttClass *klass)
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_ACTION,
0,

  •            NULL, NULL, NULL,
    
  •            NULL, NULL,
    
  •            fb_marshal_VOID__VOID,
               G_TYPE_NONE,
               0);
    

@@ -112,9 +112,10 @@ fb_mqtt_class_init(FbMqttClass *klass)
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_ACTION,
0,

  •            NULL, NULL, NULL,
    
  •            NULL, NULL,
    
  •            fb_marshal_VOID__POINTER,
               G_TYPE_NONE,
    
  •            1, G_TYPE_ERROR);
    
  •            1, G_TYPE_POINTER);
    

    /**

    • FbMqtt::open:
      @@ -128,7 +129,8 @@ fb_mqtt_class_init(FbMqttClass *klass)
      G_TYPE_FROM_CLASS(klass),
      G_SIGNAL_ACTION,
      0,
  •            NULL, NULL, NULL,
    
  •            NULL, NULL,
    
  •            fb_marshal_VOID__VOID,
               G_TYPE_NONE,
               0);
    

@@ -144,7 +146,8 @@ fb_mqtt_class_init(FbMqttClass *klass)
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_ACTION,
0,

  •            NULL, NULL, NULL,
    
  •            NULL, NULL,
    
  •            fb_marshal_VOID__STRING_BOXED,
               G_TYPE_NONE,
               2, G_TYPE_STRING, G_TYPE_BYTE_ARRAY);
    

}
@@ -158,6 +161,7 @@ fb_mqtt_init(FbMqtt *mqtt)
mqtt->priv = priv;

priv->rbuf = g_byte_array_new();
  • priv->wbuf = g_byte_array_new();
    }

static void
@@ -201,6 +205,18 @@ fb_mqtt_error_quark(void)
return q;
}

+GQuark
+fb_mqtt_ssl_error_quark(void)
+{

  • static GQuark q = 0;
  • if (G_UNLIKELY(q == 0)) {
  •   q = g_quark_from_static_string("fb-mqtt-ssl-error-quark");
    
  • }
  • return q;
    +}

FbMqtt *
fb_mqtt_new(PurpleConnection *gc)
{
@@ -224,47 +240,33 @@ fb_mqtt_close(FbMqtt *mqtt)
g_return_if_fail(FB_IS_MQTT(mqtt));
priv = mqtt->priv;

  • if (priv->tev > 0) {
  •   g_source_remove(priv->tev);
    
  •   priv->tev = 0;
    
  • if (priv->wev > 0) {
  •   purple_input_remove(priv->wev);
    
  •   priv->wev = 0;
    
    }
  • if (priv->cancellable != NULL) {
  •   g_cancellable_cancel(priv->cancellable);
    
  •   g_clear_object(&priv->cancellable);
    
  • if (priv->rev > 0) {
  •   purple_input_remove(priv->rev);
    
  •   priv->rev = 0;
    
    }
  • if (priv->conn != NULL) {
  •   purple_gio_graceful_close(priv->conn,
    
  •   		G_INPUT_STREAM(priv->input),
    
  •   		G_OUTPUT_STREAM(priv->output));
    
  •   g_clear_object(&priv->input);
    
  •   g_clear_object(&priv->output);
    
  •   g_clear_object(&priv->conn);
    
  • if (priv->tev > 0) {
  •   purple_timeout_remove(priv->tev);
    
  •   priv->tev = 0;
    
    }
  • priv->connected = FALSE;
  • g_byte_array_set_size(priv->rbuf, 0);
    -}

-static void
-fb_mqtt_take_error(FbMqtt *mqtt, GError *err, const gchar *prefix)
-{

  • if (g_error_matches(err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
  •   /* Return as cancelled means the connection is closing */
    
  •   g_error_free(err);
    
  •   return;
    
  • if (priv->gsc != NULL) {
  •   purple_ssl_close(priv->gsc);
    
  •   priv->gsc = NULL;
    
    }
  • /* Now we can check for programming errors */
  • g_return_if_fail(FB_IS_MQTT(mqtt));
  • if (prefix != NULL) {
  •   g_prefix_error(&err, "%s: ", prefix);
    
  • if (priv->wbuf->len > 0) {
  •   fb_util_debug_warning("Closing with unwritten data");
    
    }
  • g_signal_emit_by_name(mqtt, "error", err);
  • g_error_free(err);
  • priv->connected = FALSE;
  • g_byte_array_set_size(priv->rbuf, 0);
  • g_byte_array_set_size(priv->wbuf, 0);
    }

void
@@ -342,127 +344,84 @@ fb_mqtt_ping(FbMqtt *mqtt)
}

static void
-fb_mqtt_cb_fill(GObject *source, GAsyncResult *res, gpointer data)
+fb_mqtt_cb_read(gpointer data, gint fd, PurpleInputCondition cond)
{

  • GBufferedInputStream *input = G_BUFFERED_INPUT_STREAM(source);
    FbMqtt *mqtt = data;
  • gssize ret;
  • GError *err = NULL;
  • FbMqttMessage *msg;
  • FbMqttPrivate *priv = mqtt->priv;
  • gint res;
  • guint mult;
  • guint8 buf[1024];
  • guint8 byte;
  • gsize size;
  • gssize rize;
  • if (priv->remz < 1) {
  •   /* Reset the read buffer */
    
  •   g_byte_array_set_size(priv->rbuf, 0);
    
  • ret = g_buffered_input_stream_fill_finish(input, res, &err);
  •   res = purple_ssl_read(priv->gsc, &byte, sizeof byte);
    
  • if (ret < 1) {
  •   if (ret == 0) {
    
  •   	err = g_error_new_literal(G_IO_ERROR,
    
  •   			G_IO_ERROR_CONNECTION_CLOSED,
    
  •   			_("Connection closed"));
    
  •   if (res < 0 && errno == EAGAIN) {
    
  •   	return;
    
  •   } else if (res != 1) {
    
  •   	fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL,
    
  •   	              _("Failed to read fixed header"));
    
  •   	return;
      }
    
  •   fb_mqtt_take_error(mqtt, err, _("Failed to read fixed header"));
    
  •   return;
    
  • }
  •   g_byte_array_append(priv->rbuf, &byte, sizeof byte);
    
  • fb_mqtt_read_packet(mqtt);
    -}
  •   mult = 1;
    

-static void
-fb_mqtt_cb_read_packet(GObject *source, GAsyncResult *res, gpointer data)
-{

  • FbMqtt *mqtt = data;
  • FbMqttPrivate *priv;
  • gssize ret;
  • FbMqttMessage *msg;
  • GError *err = NULL;
  •   do {
    
  •   	res = purple_ssl_read(priv->gsc, &byte, sizeof byte);
    
  • ret = g_input_stream_read_finish(G_INPUT_STREAM(source), res, &err);
  •   	/* TODO: this case isn't handled yet */
    
  •   	if (0 && res < 0 && errno == EAGAIN) {
    
  •   		return;
    
  •   	} else if (res != 1) {
    
  •   		fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL,
    
  •   		              _("Failed to read packet size"));
    
  •   		return;
    
  •   	}
    
  • if (ret < 1) {
  •   if (ret == 0) {
    
  •   	err = g_error_new_literal(G_IO_ERROR,
    
  •   			G_IO_ERROR_CONNECTION_CLOSED,
    
  •   			_("Connection closed"));
    
  •   }
    
  •   	g_byte_array_append(priv->rbuf, &byte, sizeof byte);
    
  •   fb_mqtt_take_error(mqtt, err, _("Failed to read packet data"));
    
  •   return;
    
  •   	priv->remz += (byte & 127) * mult;
    
  •   	mult *= 128;
    
  •   } while ((byte & 128) != 0);
    
    }
  • priv = mqtt->priv;
  • priv->remz -= ret;
  • if (priv->remz > 0) {
  •   g_input_stream_read_async(G_INPUT_STREAM(source),
    
  •   		priv->rbuf->data +
    
  •   		priv->rbuf->len - priv->remz, priv->remz,
    
  •   		G_PRIORITY_DEFAULT, priv->cancellable,
    
  •   		fb_mqtt_cb_read_packet, mqtt);
    
  •   return;
    
  • }
  • msg = fb_mqtt_message_new_bytes(priv->rbuf);
  •   size = MIN(priv->remz, sizeof buf);
    
  •   rize = purple_ssl_read(priv->gsc, buf, size);
    
  • if (G_UNLIKELY(msg == NULL)) {
  •   fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL,
    
  •                 _("Failed to parse message"));
    
  •   return;
    
  • }
  • fb_mqtt_read(mqtt, msg);
  • g_object_unref(msg);
  •   if (rize < 0 && errno == EAGAIN) {
    
  •   	return;
    
  •   } else if (rize < 1) {
    
  •   	fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL,
    
  •   	              _("Failed to read packet data"));
    
  •   	return;
    
  •   }
    
  • /* Read another packet if connection wasn't reset in fb_mqtt_read() */
  • if (fb_mqtt_connected(mqtt, FALSE)) {
  •   fb_mqtt_read_packet(mqtt);
    
  •   g_byte_array_append(priv->rbuf, buf, rize);
    
  •   priv->remz -= rize;
    
    }
    -}

-static void
-fb_mqtt_read_packet(FbMqtt *mqtt)
-{

  • FbMqttPrivate *priv = mqtt->priv;
  • const guint8 const *buf;
  • gsize count = 0;
  • gsize pos;
  • guint mult = 1;
  • guint8 byte;
  • gsize size = 0;
  • if (priv->remz < 1) {
  •   msg = fb_mqtt_message_new_bytes(priv->rbuf);
    
  •   priv->remz = 0;
    
  • buf = g_buffered_input_stream_peek_buffer(priv->input, &count);
  • /* Start at 1 to skip the first byte */
  • pos = 1;
  • do {
  •   if (pos >= count) {
    
  •   	/* Not enough data yet, try again later */
    
  •   	g_buffered_input_stream_fill_async(priv->input, -1,
    
  •   			G_PRIORITY_DEFAULT, priv->cancellable,
    
  •   			fb_mqtt_cb_fill, mqtt);
    
  •   if (G_UNLIKELY(msg == NULL)) {
    
  •   	fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL,
    
  •   	              _("Failed to parse message"));
      	return;
      }
    
  •   byte = *(buf + pos++);
    
  •   size += (byte & 127) * mult;
    
  •   mult *= 128;
    
  • } while ((byte & 128) != 0);
  • /* Add header to size */
  • size += pos;
  • g_byte_array_set_size(priv->rbuf, size);
  • priv->remz = size;
  • /* TODO: Use g_input_stream_read_all_async() when available. */
  • /* TODO: Alternately, it would be nice to let the
    • FbMqttMessage directly use the GBufferedInputStream
    • buffer instead of copying it, provided it's consumed
    • before the next read.
  • */
  • g_input_stream_read_async(G_INPUT_STREAM(priv->input),
  •   	priv->rbuf->data, priv->rbuf->len,
    
  •   	G_PRIORITY_DEFAULT, priv->cancellable,
    
  •   	fb_mqtt_cb_read_packet, mqtt);
    
  •   fb_mqtt_read(mqtt, msg);
    
  •   g_object_unref(msg);
    
  • }
    }

void
@@ -569,16 +528,27 @@ fb_mqtt_read(FbMqtt *mqtt, FbMqttMessage *msg)
}

static void
-fb_mqtt_cb_flush(GObject *source, GAsyncResult *res, gpointer data)
+fb_mqtt_cb_write(gpointer data, gint fd, PurpleInputCondition cond)
{
FbMqtt *mqtt = data;

  • GError *err = NULL;
  • FbMqttPrivate *priv = mqtt->priv;
  • gssize wize;
  • wize = purple_ssl_write(priv->gsc, priv->wbuf->data, priv->wbuf->len);
  • if (!g_output_stream_flush_finish(G_OUTPUT_STREAM(source),
  •   	res, &err)) {
    
  •   fb_mqtt_take_error(mqtt, err, _("Failed to write data"));
    
  • if (wize < 0) {
  •   fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL,
    
  •                 _("Failed to write data"));
      return;
    
    }
  • if (wize > 0) {
  •   g_byte_array_remove_range(priv->wbuf, 0, wize);
    
  • }
  • if (priv->wbuf->len < 1) {
  •   priv->wev = 0;
    
  • }
    }

void
@@ -587,7 +557,6 @@ fb_mqtt_write(FbMqtt *mqtt, FbMqttMessage *msg)
const GByteArray *bytes;
FbMqttMessagePrivate *mriv;
FbMqttPrivate *priv;

  • GBytes *gbytes;

    g_return_if_fail(FB_IS_MQTT(mqtt));
    g_return_if_fail(FB_IS_MQTT_MESSAGE(msg));
    @@ -606,46 +575,46 @@ fb_mqtt_write(FbMqtt *mqtt, FbMqttMessage *msg)
    "Writing %d (flags: 0x%0X)",
    mriv->type, mriv->flags);

  • /* TODO: Would be nice to refactor this to not require copying bytes */

  • gbytes = g_bytes_new(bytes->data, bytes->len);

  • purple_queued_output_stream_push_bytes(priv->output, gbytes);

  • g_bytes_unref(gbytes);

  • g_byte_array_append(priv->wbuf, bytes->data, bytes->len);
  • fb_mqtt_cb_write(mqtt, priv->gsc->fd, PURPLE_INPUT_WRITE);
  • if (!g_output_stream_has_pending(G_OUTPUT_STREAM(priv->output))) {
  •   g_output_stream_flush_async(G_OUTPUT_STREAM(priv->output),
    
  •   		G_PRIORITY_DEFAULT, priv->cancellable,
    
  •   		fb_mqtt_cb_flush, mqtt);
    
  • if (priv->wev > 0) {
  •   priv->wev = purple_input_add(priv->gsc->fd,
    
  •                                PURPLE_INPUT_WRITE,
    
  •                                fb_mqtt_cb_write, mqtt);
    
    }
    }

static void
-fb_mqtt_cb_open(GObject *source, GAsyncResult *res, gpointer data)
+fb_mqtt_cb_open(gpointer data, PurpleSslConnection *ssl,

  •            PurpleInputCondition cond)
    

{
FbMqtt *mqtt = data;

  • FbMqttPrivate *priv;
  • GSocketConnection *conn;
  • GError *err = NULL;
  • conn = g_socket_client_connect_to_host_finish(G_SOCKET_CLIENT(source),
  •   	res, &err);
    
  • if (conn == NULL) {
  •   fb_mqtt_take_error(mqtt, err, NULL);
    
  •   return;
    
  • }
  • FbMqttPrivate *priv = mqtt->priv;

    fb_mqtt_timeout_clear(mqtt);

  • priv->rev = purple_input_add(priv->gsc->fd, PURPLE_INPUT_READ,

  •                            fb_mqtt_cb_read, mqtt);
    
  • g_signal_emit_by_name(mqtt, "open");
    +}

  • priv = mqtt->priv;
  • priv->conn = G_IO_STREAM(conn);
  • priv->input = G_BUFFERED_INPUT_STREAM(g_buffered_input_stream_new(
  •   	g_io_stream_get_input_stream(priv->conn)));
    
  • priv->output = purple_queued_output_stream_new(
  •   	g_io_stream_get_output_stream(priv->conn));
    

+static void
+fb_mqtt_cb_open_error(PurpleSslConnection *ssl, PurpleSslErrorType error,

  •                  gpointer data)
    

+{

  • const gchar *str;
  • FbMqtt *mqtt = data;
  • FbMqttPrivate *priv = mqtt->priv;
  • GError *err;
  • fb_mqtt_read_packet(mqtt);
  • str = purple_ssl_strerror(error);
  • err = g_error_new_literal(FB_MQTT_SSL_ERROR, error, str);
  • g_signal_emit_by_name(mqtt, "open");
  • /* Do not call purple_ssl_close() from the error_func */
  • priv->gsc = NULL;
  • g_signal_emit_by_name(mqtt, "error", err);
  • g_error_free(err);
    }

void
@@ -653,29 +622,20 @@ fb_mqtt_open(FbMqtt *mqtt, const gchar *host, gint port)
{
FbMqttPrivate *priv;
PurpleAccount *acc;

  • GSocketClient *client;

  • GError *err = NULL;

    g_return_if_fail(FB_IS_MQTT(mqtt));
    priv = mqtt->priv;

    acc = purple_connection_get_account(priv->gc);
    fb_mqtt_close(mqtt);

  • priv->gsc = purple_ssl_connect(acc, host, port, fb_mqtt_cb_open,
  •                              fb_mqtt_cb_open_error, mqtt);
    
  • client = purple_gio_socket_client_new(acc, &err);
  • if (client == NULL) {
  •   fb_mqtt_take_error(mqtt, err, NULL);
    
  • if (priv->gsc == NULL) {
  •   fb_mqtt_cb_open_error(NULL, 0, mqtt);
      return;
    
    }
  • priv->cancellable = g_cancellable_new();
  • g_socket_client_set_tls(client, TRUE);
  • g_socket_client_connect_to_host_async(client, host, port,
  •   	priv->cancellable, fb_mqtt_cb_open, mqtt);
    
  • g_object_unref(client);
  • fb_mqtt_timeout(mqtt);
    }

@@ -711,7 +671,7 @@ fb_mqtt_connected(FbMqtt *mqtt, gboolean error)

g_return_val_if_fail(FB_IS_MQTT(mqtt), FALSE);
priv = mqtt->priv;
  • connected = (priv->conn != NULL) && priv->connected;
  • connected = (priv->gsc != NULL) && priv->connected;

    if (!connected && error) {
    fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL,
    diff --git a/pidgin/libpurple/protocols/facebook/mqtt.h b/pidgin/libpurple/protocols/facebook/mqtt.h
    index 30172eb4..a33b4f52 100644
    --- a/pidgin/libpurple/protocols/facebook/mqtt.h
    +++ b/pidgin/libpurple/protocols/facebook/mqtt.h
    @@ -107,6 +107,13 @@
    */
    #define FB_MQTT_ERROR fb_mqtt_error_quark()

+/**

    • FB_MQTT_SSL_ERROR:
    • The #GQuark of the domain of MQTT SSL errors.
  • */
    +#define FB_MQTT_SSL_ERROR fb_mqtt_ssl_error_quark()

typedef struct _FbMqtt FbMqtt;
typedef struct _FbMqttClass FbMqttClass;
typedef struct _FbMqttPrivate FbMqttPrivate;
@@ -290,6 +297,16 @@ fb_mqtt_message_get_type(void);
GQuark
fb_mqtt_error_quark(void);

+/**

    • fb_mqtt_ssl_error_quark:
    • Gets the #GQuark of the domain of MQTT SSL errors.
    • Returns: The #GQuark of the domain.
  • */
    +GQuark
    +fb_mqtt_ssl_error_quark(void);

/**

  • fb_mqtt_new:
  • @gc: The #PurpleConnection.
    diff --git a/pidgin/libpurple/protocols/facebook/thrift.c b/pidgin/libpurple/protocols/facebook/thrift.c
    index d33a94e7..c4356f6f 100644
    --- a/pidgin/libpurple/protocols/facebook/thrift.c
    +++ b/pidgin/libpurple/protocols/facebook/thrift.c
    @@ -21,6 +21,7 @@

#include <string.h>

+#include "glibcompat.h"
#include "thrift.h"

struct _FbThriftPrivate
@@ -32,7 +33,7 @@ struct _FbThriftPrivate
guint lastbool;
};

-G_DEFINE_TYPE(FbThrift, fb_thrift, G_TYPE_OBJECT);
+G_DEFINE_TYPE_WITH_CODE(FbThrift, fb_thrift, G_TYPE_OBJECT, G_ADD_PRIVATE(FbThrift));

static void
fb_thrift_dispose(GObject *obj)

@grimmy
Copy link
Collaborator

grimmy commented Jan 17, 2023

I would not recommend this change. There's been very little change to the actual facebook code here and the majority of these changes are for libpurple3 only. In fact, I'm positive that not all of the patches in this repository have made it back into the copy in the pidgin3 repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants