Remove the Facebook plugin
This hasn't been used in forever and is behind on patches from the purple2
version so this for sure is not going to work. This will also stop people from
tryingt to update the purple2 version for this code as that's a horrible idea.
Testing Done:
had the turtles do their thing
Reviewed at https://reviews.imfreedom.org/r/2393/
--- a/doc/reference/protocols/facebook/facebook.toml.in Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-version = "@PURPLE_VERSION@"
-browse_url = "https://keep.imfreedom.org/pidgin/pidgin/"
-repository_url = "https://keep.imfreedom.org/pidgin/pidgin/"
-website_url = "https://keep.imfreedom.org/pidgin/pidgin/"
-authors = "Pidgin Developers"
-license = "GPL-2.0-or-later"
-description = "Purple Facebook Protocol Plugin"
-dependencies = [ "GLib-2.0", "GObject-2.0", "Purple-3.0" ]
- [dependencies."GLib-2.0"]
- description = "General-purpose, portable utility library."
- docs_url = "https://docs.gtk.org/glib/"
- [dependencies."GObject-2.0"]
- description = "The base type system library"
- docs_url = "https://docs.gtk.org/gobject/"
- [dependencies."Purple-3.0"]
- description = "Purple Universal Chat Library"
- docs_url = "https://docs.imfreedom.org/purple3/"
-show_index_summary = true
-show_class_hierarchy = true
-base_url = "https://keep.imfreedom.org/pidgin/pidgin/file/default/"
-# The same order will be used when generating the index
-urlmap_file = "urlmap.js"
--- a/doc/reference/protocols/facebook/meson.build Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-facebook_doc_content_files = []
- facebook_toml = configure_file(
- input : 'facebook.toml.in',
- output : 'facebook.toml',
- configuration : version_conf,
- install_dir : docs_dir / 'facebook',
- facebook_doc = custom_target('facebook-doc',
- input : [ facebook_toml, facebook_gir[0] ],
- '--output-dir=@OUTPUT@',
- '--content-dir=@0@'.format(meson.current_source_dir()),
- '--add-include-path=@0@'.format(meson.global_build_root() / 'subprojects/gplugin/gplugin'),
- '--add-include-path=@0@'.format(meson.global_build_root() / 'libpurple'),
- depends: [ libpurple_gir[0] ],
- depend_files : [ facebook_doc_content_files ],
- build_by_default : true,
- install_dir : docs_dir,
--- a/doc/reference/protocols/facebook/urlmap.js Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-// SPDX-FileCopyrightText: 2021 GNOME Foundation
-// SPDX-License-Identifier: LGPL-2.1-or-later
-// A map between namespaces and base URLs for their online documentation
- [ 'GLib', 'https://docs.gtk.org/glib/' ],
- [ 'GObject', 'https://docs.gtk.org/gobject/' ],
- [ 'Purple3', 'https://docs.imfreedom.org/purple3/' ],
--- a/doc/reference/protocols/meson.build Wed Mar 29 23:21:45 2023 -0500
+++ b/doc/reference/protocols/meson.build Wed Mar 29 23:22:41 2023 -0500
@@ -1,6 +1,2 @@
- protocols_doc += facebook_doc
--- a/libpurple/protocols/facebook/api.c Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3468 +0,0 @@
- * 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
- * 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 <glib/gi18n-lib.h>
-#include <json-glib/json-glib.h>
-#include <libsoup/soup.h>
-#include "libpurple/glibcompat.h"
- * Represents a Facebook Messenger connection.
-static void fb_api_error_literal(FbApi *api, FbApiError error,
-fb_api_attach(FbApi *api, FbId aid, const gchar *msgid, FbApiMessage *msg);
-fb_api_contacts_after(FbApi *api, const gchar *cursor);
-fb_api_message_send(FbApi *api, FbApiMessage *msg);
-fb_api_sticker(FbApi *api, FbId sid, FbApiMessage *msg);
-fb_api_contacts_delta(FbApi *api, const gchar *delta_cursor);
-G_DEFINE_TYPE(FbApi, fb_api, G_TYPE_OBJECT);
-fb_api_set_property(GObject *obj, guint prop, const GValue *val,
- FbApi *api = FB_API(obj);
- api->cid = g_value_dup_string(val);
- api->did = g_value_dup_string(val);
- api->mid = g_value_get_uint64(val);
- api->stoken = g_value_dup_string(val);
- api->token = g_value_dup_string(val);
- api->uid = g_value_get_int64(val);
- G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop, pspec);
-fb_api_get_property(GObject *obj, guint prop, GValue *val, GParamSpec *pspec)
- FbApi *api = FB_API(obj);
- g_value_set_string(val, api->cid);
- g_value_set_string(val, api->did);
- g_value_set_uint64(val, api->mid);
- g_value_set_string(val, api->stoken);
- g_value_set_string(val, api->token);
- g_value_set_int64(val, api->uid);
- G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop, pspec);
-fb_api_dispose(GObject *obj)
- FbApi *api = FB_API(obj);
- if(api->cons != NULL) {
- soup_session_abort(api->cons);
- g_clear_object(&api->mqtt);
- g_clear_object(&api->cons);
- if(api->msgs != NULL) {
- g_queue_free_full(api->msgs, (GDestroyNotify)fb_api_message_free);
- g_clear_pointer(&api->cid, g_free);
- g_clear_pointer(&api->did, g_free);
- g_clear_pointer(&api->stoken, g_free);
- g_clear_pointer(&api->token, g_free);
- g_clear_pointer(&api->contacts_delta, g_free);
-fb_api_class_init(FbApiClass *klass)
- GObjectClass *gklass = G_OBJECT_CLASS(klass);
- GParamSpec *props[PROP_N] = {NULL};
- gklass->set_property = fb_api_set_property;
- gklass->get_property = fb_api_get_property;
- gklass->dispose = fb_api_dispose;
- * The client identifier for MQTT. This value should be saved
- * and loaded for persistence.
- props[PROP_CID] = g_param_spec_string(
- "Client identifier for MQTT",
- * The device identifier for the MQTT message queue. This value
- * should be saved and loaded for persistence.
- props[PROP_DID] = g_param_spec_string(
- "Device identifier for the MQTT message queue",
- * The MQTT identifier. This value should be saved and loaded
- props[PROP_MID] = g_param_spec_uint64(
- * The synchronization token for the MQTT message queue. This
- * value should be saved and loaded for persistence.
- props[PROP_STOKEN] = g_param_spec_string(
- "Synchronization token for the MQTT message queue",
- * The access token for authentication. This value should be
- * saved and loaded for persistence.
- props[PROP_TOKEN] = g_param_spec_string(
- "Access token for authentication",
- * The #FbId of the user of the #FbApi.
- props[PROP_UID] = g_param_spec_int64(
- g_object_class_install_properties(gklass, PROP_N, props);
- * Emitted upon the successful completion of the authentication
- * process. This is emitted as a result of #fb_api_auth().
- G_TYPE_FROM_CLASS(klass),
- * Emitted upon the successful completion of the connection
- * process. This is emitted as a result of #fb_api_connect().
- g_signal_new("connect",
- G_TYPE_FROM_CLASS(klass),
- * @user: The #FbApiUser.
- * Emitted upon the successful reply of a contact request. This
- * is emitted as a result of #fb_api_contact().
- g_signal_new("contact",
- G_TYPE_FROM_CLASS(klass),
- * @users: The #GSList of #FbApiUser's.
- * @complete: #TRUE if the list is fetched, otherwise #FALSE.
- * Emitted upon the successful reply of a contacts request.
- * This is emitted as a result of #fb_api_contacts(). This can
- * be emitted multiple times before the entire contacts list
- * has been fetched. Use @complete for detecting the completion
- * status of the list fetch.
- g_signal_new("contacts",
- G_TYPE_FROM_CLASS(klass),
- 2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
- * FbApi::contacts-delta:
- * @added: The #GSList of added #FbApiUser's.
- * @removed: The #GSList of strings with removed user ids.
- * Like 'contacts', but only the deltas.
- g_signal_new("contacts-delta",
- G_TYPE_FROM_CLASS(klass),
- 2, G_TYPE_POINTER, G_TYPE_POINTER);
- * Emitted whenever an error is hit within the #FbApi. This
- * should disconnect the #FbApi with #fb_api_disconnect().
- G_TYPE_FROM_CLASS(klass),
- * @events: The #GSList of #FbApiEvent's.
- * Emitted upon incoming events from the stream.
- G_TYPE_FROM_CLASS(klass),
- * @msgs: The #GSList of #FbApiMessage's.
- * Emitted upon incoming messages from the stream.
- g_signal_new("messages",
- G_TYPE_FROM_CLASS(klass),
- * @press: The #GSList of #FbApiPresence's.
- * Emitted upon incoming presences from the stream.
- g_signal_new("presences",
- G_TYPE_FROM_CLASS(klass),
- * @thrd: The #FbApiThread.
- * Emitted upon the successful reply of a thread request. This
- * is emitted as a result of #fb_api_thread().
- G_TYPE_FROM_CLASS(klass),
- * FbApi::thread-create:
- * @tid: The thread #FbId.
- * Emitted upon the successful reply of a thread creation
- * request. This is emitted as a result of
- * #fb_api_thread_create().
- g_signal_new("thread-create",
- G_TYPE_FROM_CLASS(klass),
- * FbApi::thread-kicked:
- * @thrd: The #FbApiThread.
- * Emitted upon the reply of a thread request when the user is no longer
- * part of that thread. This is emitted as a result of #fb_api_thread().
- g_signal_new("thread-kicked",
- G_TYPE_FROM_CLASS(klass),
- * @thrds: The #GSList of #FbApiThread's.
- * Emitted upon the successful reply of a threads request. This
- * is emitted as a result of #fb_api_threads().
- g_signal_new("threads",
- G_TYPE_FROM_CLASS(klass),
- * @typg: The #FbApiTyping.
- * Emitted upon an incoming typing state from the stream.
- G_TYPE_FROM_CLASS(klass),
- api->msgs = g_queue_new();
-fb_api_error_quark(void)
- if (G_UNLIKELY(q == 0)) {
- q = g_quark_from_static_string("fb-api-error-quark");
-fb_api_json_chk(FbApi *api, gconstpointer data, gssize size, JsonNode **node)
- FbApiError errc = FB_API_ERROR_GENERAL;
- gboolean success = TRUE;
- static const gchar *exprs[] = {
- "$.failedSend.errorMessage",
- g_return_val_if_fail(FB_IS_API(api), FALSE);
- if (G_UNLIKELY(size == 0)) {
- fb_api_error_literal(api, FB_API_ERROR_GENERAL, _("Empty JSON data"));
- fb_util_debug(FB_UTIL_DEBUG_INFO, "Parsing JSON: %.*s\n",
- (gint) size, (const gchar *) data);
- root = fb_json_node_new(data, size, &err);
- FB_API_ERROR_EMIT(api, err, return FALSE);
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE, "$.error_code");
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE, "$.error.type");
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE, "$.errorCode");
- fb_json_values_update(values, &err);
- FB_API_ERROR_EMIT(api, err,
- g_object_unref(values);
- code = fb_json_values_next_int(values, 0);
- str = fb_json_values_next_str(values, NULL);
- if (purple_strequal(str, "OAuthException") || (code == 401)) {
- errc = FB_API_ERROR_AUTH;
- g_clear_pointer(&api->stoken, g_free);
- g_clear_pointer(&api->token, g_free);
- /* 509 is used for "invalid attachment id" */
- errc = FB_API_ERROR_NONFATAL;
- str = fb_json_values_next_str(values, NULL);
- if (purple_strequal(str, "ERROR_QUEUE_NOT_FOUND") ||
- purple_strequal(str, "ERROR_QUEUE_LOST"))
- errc = FB_API_ERROR_QUEUE;
- g_clear_pointer(&api->stoken, g_free);
- g_object_unref(values);
- for (msg = NULL, i = 0; i < G_N_ELEMENTS(exprs); i++) {
- msg = fb_json_node_get_str(root, exprs[i], NULL);
- if (!success && (msg == NULL)) {
- msg = g_strdup(_("Unknown error"));
- fb_api_error_literal(api, errc, msg);
-fb_api_http_chk(FbApi *api, SoupSession *session, GAsyncResult *result,
- SoupMessage *msg, JsonNode **root)
- GBytes *response_body = NULL;
- const gchar *reason = NULL;
- const gchar *data = NULL;
- reason = soup_message_get_reason_phrase(msg);
- code = soup_message_get_status(msg);
- fb_util_debug(FB_UTIL_DEBUG_INFO, "HTTP Response (%p):", msg);
- fb_util_debug(FB_UTIL_DEBUG_INFO, " Response Error: %s (%d)", reason,
- fb_util_debug(FB_UTIL_DEBUG_INFO, " Response Error: %d", code);
- if (fb_http_error_chk(msg, &err) && (root == NULL)) {
- response_body = soup_session_send_and_read_finish(session, result, &err);
- if(response_body != NULL) {
- data = g_bytes_get_data(response_body, &size);
- if (G_LIKELY(size > 0)) {
- fb_util_debug(FB_UTIL_DEBUG_INFO, " Response Data: %.*s",
- /* Rudimentary check to prevent wrongful error parsing */
- if ((size < 2) || (data[0] != '{') || (data[size - 1] != '}')) {
- FB_API_ERROR_EMIT(api, err, return FALSE);
- if (!fb_api_json_chk(api, data, size, root)) {
- if (G_UNLIKELY(err != NULL)) {
- FB_API_ERROR_EMIT(api, err, return FALSE);
-fb_api_http_req(FbApi *api, const gchar *url, const gchar *name,
- const gchar *method, FbHttpParams *params,
- GAsyncReadyCallback callback)
- fb_http_params_set_str(params, "api_key", FB_API_KEY);
- fb_http_params_set_str(params, "device_id", api->did);
- fb_http_params_set_str(params, "fb_api_req_friendly_name", name);
- fb_http_params_set_str(params, "format", "json");
- fb_http_params_set_str(params, "method", method);
- val = fb_util_get_locale();
- fb_http_params_set_str(params, "locale", val);
- /* Ensure an old signature is not computed */
- g_hash_table_remove(params, "sig");
- gstr = g_string_new(NULL);
- keys = g_hash_table_get_keys(params);
- keys = g_list_sort(keys, (GCompareFunc) g_ascii_strcasecmp);
- for (l = keys; l != NULL; l = l->next) {
- val = g_hash_table_lookup(params, key);
- g_string_append_printf(gstr, "%s=%s", key, val);
- g_string_append(gstr, FB_API_SECRET);
- data = g_compute_checksum_for_string(G_CHECKSUM_MD5, gstr->str,
- fb_http_params_set_str(params, "sig", data);
- g_string_free(gstr, TRUE);
- msg = soup_message_new_from_encoded_form("POST", url, soup_form_encode_hash(params));
- fb_http_params_free(params);
- if (api->token != NULL) {
- data = g_strdup_printf("OAuth %s", api->token);
- soup_message_headers_replace(soup_message_get_request_headers(msg),
- "Authorization", data);
- g_object_set_data(G_OBJECT(msg), "facebook-api", api);
- soup_session_send_and_read_async(api->cons, msg, G_PRIORITY_DEFAULT, NULL,
- fb_util_debug(FB_UTIL_DEBUG_INFO, "HTTP Request (%p):", msg);
- fb_util_debug(FB_UTIL_DEBUG_INFO, " Request URL: %s", url);
-fb_api_http_query(FbApi *api, gint64 query, JsonBuilder *builder,
- GAsyncReadyCallback hcb)
- case FB_API_QUERY_CONTACT:
- case FB_API_QUERY_CONTACTS:
- name = "FetchContactsFullQuery";
- case FB_API_QUERY_CONTACTS_AFTER:
- name = "FetchContactsFullWithAfterQuery";
- case FB_API_QUERY_CONTACTS_DELTA:
- name = "FetchContactsDeltaQuery";
- case FB_API_QUERY_STICKER:
- name = "FetchStickersWithPreviewsQuery";
- case FB_API_QUERY_THREAD:
- case FB_API_QUERY_SEQ_ID:
- case FB_API_QUERY_THREADS:
- name = "ThreadListQuery";
- g_return_val_if_reached(NULL);
- prms = fb_http_params_new();
- json = fb_json_bldr_close(builder, JSON_NODE_OBJECT, NULL);
- fb_http_params_set_strf(prms, "query_id", "%" G_GINT64_FORMAT, query);
- fb_http_params_set_str(prms, "query_params", json);
- return fb_api_http_req(api, FB_API_URL_GQL, name, "get", prms, hcb);
-fb_api_cb_http_bool(GObject *source, GAsyncResult *result, gpointer data) {
- SoupSession *session = SOUP_SESSION(source);
- SoupMessage *soupmsg = data;
- FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
- if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
- g_object_unref(soupmsg);
- if (!json_node_get_boolean(root)) {
- fb_api_error_literal(api, FB_API_ERROR,
- _("Failed generic API operation"));
- g_object_unref(soupmsg);
-fb_api_cb_mqtt_error(G_GNUC_UNUSED FbMqtt *mqtt, GError *error, gpointer data)
- fb_util_debug_info("Attempting to reconnect the MQTT stream...");
- fb_api_connect(api, api->invisible);
- g_signal_emit_by_name(api, "error", error);
-fb_api_cb_mqtt_open(FbMqtt *mqtt, gpointer data)
- const GByteArray *bytes;
- static guint8 flags = FB_MQTT_CONNECT_FLAG_USER |
- FB_MQTT_CONNECT_FLAG_PASS |
- FB_MQTT_CONNECT_FLAG_CLR;
- thft = fb_thrift_new(NULL, 0);
- /* Write the client identifier */
- fb_thrift_write_field(thft, FB_THRIFT_TYPE_STRING, 1, 0);
- fb_thrift_write_str(thft, api->cid);
- fb_thrift_write_field(thft, FB_THRIFT_TYPE_STRUCT, 4, 1);
- /* Write the user identifier */
- fb_thrift_write_field(thft, FB_THRIFT_TYPE_I64, 1, 0);
- fb_thrift_write_i64(thft, api->uid);
- /* Write the information string */
- fb_thrift_write_field(thft, FB_THRIFT_TYPE_STRING, 2, 1);
- fb_thrift_write_str(thft, FB_API_MQTT_AGENT);
- /* Write the UNKNOWN ("cp"?) */
- fb_thrift_write_field(thft, FB_THRIFT_TYPE_I64, 3, 2);
- fb_thrift_write_i64(thft, 23);
- /* Write the UNKNOWN ("ecp"?) */
- fb_thrift_write_field(thft, FB_THRIFT_TYPE_I64, 4, 3);
- fb_thrift_write_i64(thft, 26);
- /* Write the UNKNOWN */
- fb_thrift_write_field(thft, FB_THRIFT_TYPE_I32, 5, 4);
- fb_thrift_write_i32(thft, 1);
- /* Write the UNKNOWN ("no_auto_fg"?) */
- fb_thrift_write_field(thft, FB_THRIFT_TYPE_BOOL, 6, 5);
- fb_thrift_write_bool(thft, TRUE);
- /* Write the visibility state */
- fb_thrift_write_field(thft, FB_THRIFT_TYPE_BOOL, 7, 6);
- fb_thrift_write_bool(thft, !api->invisible);
- /* Write the device identifier */
- fb_thrift_write_field(thft, FB_THRIFT_TYPE_STRING, 8, 7);
- fb_thrift_write_str(thft, api->did);
- /* Write the UNKNOWN ("fg"?) */
- fb_thrift_write_field(thft, FB_THRIFT_TYPE_BOOL, 9, 8);
- fb_thrift_write_bool(thft, TRUE);
- /* Write the UNKNOWN ("nwt"?) */
- fb_thrift_write_field(thft, FB_THRIFT_TYPE_I32, 10, 9);
- fb_thrift_write_i32(thft, 1);
- /* Write the UNKNOWN ("nwst"?) */
- fb_thrift_write_field(thft, FB_THRIFT_TYPE_I32, 11, 10);
- fb_thrift_write_i32(thft, 0);
- /* Write the MQTT identifier */
- fb_thrift_write_field(thft, FB_THRIFT_TYPE_I64, 12, 11);
- fb_thrift_write_i64(thft, api->mid);
- /* Write the UNKNOWN */
- fb_thrift_write_field(thft, FB_THRIFT_TYPE_LIST, 14, 12);
- fb_thrift_write_list(thft, FB_THRIFT_TYPE_I32, 0);
- fb_thrift_write_stop(thft);
- fb_thrift_write_field(thft, FB_THRIFT_TYPE_STRING, 15, 14);
- fb_thrift_write_str(thft, api->token);
- /* Write the STOP for the struct */
- fb_thrift_write_stop(thft);
- bytes = fb_thrift_get_bytes(thft);
- cytes = fb_util_zlib_deflate(bytes, &err);
- FB_API_ERROR_EMIT(api, err,
- fb_util_debug_hexdump(FB_UTIL_DEBUG_INFO, bytes, "Writing connect");
- fb_mqtt_connect(mqtt, flags, cytes);
- g_byte_array_free(cytes, TRUE);
-fb_api_connect_queue(FbApi *api)
- bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
- fb_json_bldr_add_int(bldr, "delta_batch_size", 125);
- fb_json_bldr_add_int(bldr, "max_deltas_able_to_process", 1250);
- fb_json_bldr_add_int(bldr, "sync_api_version", 3);
- fb_json_bldr_add_str(bldr, "encoding", "JSON");
- if (api->stoken == NULL) {
- fb_json_bldr_add_int(bldr, "initial_titan_sequence_id", api->sid);
- fb_json_bldr_add_str(bldr, "device_id", api->did);
- fb_json_bldr_add_int(bldr, "entity_fbid", api->uid);
- fb_json_bldr_obj_begin(bldr, "queue_params");
- fb_json_bldr_add_str(bldr, "buzz_on_deltas_enabled", "false");
- fb_json_bldr_obj_begin(bldr, "graphql_query_hashes");
- fb_json_bldr_add_str(bldr, "xma_query_id",
- G_STRINGIFY(FB_API_QUERY_XMA));
- fb_json_bldr_obj_end(bldr);
- fb_json_bldr_obj_begin(bldr, "graphql_query_params");
- fb_json_bldr_obj_begin(bldr, G_STRINGIFY(FB_API_QUERY_XMA));
- fb_json_bldr_add_str(bldr, "xma_id", "<ID>");
- fb_json_bldr_obj_end(bldr);
- fb_json_bldr_obj_end(bldr);
- fb_json_bldr_obj_end(bldr);
- json = fb_json_bldr_close(bldr, JSON_NODE_OBJECT, NULL);
- fb_api_publish(api, "/messenger_sync_create_queue", "%s",
- fb_json_bldr_add_int(bldr, "last_seq_id", api->sid);
- fb_json_bldr_add_str(bldr, "sync_token", api->stoken);
- json = fb_json_bldr_close(bldr, JSON_NODE_OBJECT, NULL);
- fb_api_publish(api, "/messenger_sync_get_diffs", "%s", json);
- g_signal_emit_by_name(api, "connect");
- if (!g_queue_is_empty(api->msgs)) {
- msg = g_queue_peek_head(api->msgs);
- fb_api_message_send(api, msg);
- fb_util_debug_info("Reconnected the MQTT stream");
-fb_api_cb_seqid(GObject *source, GAsyncResult *result, gpointer data) {
- SoupSession *session = SOUP_SESSION(source);
- SoupMessage *soupmsg = data;
- FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
- if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
- g_object_unref(soupmsg);
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.viewer.message_threads.sync_sequence_id");
- fb_json_values_add(values, FB_JSON_TYPE_INT, TRUE,
- "$.viewer.message_threads.unread_count");
- fb_json_values_update(values, &err);
- FB_API_ERROR_EMIT(api, err,
- g_object_unref(values);
- g_object_unref(soupmsg);
- str = fb_json_values_next_str(values, "0");
- api->sid = g_ascii_strtoll(str, NULL, 10);
- api->unread = fb_json_values_next_int(values, 0);
- fb_api_error_literal(api, FB_API_ERROR_GENERAL,
- _("Failed to get sync_sequence_id"));
- fb_api_connect_queue(api);
- g_object_unref(values);
- g_object_unref(soupmsg);
-fb_api_cb_mqtt_connect(FbMqtt *mqtt, gpointer data)
- bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
- fb_json_bldr_add_bool(bldr, "foreground", TRUE);
- fb_json_bldr_add_int(bldr, "keepalive_timeout", FB_MQTT_KA);
- json = fb_json_bldr_close(bldr, JSON_NODE_OBJECT, NULL);
- fb_api_publish(api, "/foreground_state", "%s", json);
- fb_mqtt_subscribe(mqtt,
- "/messaging_events", 0,
- "/orca_typing_notifications", 0,
- /* Notifications seem to lead to some sort of sending rate limit */
- fb_mqtt_unsubscribe(mqtt, "/orca_message_notifications", NULL);
- bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
- fb_json_bldr_add_str(bldr, "1", "0");
- fb_api_http_query(api, FB_API_QUERY_SEQ_ID, bldr,
- fb_api_connect_queue(api);
-fb_api_cb_publish_mark(FbApi *api, GByteArray *pload)
- if (!fb_api_json_chk(api, pload->data, pload->len, &root)) {
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_BOOL, FALSE, "$.succeeded");
- fb_json_values_update(values, &err);
- FB_API_ERROR_EMIT(api, err,
- g_object_unref(values);
- if (!fb_json_values_next_bool(values, TRUE)) {
- fb_api_error_literal(api, FB_API_ERROR_GENERAL,
- _("Failed to mark thread as read"));
- g_object_unref(values);
-fb_api_event_parse(G_GNUC_UNUSED FbApi *api, FbApiEvent *event, GSList *events,
- JsonNode *root, GError **error)
- FB_API_EVENT_TYPE_THREAD_USER_ADDED,
- "$.log_message_data.added_participants"
- FB_API_EVENT_TYPE_THREAD_USER_REMOVED,
- "$.log_message_data.removed_participants"
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE, "$.author");
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.log_message_data.name");
- fb_json_values_update(values, &err);
- if (G_UNLIKELY(err != NULL)) {
- g_propagate_error(error, err);
- g_object_unref(values);
- str = fb_json_values_next_str(values, NULL);
- if (g_strcmp0(str, "log:thread-name") == 0) {
- str = fb_json_values_next_str(values, "");
- str = strrchr(str, ':');
- devent = g_new(FbApiEvent, 1);
- devent->type = FB_API_EVENT_TYPE_THREAD_TOPIC;
- devent->uid = FB_ID_FROM_STR(str + 1);
- devent->tid = event->tid;
- devent->text = fb_json_values_next_str_dup(values, NULL);
- events = g_slist_prepend(events, devent);
- g_object_unref(values);
- for (i = 0; i < G_N_ELEMENTS(evtypes); i++) {
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$");
- fb_json_values_set_array(values, FALSE, evtypes[i].expr);
- while (fb_json_values_update(values, &err)) {
- str = fb_json_values_next_str(values, "");
- str = strrchr(str, ':');
- devent = g_new0(FbApiEvent, 1);
- devent->type = evtypes[i].type;
- devent->uid = FB_ID_FROM_STR(str + 1);
- devent->tid = event->tid;
- events = g_slist_prepend(events, devent);
- g_object_unref(values);
- if (G_UNLIKELY(err != NULL)) {
- g_propagate_error(error, err);
-fb_api_cb_publish_mercury(FbApi *api, GByteArray *pload)
- if (!fb_api_json_chk(api, pload->data, pload->len, &root)) {
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.thread_fbid");
- fb_json_values_set_array(values, FALSE, "$.actions");
- while (fb_json_values_update(values, &err)) {
- fb_api_event_reset(&event, FALSE);
- str = fb_json_values_next_str(values, "0");
- event.tid = FB_ID_FROM_STR(str);
- node = fb_json_values_get_root(values);
- events = fb_api_event_parse(api, &event, events, node, &err);
- if (G_LIKELY(err == NULL)) {
- events = g_slist_reverse(events);
- g_signal_emit_by_name(api, "events", events);
- fb_api_error_emit(api, err);
- g_slist_free_full(events, (GDestroyNotify) fb_api_event_free);
- g_object_unref(values);
-fb_api_cb_publish_typing(FbApi *api, GByteArray *pload)
- if (!fb_api_json_chk(api, pload->data, pload->len, &root)) {
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.type");
- fb_json_values_add(values, FB_JSON_TYPE_INT, TRUE, "$.sender_fbid");
- fb_json_values_add(values, FB_JSON_TYPE_INT, TRUE, "$.state");
- fb_json_values_update(values, &err);
- FB_API_ERROR_EMIT(api, err,
- g_object_unref(values);
- str = fb_json_values_next_str(values, NULL);
- if (g_ascii_strcasecmp(str, "typ") == 0) {
- typg.uid = fb_json_values_next_int(values, 0);
- if (typg.uid != api->uid) {
- typg.state = fb_json_values_next_int(values, 0);
- g_signal_emit_by_name(api, "typing", &typg);
- g_object_unref(values);
-fb_api_cb_publish_ms_r(FbApi *api, GByteArray *pload)
- if (!fb_api_json_chk(api, pload->data, pload->len, &root)) {
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_BOOL, TRUE, "$.succeeded");
- fb_json_values_update(values, &err);
- FB_API_ERROR_EMIT(api, err,
- g_object_unref(values);
- if (fb_json_values_next_bool(values, TRUE)) {
- /* Pop and free the successful message */
- msg = g_queue_pop_head(api->msgs);
- fb_api_message_free(msg);
- if (!g_queue_is_empty(api->msgs)) {
- msg = g_queue_peek_head(api->msgs);
- fb_api_message_send(api, msg);
- fb_api_error_literal(api, FB_API_ERROR_GENERAL,
- "Failed to send message");
- g_object_unref(values);
-fb_api_xma_parse(G_GNUC_UNUSED FbApi *api, const char *body, JsonNode *root,
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.story_attachment.target.__type__.name");
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.story_attachment.url");
- fb_json_values_update(values, &err);
- if (G_UNLIKELY(err != NULL)) {
- g_propagate_error(error, err);
- g_object_unref(values);
- str = fb_json_values_next_str(values, NULL);
- url = fb_json_values_next_str(values, NULL);
- if ((str == NULL) || (url == NULL)) {
- text = g_strdup(_("<Unsupported Attachment>"));
- g_object_unref(values);
- if (purple_strequal(str, "ExternalUrl")) {
- params = fb_http_params_new_parse(url, TRUE);
- if (g_str_has_prefix(url, FB_API_FBRPC_PREFIX)) {
- text = fb_http_params_dup_str(params, "target_url", NULL);
- text = fb_http_params_dup_str(params, "u", NULL);
- fb_http_params_free(params);
- if (fb_http_urlcmp(body, text, FALSE)) {
- g_object_unref(values);
- g_object_unref(values);
-fb_api_message_parse_attach(FbApi *api, const gchar *mid, FbApiMessage *msg,
- GSList *msgs, const gchar *body, JsonNode *root,
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE, "$.xmaGraphQL");
- fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE, "$.fbid");
- fb_json_values_set_array(values, FALSE, "$.attachments");
- while (fb_json_values_update(values, &err)) {
- str = fb_json_values_next_str(values, NULL);
- id = fb_json_values_next_int(values, 0);
- dmsg = g_memdup2(msg, sizeof(*msg));
- fb_api_attach(api, id, mid, dmsg);
- node = fb_json_node_new(str, -1, &err);
- if (G_UNLIKELY(err != NULL)) {
- xode = fb_json_node_get_nth(node, 0);
- xma = fb_api_xma_parse(api, body, xode, &err);
- dmsg = g_memdup2(msg, sizeof(*msg));
- msgs = g_slist_prepend(msgs, dmsg);
- if (G_UNLIKELY(err != NULL)) {
- if (G_UNLIKELY(err != NULL)) {
- g_propagate_error(error, err);
- g_object_unref(values);
-fb_api_cb_publish_ms_new_message(FbApi *api, JsonNode *root, GSList *msgs, GError **error);
-fb_api_cb_publish_ms_event(FbApi *api, JsonNode *root, GSList *events, FbApiEventType type, GError **error);
-fb_api_cb_publish_mst(FbThrift *thft, GError **error)
- if (fb_thrift_read_isstop(thft)) {
- FB_API_TCHK(fb_thrift_read_stop(thft));
- 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));
-fb_api_cb_publish_ms(FbApi *api, GByteArray *pload)
- {"deltaNewMessage", 0, 1},
- {"deltaThreadName", FB_API_EVENT_TYPE_THREAD_TOPIC, 0},
- {"deltaParticipantsAddedToGroupThread", FB_API_EVENT_TYPE_THREAD_USER_ADDED, 0},
- {"deltaParticipantLeftGroupThread", FB_API_EVENT_TYPE_THREAD_USER_REMOVED, 0},
- /* Read identifier string (for Facebook employees) */
- thft = fb_thrift_new(pload, 0);
- fb_api_cb_publish_mst(thft, &err);
- size = fb_thrift_get_pos(thft);
- FB_API_ERROR_EMIT(api, err,
- g_return_if_fail(size < pload->len);
- data = (gchar *) pload->data + size;
- size = pload->len - size;
- if (!fb_api_json_chk(api, data, size, &root)) {
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE, "$.syncToken");
- fb_json_values_update(values, &err);
- FB_API_ERROR_EMIT(api, err,
- g_object_unref(values);
- api->sid = fb_json_values_next_int(values, 0);
- stoken = fb_json_values_next_str_dup(values, NULL);
- g_object_unref(values);
- if (G_UNLIKELY(stoken != NULL)) {
- g_signal_emit_by_name(api, "connect");
- arr = fb_json_node_get_arr(root, "$.deltas", NULL);
- elms = json_array_get_elements(arr);
- for (l = elms; l != NULL; l = l->next) {
- JsonObject *o = json_node_get_object(l->data);
- for (i = 0; i < G_N_ELEMENTS(event_types); i++) {
- if ((node = json_object_get_member(o, event_types[i].member))) {
- if (event_types[i].is_message) {
- msgs = fb_api_cb_publish_ms_new_message(
- events = fb_api_cb_publish_ms_event(
- api, node, events, event_types[i].type, &err
- if (G_UNLIKELY(err != NULL)) {
- if (G_LIKELY(err == NULL)) {
- msgs = g_slist_reverse(msgs);
- g_signal_emit_by_name(api, "messages", msgs);
- events = g_slist_reverse(events);
- g_signal_emit_by_name(api, "events", events);
- fb_api_error_emit(api, err);
- g_slist_free_full(msgs, (GDestroyNotify) fb_api_message_free);
- g_slist_free_full(events, (GDestroyNotify) fb_api_event_free);
-fb_api_cb_publish_ms_new_message(FbApi *api, JsonNode *root, GSList *msgs, GError **error)
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
- "$.messageMetadata.offlineThreadingId");
- fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
- "$.messageMetadata.actorFbId");
- fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
- ".threadKey.otherUserFbId");
- fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
- ".threadKey.threadFbId");
- fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
- "$.messageMetadata.timestamp");
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.messageMetadata.messageId");
- if (fb_json_values_update(values, &err)) {
- id = fb_json_values_next_int(values, 0);
- /* Ignore everything but new messages */
- /* Ignore sequential duplicates */
- if (id == api->lastmid) {
- fb_util_debug_info("Ignoring duplicate %" FB_ID_FORMAT, id);
- fb_api_message_reset(&msg, FALSE);
- msg.uid = fb_json_values_next_int(values, 0);
- oid = fb_json_values_next_int(values, 0);
- msg.tid = fb_json_values_next_int(values, 0);
- msg.tstamp = fb_json_values_next_int(values, 0);
- if (msg.uid == api->uid) {
- msg.flags |= FB_API_MESSAGE_FLAG_SELF;
- body = fb_json_values_next_str(values, NULL);
- dmsg = g_memdup2(&msg, sizeof(msg));
- dmsg->text = g_strdup(body);
- msgs = g_slist_prepend(msgs, dmsg);
- id = fb_json_values_next_int(values, 0);
- dmsg = g_memdup2(&msg, sizeof(msg));
- fb_api_sticker(api, id, dmsg);
- str = fb_json_values_next_str(values, NULL);
- node = fb_json_values_get_root(values);
- msgs = fb_api_message_parse_attach(api, str, &msg, msgs, body,
- if (G_UNLIKELY(err != NULL)) {
- g_propagate_error(error, err);
- g_object_unref(values);
-fb_api_cb_publish_ms_event(G_GNUC_UNUSED FbApi *api, JsonNode *root,
- GSList *events, FbApiEventType type, GError **error)
- FbJsonValues *values = NULL;
- FbJsonValues *values_inner = NULL;
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
- "$.messageMetadata.threadKey.threadFbId");
- fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
- "$.messageMetadata.actorFbId");
- case FB_API_EVENT_TYPE_THREAD_TOPIC:
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- case FB_API_EVENT_TYPE_THREAD_USER_ADDED:
- values_inner = fb_json_values_new(root);
- fb_json_values_add(values_inner, FB_JSON_TYPE_INT, FALSE,
- /* use the text field for the full name */
- fb_json_values_add(values_inner, FB_JSON_TYPE_STR, FALSE,
- fb_json_values_set_array(values_inner, FALSE,
- "$.addedParticipants");
- case FB_API_EVENT_TYPE_THREAD_USER_REMOVED:
- fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
- "$.leftParticipantFbId");
- /* use the text field for the kick message */
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.messageMetadata.adminText");
- fb_json_values_update(values, &err);
- event = g_new0(FbApiEvent, 1);
- event->tid = fb_json_values_next_int(values, 0);
- event->uid = fb_json_values_next_int(values, 0);
- if (type == FB_API_EVENT_TYPE_THREAD_TOPIC) {
- event->text = fb_json_values_next_str_dup(values, NULL);
- } else if (type == FB_API_EVENT_TYPE_THREAD_USER_REMOVED) {
- /* overwrite actor with subject */
- event->uid = fb_json_values_next_int(values, 0);
- event->text = fb_json_values_next_str_dup(values, NULL);
- } else if (type == FB_API_EVENT_TYPE_THREAD_USER_ADDED) {
- while (fb_json_values_update(values_inner, &err)) {
- FbApiEvent *devent = g_new0(FbApiEvent, 1);
- devent->type = event->type;
- devent->uid = fb_json_values_next_int(values_inner, 0);
- devent->tid = event->tid;
- devent->text = fb_json_values_next_str_dup(values_inner, NULL);
- events = g_slist_prepend(events, devent);
- g_clear_pointer(&event, fb_api_event_free);
- g_object_unref(values_inner);
- g_object_unref(values);
- if (G_UNLIKELY(err != NULL)) {
- g_propagate_error(error, err);
- events = g_slist_prepend(events, event);
-fb_api_cb_publish_pt(FbThrift *thft, GSList **presences, GError **error)
- FbApiPresence *api_presence;
- /* Read identifier string (for Facebook employees) */
- FB_API_TCHK(fb_thrift_read_str(thft, NULL));
- /* Read the full list boolean field */
- FB_API_TCHK(fb_thrift_read_field(thft, &type, &id, 0));
- FB_API_TCHK(type == FB_THRIFT_TYPE_BOOL);
- FB_API_TCHK(fb_thrift_read_bool(thft, NULL));
- /* Read the list field */
- FB_API_TCHK(fb_thrift_read_field(thft, &type, &id, id));
- FB_API_TCHK(type == FB_THRIFT_TYPE_LIST);
- FB_API_TCHK(fb_thrift_read_list(thft, &type, &size));
- FB_API_TCHK(type == FB_THRIFT_TYPE_STRUCT);
- for (i = 0; i < size; i++) {
- /* Read the user identifier field */
- FB_API_TCHK(fb_thrift_read_field(thft, &type, &id, 0));
- FB_API_TCHK(type == FB_THRIFT_TYPE_I64);
- FB_API_TCHK(fb_thrift_read_i64(thft, &i64));
- /* Read the active field */
- FB_API_TCHK(fb_thrift_read_field(thft, &type, &id, id));
- FB_API_TCHK(type == FB_THRIFT_TYPE_I32);
- FB_API_TCHK(fb_thrift_read_i32(thft, &i32));
- api_presence = g_new0(FbApiPresence, 1);
- api_presence->uid = i64;
- api_presence->active = i32 != 0;
- *presences = g_slist_prepend(*presences, api_presence);
- fb_util_debug_info("Presence: %" FB_ID_FORMAT " (%d) id: %d",
- if (fb_thrift_read_isstop(thft)) {
- FB_API_TCHK(fb_thrift_read_field(thft, &type, &id, id));
- /* Read the last active timestamp field */
- FB_API_TCHK(type == FB_THRIFT_TYPE_I64);
- FB_API_TCHK(fb_thrift_read_i64(thft, NULL));
- /* Read the active client bits field */
- FB_API_TCHK(type == FB_THRIFT_TYPE_I16);
- FB_API_TCHK(fb_thrift_read_i16(thft, NULL));
- /* Read the VoIP compatibility bits field */
- FB_API_TCHK(type == FB_THRIFT_TYPE_I64);
- FB_API_TCHK(fb_thrift_read_i64(thft, NULL));
- /* Unknown new field */
- FB_API_TCHK(type == FB_THRIFT_TYPE_I64);
- FB_API_TCHK(fb_thrift_read_i64(thft, NULL));
- /* Try to read unknown fields as varint */
- FB_API_TCHK(type == FB_THRIFT_TYPE_I16 ||
- type == FB_THRIFT_TYPE_I32 ||
- type == FB_THRIFT_TYPE_I64);
- FB_API_TCHK(fb_thrift_read_i64(thft, NULL));
- /* Read the field stop */
- FB_API_TCHK(fb_thrift_read_stop(thft));
- /* Read the field stop */
- if (fb_thrift_read_isstop(thft)) {
- FB_API_TCHK(fb_thrift_read_stop(thft));
-fb_api_cb_publish_p(FbApi *api, GByteArray *pload)
- GSList *presences = NULL;
- thft = fb_thrift_new(pload, 0);
- fb_api_cb_publish_pt(thft, &presences, &err);
- if (G_LIKELY(err == NULL)) {
- g_signal_emit_by_name(api, "presences", presences);
- fb_api_error_emit(api, err);
- g_slist_free_full(presences, (GDestroyNotify)fb_api_presence_free);
-fb_api_cb_mqtt_publish(G_GNUC_UNUSED FbMqtt *mqtt, const char *topic,
- GByteArray *pload, gpointer data)
- void (*func) (FbApi *api, GByteArray *pload);
- {"/mark_thread_response", fb_api_cb_publish_mark},
- {"/mercury", fb_api_cb_publish_mercury},
- {"/orca_typing_notifications", fb_api_cb_publish_typing},
- {"/send_message_response", fb_api_cb_publish_ms_r},
- {"/t_ms", fb_api_cb_publish_ms},
- {"/t_p", fb_api_cb_publish_p}
- comp = fb_util_zlib_test(pload);
- bytes = fb_util_zlib_inflate(pload, &err);
- FB_API_ERROR_EMIT(api, err, return);
- bytes = (GByteArray *) pload;
- fb_util_debug_hexdump(FB_UTIL_DEBUG_INFO, bytes,
- "Reading message (topic: %s)",
- for (i = 0; i < G_N_ELEMENTS(parsers); i++) {
- if (g_ascii_strcasecmp(topic, parsers[i].topic) == 0) {
- parsers[i].func(api, bytes);
- g_byte_array_free(bytes, TRUE);
-fb_api_new(PurpleConnection *gc, GProxyResolver *resolver)
- api = g_object_new(FB_TYPE_API, NULL);
- api->cons = soup_session_new_with_options(
- "proxy-resolver", resolver,
- "user-agent", FB_API_AGENT,
- api->mqtt = fb_mqtt_new(gc);
- g_signal_connect(api->mqtt,
- G_CALLBACK(fb_api_cb_mqtt_connect),
- g_signal_connect(api->mqtt,
- G_CALLBACK(fb_api_cb_mqtt_error),
- g_signal_connect(api->mqtt,
- G_CALLBACK(fb_api_cb_mqtt_open),
- g_signal_connect(api->mqtt,
- G_CALLBACK(fb_api_cb_mqtt_publish),
-fb_api_rehash(FbApi *api)
- g_return_if_fail(FB_IS_API(api));
- if (api->cid == NULL) {
- api->cid = fb_util_rand_alnum(32);
- if (api->did == NULL) {
- api->did = g_uuid_string_random();
- api->mid = g_random_int();
- if (strlen(api->cid) > 20) {
- api->cid = g_realloc_n(api->cid , 21, sizeof *api->cid);
-fb_api_is_invisible(FbApi *api)
- g_return_val_if_fail(FB_IS_API(api), FALSE);
-fb_api_error_literal(FbApi *api, FbApiError error, const gchar *msg)
- g_return_if_fail(FB_IS_API(api));
- err = g_error_new_literal(FB_API_ERROR, error, msg);
- fb_api_error_emit(api, err);
-fb_api_error(FbApi *api, FbApiError error, const gchar *format, ...)
- g_return_if_fail(FB_IS_API(api));
- err = g_error_new_valist(FB_API_ERROR, error, format, ap);
- fb_api_error_emit(api, err);
-fb_api_error_emit(FbApi *api, GError *error)
- g_return_if_fail(FB_IS_API(api));
- g_return_if_fail(error != NULL);
- g_signal_emit_by_name(api, "error", error);
-fb_api_cb_attach(GObject *source, GAsyncResult *result, gpointer data) {
- SoupSession *session = SOUP_SESSION(source);
- SoupMessage *soupmsg = data;
- FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
- static const gchar *imgexts[] = {".jpg", ".png", ".gif"};
- if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
- g_object_unref(soupmsg);
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.filename");
- fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.redirect_uri");
- fb_json_values_update(values, &err);
- FB_API_ERROR_EMIT(api, err,
- g_object_unref(values);
- g_object_unref(soupmsg);
- msg = g_object_steal_data(G_OBJECT(soupmsg), "fb-api-msg");
- str = fb_json_values_next_str(values, NULL);
- name = g_ascii_strdown(str, -1);
- for (i = 0; i < G_N_ELEMENTS(imgexts); i++) {
- if (g_str_has_suffix(name, imgexts[i])) {
- msg->flags |= FB_API_MESSAGE_FLAG_IMAGE;
- msg->text = fb_json_values_next_str_dup(values, NULL);
- msgs = g_slist_prepend(msgs, msg);
- g_signal_emit_by_name(api, "messages", msgs);
- g_slist_free_full(msgs, (GDestroyNotify) fb_api_message_free);
- g_object_unref(values);
- g_object_unref(soupmsg);
-fb_api_attach(FbApi *api, FbId aid, const gchar *msgid, FbApiMessage *msg)
- prms = fb_http_params_new();
- fb_http_params_set_str(prms, "mid", msgid);
- fb_http_params_set_strf(prms, "aid", "%" FB_ID_FORMAT, aid);
- http = fb_api_http_req(api, FB_API_URL_ATTACH, "getAttachment",
- "messaging.getAttachment", prms,
- g_object_set_data_full(G_OBJECT(http), "fb-api-msg", msg,
- (GDestroyNotify)fb_api_message_free);
-fb_api_cb_auth(GObject *source, GAsyncResult *result, gpointer data) {
- SoupSession *session = SOUP_SESSION(source);
- SoupMessage *soupmsg = data;
- FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
- if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
- g_object_unref(soupmsg);
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.access_token");
- fb_json_values_add(values, FB_JSON_TYPE_INT, TRUE, "$.uid");
- fb_json_values_update(values, &err);
- FB_API_ERROR_EMIT(api, err,
- g_object_unref(values);
- g_object_unref(soupmsg);
- api->token = fb_json_values_next_str_dup(values, NULL);
- api->uid = fb_json_values_next_int(values, 0);
- g_signal_emit_by_name(api, "auth");
- g_object_unref(values);
- g_object_unref(soupmsg);
-fb_api_auth(FbApi *api, const gchar *user, const gchar *pass)
- prms = fb_http_params_new();
- fb_http_params_set_str(prms, "email", user);
- fb_http_params_set_str(prms, "password", pass);
- fb_api_http_req(api, FB_API_URL_AUTH, "authenticate", "auth.login",
-fb_api_user_icon_checksum(gchar *icon)
- if (G_UNLIKELY(icon == NULL)) {
- prms = fb_http_params_new_parse(icon, TRUE);
- csum = fb_http_params_dup_str(prms, "oh", NULL);
- fb_http_params_free(prms);
- if (G_UNLIKELY(csum == NULL)) {
- /* Revert to the icon URL as the unique checksum */
-fb_api_cb_contact(GObject *source, GAsyncResult *result, gpointer data) {
- SoupSession *session = SOUP_SESSION(source);
- SoupMessage *soupmsg = data;
- FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
- if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
- g_object_unref(soupmsg);
- node = fb_json_node_get_nth(root, 0);
- fb_api_error_literal(api, FB_API_ERROR_GENERAL,
- _("Failed to obtain contact information"));
- g_object_unref(soupmsg);
- values = fb_json_values_new(node);
- fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.id");
- fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.name");
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.profile_pic_large.uri");
- fb_json_values_update(values, &err);
- FB_API_ERROR_EMIT(api, err,
- g_object_unref(values);
- g_object_unref(soupmsg);
- fb_api_user_reset(&user, FALSE);
- str = fb_json_values_next_str(values, "0");
- user.uid = FB_ID_FROM_STR(str);
- user.name = fb_json_values_next_str_dup(values, NULL);
- user.icon = fb_json_values_next_str_dup(values, NULL);
- user.csum = fb_api_user_icon_checksum(user.icon);
- g_signal_emit_by_name(api, "contact", &user);
- fb_api_user_reset(&user, TRUE);
- g_object_unref(values);
- g_object_unref(soupmsg);
-fb_api_contact(FbApi *api, FbId uid)
- bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
- fb_json_bldr_arr_begin(bldr, "0");
- fb_json_bldr_add_strf(bldr, NULL, "%" FB_ID_FORMAT, uid);
- fb_json_bldr_arr_end(bldr);
- fb_json_bldr_add_str(bldr, "1", "true");
- fb_api_http_query(api, FB_API_QUERY_CONTACT, bldr, fb_api_cb_contact);
-fb_api_cb_contacts_nodes(FbApi *api, JsonNode *root, GSList *users)
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.represented_profile.id");
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.represented_profile.friendship_status");
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.structured_name.text");
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.hugePictureUrl.uri");
- is_array = (JSON_NODE_TYPE(root) == JSON_NODE_ARRAY);
- fb_json_values_set_array(values, FALSE, "$");
- while (fb_json_values_update(values, &err)) {
- str = fb_json_values_next_str(values, "0");
- uid = FB_ID_FROM_STR(str);
- str = fb_json_values_next_str(values, NULL);
- if ((!purple_strequal(str, "ARE_FRIENDS") &&
- (uid != api->uid)) || (uid == 0))
- user = g_new0(FbApiUser, 1);
- user->name = fb_json_values_next_str_dup(values, NULL);
- user->icon = fb_json_values_next_str_dup(values, NULL);
- user->csum = fb_api_user_icon_checksum(user->icon);
- users = g_slist_prepend(users, user);
- g_object_unref(values);
-/* base64(contact:<our id>:<their id>:<whatever>) */
-fb_api_cb_contacts_parse_removed(G_GNUC_UNUSED FbApi *api, JsonNode *node,
- char *decoded = (char *) g_base64_decode(json_node_get_string(node), &len);
- g_return_val_if_fail(decoded[len] == '\0', users);
- g_return_val_if_fail(len == strlen(decoded), users);
- g_return_val_if_fail(g_str_has_prefix(decoded, "contact:"), users);
- split = g_strsplit_set(decoded, ":", 4);
- if (g_strv_length(split) != 4) {
- g_return_val_if_reached(users);
- users = g_slist_prepend(users, g_strdup(split[2]));
-fb_api_cb_contacts(GObject *source, GAsyncResult *result, gpointer data) {
- SoupSession *session = SOUP_SESSION(source);
- SoupMessage *soupmsg = data;
- FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
- const gchar *delta_cursor;
- if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
- g_object_unref(soupmsg);
- croot = fb_json_node_get(root, "$.viewer.messenger_contacts.deltas", NULL);
- is_delta = (croot != NULL);
- croot = fb_json_node_get(root, "$.viewer.messenger_contacts", NULL);
- node = fb_json_node_get(croot, "$.nodes", NULL);
- users = fb_api_cb_contacts_nodes(api, node, users);
- GSList *removed = NULL;
- JsonArray *arr = fb_json_node_get_arr(croot, "$.nodes", NULL);
- GList *elms = json_array_get_elements(arr);
- for (l = elms; l != NULL; l = l->next) {
- if ((node = fb_json_node_get(l->data, "$.added", NULL))) {
- added = fb_api_cb_contacts_nodes(api, node, added);
- if ((node = fb_json_node_get(l->data, "$.removed", NULL))) {
- removed = fb_api_cb_contacts_parse_removed(api, node, removed);
- g_signal_emit_by_name(api, "contacts-delta", added, removed);
- g_slist_free_full(added, (GDestroyNotify) fb_api_user_free);
- g_slist_free_full(removed, g_free);
- values = fb_json_values_new(croot);
- fb_json_values_add(values, FB_JSON_TYPE_BOOL, FALSE,
- "$.page_info.has_next_page");
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.page_info.delta_cursor");
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.page_info.end_cursor");
- fb_json_values_update(values, NULL);
- complete = !fb_json_values_next_bool(values, FALSE);
- delta_cursor = fb_json_values_next_str(values, NULL);
- cursor = fb_json_values_next_str(values, NULL);
- if (G_UNLIKELY(err == NULL)) {
- if (is_delta || complete) {
- g_free(api->contacts_delta);
- api->contacts_delta = g_strdup(is_delta ? cursor : delta_cursor);
- g_signal_emit_by_name(api, "contacts", users, complete);
- fb_api_contacts_after(api, cursor);
- fb_api_error_emit(api, err);
- g_slist_free_full(users, (GDestroyNotify) fb_api_user_free);
- g_object_unref(values);
- g_object_unref(soupmsg);
-fb_api_contacts(FbApi *api)
- g_return_if_fail(FB_IS_API(api));
- if (api->contacts_delta) {
- fb_api_contacts_delta(api, api->contacts_delta);
- bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
- fb_json_bldr_arr_begin(bldr, "0");
- fb_json_bldr_add_str(bldr, NULL, "user");
- fb_json_bldr_arr_end(bldr);
- fb_json_bldr_add_str(bldr, "1", G_STRINGIFY(FB_API_CONTACTS_COUNT));
- fb_api_http_query(api, FB_API_QUERY_CONTACTS, bldr,
-fb_api_contacts_after(FbApi *api, const gchar *cursor)
- bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
- fb_json_bldr_arr_begin(bldr, "0");
- fb_json_bldr_add_str(bldr, NULL, "user");
- fb_json_bldr_arr_end(bldr);
- fb_json_bldr_add_str(bldr, "1", cursor);
- fb_json_bldr_add_str(bldr, "2", G_STRINGIFY(FB_API_CONTACTS_COUNT));
- fb_api_http_query(api, FB_API_QUERY_CONTACTS_AFTER, bldr,
-fb_api_contacts_delta(FbApi *api, const gchar *delta_cursor)
- bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
- fb_json_bldr_add_str(bldr, "0", delta_cursor);
- fb_json_bldr_arr_begin(bldr, "1");
- fb_json_bldr_add_str(bldr, NULL, "user");
- fb_json_bldr_arr_end(bldr);
- fb_json_bldr_add_str(bldr, "2", G_STRINGIFY(FB_API_CONTACTS_COUNT));
- fb_api_http_query(api, FB_API_QUERY_CONTACTS_DELTA, bldr,
-fb_api_connect(FbApi *api, gboolean invisible)
- g_return_if_fail(FB_IS_API(api));
- api->invisible = invisible;
- fb_mqtt_open(api->mqtt, FB_MQTT_HOST, FB_MQTT_PORT);
-fb_api_disconnect(FbApi *api)
- g_return_if_fail(FB_IS_API(api));
- fb_mqtt_disconnect(api->mqtt);
-fb_api_message_send(FbApi *api, FbApiMessage *msg)
- mid = FB_API_MSGID(g_get_real_time() / 1000, g_random_int());
- bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
- fb_json_bldr_add_str(bldr, "body", msg->text);
- fb_json_bldr_add_strf(bldr, "msgid", "%" FB_ID_FORMAT, mid);
- fb_json_bldr_add_strf(bldr, "sender_fbid", "%" FB_ID_FORMAT, api->uid);
- fb_json_bldr_add_strf(bldr, "to", "%s%" FB_ID_FORMAT, tpfx, id);
- json = fb_json_bldr_close(bldr, JSON_NODE_OBJECT, NULL);
- fb_api_publish(api, "/send_message2", "%s", json);
-fb_api_message(FbApi *api, FbId id, gboolean thread, const gchar *text)
- g_return_if_fail(FB_IS_API(api));
- g_return_if_fail(text != NULL);
- msg = g_new0(FbApiMessage, 1);
- msg->text = g_strdup(text);
- empty = g_queue_is_empty(api->msgs);
- g_queue_push_tail(api->msgs, msg);
- if (empty && fb_mqtt_connected(api->mqtt, FALSE)) {
- fb_api_message_send(api, msg);
-fb_api_publish(FbApi *api, const gchar *topic, const gchar *format, ...)
- g_return_if_fail(FB_IS_API(api));
- g_return_if_fail(topic != NULL);
- g_return_if_fail(format != NULL);
- msg = g_strdup_vprintf(format, ap);
- bytes = g_byte_array_new_take((guint8 *) msg, strlen(msg));
- cytes = fb_util_zlib_deflate(bytes, &err);
- FB_API_ERROR_EMIT(api, err,
- g_byte_array_free(bytes, TRUE);
- fb_util_debug_hexdump(FB_UTIL_DEBUG_INFO, bytes,
- "Writing message (topic: %s)",
- fb_mqtt_publish(api->mqtt, topic, cytes);
- g_byte_array_free(cytes, TRUE);
- g_byte_array_free(bytes, TRUE);
-fb_api_read(FbApi *api, FbId id, gboolean thread)
- g_return_if_fail(FB_IS_API(api));
- bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
- fb_json_bldr_add_bool(bldr, "state", TRUE);
- fb_json_bldr_add_int(bldr, "syncSeqId", api->sid);
- fb_json_bldr_add_str(bldr, "mark", "read");
- key = thread ? "threadFbId" : "otherUserFbId";
- fb_json_bldr_add_strf(bldr, key, "%" FB_ID_FORMAT, id);
- json = fb_json_bldr_close(bldr, JSON_NODE_OBJECT, NULL);
- fb_api_publish(api, "/mark_thread", "%s", json);
-fb_api_cb_unread_parse_attach(FbApi *api, const gchar *mid, FbApiMessage *msg,
- GSList *msgs, JsonNode *root, GError **error)
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE,
- fb_json_values_set_array(values, FALSE, "$.blob_attachments");
- while (fb_json_values_update(values, &err)) {
- str = fb_json_values_next_str(values, NULL);
- id = FB_ID_FROM_STR(str);
- dmsg = g_memdup2(msg, sizeof(*msg));
- fb_api_attach(api, id, mid, dmsg);
- if (G_UNLIKELY(err != NULL)) {
- g_propagate_error(error, err);
- g_object_unref(values);
-fb_api_cb_unread_msgs(GObject *source, GAsyncResult *result, gpointer data) {
- SoupSession *session = SOUP_SESSION(source);
- SoupMessage *soupmsg = data;
- FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
- if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
- g_object_unref(soupmsg);
- node = fb_json_node_get_nth(root, 0);
- fb_api_error_literal(api, FB_API_ERROR_GENERAL,
- _("Failed to obtain unread messages"));
- g_object_unref(soupmsg);
- values = fb_json_values_new(node);
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.thread_key.thread_fbid");
- fb_json_values_update(values, &err);
- FB_API_ERROR_EMIT(api, err,
- g_object_unref(values);
- g_object_unref(soupmsg);
- fb_api_message_reset(&msg, FALSE);
- str = fb_json_values_next_str(values, "0");
- tid = FB_ID_FROM_STR(str);
- g_object_unref(values);
- values = fb_json_values_new(node);
- fb_json_values_add(values, FB_JSON_TYPE_BOOL, TRUE, "$.unread");
- fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE,
- "$.message_sender.messaging_actor.id");
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE, "$.message.text");
- fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE,
- "$.timestamp_precise");
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE, "$.sticker.id");
- fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.message_id");
- fb_json_values_set_array(values, FALSE, "$.messages.nodes");
- while (fb_json_values_update(values, &err)) {
- if (!fb_json_values_next_bool(values, FALSE)) {
- str = fb_json_values_next_str(values, "0");
- body = fb_json_values_next_str(values, NULL);
- fb_api_message_reset(&msg, FALSE);
- msg.uid = FB_ID_FROM_STR(str);
- str = fb_json_values_next_str(values, "0");
- msg.tstamp = g_ascii_strtoll(str, NULL, 10);
- dmsg = g_memdup2(&msg, sizeof(msg));
- dmsg->text = g_strdup(body);
- msgs = g_slist_prepend(msgs, dmsg);
- str = fb_json_values_next_str(values, NULL);
- dmsg = g_memdup2(&msg, sizeof(msg));
- id = FB_ID_FROM_STR(str);
- fb_api_sticker(api, id, dmsg);
- node = fb_json_values_get_root(values);
- xode = fb_json_node_get(node, "$.extensible_attachment", NULL);
- xma = fb_api_xma_parse(api, body, xode, &err);
- dmsg = g_memdup2(&msg, sizeof(msg));
- msgs = g_slist_prepend(msgs, dmsg);
- if (G_UNLIKELY(err != NULL)) {
- str = fb_json_values_next_str(values, NULL);
- msgs = fb_api_cb_unread_parse_attach(api, str, &msg, msgs,
- if (G_UNLIKELY(err != NULL)) {
- if (G_UNLIKELY(err == NULL)) {
- msgs = g_slist_reverse(msgs);
- g_signal_emit_by_name(api, "messages", msgs);
- fb_api_error_emit(api, err);
- g_slist_free_full(msgs, (GDestroyNotify) fb_api_message_free);
- g_object_unref(values);
- g_object_unref(soupmsg);
-fb_api_cb_unread(GObject *source, GAsyncResult *result, gpointer data) {
- SoupSession *session = SOUP_SESSION(source);
- SoupMessage *soupmsg = data;
- FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
- if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
- g_object_unref(soupmsg);
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_INT, TRUE, "$.unread_count");
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.thread_key.other_user_id");
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.thread_key.thread_fbid");
- fb_json_values_set_array(values, FALSE, "$.viewer.message_threads"
- while (fb_json_values_update(values, &err)) {
- count = fb_json_values_next_int(values, -5);
- id = fb_json_values_next_str(values, NULL);
- id = fb_json_values_next_str(values, "0");
- bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
- fb_json_bldr_arr_begin(bldr, "0");
- fb_json_bldr_add_str(bldr, NULL, id);
- fb_json_bldr_arr_end(bldr);
- fb_json_bldr_add_str(bldr, "10", "true");
- fb_json_bldr_add_str(bldr, "11", "true");
- fb_json_bldr_add_int(bldr, "12", count);
- fb_json_bldr_add_str(bldr, "13", "false");
- fb_api_http_query(api, FB_API_QUERY_THREAD, bldr,
- fb_api_cb_unread_msgs);
- if (G_UNLIKELY(err != NULL)) {
- fb_api_error_emit(api, err);
- g_object_unref(values);
- g_object_unref(soupmsg);
-fb_api_unread(FbApi *api)
- g_return_if_fail(FB_IS_API(api));
- bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
- fb_json_bldr_add_str(bldr, "2", "true");
- fb_json_bldr_add_int(bldr, "1", api->unread);
- fb_json_bldr_add_str(bldr, "12", "true");
- fb_json_bldr_add_str(bldr, "13", "false");
- fb_api_http_query(api, FB_API_QUERY_THREADS, bldr,
-fb_api_cb_sticker(GObject *source, GAsyncResult *result, gpointer data) {
- SoupSession *session = SOUP_SESSION(source);
- SoupMessage *soupmsg = data;
- FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
- if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
- g_object_unref(soupmsg);
- node = fb_json_node_get_nth(root, 0);
- values = fb_json_values_new(node);
- fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE,
- fb_json_values_update(values, &err);
- FB_API_ERROR_EMIT(api, err,
- g_object_unref(values);
- g_object_unref(soupmsg);
- msg = g_object_steal_data(G_OBJECT(soupmsg), "fb-api-msg");
- msg->flags |= FB_API_MESSAGE_FLAG_IMAGE;
- msg->text = fb_json_values_next_str_dup(values, NULL);
- msgs = g_slist_prepend(msgs, msg);
- g_signal_emit_by_name(api, "messages", msgs);
- g_slist_free_full(msgs, (GDestroyNotify) fb_api_message_free);
- g_object_unref(values);
- g_object_unref(soupmsg);
-fb_api_sticker(FbApi *api, FbId sid, FbApiMessage *msg)
- bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
- fb_json_bldr_arr_begin(bldr, "0");
- fb_json_bldr_add_strf(bldr, NULL, "%" FB_ID_FORMAT, sid);
- fb_json_bldr_arr_end(bldr);
- http = fb_api_http_query(api, FB_API_QUERY_STICKER, bldr,
- g_object_set_data_full(G_OBJECT(http), "fb-api-msg", msg,
- (GDestroyNotify)fb_api_message_free);
-fb_api_thread_parse(FbApi *api, FbApiThread *thrd, JsonNode *root,
- gboolean haself = FALSE;
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.thread_key.thread_fbid");
- fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE, "$.name");
- fb_json_values_update(values, &err);
- if (G_UNLIKELY(err != NULL)) {
- g_propagate_error(error, err);
- g_object_unref(values);
- str = fb_json_values_next_str(values, NULL);
- g_object_unref(values);
- thrd->tid = FB_ID_FROM_STR(str);
- thrd->topic = fb_json_values_next_str_dup(values, NULL);
- g_object_unref(values);
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE,
- "$.messaging_actor.id");
- fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE,
- "$.messaging_actor.name");
- fb_json_values_set_array(values, TRUE, "$.all_participants.nodes");
- while (fb_json_values_update(values, &err)) {
- str = fb_json_values_next_str(values, "0");
- uid = FB_ID_FROM_STR(str);
- user = g_new0(FbApiUser, 1);
- user->name = fb_json_values_next_str_dup(values, NULL);
- thrd->users = g_slist_prepend(thrd->users, user);
- if (G_UNLIKELY(err != NULL)) {
- g_propagate_error(error, err);
- fb_api_thread_reset(thrd, TRUE);
- g_object_unref(values);
- if (num_users < 2 || !haself) {
- g_object_unref(values);
- g_object_unref(values);
-fb_api_cb_thread(GObject *source, GAsyncResult *result, gpointer data) {
- SoupSession *session = SOUP_SESSION(source);
- SoupMessage *soupmsg = data;
- FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
- if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
- g_object_unref(soupmsg);
- node = fb_json_node_get_nth(root, 0);
- fb_api_error_literal(api, FB_API_ERROR_GENERAL,
- _("Failed to obtain thread information"));
- g_object_unref(soupmsg);
- fb_api_thread_reset(&thrd, FALSE);
- if (!fb_api_thread_parse(api, &thrd, node, &err)) {
- if (G_LIKELY(err == NULL)) {
- g_signal_emit_by_name(api, "thread-kicked", &thrd);
- fb_api_error_literal(api, FB_API_ERROR_GENERAL,
- _("Failed to parse thread information"));
- fb_api_error_emit(api, err);
- g_signal_emit_by_name(api, "thread", &thrd);
- fb_api_thread_reset(&thrd, TRUE);
- g_object_unref(soupmsg);
-fb_api_thread(FbApi *api, FbId tid)
- bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
- fb_json_bldr_arr_begin(bldr, "0");
- fb_json_bldr_add_strf(bldr, NULL, "%" FB_ID_FORMAT, tid);
- fb_json_bldr_arr_end(bldr);
- fb_json_bldr_add_str(bldr, "10", "false");
- fb_json_bldr_add_str(bldr, "11", "false");
- fb_json_bldr_add_str(bldr, "13", "false");
- fb_api_http_query(api, FB_API_QUERY_THREAD, bldr, fb_api_cb_thread);
-fb_api_cb_thread_create(GObject *source, GAsyncResult *result, gpointer data) {
- SoupSession *session = SOUP_SESSION(source);
- SoupMessage *soupmsg = data;
- FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
- if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
- g_object_unref(soupmsg);
- values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.id");
- fb_json_values_update(values, &err);
- FB_API_ERROR_EMIT(api, err,
- g_object_unref(values);
- g_object_unref(soupmsg);
- str = fb_json_values_next_str(values, "0");
- tid = FB_ID_FROM_STR(str);
- g_signal_emit_by_name(api, "thread-create", tid);
- g_object_unref(values);
- g_object_unref(soupmsg);
-fb_api_thread_create(FbApi *api, GSList *uids)
- g_return_if_fail(FB_IS_API(api));
- g_warn_if_fail(g_slist_length(uids) > 1);
- bldr = fb_json_bldr_new(JSON_NODE_ARRAY);
- fb_json_bldr_obj_begin(bldr, NULL);
- fb_json_bldr_add_str(bldr, "type", "id");
- fb_json_bldr_add_strf(bldr, "id", "%" FB_ID_FORMAT, api->uid);
- fb_json_bldr_obj_end(bldr);
- for (l = uids; l != NULL; l = l->next) {
- fb_json_bldr_obj_begin(bldr, NULL);
- fb_json_bldr_add_str(bldr, "type", "id");
- fb_json_bldr_add_strf(bldr, "id", "%" FB_ID_FORMAT, *uid);
- fb_json_bldr_obj_end(bldr);
- json = fb_json_bldr_close(bldr, JSON_NODE_ARRAY, NULL);
- prms = fb_http_params_new();
- fb_http_params_set_str(prms, "recipients", json);
- fb_api_http_req(api, FB_API_URL_THREADS, "createGroup", "POST",
- prms, fb_api_cb_thread_create);
-fb_api_thread_invite(FbApi *api, FbId tid, FbId uid)
- bldr = fb_json_bldr_new(JSON_NODE_ARRAY);
- fb_json_bldr_obj_begin(bldr, NULL);
- fb_json_bldr_add_str(bldr, "type", "id");
- fb_json_bldr_add_strf(bldr, "id", "%" FB_ID_FORMAT, uid);
- fb_json_bldr_obj_end(bldr);
- json = fb_json_bldr_close(bldr, JSON_NODE_ARRAY, NULL);
- prms = fb_http_params_new();
- fb_http_params_set_str(prms, "to", json);
- fb_http_params_set_strf(prms, "id", "t_%" FB_ID_FORMAT, tid);
- fb_api_http_req(api, FB_API_URL_PARTS, "addMembers", "POST",
- prms, fb_api_cb_http_bool);
-fb_api_thread_remove(FbApi *api, FbId tid, FbId uid)
- g_return_if_fail(FB_IS_API(api));
- prms = fb_http_params_new();
- fb_http_params_set_strf(prms, "id", "t_%" FB_ID_FORMAT, tid);
- bldr = fb_json_bldr_new(JSON_NODE_ARRAY);
- fb_json_bldr_add_strf(bldr, NULL, "%" FB_ID_FORMAT, uid);
- json = fb_json_bldr_close(bldr, JSON_NODE_ARRAY, NULL);
- fb_http_params_set_str(prms, "to", json);
- fb_api_http_req(api, FB_API_URL_PARTS, "removeMembers", "DELETE",
- prms, fb_api_cb_http_bool);
-fb_api_thread_topic(FbApi *api, FbId tid, const gchar *topic)
- prms = fb_http_params_new();
- fb_http_params_set_str(prms, "name", topic);
- fb_http_params_set_int(prms, "tid", tid);
- fb_api_http_req(api, FB_API_URL_TOPIC, "setThreadName",
- "messaging.setthreadname", prms, fb_api_cb_http_bool);
-fb_api_cb_threads(GObject *source, GAsyncResult *result, gpointer data) {
- SoupSession *session = SOUP_SESSION(source);
- SoupMessage *soupmsg = data;
- FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
- if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
- g_object_unref(soupmsg);
- arr = fb_json_node_get_arr(root, "$.viewer.message_threads.nodes",
- FB_API_ERROR_EMIT(api, err,
- g_object_unref(soupmsg);
- elms = json_array_get_elements(arr);
- for (l = elms; l != NULL; l = l->next) {
- fb_api_thread_reset(&thrd, FALSE);
- if (fb_api_thread_parse(api, &thrd, l->data, &err)) {
- dthrd = g_memdup2(&thrd, sizeof(thrd));
- thrds = g_slist_prepend(thrds, dthrd);
- fb_api_thread_reset(&thrd, TRUE);
- if (G_UNLIKELY(err != NULL)) {
- if (G_LIKELY(err == NULL)) {
- thrds = g_slist_reverse(thrds);
- g_signal_emit_by_name(api, "threads", thrds);
- fb_api_error_emit(api, err);
- g_slist_free_full(thrds, (GDestroyNotify) fb_api_thread_free);
- g_object_unref(soupmsg);
-fb_api_threads(FbApi *api)
- bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
- fb_json_bldr_add_str(bldr, "2", "true");
- fb_json_bldr_add_str(bldr, "12", "false");
- fb_json_bldr_add_str(bldr, "13", "false");
- fb_api_http_query(api, FB_API_QUERY_THREADS, bldr, fb_api_cb_threads);
-fb_api_typing(FbApi *api, FbId uid, gboolean state)
- bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
- fb_json_bldr_add_int(bldr, "state", state != 0);
- fb_json_bldr_add_strf(bldr, "to", "%" FB_ID_FORMAT, uid);
- json = fb_json_bldr_close(bldr, JSON_NODE_OBJECT, NULL);
- fb_api_publish(api, "/typing", "%s", json);
-fb_api_event_dup(const FbApiEvent *event)
- ret = g_memdup2(event, sizeof *event);
- ret->text = g_strdup(event->text);
-fb_api_event_reset(FbApiEvent *event, gboolean deep)
- g_return_if_fail(event != NULL);
- memset(event, 0, sizeof *event);
-fb_api_event_free(FbApiEvent *event)
- if (G_LIKELY(event != NULL)) {
-G_DEFINE_BOXED_TYPE(FbApiEvent, fb_api_event, fb_api_event_dup,
-fb_api_message_dup(const FbApiMessage *msg)
- ret = g_memdup2(msg, sizeof *msg);
- ret->text = g_strdup(msg->text);
-fb_api_message_reset(FbApiMessage *msg, gboolean deep)
- g_return_if_fail(msg != NULL);
- memset(msg, 0, sizeof *msg);
-fb_api_message_free(FbApiMessage *msg)
- if (G_LIKELY(msg != NULL)) {
-G_DEFINE_BOXED_TYPE(FbApiMessage, fb_api_message, fb_api_message_dup,
-fb_api_presence_dup(const FbApiPresence *presence)
- return g_memdup2(presence, sizeof *presence);
-fb_api_presence_reset(FbApiPresence *presence)
- g_return_if_fail(presence != NULL);
- memset(presence, 0, sizeof *presence);
-fb_api_presence_free(FbApiPresence *presence)
- if (G_LIKELY(presence != NULL)) {
-G_DEFINE_BOXED_TYPE(FbApiPresence, fb_api_presence, fb_api_presence_dup,
-fb_api_thread_dup(const FbApiThread *thrd)
- ret = g_memdup2(thrd, sizeof *thrd);
- ret->topic = g_strdup(thrd->topic);
- ret->users = g_slist_copy_deep(thrd->users,
- (GCopyFunc)(GCallback)fb_api_user_dup,
-fb_api_thread_reset(FbApiThread *thrd, gboolean deep)
- g_return_if_fail(thrd != NULL);
- g_slist_free_full(thrd->users, (GDestroyNotify) fb_api_user_free);
- memset(thrd, 0, sizeof *thrd);
-fb_api_thread_free(FbApiThread *thrd)
- if (G_LIKELY(thrd != NULL)) {
- g_slist_free_full(thrd->users, (GDestroyNotify) fb_api_user_free);
-G_DEFINE_BOXED_TYPE(FbApiThread, fb_api_thread, fb_api_thread_dup,
-fb_api_typing_dup(const FbApiTyping *typg)
- return g_memdup2(typg, sizeof *typg);
-fb_api_typing_reset(FbApiTyping *typg)
- g_return_if_fail(typg != NULL);
- memset(typg, 0, sizeof *typg);
-fb_api_typing_free(FbApiTyping *typg)
- if (G_LIKELY(typg != NULL)) {
-G_DEFINE_BOXED_TYPE(FbApiTyping, fb_api_typing, fb_api_typing_dup,
-fb_api_user_dup(const FbApiUser *user)
- ret = g_memdup2(user, sizeof *user);
- ret->name = g_strdup(user->name);
- ret->icon = g_strdup(user->icon);
- ret->csum = g_strdup(user->csum);
-fb_api_user_reset(FbApiUser *user, gboolean deep)
- g_return_if_fail(user != NULL);
- memset(user, 0, sizeof *user);
-fb_api_user_free(FbApiUser *user)
- if (G_LIKELY(user != NULL)) {
-G_DEFINE_BOXED_TYPE(FbApiUser, fb_api_user, fb_api_user_dup, fb_api_user_free)
--- a/libpurple/protocols/facebook/api.h Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1002 +0,0 @@
- * 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
- * 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_FACEBOOK_API_H
-#define PURPLE_FACEBOOK_API_H
-#define FB_TYPE_API fb_api_get_type()
- * The HTTP host for the Facebook API.
-#define FB_API_AHOST "https://api.facebook.com"
- * The HTTP host for the Facebook BAPI.
-#define FB_API_BHOST "https://b-api.facebook.com"
- * The HTTP host for the Facebook Graph API.
-#define FB_API_GHOST "https://graph.facebook.com"
- * The HTTP host for the Facebook website.
-#define FB_API_WHOST "https://www.facebook.com"
- * The fbrpc URL prefix used in links shared from the mobile app.
-#define FB_API_FBRPC_PREFIX "fbrpc://facebook/nativethirdparty"
- * The Facebook API key.
-#define FB_API_KEY "256002347743983"
- * The Facebook API secret.
-#define FB_API_SECRET "374e60f8b9bb6b8cbb30f78030438895"
- * The part of the user agent that looks like the official client, since the
- * server started checking this.
-#define FB_ORCA_AGENT "[FBAN/Orca-Android;FBAV/537.0.0.31.101;FBPN/com.facebook.orca;FBLC/en_US;FBBV/52182662]"
- * The HTTP User-Agent header.
-#define FB_API_AGENT "Facebook plugin / Purple / 0.9.5 " FB_ORCA_AGENT
- * The client information string sent in the MQTT CONNECT message
-#define FB_API_MQTT_AGENT FB_API_AGENT
- * The URL for attachment URL requests.
-#define FB_API_URL_ATTACH FB_API_AHOST "/method/messaging.getAttachment"
-//#define FB_API_URL_ATTACH FB_API_AHOST "/method/messaging.attachmentRedirect"
- * The URL for authentication requests.
-#define FB_API_URL_AUTH FB_API_BHOST "/method/auth.login"
- * The URL for GraphQL requests.
-#define FB_API_URL_GQL FB_API_GHOST "/graphql"
- * The URL for linking message threads.
-#define FB_API_URL_MESSAGES FB_API_WHOST "/messages"
- * The URL for participant management requests.
-#define FB_API_URL_PARTS FB_API_GHOST "/participants"
- * The URL for thread management requests.
-#define FB_API_URL_THREADS FB_API_GHOST "/me/group_threads"
- * The URL for thread topic requests.
-#define FB_API_URL_TOPIC FB_API_AHOST "/method/messaging.setthreadname"
- * FB_API_QUERY_CONTACT:
- * The query hash for the `UsersQuery`.
- * 1: include_full_user_info
- * 2: profile_pic_large_size
- * 3: profile_pic_medium_size
- * 4: profile_pic_small_size
-#define FB_API_QUERY_CONTACT 10153915107411729
- * FB_API_QUERY_CONTACTS:
- * The query hash for the `FetchContactsFullQuery`.
-#define FB_API_QUERY_CONTACTS 10154444360806729
- * FB_API_QUERY_CONTACTS_AFTER:
- * The query hash for the `FetchContactsFullWithAfterQuery`.
-#define FB_API_QUERY_CONTACTS_AFTER 10154444360816729
- * FB_API_QUERY_CONTACTS_DELTA:
- * The query hash for the `FetchContactsDeltaQuery`.
-#define FB_API_QUERY_CONTACTS_DELTA 10154444360801729
- * FB_API_QUERY_STICKER:
- * The query hash for the `FetchStickersWithPreviewsQuery`.
- * 4: animated_media_type
-#define FB_API_QUERY_STICKER 10152877994321729
- * The query hash for the `ThreadQuery`.
- * 3: small_preview_size
- * 4: large_preview_size
- * 7: full_screen_height
- * 9: medium_preview_size
- * 10: fetch_users_separately
- * 11: include_message_info
- * 13: include_full_user_info
- * 14: profile_pic_large_size
- * 15: profile_pic_medium_size
- * 16: profile_pic_small_size
-#define FB_API_QUERY_THREAD 10153919752036729
- * FB_API_QUERY_THREADS:
- * The query hash for the `ThreadListQuery`.
- * 2: include_thread_info
- * 5: small_preview_size
- * 6: large_preview_size
- * 9: full_screen_height
- * 10: full_screen_width
- * 11: medium_preview_size
- * 12: fetch_users_separately
- * 13: include_message_info
- * 16: profile_pic_large_size
- * 17: profile_pic_medium_size
- * 18: profile_pic_small_size
-#define FB_API_QUERY_THREADS 10153919752026729
- * A variant of ThreadListQuery with sequence ID
-#define FB_API_QUERY_SEQ_ID 10155268192741729
- * The query hash for the `XMAQuery`.
-#define FB_API_QUERY_XMA 10153919431161729
- * FB_API_CONTACTS_COUNT:
- * The maximum amount of contacts to fetch in a single request. If this
- * value is set too high, HTTP request will fail. This is due to the
- * request data being too large.
-#define FB_API_CONTACTS_COUNT 500
- * Checks the Thrift related expression to ensure that it evaluates to
- * #TRUE. If the expression evaluates to #FALSE, a #GError is assigned
- * to the local `error` variable, then returns with no value.
- * This macro is meant to only be used for Thrift related expressions,
- * where the calling function has a `void` return type. This macro also
- * requires the existence of a predefined `error` variable, which is a
- * pointer of a pointer to a #GError.
-#define FB_API_TCHK(e) \
- if (G_UNLIKELY(!(e))) { \
- g_set_error(error, FB_API_ERROR, FB_API_ERROR_GENERAL, \
- "Failed to read thrift: %s:%d " \
- "%s: assertion '%s' failed", \
- __FILE__, __LINE__, G_STRFUNC, #e); \
- * @m: The time in milliseconds.
- * @i: The random integer.
- * Creates a 64-bit message identifier in the Facebook format.
- * Returns: The message identifier.
-#define FB_API_MSGID(m, i) ((guint64) ( \
- (((guint32) i) & 0x3FFFFF) | \
- (((guint64) m) << 22) \
- * @c: The code to execute.
- * Emits a #GError on behalf of the #FbApi.
-#define FB_API_ERROR_EMIT(a, e, c) \
- if (G_UNLIKELY((e) != NULL)) { \
- fb_api_error_emit(a, e); \
- * The #GQuark of the domain of API errors.
-#define FB_API_ERROR fb_api_error_quark()
-typedef struct _FbApiEvent FbApiEvent;
-typedef struct _FbApiMessage FbApiMessage;
-typedef struct _FbApiPresence FbApiPresence;
-typedef struct _FbApiThread FbApiThread;
-typedef struct _FbApiTyping FbApiTyping;
-typedef struct _FbApiUser FbApiUser;
- * @FB_API_ERROR_GENERAL: General failure.
- * @FB_API_ERROR_AUTH: Authentication failure.
- * @FB_API_ERROR_QUEUE: Queue failure.
- * @FB_API_ERROR_NONFATAL: Other non-fatal errors.
- * The error codes for the #FB_API_ERROR domain.
- * @FB_API_EVENT_TYPE_THREAD_TOPIC: The thread topic was changed.
- * @FB_API_EVENT_TYPE_THREAD_USER_ADDED: A thread user was added.
- * @FB_API_EVENT_TYPE_THREAD_USER_REMOVED: A thread user was removed.
- * The #FbApiEvent types.
- FB_API_EVENT_TYPE_THREAD_TOPIC,
- FB_API_EVENT_TYPE_THREAD_USER_ADDED,
- FB_API_EVENT_TYPE_THREAD_USER_REMOVED
- * @FB_API_MESSAGE_FLAG_DONE: The text has been processed.
- * @FB_API_MESSAGE_FLAG_IMAGE: The text is a URL to an image.
- * @FB_API_MESSAGE_FLAG_SELF: The text is from the #FbApi user.
- * The #FbApiMessage flags.
- FB_API_MESSAGE_FLAG_DONE = 1 << 0,
- FB_API_MESSAGE_FLAG_IMAGE = 1 << 1,
- FB_API_MESSAGE_FLAG_SELF = 1 << 2
-#define FB_TYPE_API_EVENT (fb_api_event_get_type())
- * @type: The #FbApiEventType.
- * @uid: The user #FbId.
- * @tid: The thread #FbId.
- * @text: The event text.
- * Represents a Facebook update event.
-#define FB_TYPE_API_MESSAGE (fb_api_message_get_type())
- * @flags: The #FbApiMessageFlags.
- * @uid: The user #FbId.
- * @tid: The thread #FbId.
- * @tstamp: The timestamp in milliseconds (UTC).
- * @text: The message text.
- * Represents a Facebook user message.
- FbApiMessageFlags flags;
-#define FB_TYPE_API_PRESENCE (fb_api_presence_get_type())
- * @uid: The user #FbId.
- * @active: #TRUE if the user is active, otherwise #FALSE.
- * Represents a Facebook presence message.
-#define FB_TYPE_API_THREAD (fb_api_thread_get_type())
- * @tid: The thread #FbId.
- * @users: The #GSList of #FbApiUser's.
- * Represents a Facebook message thread.
-#define FB_TYPE_API_TYPING (fb_api_typing_get_type())
- * @uid: The user #FbId.
- * @state: #TRUE if the user is typing, otherwise #FALSE.
- * Represents a Facebook typing message.
-#define FB_TYPE_API_USER (fb_api_user_get_type())
- * @uid: The user #FbId.
- * @name: The name of the user.
- * @csum: The checksum of @icon.
- * Represents a Facebook user.
-G_DECLARE_FINAL_TYPE(FbApi, fb_api, FB, API, GObject)
- * Gets the #GQuark of the domain of API errors.
- * Returns: The #GQuark of the domain.
-fb_api_error_quark(void);
- * @gc: The #PurpleConnection.
- * @resolver: The proxy resolver to use from the account.
- * Creates a new #FbApi. The returned #FbApi should be freed with
- * #g_object_unref() when no longer needed.
- * Returns: The new #FbApi.
-FbApi *fb_api_new(PurpleConnection *gc, GProxyResolver *resolver);
- * Rehashes and updates internal data of the #FbApi. This should be
- * called whenever properties are modified.
-fb_api_rehash(FbApi *api);
- * Determines if the user of the #FbApi is invisible.
- * Returns: #TRUE if the #FbApi user is invisible, otherwise #FALSE.
-fb_api_is_invisible(FbApi *api);
- * @error: The #FbApiError.
- * @format: The format string literal.
- * @...: The arguments for @format.
- * Emits an #FbApiError.
-fb_api_error(FbApi *api, FbApiError error, const gchar *format, ...)
- * Emits a #GError on an #FbApiError.
-fb_api_error_emit(FbApi *api, GError *error);
- * @user: The Facebook user name, email, or phone number.
- * @pass: The Facebook password.
- * Sends an authentication request to Facebook. This will obtain
- * session information, which is required for all other requests.
-fb_api_auth(FbApi *api, const gchar *user, const gchar *pass);
- * @uid: The user #FbId.
- * Sends a contact request. This will obtain the general information of
-fb_api_contact(FbApi *api, FbId uid);
- * Sends a contacts request. This will obtain a full list of detailed
- * contact information about the friends of the #FbApi user.
-fb_api_contacts(FbApi *api);
- * @invisible: #TRUE to make the user invisible, otherwise #FALSE.
- * Initializes and establishes the underlying MQTT connection.
-fb_api_connect(FbApi *api, gboolean invisible);
- * Closes the underlying MQTT connection.
-fb_api_disconnect(FbApi *api);
- * @id: The user or thread #FbId.
- * @thread: #TRUE if @id is a thread, otherwise #FALSE.
- * @text: The message text.
- * Sends a message as the user of the #FbApi to a user or a thread.
-fb_api_message(FbApi *api, FbId id, gboolean thread, const gchar *text);
- * @format: The format string literal.
- * @...: The arguments for @format.
- * Publishes an MQTT message.
-fb_api_publish(FbApi *api, const gchar *topic, const gchar *format, ...)
- * @id: The user or thread #FbId.
- * @thread: #TRUE if @id is a thread, otherwise #FALSE.
- * Marks a message thread as read.
-fb_api_read(FbApi *api, FbId id, gboolean thread);
- * Sends an unread message request.
-fb_api_unread(FbApi *api);
- * @tid: The thread #FbId.
- * Sends a thread request. This will obtain the general information of
-fb_api_thread(FbApi *api, FbId tid);
- * fb_api_thread_create:
- * @uids: (element-type FbId): The #GSList of #FbId's.
- * Sends a thread creation request. In order to create a thread, there
- * must be at least two other users in @uids.
-fb_api_thread_create(FbApi *api, GSList *uids);
- * fb_api_thread_invite:
- * @tid: The thread #FbId.
- * @uid: The user #FbId.
- * Sends a thread user invitation request.
-fb_api_thread_invite(FbApi *api, FbId tid, FbId uid);
- * fb_api_thread_remove:
- * @tid: The thread #FbId.
- * @uid: The user #FbId.
- * Sends a thread user removal request.
-fb_api_thread_remove(FbApi *api, FbId tid, FbId uid);
- * @tid: The thread #FbId.
- * Sends a thread topic change request.
-fb_api_thread_topic(FbApi *api, FbId tid, const gchar *topic);
- * Sends a threads request. This will obtain a full list of detailed
- * thread information about the threads of the #FbApi user.
-fb_api_threads(FbApi *api);
- * @uid: The user #FbId.
- * @state: #TRUE if the #FbApi user is typing, otherwise #FALSE.
- * Sends a typing state message for the user of the #FbApi.
-fb_api_typing(FbApi *api, FbId uid, gboolean state);
- * fb_api_event_get_type:
- * Returns: The #GType for the #FbApiEvent boxed structure.
-GType fb_api_event_get_type(void);
- * @event: The #FbApiEvent or #NULL.
- * Duplicates an #FbApiEvent. The returned #FbApiEvent should be freed with
- * #fb_api_event_free() when no longer needed.
- * Returns: The new #FbApiEvent.
-fb_api_event_dup(const FbApiEvent *event);
- * @event: The #FbApiEvent.
- * @deep: #TRUE to free allocated data, otherwise #FALSE.
- * Resets an #FbApiEvent.
-fb_api_event_reset(FbApiEvent *event, gboolean deep);
- * @event: The #FbApiEvent.
- * Frees all memory used by the #FbApiEvent.
-fb_api_event_free(FbApiEvent *event);
- * fb_api_message_get_type:
- * Returns: The #GType for the #FbApiMessage boxed structure.
-GType fb_api_message_get_type(void);
- * @msg: The #FbApiMessage or #NULL.
- * Duplicates an #FbApiMessage. The returned #FbApiMessage should be freed with
- * #fb_api_message_free() when no longer needed.
- * Returns: The new #FbApiMessage.
-fb_api_message_dup(const FbApiMessage *msg);
- * fb_api_message_reset:
- * @msg: The #FbApiMessage.
- * @deep: #TRUE to free allocated data, otherwise #FALSE.
- * Resets an #FbApiMessage.
-fb_api_message_reset(FbApiMessage *msg, gboolean deep);
- * @msg: The #FbApiMessage.
- * Frees all memory used by the #FbApiMessage.
-fb_api_message_free(FbApiMessage *msg);
- * fb_api_presence_get_type:
- * Returns: The #GType for the #FbApiPresence boxed structure.
-GType fb_api_presence_get_type(void);
- * @presence: The #FbApiPresence or %NULL.
- * Duplicates an #FbApiPresence. The returned #FbApiPresence should be freed
- * with #fb_api_presence_free() when no longer needed.
- * Returns: The new #FbApiPresence.
-fb_api_presence_dup(const FbApiPresence *presence);
- * fb_api_presence_reset:
- * @presence: The #FbApiPresence.
- * Resets an #FbApiPresence.
-fb_api_presence_reset(FbApiPresence *presence);
- * fb_api_presence_free:
- * @presence: The #FbApiPresence.
- * Frees all memory used by the #FbApiPresence.
-fb_api_presence_free(FbApiPresence *presence);
- * fb_api_thread_get_type:
- * Returns: The #GType for the #FbApiThread boxed structure.
-GType fb_api_thread_get_type(void);
- * @thrd: The #FbApiThread or #NULL.
- * Duplicates an #FbApiThread. The returned #FbApiThread should be freed with
- * #fb_api_thread_free() when no longer needed.
- * Returns: The new #FbApiThread.
-fb_api_thread_dup(const FbApiThread *thrd);
- * @thrd: The #FbApiThread.
- * @deep: #TRUE to free allocated data, otherwise #FALSE.
- * Resets an #FbApiThread.
-fb_api_thread_reset(FbApiThread *thrd, gboolean deep);
- * @thrd: The #FbApiThread.
- * Frees all memory used by the #FbApiThread.
-fb_api_thread_free(FbApiThread *thrd);
- * fb_api_typing_get_type:
- * Returns: The #GType for the #FbApiTyping boxed structure.
-GType fb_api_typing_get_type(void);
- * @typg: The #FbApiTyping or #NULL.
- * Duplicates an #FbApiTyping. The returned #FbApiTyping should be freed with
- * #fb_api_typing_free() when no longer needed.
- * Returns: The new #FbApiTyping.
-fb_api_typing_dup(const FbApiTyping *typg);
- * @typg: The #FbApiTyping.
- * Resets an #FbApiTyping.
-fb_api_typing_reset(FbApiTyping *typg);
- * @typg: The #FbApiTyping.
- * Frees all memory used by the #FbApiTyping.
-fb_api_typing_free(FbApiTyping *typg);
- * fb_api_user_get_type:
- * Returns: The #GType for the #FbApiUser boxed structure.
-GType fb_api_user_get_type(void);
- * @user: The #FbApiUser or #NULL.
- * Duplicates an #FbApiUser. The returned #FbApiUser should be freed with
- * #fb_api_user_free() when no longer needed.
- * Returns: The new #FbApiUser.
-fb_api_user_dup(const FbApiUser *user);
- * @user: The #FbApiUser.
- * @deep: #TRUE to free allocated data, otherwise #FALSE.
- * Resets an #FbApiUser.
-fb_api_user_reset(FbApiUser *user, gboolean deep);
- * @user: The #FbApiUser.
- * Frees all memory used by the #FbApiUser.
-fb_api_user_free(FbApiUser *user);
-#endif /* PURPLE_FACEBOOK_API_H */
--- a/libpurple/protocols/facebook/data.c Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,558 +0,0 @@
- * 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
- * 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 <libsoup/soup.h>
-#include "libpurple/glibcompat.h"
- * Represents the connection data used by #FacebookProtocol.
- PurpleRoomlist *roomlist;
- * Represents the data used for fetching images.
-static const gchar *fb_props_strs[] = {
-G_DEFINE_TYPE(FbData, fb_data, G_TYPE_OBJECT);
-G_DEFINE_TYPE(FbDataImage, fb_data_image, G_TYPE_OBJECT);
-fb_data_dispose(GObject *obj)
- FbData *fata = FB_DATA(obj);
- if(fata->cons != NULL) {
- soup_session_abort(fata->cons);
- if(fata->evs != NULL) {
- g_hash_table_iter_init(&iter, fata->evs);
- while (g_hash_table_iter_next(&iter, NULL, &ptr)) {
- g_source_remove(GPOINTER_TO_UINT(ptr));
- g_clear_object(&fata->api);
- g_clear_object(&fata->cons);
- if(fata->msgs != NULL) {
- g_queue_free_full(fata->msgs, (GDestroyNotify)fb_api_message_free);
- g_clear_pointer(&fata->imgs, g_hash_table_destroy);
- g_clear_pointer(&fata->unread, g_hash_table_destroy);
- g_clear_pointer(&fata->evs, g_hash_table_destroy);
-fb_data_class_init(FbDataClass *klass)
- GObjectClass *gklass = G_OBJECT_CLASS(klass);
- gklass->dispose = fb_data_dispose;
-fb_data_init(FbData *fata)
- fata->msgs = g_queue_new();
- fata->imgs = g_hash_table_new_full(g_direct_hash, g_direct_equal,
- fata->unread = g_hash_table_new_full(fb_id_hash, fb_id_equal,
- fata->evs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
-fb_data_image_dispose(GObject *obj)
- FbDataImage *img = FB_DATA_IMAGE(obj);
- FbData *fata = img->fata;
- if (img->dunc != NULL && img->data != NULL) {
- g_clear_pointer(&img->url, g_free);
- g_hash_table_steal(fata->imgs, img);
-fb_data_image_class_init(FbDataImageClass *klass)
- GObjectClass *gklass = G_OBJECT_CLASS(klass);
- gklass->dispose = fb_data_image_dispose;
-fb_data_image_init(G_GNUC_UNUSED FbDataImage *img)
-fb_data_new(PurpleConnection *gc, GProxyResolver *resolver)
- fata = g_object_new(FB_TYPE_DATA, NULL);
- fata->cons = soup_session_new_with_options("proxy-resolver", resolver,
- fata->api = fb_api_new(gc, resolver);
-fb_data_load(FbData *fata)
- GValue val = G_VALUE_INIT;
- g_return_val_if_fail(FB_IS_DATA(fata), FALSE);
- acct = purple_connection_get_account(fata->gc);
- for (i = 0; i < G_N_ELEMENTS(fb_props_strs); i++) {
- str = purple_account_get_string(acct, fb_props_strs[i], NULL);
- g_value_init(&val, G_TYPE_STRING);
- g_value_set_string(&val, str);
- g_object_set_property(G_OBJECT(fata->api), fb_props_strs[i],
- str = purple_account_get_string(acct, "mid", NULL);
- uint = g_ascii_strtoull(str, NULL, 10);
- g_value_init(&val, G_TYPE_UINT64);
- g_value_set_uint64(&val, uint);
- g_object_set_property(G_OBJECT(fata->api), "mid", &val);
- str = purple_account_get_string(acct, "uid", NULL);
- id = FB_ID_FROM_STR(str);
- g_value_init(&val, FB_TYPE_ID);
- g_value_set_int64(&val, id);
- g_object_set_property(G_OBJECT(fata->api), "uid", &val);
- fb_api_rehash(fata->api);
-fb_data_save(FbData *fata)
- GValue val = G_VALUE_INIT;
- g_return_if_fail(FB_IS_DATA(fata));
- acct = purple_connection_get_account(fata->gc);
- for (i = 0; i < G_N_ELEMENTS(fb_props_strs); i++) {
- g_value_init(&val, G_TYPE_STRING);
- g_object_get_property(G_OBJECT(fata->api), fb_props_strs[i],
- str = g_value_get_string(&val);
- if (purple_strequal(fb_props_strs[i], "token") && !purple_account_get_remember_password(acct)) {
- purple_account_set_string(acct, fb_props_strs[i], str);
- g_value_init(&val, G_TYPE_UINT64);
- g_object_get_property(G_OBJECT(fata->api), "mid", &val);
- uint = g_value_get_uint64(&val);
- dup = g_strdup_printf("%" G_GINT64_FORMAT, uint);
- purple_account_set_string(acct, "mid", dup);
- g_value_init(&val, G_TYPE_INT64);
- g_object_get_property(G_OBJECT(fata->api), "uid", &val);
- uint = g_value_get_int64(&val);
- dup = g_strdup_printf("%" FB_ID_FORMAT, uint);
- purple_account_set_string(acct, "uid", dup);
-fb_data_save_timeout(FbData *fata, const gchar *name, guint id)
- g_return_if_fail(FB_IS_DATA(fata));
- fb_data_clear_timeout(fata, name, TRUE);
- g_hash_table_replace(fata->evs, g_strdup(name), GUINT_TO_POINTER(id));
-fb_data_clear_timeout(FbData *fata, const gchar *name, gboolean remove)
- g_return_if_fail(FB_IS_DATA(fata));
- ptr = g_hash_table_lookup(fata->evs, name);
- id = GPOINTER_TO_UINT(ptr);
- g_clear_handle_id(&id, g_source_remove);
- g_hash_table_remove(fata->evs, name);
-fb_data_get_api(FbData *fata)
- g_return_val_if_fail(FB_IS_DATA(fata), NULL);
-fb_data_get_connection(FbData *fata)
- g_return_val_if_fail(FB_IS_DATA(fata), NULL);
-fb_data_get_roomlist(FbData *fata)
- g_return_val_if_fail(FB_IS_DATA(fata), NULL);
-fb_data_get_unread(FbData *fata, FbId id)
- g_return_val_if_fail(FB_IS_DATA(fata), FALSE);
- g_return_val_if_fail(id != 0, FALSE);
- ptr = g_hash_table_lookup(fata->unread, &id);
- return GPOINTER_TO_INT(ptr);
-fb_data_set_roomlist(FbData *fata, PurpleRoomlist *list)
- g_return_if_fail(FB_IS_DATA(fata));
-fb_data_set_unread(FbData *fata, FbId id, gboolean unread)
- g_return_if_fail(FB_IS_DATA(fata));
- g_return_if_fail(id != 0);
- g_hash_table_remove(fata->unread, &id);
- key = g_memdup2(&id, sizeof id);
- g_hash_table_replace(fata->unread, key, GINT_TO_POINTER(unread));
-fb_data_add_message(FbData *fata, FbApiMessage *msg)
- g_return_if_fail(FB_IS_DATA(fata));
- g_queue_push_tail(fata->msgs, msg);
-fb_data_remove_message(FbData *fata, FbApiMessage *msg)
- g_return_if_fail(FB_IS_DATA(fata));
- g_queue_remove(fata->msgs, msg);
-fb_data_take_messages(FbData *fata, FbId uid)
- g_return_val_if_fail(FB_IS_DATA(fata), NULL);
- msgs = g_slist_prepend(msgs, msg);
- g_queue_delete_link(fata->msgs, l);
-fb_data_image_add(FbData *fata, const gchar *url, FbDataImageFunc func,
- gpointer data, GDestroyNotify dunc)
- g_return_val_if_fail(FB_IS_DATA(fata), NULL);
- g_return_val_if_fail(url != NULL, NULL);
- g_return_val_if_fail(func != NULL, NULL);
- img = g_object_new(FB_TYPE_DATA_IMAGE, NULL);
- img->url = g_strdup(url);
- g_hash_table_add(fata->imgs, img);
-fb_data_image_get_active(FbDataImage *img)
- g_return_val_if_fail(FB_IS_DATA_IMAGE(img), FALSE);
-fb_data_image_get_data(FbDataImage *img)
- g_return_val_if_fail(FB_IS_DATA_IMAGE(img), NULL);
-fb_data_image_get_fata(FbDataImage *img)
- g_return_val_if_fail(FB_IS_DATA_IMAGE(img), NULL);
-fb_data_image_get_image(FbDataImage *img, gsize *size)
- g_return_val_if_fail(FB_IS_DATA_IMAGE(img), NULL);
-fb_data_image_dup_image(FbDataImage *img, gsize *size)
- g_return_val_if_fail(FB_IS_DATA_IMAGE(img), NULL);
- return g_memdup2(img->image, img->size);
-fb_data_image_get_url(FbDataImage *img)
- g_return_val_if_fail(FB_IS_DATA_IMAGE(img), NULL);
-fb_data_image_cb(GObject *source, GAsyncResult *result, gpointer data) {
- SoupMessage *msg = data;
- FbDataImage *img = g_object_get_data(G_OBJECT(msg), "facebook-data-image");
- if(fb_http_error_chk(msg, &err)) {
- bytes = soup_session_send_and_read_finish(SOUP_SESSION(source),
- img->image = g_bytes_unref_to_data(bytes, &img->size);
- if (G_LIKELY(err == NULL)) {
- fb_data_image_queue(img->fata);
-fb_data_image_queue(FbData *fata)
- g_return_if_fail(FB_IS_DATA(fata));
- g_hash_table_iter_init(&iter, fata->imgs);
- while (g_hash_table_iter_next(&iter, (gpointer *) &img, NULL)) {
- if (fb_data_image_get_active(img)) {
- if (active >= FB_DATA_ICON_MAX) {
- g_hash_table_iter_init(&iter, fata->imgs);
- while (g_hash_table_iter_next(&iter, (gpointer *) &img, NULL)) {
- if (fb_data_image_get_active(img)) {
- url = fb_data_image_get_url(img);
- msg = soup_message_new("GET", url);
- g_object_set_data(G_OBJECT(msg), "facebook-data-image", img);
- // purple_http_request_set_max_len(req, FB_DATA_ICON_SIZE_MAX);
- soup_session_send_and_read_async(fata->cons, msg, G_PRIORITY_DEFAULT,
- NULL, fb_data_image_cb, msg);
- if (++active >= FB_DATA_ICON_MAX) {
--- a/libpurple/protocols/facebook/data.h Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,318 +0,0 @@
- * 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
- * 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_FACEBOOK_DATA_H
-#define PURPLE_FACEBOOK_DATA_H
-#define FB_TYPE_DATA fb_data_get_type()
-#define FB_TYPE_DATA_IMAGE fb_data_image_get_type()
- * The maximum of number of concurrent icon fetches.
-#define FB_DATA_ICON_MAX 4
- * FB_DATA_ICON_SIZE_MAX:
- * The maximum size of a fetched icon.
-#define FB_DATA_ICON_SIZE_MAX 0xa00000 /* 10MiB */
-G_DECLARE_FINAL_TYPE(FbData, fb_data, FB, DATA, GObject)
-G_DECLARE_FINAL_TYPE(FbDataImage, fb_data_image, FB, DATA_IMAGE, GObject)
- * @img: The #FbDataImage.
- * @error: The #GError or #NULL.
- * The callback for a fetched #FbDataImage.
-typedef void (*FbDataImageFunc) (FbDataImage *img, GError *error);
- * @gc: The #PurpleConnection.
- * @resolver: The proxy resolver to use from the account.
- * Creates a new #FbData. The returned #FbData should be freed with
- * #g_object_unref() when no longer needed.
- * Returns: The new #FbData.
-FbData *fb_data_new(PurpleConnection *gc, GProxyResolver *resolver);
- * Loads the internal data from the underlying #PurpleAccount.
- * Return: #TRUE if all of the data was loaded, otherwise #FALSE.
-fb_data_load(FbData *fata);
- * Saves the internal data to the underlying #PurpleAccount.
-fb_data_save(FbData *fata);
- * fb_data_save_timeout:
- * @name: The name of the timeout.
- * @id: The source id of the timeout.
- * Saves a new callback timer. The callback should be added to the main loop
- * with `g_timeout_add` or similar, and the returned source identifier passed
- * to this function. The timeout should be cleared with
- * #fb_data_clear_timeout() when no longer needed.
-fb_data_save_timeout(FbData *fata, const gchar *name, guint id);
- * fb_data_clear_timeout:
- * @name: The name of the timeout.
- * @remove: #TRUE to remove from the event loop, otherwise #FALSE.
- * Clears and removes a callback timer. The only time @remove should be
- * #FALSE, is when being called from a #GSourceFunc, which is returning
-fb_data_clear_timeout(FbData *fata, const gchar *name, gboolean remove);
- * Gets the #FbApi from the #FbData.
- * Return: (transfer none): The #FbApi.
-fb_data_get_api(FbData *fata);
- * fb_data_get_connection:
- * Gets the #PurpleConnection from the #FbData.
- * Return: (transfer none): The #PurpleConnection.
-fb_data_get_connection(FbData *fata);
- * fb_data_get_roomlist:
- * Gets the #PurpleRoomlist from the #FbData.
- * Return: (transfer none): The #PurpleRoomlist.
-fb_data_get_roomlist(FbData *fata);
- * Gets the unread state of an #FbId.
- * Return: #TRUE if the #FbId is unread, otherwise #FALSE.
-fb_data_get_unread(FbData *fata, FbId id);
- * fb_data_set_roomlist:
- * @list: The #PurpleRoomlist.
- * Sets the #PurpleRoomlist to the #FbData.
-fb_data_set_roomlist(FbData *fata, PurpleRoomlist *list);
- * @unread: #TRUE if the #FbId is unread, otherwise #FALSE.
- * Sets the unread state of an #FbId to the #FbData.
-fb_data_set_unread(FbData *fata, FbId id, gboolean unread);
- * @msg: The #FbApiMessage.
- * Adds an #FbApiMessage to the #FbData.
-fb_data_add_message(FbData *fata, FbApiMessage *msg);
- * fb_data_remove_message:
- * @msg: The #FbApiMessage.
- * Removes an #FbApiMessage from the #FbData.
-fb_data_remove_message(FbData *fata, FbApiMessage *msg);
- * fb_data_take_messages:
- * @uid: The user #FbId.
- * Gets a #GSList of messages by the user #FbId from the #FbData. The
- * #FbApiMessage's are removed from the #FbData.
- * Returns: (element-type FbApiMessage) (transfer full): The messages from the
-fb_data_take_messages(FbData *fata, FbId uid);
- * @func: The #FbDataImageFunc.
- * @data: The user-defined data.
- * @dunc: The #GDestroyNotify for @data or #NULL.
- * Adds a new #FbDataImage to the #FbData. This is used to fetch images
- * from HTTP sources. After calling this, #fb_data_image_queue() should
- * be called to queue the fetching process.
- * Return: (transfer none): The #FbDataImage.
-fb_data_image_add(FbData *fata, const gchar *url, FbDataImageFunc func,
- gpointer data, GDestroyNotify dunc);
- * fb_data_image_get_active:
- * @img: The #FbDataImage.
- * Gets the active fetching state from the #FbDataImage.
- * Returns: #TRUE if the image is being fetched, otherwise #FALSE.
-fb_data_image_get_active(FbDataImage *img);
- * fb_data_image_get_data:
- * @img: The #FbDataImage.
- * Gets the user-defined data from the #FbDataImage.
- * Returns: The user-defined data.
-fb_data_image_get_data(FbDataImage *img);
- * fb_data_image_get_fata:
- * @img: The #FbDataImage.
- * Gets the #FbData from the #FbDataImage.
- * Returns: (transfer none): The #FbData.
-fb_data_image_get_fata(FbDataImage *img);
- * fb_data_image_get_image:
- * @img: The #FbDataImage.
- * @size: The return location for the image size or #NULL.
- * Gets the image data from the #FbDataImage.
- * Returns: The image data.
-fb_data_image_get_image(FbDataImage *img, gsize *size);
- * fb_data_image_dup_image:
- * @img: The #FbDataImage.
- * @size: The return location for the image size or #NULL.
- * Gets the duplicated image data from the #FbDataImage. The returned
- * data should be freed with #g_free() when no longer needed.
- * Returns: The duplicated image data.
-fb_data_image_dup_image(FbDataImage *img, gsize *size);
- * fb_data_image_get_url:
- * @img: The #FbDataImage.
- * Gets the image URL from the #FbDataImage.
- * Returns: The image URL.
-fb_data_image_get_url(FbDataImage *img);
- * Queues the next #FbDataImage fetches.
-fb_data_image_queue(FbData *fata);
-#endif /* PURPLE_FACEBOOK_DATA_H */
--- a/libpurple/protocols/facebook/facebook.c Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1740 +0,0 @@
- * 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
- * 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 <glib/gi18n-lib.h>
-#include <gplugin-native.h>
-#include "libpurple/glibcompat.h"
-struct _FacebookProtocol {
-static GSList *fb_cmds = NULL;
-static PurpleProtocol *fb_protocol = NULL;
-fb_cb_api_messages(FbApi *api, GSList *msgs, gpointer data);
-fb_get_group(gboolean friend)
- title = _("Facebook Friends");
- title = _("Facebook Non-Friends");
- grp = purple_blist_find_group(title);
- if (G_UNLIKELY(grp == NULL)) {
- grp = purple_group_new(title);
- for (n = purple_blist_get_default_root(); n != NULL;
- /* Append to the end of the buddy list */
- purple_blist_add_group(grp, node);
- node = PURPLE_BLIST_NODE(grp);
- purple_blist_node_set_bool(node, "collapsed", TRUE);
-fb_buddy_add_nonfriend(PurpleAccount *acct, FbApiUser *user)
- gchar uid[FB_ID_STRMAX];
- FB_ID_TO_STR(user->uid, uid);
- bdy = purple_buddy_new(acct, uid, user->name);
- grp = fb_get_group(FALSE);
- purple_buddy_set_server_alias(bdy, user->name);
- purple_blist_add_buddy(bdy, NULL, grp, NULL);
-fb_cb_api_auth(FbApi *api, gpointer data)
-fb_cb_api_connect(FbApi *api, gpointer data)
- gc = fb_data_get_connection(fata);
- acct = purple_connection_get_account(gc);
- purple_connection_set_state(gc, PURPLE_CONNECTION_STATE_CONNECTED);
- if (purple_account_get_bool(acct, "show-unread", TRUE)) {
-fb_cb_api_contact(FbApi *api, FbApiUser *user, gpointer data)
- gchar uid[FB_ID_STRMAX];
- gc = fb_data_get_connection(fata);
- acct = purple_connection_get_account(gc);
- FB_ID_TO_STR(user->uid, uid);
- if (purple_blist_find_buddy(acct, uid) == NULL) {
- fb_buddy_add_nonfriend(acct, user);
- msgs = fb_data_take_messages(fata, user->uid);
- fb_cb_api_messages(api, msgs, fata);
- g_slist_free_full(msgs, (GDestroyNotify) fb_api_message_free);
-fb_cb_sync_contacts(gpointer data)
- api = fb_data_get_api(fata);
- fb_data_clear_timeout(fata, "sync-contacts", FALSE);
-fb_cb_icon(FbDataImage *img, GError *error)
- bdy = fb_data_image_get_data(img);
- acct = purple_buddy_get_account(bdy);
- name = purple_buddy_get_name(bdy);
- if (G_UNLIKELY(error != NULL)) {
- fb_util_debug_warning("Failed to retrieve icon for %s: %s",
- str = fb_data_image_get_url(img);
- params = fb_http_params_new_parse(str, TRUE);
- csum = fb_http_params_get_str(params, "oh", NULL);
- image = fb_data_image_dup_image(img, &size);
- purple_buddy_icons_set_for_user(acct, name, image, size, csum);
- fb_http_params_free(params);
-fb_sync_contacts_add_timeout(FbData *fata)
- gc = fb_data_get_connection(fata);
- acct = purple_connection_get_account(gc);
- sync = purple_account_get_int(acct, "sync-interval", 5);
- purple_account_set_int(acct, "sync-interval", 1);
- fb_data_save_timeout(fata, "sync-contacts",
- g_timeout_add_seconds(sync, fb_cb_sync_contacts, fata));
-fb_cb_api_contacts(FbApi *api, GSList *users, gboolean complete, gpointer data)
- gchar uid[FB_ID_STRMAX];
- GValue val = G_VALUE_INIT;
- PurpleConnectionState state;
- PurpleStatusPrimitive pstat;
- PurpleStatusType *type;
- gc = fb_data_get_connection(fata);
- acct = purple_connection_get_account(gc);
- grp = fb_get_group(TRUE);
- grpn = fb_get_group(FALSE);
- alias = purple_contact_info_get_alias(PURPLE_CONTACT_INFO(acct));
- state = purple_connection_get_state(gc);
- g_value_init(&val, FB_TYPE_ID);
- g_object_get_property(G_OBJECT(api), "uid", &val);
- muid = g_value_get_int64(&val);
- for (l = users; l != NULL; l = l->next) {
- FB_ID_TO_STR(user->uid, uid);
- if (G_UNLIKELY(user->uid == muid)) {
- PurpleContactInfo *info = NULL;
- if (G_UNLIKELY(alias != NULL)) {
- info = PURPLE_CONTACT_INFO(acct);
- purple_contact_info_set_alias(info, user->name);
- bdy = purple_blist_find_buddy(acct, uid);
- if ((bdy != NULL) && (purple_buddy_get_group(bdy) == grpn)) {
- purple_blist_remove_buddy(bdy);
- bdy = purple_buddy_new(acct, uid, NULL);
- purple_blist_add_buddy(bdy, NULL, grp, NULL);
- purple_buddy_set_server_alias(bdy, user->name);
- csum = purple_buddy_icons_get_checksum_for_user(bdy);
- if (!purple_strequal(csum, user->csum)) {
- fb_data_image_add(fata, user->icon, fb_cb_icon,
- fb_data_image_queue(fata);
- if (state != PURPLE_CONNECTION_STATE_CONNECTED) {
- status = purple_account_get_active_status(acct);
- type = purple_status_get_status_type(status);
- pstat = purple_status_type_get_primitive(type);
- fb_api_connect(api, pstat == PURPLE_STATUS_INVISIBLE);
- fb_sync_contacts_add_timeout(fata);
-fb_cb_api_contacts_delta(G_GNUC_UNUSED FbApi *api, GSList *added,
- GSList *removed, gpointer data)
- gchar uid[FB_ID_STRMAX];
- gc = fb_data_get_connection(fata);
- acct = purple_connection_get_account(gc);
- grp = fb_get_group(TRUE);
- grpn = fb_get_group(FALSE);
- for (l = added; l != NULL; l = l->next) {
- FB_ID_TO_STR(user->uid, uid);
- bdy = purple_blist_find_buddy(acct, uid);
- if ((bdy != NULL) && (purple_buddy_get_group(bdy) == grpn)) {
- purple_blist_remove_buddy(bdy);
- bdy = purple_buddy_new(acct, uid, NULL);
- purple_blist_add_buddy(bdy, NULL, grp, NULL);
- purple_buddy_set_server_alias(bdy, user->name);
- for (l = removed; l != NULL; l = l->next) {
- bdy = purple_blist_find_buddy(acct, l->data);
- purple_blist_remove_buddy(bdy);
- fb_sync_contacts_add_timeout(fata);
-fb_cb_api_error(G_GNUC_UNUSED FbApi *api, GError *error, gpointer data)
- PurpleConnectionError errc;
- gc = fb_data_get_connection(fata);
- if (error->domain == G_IO_ERROR) {
- purple_connection_g_error(gc, error);
- if (g_error_matches(error, FB_API_ERROR, FB_API_ERROR_QUEUE)) {
- /* Save the reset data */
- if ((error->domain == FB_HTTP_ERROR) &&
- (error->code >= 400) &&
- errc = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
- } else if (g_error_matches(error, FB_API_ERROR, FB_API_ERROR_AUTH)) {
- errc = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
- errc = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
- if (!g_error_matches(error, FB_API_ERROR, FB_API_ERROR_NONFATAL)) {
- purple_connection_error(gc, errc, error->message);
-fb_cb_api_events(FbApi *api, GSList *events, gpointer data)
- gchar uid[FB_ID_STRMAX];
- gchar tid[FB_ID_STRMAX];
- PurpleConversation *chat;
- PurpleConversationManager *manager;
- gc = fb_data_get_connection(fata);
- acct = purple_connection_get_account(gc);
- fetch = g_hash_table_new(fb_id_hash, fb_id_equal);
- manager = purple_conversation_manager_get_default();
- for (l = events; l != NULL; l = l->next) {
- FB_ID_TO_STR(event->tid, tid);
- chat = purple_conversation_manager_find_chat(manager, acct, tid);
- FB_ID_TO_STR(event->uid, uid);
- case FB_API_EVENT_TYPE_THREAD_TOPIC:
- purple_chat_conversation_set_topic(PURPLE_CHAT_CONVERSATION(chat), uid,
- case FB_API_EVENT_TYPE_THREAD_USER_ADDED:
- if (purple_blist_find_buddy(acct, uid) == NULL) {
- FbApiUser *user = g_new0(FbApiUser, 1);
- user->uid = event->uid;
- user->name = g_strdup(event->text);
- fb_buddy_add_nonfriend(acct, user);
- fb_api_user_free(user);
- g_hash_table_insert(fetch, &event->tid, event);
- purple_chat_conversation_add_user(PURPLE_CHAT_CONVERSATION(chat), uid, NULL, 0,
- case FB_API_EVENT_TYPE_THREAD_USER_REMOVED:
- purple_chat_conversation_remove_user(PURPLE_CHAT_CONVERSATION(chat), uid, event->text);
- g_hash_table_iter_init(&iter, fetch);
- while (g_hash_table_iter_next(&iter, NULL, (gpointer) &event)) {
- fb_api_thread(api, event->tid);
- g_hash_table_destroy(fetch);
-fb_cb_image(FbDataImage *img, GError *error)
- fata = fb_data_image_get_fata(img);
- msg = fb_data_image_get_data(img);
- if (G_UNLIKELY(error != NULL)) {
- url = fb_data_image_get_url(img);
- fb_util_debug_warning("Failed to retrieve image %s: %s",
- api = fb_data_get_api(fata);
- image = fb_data_image_dup_image(img, &size);
- pimg = purple_image_new_from_data(image, size);
- id = purple_image_store_add_weak(pimg);
- msg->text = g_strdup_printf("<img src=\""
- PURPLE_IMAGE_STORE_PROTOCOL
- msg->flags |= FB_API_MESSAGE_FLAG_DONE;
- msgs = g_slist_prepend(msgs, msg);
- fb_cb_api_messages(api, msgs, fata);
-fb_cb_api_messages(FbApi *api, GSList *msgs, gpointer data)
- gchar tid[FB_ID_STRMAX];
- gchar uid[FB_ID_STRMAX];
- PurpleConversation *chat;
- PurpleConversationManager *manager;
- PurpleMessageFlags flags;
- gc = fb_data_get_connection(fata);
- acct = purple_connection_get_account(gc);
- mark = purple_account_get_bool(acct, "mark-read", TRUE);
- open = purple_account_get_bool(acct, "group-chat-open", TRUE);
- self = purple_account_get_bool(acct, "show-self", TRUE);
- manager = purple_conversation_manager_get_default();
- for (l = msgs; l != NULL; l = l->next) {
- FB_ID_TO_STR(msg->uid, uid);
- if (purple_blist_find_buddy(acct, uid) == NULL) {
- msg = fb_api_message_dup(msg);
- fb_data_add_message(fata, msg);
- fb_api_contact(api, msg->uid);
- isself = (msg->flags & FB_API_MESSAGE_FLAG_SELF) != 0;
- flags = isself ? PURPLE_MESSAGE_SEND : PURPLE_MESSAGE_RECV;
- tstamp = msg->tstamp / 1000;
- if (msg->flags & FB_API_MESSAGE_FLAG_IMAGE) {
- if (!(msg->flags & FB_API_MESSAGE_FLAG_DONE)) {
- msg = fb_api_message_dup(msg);
- fb_data_image_add(fata, msg->text, fb_cb_image,
- fb_data_image_queue(fata);
- flags |= PURPLE_MESSAGE_IMAGES;
- html = g_markup_escape_text(msg->text, -1);
- fb_data_set_unread(fata, msg->uid, TRUE);
- fb_util_serv_got_im(gc, uid, text, flags, tstamp);
- FB_ID_TO_STR(msg->tid, tid);
- chat = purple_conversation_manager_find_chat(manager, acct, tid);
- id = fb_id_hash(&msg->tid);
- purple_serv_got_joined_chat(gc, id, tid);
- fb_api_thread(api, msg->tid);
- id = purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(chat));
- fb_data_set_unread(fata, msg->tid, TRUE);
- fb_util_serv_got_chat_in(gc, id, uid, text, flags, tstamp);
-fb_cb_api_presences(G_GNUC_UNUSED FbApi *api, GSList *presences, gpointer data)
- gchar uid[FB_ID_STRMAX];
- PurpleStatusPrimitive pstat;
- gc = fb_data_get_connection(fata);
- acct = purple_connection_get_account(gc);
- for (l = presences; l != NULL; l = l->next) {
- FbApiPresence *api_presence = l->data;
- if (api_presence->active) {
- pstat = PURPLE_STATUS_AVAILABLE;
- pstat = PURPLE_STATUS_OFFLINE;
- FB_ID_TO_STR(api_presence->uid, uid);
- statid = purple_primitive_get_id_from_type(pstat);
- purple_protocol_got_user_status(acct, uid, statid, NULL);
-fb_cb_api_thread(G_GNUC_UNUSED FbApi *api, FbApiThread *thrd, gpointer data)
- gchar tid[FB_ID_STRMAX];
- gchar uid[FB_ID_STRMAX];
- PurpleConversation *conv;
- PurpleConversationManager *manager;
- PurpleChatConversation *chat;
- gc = fb_data_get_connection(fata);
- acct = purple_connection_get_account(gc);
- id = fb_id_hash(&thrd->tid);
- FB_ID_TO_STR(thrd->tid, tid);
- manager = purple_conversation_manager_get_default();
- conv = purple_conversation_manager_find_chat(manager, acct, tid);
- if((conv == NULL) || purple_chat_conversation_has_left(PURPLE_CHAT_CONVERSATION(conv))) {
- conv = purple_serv_got_joined_chat(gc, id, tid);
- chat = PURPLE_CHAT_CONVERSATION(conv);
- /* If there are no users in the group chat, including
- * the local user, then the group chat has yet to be
- * setup by this function. As a result, any group chat
- * without users is inactive.
- chat = PURPLE_CHAT_CONVERSATION(conv);
- active = purple_chat_conversation_get_users_count(chat) > 0;
- name = purple_contact_info_get_username(PURPLE_CONTACT_INFO(acct));
- purple_chat_conversation_add_user(chat, name, NULL, 0, FALSE);
- purple_chat_conversation_set_topic(chat, NULL, thrd->topic);
- for (l = thrd->users; l != NULL; l = l->next) {
- FB_ID_TO_STR(user->uid, uid);
- if (purple_chat_conversation_has_user(chat, uid)) {
- if (purple_blist_find_buddy(acct, uid) == NULL) {
- fb_buddy_add_nonfriend(acct, user);
- purple_chat_conversation_add_user(chat, uid, NULL, 0, active);
-fb_cb_api_thread_create(G_GNUC_UNUSED FbApi *api, FbId tid, gpointer data)
- gchar sid[FB_ID_STRMAX];
- gc = fb_data_get_connection(fata);
- FB_ID_TO_STR(tid, sid);
- table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
- g_hash_table_insert(table, "name", g_strdup(sid));
- purple_serv_join_chat(gc, table);
- g_hash_table_destroy(table);
-fb_cb_api_thread_kicked(G_GNUC_UNUSED FbApi *api, FbApiThread *thrd,
- gchar tid[FB_ID_STRMAX];
- PurpleConversation *chat;
- PurpleConversationManager *manager;
- FB_ID_TO_STR(thrd->tid, tid);
- gc = fb_data_get_connection(fata);
- acct = purple_connection_get_account(gc);
- manager = purple_conversation_manager_get_default();
- chat = purple_conversation_manager_find_chat(manager, acct, tid);
- PurpleRequestCommonParameters *cpar;
- cpar = purple_request_cpar_from_connection(gc);
- purple_notify_error(gc,
- _("Failed to Join Chat"),
- _("You have been removed from this chat"),
- purple_conversation_write_system_message(chat,
- _("You have been removed from this chat"), 0);
- purple_serv_got_chat_left(gc, purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(chat)));
-fb_cb_api_threads(G_GNUC_UNUSED FbApi *api, GSList *thrds, gpointer data)
- gchar tid[FB_ID_STRMAX];
- gchar uid[FB_ID_STRMAX];
- PurpleRoomlistRoom *room;
- list = fb_data_get_roomlist(fata);
- if (G_UNLIKELY(list == NULL)) {
- gc = fb_data_get_connection(fata);
- acct = purple_connection_get_account(gc);
- gstr = g_string_new(NULL);
- for (l = thrds; l != NULL; l = l->next) {
- FB_ID_TO_STR(thrd->tid, tid);
- g_string_truncate(gstr, 0);
- for (m = thrd->users; m != NULL; m = m->next) {
- FB_ID_TO_STR(user->uid, uid);
- bdy = purple_blist_find_buddy(acct, uid);
- alias = purple_buddy_get_alias(bdy);
- g_string_append(gstr, ", ");
- g_string_append(gstr, alias);
- room = purple_roomlist_room_new(tid, thrd->topic);
- purple_roomlist_room_add_field(room, "topic", g_strdup(thrd->topic));
- purple_roomlist_room_add_field(room, "users", g_strdup(gstr->str));
- purple_roomlist_room_add(list, room);
- purple_roomlist_set_in_progress(list, FALSE);
- fb_data_set_roomlist(fata, NULL);
- g_string_free(gstr, TRUE);
-fb_cb_api_typing(G_GNUC_UNUSED FbApi *api, FbApiTyping *typg, gpointer data)
- gchar uid[FB_ID_STRMAX];
- gc = fb_data_get_connection(fata);
- FB_ID_TO_STR(typg->uid, uid);
- purple_serv_got_typing(gc, uid, 0, PURPLE_IM_TYPING);
- purple_serv_got_typing_stopped(gc, uid);
-fb_mark_read(FbData *fata, FbId id, gboolean thread)
- gc = fb_data_get_connection(fata);
- acct = purple_connection_get_account(gc);
- api = fb_data_get_api(fata);
- if (!fb_data_get_unread(fata, id) ||
- (purple_account_get_bool(acct, "mark-read-available", FALSE) &&
- fb_api_is_invisible(api)))
- fb_data_set_unread(fata, id, FALSE);
- fb_api_read(api, id, thread);
-fb_cb_conv_read(gpointer data)
- PurpleConversation *conv = data;
- gc = purple_conversation_get_connection(conv);
- fata = purple_connection_get_protocol_data(gc);
- name = purple_conversation_get_name(conv);
- id = FB_ID_FROM_STR(name);
- tname = g_strconcat("conv-read-", name, NULL);
- fb_data_clear_timeout(fata, tname, FALSE);
- if (purple_conversation_has_focus(conv)) {
- fb_mark_read(fata, id, PURPLE_IS_CHAT_CONVERSATION(conv));
-fb_cb_conv_updated(PurpleConversation *conv, PurpleConversationUpdateType type,
- acct = purple_conversation_get_account(conv);
- pid = purple_account_get_protocol_id(acct);
- if ((type == PURPLE_CONVERSATION_UPDATE_UNSEEN) &&
- purple_strequal(pid, FB_PROTOCOL_ID) &&
- purple_account_get_bool(acct, "mark-read", TRUE))
- /* Use event loop for purple_conversation_has_focus() */
- name = purple_conversation_get_name(conv);
- tname = g_strconcat("conv-read-", name, NULL);
- fb_data_save_timeout(fata, tname,
- g_timeout_add_seconds(0, fb_cb_conv_read, conv));
-fb_cb_conv_deleting(PurpleConversation *conv, gpointer data)
- acct = purple_conversation_get_account(conv);
- pid = purple_account_get_protocol_id(acct);
- if (!purple_strequal(pid, FB_PROTOCOL_ID)) {
- name = purple_conversation_get_name(conv);
- tname = g_strconcat("conv-read-", name, NULL);
- fb_data_clear_timeout(fata, tname, TRUE);
-fb_blist_chat_create(GSList *buddies, gpointer data)
- PurpleRequestCommonParameters *cpar;
- gc = fb_data_get_connection(fata);
- api = fb_data_get_api(fata);
- if (g_slist_length(buddies) < 2) {
- cpar = purple_request_cpar_from_connection(gc);
- purple_notify_error(gc,
- _("Failed to Initiate Chat"),
- _("At least two initial chat participants"
- for (l = buddies; l != NULL; l = l->next) {
- name = purple_buddy_get_name(l->data);
- uid = FB_ID_FROM_STR(name);
- did = g_memdup2(&uid, sizeof uid);
- uids = g_slist_prepend(uids, did);
- fb_api_thread_create(api, uids);
- g_slist_free_full(uids, g_free);
-fb_blist_chat_init(PurpleBlistNode *node, gpointer data)
- if (!PURPLE_IS_BUDDY(node)) {
- gc = fb_data_get_connection(fata);
- select = g_slist_prepend(select, PURPLE_BUDDY(node));
- fb_util_request_buddy(gc,
- _("Initial Chat Participants"),
- _("Select at least two initial participants."),
- G_CALLBACK(fb_blist_chat_create), NULL,
-fb_get_account_options(G_GNUC_UNUSED PurpleProtocol *protocol) {
- PurpleAccountOption *opt;
- opt = purple_account_option_int_new(_("Buddy list sync interval"),
- opts = g_list_prepend(opts, opt);
- opt = purple_account_option_bool_new(_("Mark messages as read on focus"),
- 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"),
- opts = g_list_prepend(opts, opt);
- opt = purple_account_option_bool_new(_("Show unread messages"),
- opts = g_list_prepend(opts, opt);
- opt = purple_account_option_bool_new(_("Open new group chats with "
- "group-chat-open", TRUE);
- opts = g_list_prepend(opts, opt);
- return g_list_reverse(opts);
-fb_login(G_GNUC_UNUSED PurpleProtocol *protocol, PurpleAccount *acct) {
- GProxyResolver *resolver;
- gc = purple_account_get_connection(acct);
- resolver = purple_proxy_get_proxy_resolver(acct, &error);
- if (resolver == NULL) {
- fb_util_debug_error("Unable to get account proxy resolver: %s",
- purple_connection_take_error(gc, error);
- fata = fb_data_new(gc, resolver);
- api = fb_data_get_api(fata);
- convh = purple_conversations_get_handle();
- purple_connection_set_protocol_data(gc, fata);
- G_CALLBACK(fb_cb_api_auth),
- G_CALLBACK(fb_cb_api_connect),
- G_CALLBACK(fb_cb_api_contact),
- G_CALLBACK(fb_cb_api_contacts),
- G_CALLBACK(fb_cb_api_contacts_delta),
- G_CALLBACK(fb_cb_api_error),
- G_CALLBACK(fb_cb_api_events),
- G_CALLBACK(fb_cb_api_messages),
- G_CALLBACK(fb_cb_api_presences),
- G_CALLBACK(fb_cb_api_thread),
- G_CALLBACK(fb_cb_api_thread_create),
- G_CALLBACK(fb_cb_api_thread_kicked),
- G_CALLBACK(fb_cb_api_threads),
- G_CALLBACK(fb_cb_api_typing),
- purple_signal_connect(convh,
- "conversation-updated",
- G_CALLBACK(fb_cb_conv_updated),
- purple_signal_connect(convh,
- "deleting-conversation",
- G_CALLBACK(fb_cb_conv_deleting),
- if (!fb_data_load(fata) || !purple_account_get_remember_password(acct)) {
- user = purple_contact_info_get_username(PURPLE_CONTACT_INFO(acct));
- pass = purple_connection_get_password(gc);
- fb_api_auth(api, user, pass);
-fb_close(G_GNUC_UNUSED PurpleProtocol *protocol, PurpleConnection *gc) {
- fata = purple_connection_get_protocol_data(gc);
- api = fb_data_get_api(fata);
- fb_api_disconnect(api);
- purple_connection_set_protocol_data(gc, NULL);
- purple_signals_disconnect_by_handle(gc);
-fb_status_types(G_GNUC_UNUSED PurpleProtocol *protocol,
- G_GNUC_UNUSED PurpleAccount *acct)
- PurpleStatusType *type;
- type = purple_status_type_new(PURPLE_STATUS_AVAILABLE,
- types = g_list_prepend(types, type);
- /* Just a NULL state (as of now) for compatibility */
- type = purple_status_type_new(PURPLE_STATUS_AWAY,
- types = g_list_prepend(types, type);
- type = purple_status_type_new(PURPLE_STATUS_INVISIBLE,
- types = g_list_prepend(types, type);
- type = purple_status_type_new(PURPLE_STATUS_OFFLINE,
- types = g_list_prepend(types, type);
- return g_list_reverse(types);
-fb_client_blist_node_menu(G_GNUC_UNUSED PurpleProtocolClient *client,
- if (!PURPLE_IS_BUDDY(node)) {
- acct = purple_buddy_get_account(PURPLE_BUDDY(node));
- gc = purple_account_get_connection(acct);
- fata = purple_connection_get_protocol_data(gc);
- act = purple_action_menu_new(_("Initiate _Chat"),
- G_CALLBACK(fb_blist_chat_init),
- acts = g_list_prepend(acts, act);
- return g_list_reverse(acts);
-fb_client_offline_message(G_GNUC_UNUSED PurpleProtocolClient *client,
- G_GNUC_UNUSED PurpleBuddy *buddy)
-fb_server_set_status(G_GNUC_UNUSED PurpleProtocolServer *protocol_server,
- PurpleAccount *acct, PurpleStatus *status)
- PurpleStatusPrimitive pstat;
- PurpleStatusType *type;
- gc = purple_account_get_connection(acct);
- fata = purple_connection_get_protocol_data(gc);
- api = fb_data_get_api(fata);
- type = purple_status_get_status_type(status);
- pstat = purple_status_type_get_primitive(type);
- invis = fb_api_is_invisible(api);
- if ((pstat == PURPLE_STATUS_INVISIBLE) && !invis) {
- fb_api_connect(api, TRUE);
- } else if ((pstat != PURPLE_STATUS_OFFLINE) && invis) {
- fb_api_connect(api, FALSE);
-fb_im_send(G_GNUC_UNUSED PurpleProtocolIM *im, PurpleConnection *gc,
- fata = purple_connection_get_protocol_data(gc);
- api = fb_data_get_api(fata);
- name = purple_message_get_recipient(msg);
- uid = FB_ID_FROM_STR(name);
- text = purple_message_get_contents(msg);
- sext = purple_markup_strip_html(text);
- fb_api_message(api, uid, FALSE, sext);
-fb_im_send_typing(G_GNUC_UNUSED PurpleProtocolIM *im, PurpleConnection *gc,
- const gchar *name, PurpleIMTypingState state)
- fata = purple_connection_get_protocol_data(gc);
- api = fb_data_get_api(fata);
- uid = FB_ID_FROM_STR(name);
- fb_api_typing(api, uid, state != PURPLE_IM_NOT_TYPING);
-fb_chat_info(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat,
- G_GNUC_UNUSED PurpleConnection *connection)
- PurpleProtocolChatEntry *pce;
- pce = g_new0(PurpleProtocolChatEntry, 1);
- pce->label = _("Chat _Name");
- pce->identifier = "name";
- pces = g_list_prepend(pces, pce);
- return g_list_reverse(pces);
-fb_chat_info_defaults(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat,
- G_GNUC_UNUSED PurpleConnection *connection,
- data = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
- g_hash_table_insert(data, "name", g_strdup(name));
-fb_chat_join(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat,
- PurpleConnection *gc, GHashTable *data)
- PurpleConversation *chat;
- PurpleConversationManager *manager;
- PurpleRequestCommonParameters *cpar;
- name = g_hash_table_lookup(data, "name");
- g_return_if_fail(name != NULL);
- if (!FB_ID_IS_STR(name)) {
- cpar = purple_request_cpar_from_connection(gc);
- purple_notify_error(gc,
- _("Failed to Join Chat"),
- _("Invalid Facebook identifier."),
- tid = FB_ID_FROM_STR(name);
- manager = purple_conversation_manager_get_default();
- chat = purple_conversation_manager_find_chat_by_id(manager,
- purple_connection_get_account(gc),
- if ((chat != NULL) && !purple_chat_conversation_has_left(PURPLE_CHAT_CONVERSATION(chat))) {
- purple_conversation_present(chat);
- fata = purple_connection_get_protocol_data(gc);
- api = fb_data_get_api(fata);
- fb_api_thread(api, tid);
-fb_chat_get_name(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat,
- name = g_hash_table_lookup(data, "name");
- g_return_val_if_fail(name != NULL, NULL);
-fb_chat_invite(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat,
- PurpleConnection *gc, gint id, G_GNUC_UNUSED const char *msg,
- PurpleConversation *chat;
- PurpleConversationManager *manager;
- PurpleRequestCommonParameters *cpar;
- if (!FB_ID_IS_STR(who)) {
- cpar = purple_request_cpar_from_connection(gc);
- purple_notify_error(gc,
- _("Invite Buddy Into Chat Room"),
- _("Failed to Invite User"),
- _("Invalid Facebook identifier."),
- fata = purple_connection_get_protocol_data(gc);
- api = fb_data_get_api(fata);
- manager = purple_conversation_manager_get_default();
- chat = purple_conversation_manager_find_chat_by_id(manager,
- purple_connection_get_account(gc),
- name = purple_conversation_get_name(chat);
- tid = FB_ID_FROM_STR(name);
- uid = FB_ID_FROM_STR(who);
- fb_api_thread_invite(api, tid, uid);
-fb_chat_send(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat,
- PurpleConnection *gc, gint id, PurpleMessage *msg)
- PurpleConversation *chat;
- PurpleConversationManager *manager;
- acct = purple_connection_get_account(gc);
- fata = purple_connection_get_protocol_data(gc);
- api = fb_data_get_api(fata);
- manager = purple_conversation_manager_get_default();
- chat = purple_conversation_manager_find_chat_by_id(manager, acct, id);
- name = purple_conversation_get_name(chat);
- tid = FB_ID_FROM_STR(name);
- text = purple_message_get_contents(msg);
- sext = purple_markup_strip_html(text);
- fb_api_message(api, tid, TRUE, sext);
- name = purple_contact_info_get_username(PURPLE_CONTACT_INFO(acct));
- purple_serv_got_chat_in(gc, id, name,
- purple_message_get_flags(msg),
- purple_message_get_contents(msg),
-fb_chat_set_topic(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat,
- PurpleConnection *gc, gint id, const char *topic)
- PurpleConversation *chat;
- PurpleConversationManager *manager;
- fata = purple_connection_get_protocol_data(gc);
- api = fb_data_get_api(fata);
- manager = purple_conversation_manager_get_default();
- chat = purple_conversation_manager_find_chat_by_id(manager,
- purple_connection_get_account(gc),
- name = purple_conversation_get_name(chat);
- tid = FB_ID_FROM_STR(name);
- fb_api_thread_topic(api, tid, topic);
-fb_roomlist_get_list(G_GNUC_UNUSED PurpleProtocolRoomlist *protocol_roomlist,
- fata = purple_connection_get_protocol_data(gc);
- list = fb_data_get_roomlist(fata);
- g_return_val_if_fail(list == NULL, NULL);
- api = fb_data_get_api(fata);
- acct = purple_connection_get_account(gc);
- list = purple_roomlist_new(acct);
- fb_data_set_roomlist(fata, list);
- purple_roomlist_set_in_progress(list, TRUE);
-fb_roomlist_cancel(G_GNUC_UNUSED PurpleProtocolRoomlist *protocol_roomlist,
- acct = purple_roomlist_get_account(list);
- gc = purple_account_get_connection(acct);
- fata = purple_connection_get_protocol_data(gc);
- cist = fb_data_get_roomlist(fata);
- if (G_LIKELY(cist == list)) {
- fb_data_set_roomlist(fata, NULL);
- purple_roomlist_set_in_progress(list, FALSE);
-fb_cmd_kick(PurpleConversation *conv, G_GNUC_UNUSED const char *cmd,
- char **args, char **error, G_GNUC_UNUSED gpointer data)
- PurpleChatConversation *chat;
- g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(conv),
- PURPLE_CMD_RET_FAILED);
- gc = purple_conversation_get_connection(conv);
- acct = purple_connection_get_account(gc);
- chat = PURPLE_CHAT_CONVERSATION(conv);
- bdy = fb_util_account_find_buddy(acct, chat, args[0], &err);
- *error = g_strdup_printf(_("%s."), err->message);
- return PURPLE_CMD_RET_FAILED;
- fata = purple_connection_get_protocol_data(gc);
- api = fb_data_get_api(fata);
- name = purple_conversation_get_name(conv);
- tid = FB_ID_FROM_STR(name);
- name = purple_buddy_get_name(bdy);
- uid = FB_ID_FROM_STR(name);
- fb_api_thread_remove(api, tid, uid);
- return PURPLE_CMD_RET_OK;
-fb_cmd_leave(PurpleConversation *conv, G_GNUC_UNUSED const char *cmd,
- G_GNUC_UNUSED char **args, G_GNUC_UNUSED char **error,
- G_GNUC_UNUSED gpointer data)
- PurpleChatConversation *chat;
- g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(conv),
- PURPLE_CMD_RET_FAILED);
- gc = purple_conversation_get_connection(conv);
- fata = purple_connection_get_protocol_data(gc);
- api = fb_data_get_api(fata);
- chat = PURPLE_CHAT_CONVERSATION(conv);
- id = purple_chat_conversation_get_id(chat);
- name = purple_conversation_get_name(conv);
- tid = FB_ID_FROM_STR(name);
- purple_serv_got_chat_left(gc, id);
- fb_api_thread_remove(api, tid, 0);
- return PURPLE_CMD_RET_OK;
-facebook_protocol_init(G_GNUC_UNUSED FacebookProtocol *self) {
-facebook_protocol_class_init(FacebookProtocolClass *klass)
- PurpleProtocolClass *protocol_class = PURPLE_PROTOCOL_CLASS(klass);
- protocol_class->get_account_options = fb_get_account_options;
- protocol_class->login = fb_login;
- protocol_class->close = fb_close;
- protocol_class->status_types = fb_status_types;
-facebook_protocol_class_finalize(G_GNUC_UNUSED FacebookProtocolClass *klass)
-facebook_protocol_client_iface_init(PurpleProtocolClientInterface *iface)
- iface->blist_node_menu = fb_client_blist_node_menu;
- iface->offline_message = fb_client_offline_message;
-facebook_protocol_server_init(PurpleProtocolServerInterface *iface)
- iface->set_status = fb_server_set_status;
-facebook_protocol_im_iface_init(PurpleProtocolIMInterface *iface)
- iface->send = fb_im_send;
- iface->send_typing = fb_im_send_typing;
-facebook_protocol_chat_iface_init(PurpleProtocolChatInterface *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;
-facebook_protocol_roomlist_iface_init(PurpleProtocolRoomlistInterface *iface)
- iface->get_list = fb_roomlist_get_list;
- iface->cancel = fb_roomlist_cancel;
-G_DEFINE_DYNAMIC_TYPE_EXTENDED(
- G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_CLIENT,
- facebook_protocol_client_iface_init)
- G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_SERVER,
- facebook_protocol_server_init)
- G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_IM,
- facebook_protocol_im_iface_init)
- G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_CHAT,
- facebook_protocol_chat_iface_init)
- G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_ROOMLIST,
- facebook_protocol_roomlist_iface_init))
- static PurpleCmdFlag cflags =
- PURPLE_CMD_FLAG_PROTOCOL_ONLY;
- g_return_if_fail(fb_cmds == NULL);
- id = purple_cmd_register("kick", "s", PURPLE_CMD_P_PROTOCOL, cflags,
- FB_PROTOCOL_ID, fb_cmd_kick,
- _("kick: Kick someone from the chat"),
- 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,
- _("leave: Leave the chat"),
- fb_cmds = g_slist_prepend(fb_cmds, GUINT_TO_POINTER(id));
-fb_cmds_unregister_free(gpointer data)
- PurpleCmdId id = GPOINTER_TO_UINT(data);
- purple_cmd_unregister(id);
-fb_cmds_unregister(void)
- g_clear_slist(&fb_cmds, fb_cmds_unregister_free);
-static GPluginPluginInfo *
-facebook_query(G_GNUC_UNUSED GError **error)
- return purple_plugin_info_new(
- "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,
-facebook_load(GPluginPlugin *plugin, GError **error)
- PurpleProtocolManager *manager = purple_protocol_manager_get_default();
- facebook_protocol_register_type(G_TYPE_MODULE(plugin));
- fb_protocol = g_object_new(FACEBOOK_TYPE_PROTOCOL,
- "description", _("Facebook Messenger allows "
- "you to talk with your "
- "friends on Facebook."),
- "icon-name", "im-facebook",
- "icon-resource-path", "/im/pidgin/libpurple/facebook/icons",
- "options", OPT_PROTO_CHAT_TOPIC,
- if(!purple_protocol_manager_register(manager, fb_protocol, error)) {
- g_clear_object(&fb_protocol);
-facebook_unload(G_GNUC_UNUSED GPluginPlugin *plugin,
- G_GNUC_UNUSED gboolean shutdown, GError **error)
- PurpleProtocolManager *manager = purple_protocol_manager_get_default();
- if(!purple_protocol_manager_unregister(manager, fb_protocol, error)) {
- g_clear_object(&fb_protocol);
-GPLUGIN_NATIVE_PLUGIN_DECLARE(facebook)
--- a/libpurple/protocols/facebook/facebook.h Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
- * 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
- * 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_FACEBOOK_FACEBOOK_H
-#define PURPLE_FACEBOOK_FACEBOOK_H
-#define FACEBOOK_TYPE_PROTOCOL (facebook_protocol_get_type())
-G_DECLARE_FINAL_TYPE(FacebookProtocol, facebook_protocol, FACEBOOK, PROTOCOL,
- * The Facebook protocol identifier.
-#define FB_PROTOCOL_ID "prpl-facebook"
- * Represents the Facebook #PurpleProtocol.
- * FacebookProtocolClass:
- * The base class for all #FacebookProtocol's.
-#endif /* PURPLE_FACEBOOK_FACEBOOK_H */
--- a/libpurple/protocols/facebook/http.c Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,282 +0,0 @@
- * 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
- * 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 <glib/gi18n-lib.h>
-fb_http_error_quark(void)
- if (G_UNLIKELY(q == 0)) {
- q = g_quark_from_static_string("fb-http-error-quark");
-fb_http_error_chk(SoupMessage *res, GError **error)
- SoupStatus status_code = soup_message_get_status(res);
- if (SOUP_STATUS_IS_SUCCESSFUL(status_code)) {
- g_set_error(error, FB_HTTP_ERROR, status_code, "%s",
- soup_message_get_reason_phrase(res));
-fb_http_params_new(void)
- return g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
-fb_http_params_new_parse(const gchar *data, gboolean isurl)
- return fb_http_params_new();
- if (!g_uri_split(data, G_URI_FLAGS_ENCODED_QUERY, NULL, NULL, NULL,
- NULL, NULL, &query, NULL, NULL))
- return fb_http_params_new();
- params = soup_form_decode(data);
-fb_http_params_free(FbHttpParams *params)
- g_hash_table_destroy(params);
-fb_http_params_get(FbHttpParams *params, const gchar *name, GError **error)
- ret = g_hash_table_lookup(params, name);
- g_set_error(error, FB_HTTP_ERROR, FB_HTTP_ERROR_NOMATCH,
- _("No matches for %s"), name);
-fb_http_params_get_bool(FbHttpParams *params, const gchar *name,
- val = fb_http_params_get(params, name, error);
- return g_ascii_strcasecmp(val, "TRUE") == 0;
-fb_http_params_get_dbl(FbHttpParams *params, const gchar *name,
- val = fb_http_params_get(params, name, error);
- return g_ascii_strtod(val, NULL);
-fb_http_params_get_int(FbHttpParams *params, const gchar *name,
- val = fb_http_params_get(params, name, error);
- return g_ascii_strtoll(val, NULL, 10);
-fb_http_params_get_str(FbHttpParams *params, const gchar *name,
- return fb_http_params_get(params, name, error);
-fb_http_params_dup_str(FbHttpParams *params, const gchar *name,
- str = fb_http_params_get(params, name, error);
-fb_http_params_set(FbHttpParams *params, const gchar *name, gchar *value)
- g_hash_table_replace(params, key, value);
-fb_http_params_set_bool(FbHttpParams *params, const gchar *name,
- val = g_strdup(value ? "true" : "false");
- fb_http_params_set(params, name, val);
-fb_http_params_set_dbl(FbHttpParams *params, const gchar *name, gdouble value)
- val = g_strdup_printf("%f", value);
- fb_http_params_set(params, name, val);
-fb_http_params_set_int(FbHttpParams *params, const gchar *name, gint64 value)
- val = g_strdup_printf("%" G_GINT64_FORMAT, value);
- fb_http_params_set(params, name, val);
-fb_http_params_set_str(FbHttpParams *params, const gchar *name,
- fb_http_params_set(params, name, val);
-fb_http_params_set_strf(FbHttpParams *params, const gchar *name,
- const gchar *format, ...)
- val = g_strdup_vprintf(format, ap);
- fb_http_params_set(params, name, val);
-fb_http_urlcmp(const gchar *url1, const gchar *url2, gboolean protocol)
- if ((url1 == NULL) || (url2 == NULL)) {
- if (strstr(url1, url2) != NULL || strstr(url2, url1) != NULL) {
- uri1 = g_uri_parse(url1, SOUP_HTTP_URI_FLAGS, NULL);
- return g_ascii_strcasecmp(url1, url2) == 0;
- uri2 = g_uri_parse(url2, SOUP_HTTP_URI_FLAGS, NULL);
- return g_ascii_strcasecmp(url1, url2) == 0;
- /* Force the same scheme (and same port). */
- tmp = soup_uri_copy(uri1,
- SOUP_URI_SCHEME, "https",
- tmp = soup_uri_copy(uri2,
- SOUP_URI_SCHEME, "https",
- ret = soup_uri_equal(uri1, uri2);
--- a/libpurple/protocols/facebook/http.h Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,266 +0,0 @@
- * 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
- * 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_FACEBOOK_HTTP_H
-#define PURPLE_FACEBOOK_HTTP_H
-#include <libsoup/soup.h>
- * The #GQuark of the domain of HTTP errors.
-#define FB_HTTP_ERROR fb_http_error_quark()
- * Represents a set of key/value HTTP parameters.
-typedef GHashTable FbHttpParams;
- * @FB_HTTP_ERROR_SUCCESS: There is no error.
- * @FB_HTTP_ERROR_NOMATCH: The name does not match anything.
- * The error codes for the #FB_HTTP_ERROR domain.
- FB_HTTP_ERROR_SUCCESS = 0,
- * Gets the #GQuark of the domain of HTTP errors.
- * Returns: The #GQuark of the domain.
-fb_http_error_quark(void);
- * @res: The #SoupMessage.
- * @error: The return location for the #GError or #NULL.
- * Checks a #SoupMessage for success. This optionally assigns an
- * appropriate #GError upon failure.
- * Returns: #TRUE if the request was successful, otherwise #FALSE.
-gboolean fb_http_error_chk(SoupMessage *res, GError **error);
- * Creates a new #FbHttpParams. The returned #FbHttpParams should be
- * freed with #fb_http_params_free() when no longer needed. Optionally,
- * instead of freeing, the returned #FbHttpParams can be closed with
- * #fb_http_params_close().
- * Returns: (transfer full): The new #FbHttpParams.
-fb_http_params_new(void);
- * fb_http_params_new_parse:
- * @data: The string containing HTTP parameters.
- * @isurl: #TRUE if @data is a URL, otherwise #FALSE.
- * Creates a new #FbHttpParams. This parses the #FbHttpParams from a
- * string, which can be a URL. The returned #FbHttpParams should be
- * freed with #fb_http_params_free() when no longer needed. Optionally,
- * instead of freeing, the returned #FbHttpParams can be closed with
- * #fb_http_params_close().
- * Returns: (transfer full): The new #FbHttpParams.
-fb_http_params_new_parse(const gchar *data, gboolean isurl);
- * @params: The #FbHttpParams.
- * Frees all memory used by the #FbHttpParams.
-fb_http_params_free(FbHttpParams *params);
- * fb_http_params_get_bool:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * @error: The return location for the #GError or #NULL.
- * Gets a boolean value from the #FbHttpParams. This optionally assigns
- * an appropriate #GError upon failure.
- * Return: The boolean value.
-fb_http_params_get_bool(FbHttpParams *params, const gchar *name,
- * fb_http_params_get_dbl:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * @error: The return location for the #GError or #NULL.
- * Gets a floating point value from the #FbHttpParams. This optionally
- * assigns an appropriate #GError upon failure.
- * Return: The floating point value.
-fb_http_params_get_dbl(FbHttpParams *params, const gchar *name,
- * fb_http_params_get_int:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * @error: The return location for the #GError or #NULL.
- * Gets an integer value from the #FbHttpParams. This optionally
- * assigns an appropriate #GError upon failure.
- * Return: The integer value.
-fb_http_params_get_int(FbHttpParams *params, const gchar *name,
- * fb_http_params_get_str:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * @error: The return location for the #GError or #NULL.
- * Gets a string value from the #FbHttpParams. This optionally assigns
- * an appropriate #GError upon failure.
- * Return: The string value.
-fb_http_params_get_str(FbHttpParams *params, const gchar *name,
- * fb_http_params_dup_str:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * @error: The return location for the #GError or #NULL.
- * Gets a duplicated string value from the #FbHttpParams. This
- * optionally assigns an appropriate #GError upon failure. The returned
- * string should be freed with #g_free() when no longer needed.
- * Return: The duplicated string value.
-fb_http_params_dup_str(FbHttpParams *params, const gchar *name,
- * fb_http_params_set_bool:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * Sets a boolean value to the #FbHttpParams.
-fb_http_params_set_bool(FbHttpParams *params, const gchar *name,
- * fb_http_params_set_dbl:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * Sets a floating point value to the #FbHttpParams.
-fb_http_params_set_dbl(FbHttpParams *params, const gchar *name, gdouble value);
- * fb_http_params_set_int:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * Sets an integer value to the #FbHttpParams.
-fb_http_params_set_int(FbHttpParams *params, const gchar *name, gint64 value);
- * fb_http_params_set_str:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * Sets a string value to the #FbHttpParams.
-fb_http_params_set_str(FbHttpParams *params, const gchar *name,
- * fb_http_params_set_strf:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * @format: The format string literal.
- * @...: The arguments for @format.
- * Sets a formatted string value to the #FbHttpParams.
-fb_http_params_set_strf(FbHttpParams *params, const gchar *name,
- const gchar *format, ...)
- * @url1: The first URL.
- * @url2: The second URL.
- * @protocol: #TRUE to match the protocols, otherwise #FALSE.
- * Compares two URLs. This is more reliable than just comparing two URL
- * strings, as it avoids casing in some areas, while not in others. It
- * can also, optionally, ignore the matching of the URL protocol.
- * Returns: #TRUE if the URLs match, otherwise #FALSE.
-fb_http_urlcmp(const gchar *url1, const gchar *url2, gboolean protocol);
-#endif /* PURPLE_FACEBOOK_HTTP_H */
--- a/libpurple/protocols/facebook/id.h Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
- * 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
- * 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_FACEBOOK_ID_H
-#define PURPLE_FACEBOOK_ID_H
-#include <glib/gprintf.h>
- * The format specifier for printing and scanning an #FbId.
-#define FB_ID_FORMAT G_GINT64_FORMAT
- * The length modifier for printing an #FbId.
-#define FB_ID_MODIFIER G_GINT64_MODIFIER
- * The maximum length, including a null-terminating character, of the
- * string representation of an #FbId.
- * The #GType of an #FbId.
-#define FB_TYPE_ID G_TYPE_INT64
- * Inserts a literal #FbId into source code.
- * Return: The literal #FbId value.
-#define FB_ID_CONSTANT(v) G_GINT64_CONSTANT(v)
- * @s: The string value.
- * Converts a string to an #FbId.
- * Return: The converted #FbId value.
-#define FB_ID_FROM_STR(s) g_ascii_strtoll(s, NULL, 10)
- * @s: The string value.
- * Determines if a string is an #FbId.
- * Return: #TRUE if the string is an #FbId, otherwise #FALSE.
-#define FB_ID_IS_STR(s) fb_util_strtest(s, G_ASCII_DIGIT)
- * @s: The string buffer.
- * Converts an #FbId to a string. The buffer should be at least the
- * size of #FB_ID_STRMAX.
- * Return: The converted string value.
-#define FB_ID_TO_STR(i, s) g_sprintf(s, "%" FB_ID_FORMAT, (FbId) i)
- * Compares the values of two #FbId's for equality. See #g_int64_equal.
-#define fb_id_equal g_int64_equal
- * Converts a pointer to a #FbId hash value. See #g_int64_hash.
-#define fb_id_hash g_int64_hash
- * Represents a numeric Facebook identifier.
-#endif /* PURPLE_FACEBOOK_ID_H */
--- a/libpurple/protocols/facebook/json.c Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,658 +0,0 @@
- * 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
- * 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 <glib/gi18n-lib.h>
-typedef struct _FbJsonValue FbJsonValue;
- * Represents a JSON value handler.
-G_DEFINE_TYPE(FbJsonValues, fb_json_values, G_TYPE_OBJECT);
-fb_json_values_dispose(GObject *obj)
- FbJsonValues *values = FB_JSON_VALUES(obj);
- if(values->queue != NULL) {
- while(!g_queue_is_empty(values->queue)) {
- FbJsonValue *value = g_queue_pop_head(values->queue);
- if(G_IS_VALUE(&value->value)) {
- g_value_unset(&value->value);
- g_clear_pointer(&values->array, json_array_unref);
- g_clear_error(&values->error);
- g_clear_pointer(&values->queue, g_queue_free);
-fb_json_values_class_init(FbJsonValuesClass *klass)
- GObjectClass *gklass = G_OBJECT_CLASS(klass);
- gklass->dispose = fb_json_values_dispose;
-fb_json_values_init(FbJsonValues *values)
- values->queue = g_queue_new();
-fb_json_error_quark(void)
- if (G_UNLIKELY(q == 0)) {
- q = g_quark_from_static_string("fb-json-error-quark");
-fb_json_bldr_new(JsonNodeType type)
- bldr = json_builder_new();
- fb_json_bldr_arr_begin(bldr, NULL);
- fb_json_bldr_obj_begin(bldr, NULL);
-fb_json_bldr_close(JsonBuilder *bldr, JsonNodeType type, gsize *size)
- fb_json_bldr_arr_end(bldr);
- fb_json_bldr_obj_end(bldr);
- genr = json_generator_new();
- root = json_builder_get_root(bldr);
- json_generator_set_root(genr, root);
- ret = json_generator_to_data(genr, size);
-fb_json_bldr_arr_begin(JsonBuilder *bldr, const gchar *name)
- json_builder_set_member_name(bldr, name);
- json_builder_begin_array(bldr);
-fb_json_bldr_arr_end(JsonBuilder *bldr)
- json_builder_end_array(bldr);
-fb_json_bldr_obj_begin(JsonBuilder *bldr, const gchar *name)
- json_builder_set_member_name(bldr, name);
- json_builder_begin_object(bldr);
-fb_json_bldr_obj_end(JsonBuilder *bldr)
- json_builder_end_object(bldr);
-fb_json_bldr_add_bool(JsonBuilder *bldr, const gchar *name, gboolean value)
- json_builder_set_member_name(bldr, name);
- json_builder_add_boolean_value(bldr, value);
-fb_json_bldr_add_dbl(JsonBuilder *bldr, const gchar *name, gdouble value)
- json_builder_set_member_name(bldr, name);
- json_builder_add_double_value(bldr, value);
-fb_json_bldr_add_int(JsonBuilder *bldr, const gchar *name, gint64 value)
- json_builder_set_member_name(bldr, name);
- json_builder_add_int_value(bldr, value);
-fb_json_bldr_add_str(JsonBuilder *bldr, const gchar *name, const gchar *value)
- json_builder_set_member_name(bldr, name);
- json_builder_add_string_value(bldr, value);
-fb_json_bldr_add_strf(JsonBuilder *bldr, const gchar *name,
- const gchar *format, ...)
- value = g_strdup_vprintf(format, ap);
- fb_json_bldr_add_str(bldr, name, value);
-fb_json_node_new(const gchar *data, gssize size, GError **error)
- g_return_val_if_fail(data != NULL, NULL);
- /* Ensure data is null terminated for json-glib < 1.0.2 */
- slice = g_strndup(data, size);
- prsr = json_parser_new();
- if (!json_parser_load_from_data(prsr, slice, size, error)) {
- root = json_parser_get_root(prsr);
- root = json_node_copy(root);
-fb_json_node_get(JsonNode *root, const gchar *expr, GError **error)
- /* Special case for json-glib < 0.99.2 */
- if (purple_strequal(expr, "$")) {
- return json_node_copy(root);
- node = json_path_query(expr, root, &err);
- g_propagate_error(error, err);
- rslt = json_node_get_array(node);
- size = json_array_get_length(rslt);
- g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_NOMATCH,
- _("No matches for %s"), expr);
- g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_AMBIGUOUS,
- _("Ambiguous matches for %s"), expr);
- if (json_array_get_null_element(rslt, 0)) {
- g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_NULL,
- _("Null value for %s"), expr);
- ret = json_array_dup_element(rslt, 0);
-fb_json_node_get_nth(JsonNode *root, guint n)
- obj = json_node_get_object(root);
- vals = json_object_get_values(obj);
- ret = g_list_nth_data(vals, n);
-fb_json_node_get_arr(JsonNode *root, const gchar *expr, GError **error)
- rslt = fb_json_node_get(root, expr, error);
- ret = json_node_dup_array(rslt);
-fb_json_node_get_bool(JsonNode *root, const gchar *expr, GError **error)
- rslt = fb_json_node_get(root, expr, error);
- ret = json_node_get_boolean(rslt);
-fb_json_node_get_dbl(JsonNode *root, const gchar *expr, GError **error)
- rslt = fb_json_node_get(root, expr, error);
- ret = json_node_get_double(rslt);
-fb_json_node_get_int(JsonNode *root, const gchar *expr, GError **error)
- rslt = fb_json_node_get(root, expr, error);
- ret = json_node_get_int(rslt);
-fb_json_node_get_str(JsonNode *root, const gchar *expr, GError **error)
- rslt = fb_json_node_get(root, expr, error);
- ret = json_node_dup_string(rslt);
-fb_json_values_new(JsonNode *root)
- g_return_val_if_fail(root != NULL, NULL);
- values = g_object_new(FB_TYPE_JSON_VALUES, NULL);
-fb_json_values_add(FbJsonValues *values, FbJsonType type, gboolean required,
- g_return_if_fail(values != NULL);
- g_return_if_fail(expr != NULL);
- value = g_new0(FbJsonValue, 1);
- value->required = required;
- g_queue_push_tail(values->queue, value);
-fb_json_values_get_root(FbJsonValues *values)
- g_return_val_if_fail(values != NULL, NULL);
- if(values->array == NULL) {
- g_return_val_if_fail(values->index > 0, NULL);
- index = values->index - 1;
- if(json_array_get_length(values->array) <= index) {
- return json_array_get_element(values->array, index);
-fb_json_values_set_array(FbJsonValues *values, gboolean required,
- g_return_if_fail(values != NULL);
- values->array = fb_json_node_get_arr(values->root, expr, &values->error);
- values->isarray = TRUE;
- g_clear_error(&values->error);
-fb_json_values_update(FbJsonValues *values, GError **error)
- g_return_val_if_fail(values != NULL, FALSE);
- if(G_UNLIKELY(values->error != NULL)) {
- g_propagate_error(error, values->error);
- if(values->array == NULL ||
- json_array_get_length(values->array) <= values->index)
- root = json_array_get_element(values->array, values->index++);
- g_return_val_if_fail(root != NULL, FALSE);
- for(l = values->queue->head; l != NULL; l = l->next) {
- node = fb_json_node_get(root, value->expr, &err);
- if (G_IS_VALUE(&value->value)) {
- g_value_unset(&value->value);
- g_propagate_error(error, err);
- type = json_node_get_value_type(node);
- if (G_UNLIKELY(type != value->type)) {
- g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_TYPE,
- _("Expected a %s but got a %s for %s"),
- g_type_name(value->type),
- json_node_get_value(node, &value->value);
- values->next = values->queue->head;
-fb_json_values_next(FbJsonValues *values)
- g_return_val_if_fail(values != NULL, NULL);
- g_return_val_if_fail(values->next != NULL, NULL);
- value = values->next->data;
- values->next = values->next->next;
- if (!G_IS_VALUE(&value->value)) {
-fb_json_values_next_bool(FbJsonValues *values, gboolean defval)
- value = fb_json_values_next(values);
- if (G_UNLIKELY(value == NULL)) {
- return g_value_get_boolean(value);
-fb_json_values_next_dbl(FbJsonValues *values, gdouble defval)
- value = fb_json_values_next(values);
- if (G_UNLIKELY(value == NULL)) {
- return g_value_get_double(value);
-fb_json_values_next_int(FbJsonValues *values, gint64 defval)
- value = fb_json_values_next(values);
- if (G_UNLIKELY(value == NULL)) {
- return g_value_get_int64(value);
-fb_json_values_next_str(FbJsonValues *values, const gchar *defval)
- value = fb_json_values_next(values);
- if (G_UNLIKELY(value == NULL)) {
- return g_value_get_string(value);
-fb_json_values_next_str_dup(FbJsonValues *values, const gchar *defval)
- value = fb_json_values_next(values);
- if (G_UNLIKELY(value == NULL)) {
- return g_strdup(defval);
- return g_value_dup_string(value);
--- a/libpurple/protocols/facebook/json.h Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,471 +0,0 @@
- * 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
- * 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_FACEBOOK_JSON_H
-#define PURPLE_FACEBOOK_JSON_H
-#include <json-glib/json-glib.h>
-#define FB_TYPE_JSON_VALUES fb_json_values_get_type()
- * The #GQuark of the domain of JSON errors.
-#define FB_JSON_ERROR fb_json_error_quark()
- * @FB_JSON_ERROR_SUCCESS: There is no error.
- * @FB_JSON_ERROR_AMBIGUOUS: The node has ambiguous matches.
- * @FB_JSON_ERROR_GENERAL: General failure.
- * @FB_JSON_ERROR_NOMATCH: The node does not match anything.
- * @FB_JSON_ERROR_NULL: The node is of type NULL.
- * @FB_JSON_ERROR_TYPE: The node has an unexpected type.
- * The error codes for the #FB_JSON_ERROR domain.
- FB_JSON_ERROR_SUCCESS = 0,
- FB_JSON_ERROR_AMBIGUOUS,
- * @FB_JSON_TYPE_NULL: An unknown value.
- * @FB_JSON_TYPE_BOOL: A boolean (#TRUE or #FALSE).
- * @FB_JSON_TYPE_DBL: A floating point number.
- * @FB_JSON_TYPE_INT: A signed integer.
- * @FB_JSON_TYPE_STR: A string.
- FB_JSON_TYPE_BOOL = G_TYPE_BOOLEAN,
- FB_JSON_TYPE_DBL = G_TYPE_DOUBLE,
- FB_JSON_TYPE_INT = G_TYPE_INT64,
- FB_JSON_TYPE_STR = G_TYPE_STRING
-G_DECLARE_FINAL_TYPE(FbJsonValues, fb_json_values, FB, JSON_VALUES,
- * Gets the #GQuark of the domain of JSON errors.
- * Returns: The #GQuark of the domain.
-fb_json_error_quark(void);
- * @type: The starting #JsonNodeType.
- * Creates a new #JsonBuilder. The starting #JsonNodeType is likely to
- * be #JSON_NODE_OBJECT. The returned #JsonBuilder should be freed with
- * #g_object_unref() when no longer needed. Optionally, instead of
- * freeing, the returned #JsonBuilder can be closed with
- * #fb_json_bldr_close().
- * Returns: (transfer full): The new #JsonBuilder.
-fb_json_bldr_new(JsonNodeType type);
- * @bldr: The #JsonBuilder.
- * @type: The ending #JsonNodeType.
- * @size: The return local for the size of the returned string.
- * Closes the #JsonBuilder by returning a string representing the
- * #JsonBuilder. The ending #JsonNodeType is likely to be
- * #JSON_NODE_OBJECT. This calls #g_object_unref(). The returned
- * string should be freed with #g_free() when no longer needed.
- * Returns: The string representation of the #JsonBuilder.
-fb_json_bldr_close(JsonBuilder *bldr, JsonNodeType type, gsize *size);
- * fb_json_bldr_arr_begin:
- * @bldr: The #JsonBuilder.
- * @name: The member name or #NULL.
- * Begins an array member in the #JsonBuilder.
-fb_json_bldr_arr_begin(JsonBuilder *bldr, const gchar *name);
- * fb_json_bldr_arr_end:
- * @bldr: The #JsonBuilder.
- * Ends an array member in the #JsonBuilder.
-fb_json_bldr_arr_end(JsonBuilder *bldr);
- * fb_json_bldr_obj_begin:
- * @bldr: The #JsonBuilder.
- * @name: The member name or #NULL.
- * Begins an object member in the #JsonBuilder.
-fb_json_bldr_obj_begin(JsonBuilder *bldr, const gchar *name);
- * fb_json_bldr_obj_end:
- * @bldr: The #JsonBuilder.
- * Ends an array member in the #JsonBuilder.
-fb_json_bldr_obj_end(JsonBuilder *bldr);
- * fb_json_bldr_add_bool:
- * @bldr: The #JsonBuilder.
- * @name: The member name or #NULL.
- * Adds a boolean member to the #JsonBuilder.
-fb_json_bldr_add_bool(JsonBuilder *bldr, const gchar *name, gboolean value);
- * fb_json_bldr_add_dbl:
- * @bldr: The #JsonBuilder.
- * @name: The member name or #NULL.
- * Adds a floating point member to the #JsonBuilder.
-fb_json_bldr_add_dbl(JsonBuilder *bldr, const gchar *name, gdouble value);
- * fb_json_bldr_add_int:
- * @bldr: The #JsonBuilder.
- * @name: The member name or #NULL.
- * Adds an integer member to the #JsonBuilder.
-fb_json_bldr_add_int(JsonBuilder *bldr, const gchar *name, gint64 value);
- * fb_json_bldr_add_str:
- * @bldr: The #JsonBuilder.
- * @name: The member name or #NULL.
- * Adds a string member to the #JsonBuilder.
-fb_json_bldr_add_str(JsonBuilder *bldr, const gchar *name, const gchar *value);
- * fb_json_bldr_add_strf:
- * @bldr: The #JsonBuilder.
- * @name: The member name or #NULL.
- * @format: The format string literal.
- * @...: The arguments for @format.
- * Adds a formatted string member to the #JsonBuilder.
-fb_json_bldr_add_strf(JsonBuilder *bldr, const gchar *name,
- const gchar *format, ...)
- * @data: The string JSON.
- * @size: The size of @json or -1 if null-terminated.
- * @error: The return location for the #GError or #NULL.
- * Creates a new #JsonNode. The returned #JsonBuilder should be freed
- * wuth #json_node_free() when no longer needed.
- * Returns: The new #JsonNode.
-fb_json_node_new(const gchar *data, gssize size, GError **error);
- * @root: The root #JsonNode.
- * @expr: The #JsonPath expression.
- * @error: The return location for the #GError or #NULL.
- * Gets a new #JsonNode value from a parent #JsonNode with a #JsonPath
- * expression. The returned #JsonNode should be freed with
- * #json_node_free() when no longer needed.
- * Returns: The new #JsonNode.
-fb_json_node_get(JsonNode *root, const gchar *expr, GError **error);
- * fb_json_node_get_nth:
- * @root: The root #JsonNode.
- * @n: The index number.
- * Gets a #JsonNode value from a parent #JsonNode by index. The
- * returned #JsonNode should not be freed.
- * Return: The #JsonNode.
-fb_json_node_get_nth(JsonNode *root, guint n);
- * fb_json_node_get_arr:
- * @root: The root #JsonNode.
- * @expr: The #JsonPath expression.
- * @error: The return location for the #GError or #NULL.
- * Gets a new #JsonArray value from a parent #JsonNode with a #JsonPath
- * expression. The returned #JsonArray should be freed with
- * #json_array_unref() when no longer needed.
- * Returns: The new #JsonArray.
-fb_json_node_get_arr(JsonNode *root, const gchar *expr, GError **error);
- * fb_json_node_get_bool:
- * @root: The root #JsonNode.
- * @expr: The #JsonPath expression.
- * @error: The return location for the #GError or #NULL.
- * Gets a boolean value from a parent #JsonNode with a #JsonPath
- * Returns: The boolean value.
-fb_json_node_get_bool(JsonNode *root, const gchar *expr, GError **error);
- * fb_json_node_get_dbl:
- * @root: The root #JsonNode.
- * @expr: The #JsonPath expression.
- * @error: The return location for the #GError or #NULL.
- * Gets a floating point value from a parent #JsonNode with a #JsonPath
- * Returns: The floating point value.
-fb_json_node_get_dbl(JsonNode *root, const gchar *expr, GError **error);
- * fb_json_node_get_int:
- * @root: The root #JsonNode.
- * @expr: The #JsonPath expression.
- * @error: The return location for the #GError or #NULL.
- * Gets an integer value from a parent #JsonNode with a #JsonPath
- * Returns: The integer value.
-fb_json_node_get_int(JsonNode *root, const gchar *expr, GError **error);
- * fb_json_node_get_str:
- * @root: The root #JsonNode.
- * @expr: The #JsonPath expression.
- * @error: The return location for the #GError or #NULL.
- * Gets an string value from a parent #JsonNode with a #JsonPath
- * expression. The returned string should be freed with #g_free()
- * when no longer needed.
- * Returns: The string value.
-fb_json_node_get_str(JsonNode *root, const gchar *expr, GError **error);
- * @root: The root #JsonNode.
- * Creates a new #FbJsonValues. The returned #FbJsonValues should be
- * freed with #g_object_unref when no longer needed.
- * Returns: The new #FbJsonValues.
-fb_json_values_new(JsonNode *root);
- * @values: The #FbJsonValues.
- * @type: The #FbJsonType.
- * @required: #TRUE if the node is required, otherwise #FALSE.
- * @expr: The #JsonPath expression.
- * Adds a new #FbJsonValue to the #FbJsonValues.
-fb_json_values_add(FbJsonValues *values, FbJsonType type, gboolean required,
- * fb_json_values_get_root:
- * @values: The #FbJsonValues.
- * Gets the current working root #JsonNode. This is either the current
- * array #JsonNode or the root #JsonNode. The returned #JsonNode should
-fb_json_values_get_root(FbJsonValues *values);
- * fb_json_values_set_array:
- * @values: The #FbJsonValues.
- * @required: #TRUE if the node is required, otherwise #FALSE.
- * @expr: The #JsonPath expression.
- * Sets the #JsonPath for an array to base all #FbJsonValue's off.
-fb_json_values_set_array(FbJsonValues *values, gboolean required,
- * fb_json_values_update:
- * @values: The #FbJsonValues.
- * @error: The return location for the #GError or #NULL.
- * Updates the current working root. This should be called after all of
- * the #FbJsonValue's have been added with #fb_json_values_add(). If an
- * array was set with #fb_json_values_set_array(), then this should be
- * called in a while loop, until #FALSE is returned.
- * Returns: #TRUE if the values were updated, otherwise #FALSE.
-fb_json_values_update(FbJsonValues *values, GError **error);
- * @values: The #FbJsonValues.
- * Gets the next #GValue from the #FbJsonValues. Before calling this
- * function, #fb_json_values_update() must be called.
- * Returns: The #GValue.
-fb_json_values_next(FbJsonValues *values);
- * fb_json_values_next_bool:
- * @values: The #FbJsonValues.
- * @defval: The default value.
- * Gets the next boolean value from the #FbJsonValues. Before calling
- * this function, #fb_json_values_update() must be called.
- * Returns: The boolean value.
-fb_json_values_next_bool(FbJsonValues *values, gboolean defval);
- * fb_json_values_next_dbl:
- * @values: The #FbJsonValues.
- * @defval: The default value.
- * Gets the next floating point value from the #FbJsonValues. Before
- * calling this function, #fb_json_values_update() must be called.
- * Returns: The floating point value.
-fb_json_values_next_dbl(FbJsonValues *values, gdouble defval);
- * fb_json_values_next_int:
- * @values: The #FbJsonValues.
- * @defval: The default value.
- * Gets the next integer value from the #FbJsonValues. Before calling
- * this function, #fb_json_values_update() must be called.
- * Returns: The integer value.
-fb_json_values_next_int(FbJsonValues *values, gint64 defval);
- * fb_json_values_next_str:
- * @values: The #FbJsonValues.
- * @defval: The default value.
- * Gets the next string value from the #FbJsonValues. Before calling
- * this function, #fb_json_values_update() must be called.
- * Returns: The string value.
-fb_json_values_next_str(FbJsonValues *values, const gchar *defval);
- * fb_json_values_next_str_dup:
- * @values: The #FbJsonValues.
- * @defval: The default value.
- * Gets the next duplicate string value from the #FbJsonValues. Before
- * calling this function, #fb_json_values_update() must be called.
- * Returns: The duplicate string value.
-fb_json_values_next_str_dup(FbJsonValues *values, const gchar *defval);
-#endif /* PURPLE_FACEBOOK_JSON_H */
--- a/libpurple/protocols/facebook/meson.build Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-FACEBOOK_BUILT_SOURCES = []
- facebook_resources = gnome.compile_resources('facebookresource',
- 'resources/facebook.gresource.xml',
- source_dir : 'resources',
- FACEBOOK_BUILT_SOURCES += facebook_resources
- facebook_prpl = shared_library('facebook',
- FACEBOOK_SOURCES + FACEBOOK_BUILT_SOURCES,
- c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="Purple-Facebook"'],
- dependencies : [json, libpurple_dep, libsoup, glib],
- install_dir : PURPLE_PLUGINDIR)
- # Used to produce docs.
- facebook_inc = include_directories('.')
- facebook_dep = declare_dependency(
- link_with : facebook_prpl,
- dependencies : [json, libpurple_dep, glib])
- devenv.append('PURPLE_PLUGIN_PATH', meson.current_build_dir())
- if enable_introspection
- introspection_sources = FACEBOOK_SOURCES
- facebook_gir_includes = ['GObject-2.0', 'Gio-2.0', 'Gst-1.0',
- 'Json-1.0', 'Soup-3.0', libpurple_gir[0]]
- facebook_gir = gnome.generate_gir(facebook_prpl,
- sources : introspection_sources,
- includes : facebook_gir_includes,
- namespace : 'Facebook',
- identifier_prefix : 'Fb',
- nsversion : f'@purple_major_version@.@purple_minor_version@',
- dependencies: [gplugin_dep, libpurple_dep],
- extra_args : ['-DPURPLE_COMPILATION', '--quiet'])
--- a/libpurple/protocols/facebook/mqtt.c Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1016 +0,0 @@
- * 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
- * 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 <glib/gi18n-lib.h>
-#include <glib/gprintf.h>
- * Represents an MQTT connection.
- GBufferedInputStream *input;
- PurpleQueuedOutputStream *output;
- GCancellable *cancellable;
-G_DEFINE_TYPE(FbMqtt, fb_mqtt, G_TYPE_OBJECT);
- * Represents a reader/writer for an MQTT message.
- FbMqttMessageType type;
- FbMqttMessageFlags flags;
-G_DEFINE_TYPE(FbMqttMessage, fb_mqtt_message, G_TYPE_OBJECT);
-static void fb_mqtt_read_packet(FbMqtt *mqtt);
-fb_mqtt_dispose(GObject *obj)
- FbMqtt *mqtt = FB_MQTT(obj);
- g_byte_array_free(mqtt->rbuf, TRUE);
-fb_mqtt_class_init(FbMqttClass *klass)
- GObjectClass *gklass = G_OBJECT_CLASS(klass);
- gklass->dispose = fb_mqtt_dispose;
- * Emitted upon the successful completion of the connection
- * process. This is emitted as a result of #fb_mqtt_connect().
- g_signal_new("connect",
- G_TYPE_FROM_CLASS(klass),
- * Emitted whenever an error is hit within the #FbMqtt. This
- * should close the #FbMqtt with #fb_mqtt_close().
- G_TYPE_FROM_CLASS(klass),
- * Emitted upon the successful opening of the remote socket.
- * This is emitted as a result of #fb_mqtt_open(). This should
- * call #fb_mqtt_connect().
- G_TYPE_FROM_CLASS(klass),
- * Emitted upon an incoming message from the steam.
- g_signal_new("publish",
- G_TYPE_FROM_CLASS(klass),
- 2, G_TYPE_STRING, G_TYPE_BYTE_ARRAY);
-fb_mqtt_init(FbMqtt *mqtt)
- mqtt->rbuf = g_byte_array_new();
-fb_mqtt_message_dispose(GObject *obj)
- FbMqttMessage *msg = FB_MQTT_MESSAGE(obj);
- if(msg->bytes != NULL && msg->local) {
- g_byte_array_free(msg->bytes, TRUE);
-fb_mqtt_message_class_init(FbMqttMessageClass *klass)
- GObjectClass *gklass = G_OBJECT_CLASS(klass);
- gklass->dispose = fb_mqtt_message_dispose;
-fb_mqtt_message_init(G_GNUC_UNUSED FbMqttMessage *msg)
-fb_mqtt_error_quark(void)
- if (G_UNLIKELY(q == 0)) {
- q = g_quark_from_static_string("fb-mqtt-error-quark");
-fb_mqtt_new(PurpleConnection *gc)
- g_return_val_if_fail(PURPLE_IS_CONNECTION(gc), NULL);
- mqtt = g_object_new(FB_TYPE_MQTT, NULL);
-fb_mqtt_close(FbMqtt *mqtt)
- g_return_if_fail(FB_IS_MQTT(mqtt));
- g_clear_handle_id(&mqtt->tev, g_source_remove);
- if(mqtt->cancellable != NULL) {
- g_cancellable_cancel(mqtt->cancellable);
- g_clear_object(&mqtt->cancellable);
- if(mqtt->conn != NULL) {
- purple_gio_graceful_close(mqtt->conn,
- G_INPUT_STREAM(mqtt->input),
- G_OUTPUT_STREAM(mqtt->output));
- g_clear_object(&mqtt->input);
- g_clear_object(&mqtt->output);
- g_clear_object(&mqtt->conn);
- mqtt->connected = FALSE;
- g_byte_array_set_size(mqtt->rbuf, 0);
-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 */
- /* Now we can check for programming errors */
- g_return_if_fail(FB_IS_MQTT(mqtt));
- g_prefix_error(&err, "%s: ", prefix);
- g_signal_emit_by_name(mqtt, "error", err);
-fb_mqtt_error_literal(FbMqtt *mqtt, FbMqttError error, const gchar *msg)
- g_return_if_fail(FB_IS_MQTT(mqtt));
- err = g_error_new_literal(FB_MQTT_ERROR, error, msg);
- g_signal_emit_by_name(mqtt, "error", err);
-fb_mqtt_error(FbMqtt *mqtt, FbMqttError error, const gchar *format, ...)
- g_return_if_fail(FB_IS_MQTT(mqtt));
- err = g_error_new_valist(FB_MQTT_ERROR, error, format, ap);
- g_signal_emit_by_name(mqtt, "error", err);
-fb_mqtt_cb_timeout(gpointer data)
- fb_mqtt_error_literal(mqtt, FB_MQTT_ERROR_GENERAL,
- _("Connection timed out"));
-fb_mqtt_timeout_clear(FbMqtt *mqtt)
- g_clear_handle_id(&mqtt->tev, g_source_remove);
-fb_mqtt_timeout(FbMqtt *mqtt)
- fb_mqtt_timeout_clear(mqtt);
- mqtt->tev = g_timeout_add_seconds(FB_MQTT_TIMEOUT_CONN, fb_mqtt_cb_timeout,
-fb_mqtt_cb_ping(gpointer data)
- msg = fb_mqtt_message_new(FB_MQTT_MESSAGE_TYPE_PINGREQ, 0);
- fb_mqtt_write(mqtt, msg);
-fb_mqtt_ping(FbMqtt *mqtt)
- fb_mqtt_timeout_clear(mqtt);
- mqtt->tev = g_timeout_add_seconds(FB_MQTT_TIMEOUT_PING, fb_mqtt_cb_ping,
-fb_mqtt_cb_fill(GObject *source, GAsyncResult *res, gpointer data)
- GBufferedInputStream *input = G_BUFFERED_INPUT_STREAM(source);
- ret = g_buffered_input_stream_fill_finish(input, res, &err);
- err = g_error_new_literal(G_IO_ERROR,
- G_IO_ERROR_CONNECTION_CLOSED,
- _("Connection closed"));
- fb_mqtt_take_error(mqtt, err, _("Failed to read fixed header"));
- fb_mqtt_read_packet(mqtt);
-fb_mqtt_cb_read_packet(GObject *source, GAsyncResult *res, gpointer data)
- ret = g_input_stream_read_finish(G_INPUT_STREAM(source), res, &err);
- err = g_error_new_literal(G_IO_ERROR,
- G_IO_ERROR_CONNECTION_CLOSED,
- _("Connection closed"));
- fb_mqtt_take_error(mqtt, err, _("Failed to read packet data"));
- g_input_stream_read_async(G_INPUT_STREAM(source),
- mqtt->rbuf->data + mqtt->rbuf->len - mqtt->remz,
- mqtt->remz, G_PRIORITY_DEFAULT,
- mqtt->cancellable, fb_mqtt_cb_read_packet,
- msg = fb_mqtt_message_new_bytes(mqtt->rbuf);
- if (G_UNLIKELY(msg == NULL)) {
- fb_mqtt_error_literal(mqtt, FB_MQTT_ERROR_GENERAL,
- _("Failed to parse message"));
- fb_mqtt_read(mqtt, msg);
- /* Read another packet if connection wasn't reset in fb_mqtt_read() */
- if (fb_mqtt_connected(mqtt, FALSE)) {
- fb_mqtt_read_packet(mqtt);
-fb_mqtt_read_packet(FbMqtt *mqtt)
- buf = g_buffered_input_stream_peek_buffer(mqtt->input, &count);
- /* Start at 1 to skip the first byte */
- /* Not enough data yet, try again later */
- g_buffered_input_stream_fill_async(mqtt->input, -1,
- fb_mqtt_cb_fill, mqtt);
- size += (byte & 127) * mult;
- } while ((byte & 128) != 0);
- /* Add header to size */
- g_byte_array_set_size(mqtt->rbuf, 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(mqtt->input), mqtt->rbuf->data,
- mqtt->rbuf->len, G_PRIORITY_DEFAULT,
- mqtt->cancellable, fb_mqtt_cb_read_packet, mqtt);
-fb_mqtt_read(FbMqtt *mqtt, FbMqttMessage *msg)
- g_return_if_fail(FB_IS_MQTT(mqtt));
- fb_util_debug_hexdump(FB_UTIL_DEBUG_INFO, msg->bytes,
- "Reading %d (flags: 0x%0X)",
- msg->type, msg->flags);
- case FB_MQTT_MESSAGE_TYPE_CONNACK:
- if (!fb_mqtt_message_read_byte(msg, NULL) ||
- !fb_mqtt_message_read_byte(msg, &chr))
- if (chr != FB_MQTT_ERROR_SUCCESS) {
- fb_mqtt_error(mqtt, chr, _("Connection failed (%u)"),
- mqtt->connected = TRUE;
- g_signal_emit_by_name(mqtt, "connect");
- case FB_MQTT_MESSAGE_TYPE_PUBLISH:
- if (!fb_mqtt_message_read_str(msg, &str)) {
- if((msg->flags & FB_MQTT_MESSAGE_FLAG_QOS1) ||
- (msg->flags & FB_MQTT_MESSAGE_FLAG_QOS2))
- if(msg->flags & FB_MQTT_MESSAGE_FLAG_QOS1) {
- chr = FB_MQTT_MESSAGE_TYPE_PUBACK;
- chr = FB_MQTT_MESSAGE_TYPE_PUBREC;
- if (!fb_mqtt_message_read_mid(msg, &mid)) {
- nsg = fb_mqtt_message_new(chr, 0);
- fb_mqtt_message_write_u16(nsg, mid);
- fb_mqtt_write(mqtt, nsg);
- wytes = g_byte_array_new();
- fb_mqtt_message_read_r(msg, wytes);
- g_signal_emit_by_name(mqtt, "publish", str, wytes);
- g_byte_array_free(wytes, TRUE);
- case FB_MQTT_MESSAGE_TYPE_PUBREL:
- if (!fb_mqtt_message_read_mid(msg, &mid)) {
- nsg = fb_mqtt_message_new(FB_MQTT_MESSAGE_TYPE_PUBCOMP, 0);
- fb_mqtt_message_write_u16(nsg, mid); /* Message identifier */
- fb_mqtt_write(mqtt, nsg);
- case FB_MQTT_MESSAGE_TYPE_PINGRESP:
- case FB_MQTT_MESSAGE_TYPE_PUBACK:
- case FB_MQTT_MESSAGE_TYPE_PUBCOMP:
- case FB_MQTT_MESSAGE_TYPE_SUBACK:
- case FB_MQTT_MESSAGE_TYPE_UNSUBACK:
- fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL,
- _("Unknown packet (%u)"), msg->type);
- /* Since no case returned, there was a parse error. */
- fb_mqtt_error_literal(mqtt, FB_MQTT_ERROR_GENERAL,
- _("Failed to parse message"));
-fb_mqtt_cb_push_bytes(GObject *source, GAsyncResult *res, gpointer data)
- PurpleQueuedOutputStream *stream = PURPLE_QUEUED_OUTPUT_STREAM(source);
- if (!purple_queued_output_stream_push_bytes_finish(stream,
- purple_queued_output_stream_clear_queue(stream);
- fb_mqtt_take_error(mqtt, err, _("Failed to write data"));
-fb_mqtt_write(FbMqtt *mqtt, FbMqttMessage *msg)
- const GByteArray *bytes;
- g_return_if_fail(FB_IS_MQTT(mqtt));
- g_return_if_fail(FB_IS_MQTT_MESSAGE(msg));
- bytes = fb_mqtt_message_bytes(msg);
- if (G_UNLIKELY(bytes == NULL)) {
- fb_mqtt_error_literal(mqtt, FB_MQTT_ERROR_GENERAL,
- _("Failed to format data"));
- fb_util_debug_hexdump(FB_UTIL_DEBUG_INFO, msg->bytes,
- "Writing %d (flags: 0x%0X)",
- msg->type, msg->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_async(mqtt->output, gbytes,
- fb_mqtt_cb_push_bytes, mqtt);
-fb_mqtt_cb_open(GObject *source, GAsyncResult *res, gpointer data)
- GSocketConnection *conn;
- conn = g_socket_client_connect_to_host_finish(G_SOCKET_CLIENT(source),
- fb_mqtt_take_error(mqtt, err, NULL);
- fb_mqtt_timeout_clear(mqtt);
- mqtt->conn = G_IO_STREAM(conn);
- mqtt->input = G_BUFFERED_INPUT_STREAM(g_buffered_input_stream_new(
- g_io_stream_get_input_stream(mqtt->conn)));
- mqtt->output = purple_queued_output_stream_new(
- g_io_stream_get_output_stream(mqtt->conn));
- fb_mqtt_read_packet(mqtt);
- g_signal_emit_by_name(mqtt, "open");
-fb_mqtt_open(FbMqtt *mqtt, const gchar *host, gint port)
- g_return_if_fail(FB_IS_MQTT(mqtt));
- acc = purple_connection_get_account(mqtt->gc);
- client = purple_gio_socket_client_new(acc, &err);
- fb_mqtt_take_error(mqtt, err, NULL);
- mqtt->cancellable = g_cancellable_new();
- g_socket_client_set_tls(client, TRUE);
- g_socket_client_connect_to_host_async(client, host, port,
- mqtt->cancellable, fb_mqtt_cb_open,
- g_object_unref(client);
-fb_mqtt_connect(FbMqtt *mqtt, guint8 flags, const GByteArray *pload)
- g_return_if_fail(!fb_mqtt_connected(mqtt, FALSE));
- g_return_if_fail(pload != NULL);
- /* Facebook always sends a CONNACK, use QoS1 */
- flags |= FB_MQTT_CONNECT_FLAG_QOS1;
- msg = fb_mqtt_message_new(FB_MQTT_MESSAGE_TYPE_CONNECT, 0);
- fb_mqtt_message_write_str(msg, FB_MQTT_NAME); /* Protocol name */
- fb_mqtt_message_write_byte(msg, FB_MQTT_LEVEL); /* Protocol level */
- fb_mqtt_message_write_byte(msg, flags); /* Flags */
- fb_mqtt_message_write_u16(msg, FB_MQTT_KA); /* Keep alive */
- fb_mqtt_message_write(msg, pload->data, pload->len);
- fb_mqtt_write(mqtt, msg);
-fb_mqtt_connected(FbMqtt *mqtt, gboolean error)
- g_return_val_if_fail(FB_IS_MQTT(mqtt), FALSE);
- connected = (mqtt->conn != NULL) && mqtt->connected;
- if (!connected && error) {
- fb_mqtt_error_literal(mqtt, FB_MQTT_ERROR_GENERAL, _("Not connected"));
-fb_mqtt_disconnect(FbMqtt *mqtt)
- if (G_UNLIKELY(!fb_mqtt_connected(mqtt, FALSE))) {
- msg = fb_mqtt_message_new(FB_MQTT_MESSAGE_TYPE_DISCONNECT, 0);
- fb_mqtt_write(mqtt, msg);
-fb_mqtt_publish(FbMqtt *mqtt, const gchar *topic, const GByteArray *pload)
- g_return_if_fail(FB_IS_MQTT(mqtt));
- g_return_if_fail(fb_mqtt_connected(mqtt, FALSE));
- /* Message identifier not required, but for consistency use QoS1 */
- msg = fb_mqtt_message_new(FB_MQTT_MESSAGE_TYPE_PUBLISH,
- FB_MQTT_MESSAGE_FLAG_QOS1);
- fb_mqtt_message_write_str(msg, topic); /* Message topic */
- fb_mqtt_message_write_mid(msg, &mqtt->mid); /* Message identifier */
- fb_mqtt_message_write(msg, pload->data, pload->len);
- fb_mqtt_write(mqtt, msg);
-fb_mqtt_subscribe(FbMqtt *mqtt, ...)
- g_return_if_fail(FB_IS_MQTT(mqtt));
- g_return_if_fail(fb_mqtt_connected(mqtt, FALSE));
- /* Facebook requires a message identifier, use QoS1 */
- msg = fb_mqtt_message_new(FB_MQTT_MESSAGE_TYPE_SUBSCRIBE,
- FB_MQTT_MESSAGE_FLAG_QOS1);
- fb_mqtt_message_write_mid(msg, &mqtt->mid); /* Message identifier */
- while ((topic = va_arg(ap, const gchar*)) != NULL) {
- qos = va_arg(ap, guint);
- fb_mqtt_message_write_str(msg, topic);
- fb_mqtt_message_write_byte(msg, qos);
- fb_mqtt_write(mqtt, msg);
-fb_mqtt_unsubscribe(FbMqtt *mqtt, const gchar *topic1, ...)
- g_return_if_fail(FB_IS_MQTT(mqtt));
- g_return_if_fail(fb_mqtt_connected(mqtt, FALSE));
- /* Facebook requires a message identifier, use QoS1 */
- msg = fb_mqtt_message_new(FB_MQTT_MESSAGE_TYPE_UNSUBSCRIBE,
- FB_MQTT_MESSAGE_FLAG_QOS1);
- fb_mqtt_message_write_mid(msg, &mqtt->mid); /* Message identifier */
- fb_mqtt_message_write_str(msg, topic1); /* First topic */
- while ((topic = va_arg(ap, const gchar*)) != NULL) {
- fb_mqtt_message_write_str(msg, topic); /* Remaining topics */
- fb_mqtt_write(mqtt, msg);
-fb_mqtt_message_new(FbMqttMessageType type, FbMqttMessageFlags flags)
- msg = g_object_new(FB_TYPE_MQTT_MESSAGE, NULL);
- msg->bytes = g_byte_array_new();
-fb_mqtt_message_new_bytes(GByteArray *bytes)
- g_return_val_if_fail(bytes != NULL, NULL);
- g_return_val_if_fail(bytes->len >= 2, NULL);
- msg = g_object_new(FB_TYPE_MQTT_MESSAGE, NULL);
- msg->type = (*bytes->data & 0xF0) >> 4;
- msg->flags = *bytes->data & 0x0F;
- /* Skip the fixed header */
- byte = msg->bytes->data + 1;
- while((*byte & 128) != 0) {
- msg->offset = byte - bytes->data;
- msg->pos = msg->offset;
-fb_mqtt_message_reset(FbMqttMessage *msg)
- g_return_if_fail(FB_IS_MQTT_MESSAGE(msg));
- g_byte_array_remove_range(msg->bytes, 0, msg->offset);
-fb_mqtt_message_bytes(FbMqttMessage *msg)
- g_return_val_if_fail(FB_IS_MQTT_MESSAGE(msg), NULL);
- size = msg->bytes->len - msg->offset;
- if (G_UNLIKELY(i >= G_N_ELEMENTS(sbuf))) {
- fb_mqtt_message_reset(msg);
- g_byte_array_prepend(msg->bytes, sbuf, i);
- byte = ((msg->type & 0x0F) << 4) | (msg->flags & 0x0F);
- g_byte_array_prepend(msg->bytes, &byte, sizeof byte);
- msg->pos = (i + 1) * (sizeof byte);
-fb_mqtt_message_read(FbMqttMessage *msg, gpointer data, guint size)
- g_return_val_if_fail(FB_IS_MQTT_MESSAGE(msg), FALSE);
- if((msg->pos + size) > msg->bytes->len) {
- if ((data != NULL) && (size > 0)) {
- memcpy(data, msg->bytes->data + msg->pos, size);
-fb_mqtt_message_read_r(FbMqttMessage *msg, GByteArray *bytes)
- g_return_val_if_fail(FB_IS_MQTT_MESSAGE(msg), FALSE);
- size = msg->bytes->len - msg->pos;
- if (G_LIKELY(size > 0)) {
- g_byte_array_append(bytes, msg->bytes->data + msg->pos, size);
-fb_mqtt_message_read_byte(FbMqttMessage *msg, guint8 *value)
- return fb_mqtt_message_read(msg, value, sizeof *value);
-fb_mqtt_message_read_mid(FbMqttMessage *msg, guint16 *value)
- return fb_mqtt_message_read_u16(msg, value);
-fb_mqtt_message_read_u16(FbMqttMessage *msg, guint16 *value)
- if (!fb_mqtt_message_read(msg, value, sizeof *value)) {
- *value = g_ntohs(*value);
-fb_mqtt_message_read_str(FbMqttMessage *msg, gchar **value)
- if (!fb_mqtt_message_read_u16(msg, &size)) {
- data = g_new(guint8, size + 1);
- if (!fb_mqtt_message_read(msg, data, size)) {
- *value = (gchar *) data;
-fb_mqtt_message_write(FbMqttMessage *msg, gconstpointer data, guint size)
- g_return_if_fail(FB_IS_MQTT_MESSAGE(msg));
- g_byte_array_append(msg->bytes, data, size);
-fb_mqtt_message_write_byte(FbMqttMessage *msg, guint8 value)
- fb_mqtt_message_write(msg, &value, sizeof value);
-fb_mqtt_message_write_mid(FbMqttMessage *msg, guint16 *value)
- g_return_if_fail(value != NULL);
- fb_mqtt_message_write_u16(msg, ++(*value));
-fb_mqtt_message_write_u16(FbMqttMessage *msg, guint16 value)
- value = g_htons(value);
- fb_mqtt_message_write(msg, &value, sizeof value);
-fb_mqtt_message_write_str(FbMqttMessage *msg, const gchar *value)
- g_return_if_fail(value != NULL);
- fb_mqtt_message_write_u16(msg, size);
- fb_mqtt_message_write(msg, value, size);
--- a/libpurple/protocols/facebook/mqtt.h Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,520 +0,0 @@
- * 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
- * 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_FACEBOOK_MQTT_H
-#define PURPLE_FACEBOOK_MQTT_H
-#define FB_TYPE_MQTT fb_mqtt_get_type()
-#define FB_TYPE_MQTT_MESSAGE fb_mqtt_message_get_type()
- * The name of the MQTT version.
-#define FB_MQTT_NAME "MQTToT"
- * The level of the MQTT version.
- * The keep-alive timeout, in seconds, of the MQTT connection.
- * The MQTT host name for Facebook.
-#define FB_MQTT_HOST "mqtt.facebook.com"
- * The MQTT host port for Facebook.
-#define FB_MQTT_PORT 443
- * FB_MQTT_TIMEOUT_CONN:
- * The timeout, in seconds, to wait for a PING back from the server.
-#define FB_MQTT_TIMEOUT_CONN ((guint)(FB_MQTT_KA * 1.5))
- * FB_MQTT_TIMEOUT_PING:
- * The timeout, in seconds, to send a PING to the server.
-#define FB_MQTT_TIMEOUT_PING (FB_MQTT_KA)
- * The #GQuark of the domain of MQTT errors.
-#define FB_MQTT_ERROR fb_mqtt_error_quark()
- * @FB_MQTT_CONNECT_FLAG_CLR: Clear the session.
- * @FB_MQTT_CONNECT_FLAG_WILL: A will message is in the payload.
- * @FB_MQTT_CONNECT_FLAG_RET: Retain the will message.
- * @FB_MQTT_CONNECT_FLAG_PASS: A password is in the payload.
- * @FB_MQTT_CONNECT_FLAG_USER: A user name is in the payload.
- * @FB_MQTT_CONNECT_FLAG_QOS0: Use no quality of service.
- * @FB_MQTT_CONNECT_FLAG_QOS1: Use level one quality of service.
- * @FB_MQTT_CONNECT_FLAG_QOS2: Use level two quality of service.
- * The #FbMqttMessage flags for the CONNECT message.
- FB_MQTT_CONNECT_FLAG_CLR = 1 << 1,
- FB_MQTT_CONNECT_FLAG_WILL = 1 << 2,
- FB_MQTT_CONNECT_FLAG_RET = 1 << 5,
- FB_MQTT_CONNECT_FLAG_PASS = 1 << 6,
- FB_MQTT_CONNECT_FLAG_USER = 1 << 7,
- FB_MQTT_CONNECT_FLAG_QOS0 = 0 << 3,
- FB_MQTT_CONNECT_FLAG_QOS1 = 1 << 3,
- FB_MQTT_CONNECT_FLAG_QOS2 = 2 << 3
- * @FB_MQTT_ERROR_SUCCESS: There is no error.
- * @FB_MQTT_ERROR_PRTVERS: Unacceptable protocol version.
- * @FB_MQTT_ERROR_IDREJECT: Identifier rejected.
- * @FB_MQTT_ERROR_SRVGONE: Server unavailable.
- * @FB_MQTT_ERROR_USERPASS: Bad user name or password.
- * @FB_MQTT_ERROR_UNAUTHORIZED: Not authorized.
- * @FB_MQTT_ERROR_GENERAL: General failure.
- * The error codes for the #FB_MQTT_ERROR domain.
- FB_MQTT_ERROR_SUCCESS = 0,
- FB_MQTT_ERROR_PRTVERS = 1,
- FB_MQTT_ERROR_IDREJECT = 2,
- FB_MQTT_ERROR_SRVGONE = 3,
- FB_MQTT_ERROR_USERPASS = 4,
- FB_MQTT_ERROR_UNAUTHORIZED = 5,
- * @FB_MQTT_MESSAGE_FLAG_RET: Retain messages.
- * @FB_MQTT_MESSAGE_FLAG_DUP: Duplicate delivery of control packet.
- * @FB_MQTT_MESSAGE_FLAG_QOS0: Use no quality of service.
- * @FB_MQTT_MESSAGE_FLAG_QOS1: Use level one quality of service.
- * @FB_MQTT_MESSAGE_FLAG_QOS2: Use level two quality of service.
- * The #FbMqttMessage flags.
- FB_MQTT_MESSAGE_FLAG_RET = 1 << 0,
- FB_MQTT_MESSAGE_FLAG_DUP = 1 << 3,
- FB_MQTT_MESSAGE_FLAG_QOS0 = 0 << 1,
- FB_MQTT_MESSAGE_FLAG_QOS1 = 1 << 1,
- FB_MQTT_MESSAGE_FLAG_QOS2 = 2 << 1
- * @FB_MQTT_MESSAGE_TYPE_CONNECT: Requests a connection.
- * @FB_MQTT_MESSAGE_TYPE_CONNACK: Connection acknowledgment.
- * @FB_MQTT_MESSAGE_TYPE_PUBLISH: Requests a message publication.
- * @FB_MQTT_MESSAGE_TYPE_PUBACK: Publication acknowledgment.
- * @FB_MQTT_MESSAGE_TYPE_PUBREC: Publication received.
- * @FB_MQTT_MESSAGE_TYPE_PUBREL: Publication released.
- * @FB_MQTT_MESSAGE_TYPE_PUBCOMP: Publication complete.
- * @FB_MQTT_MESSAGE_TYPE_SUBSCRIBE: Requests a subscription.
- * @FB_MQTT_MESSAGE_TYPE_SUBACK: Subscription acknowledgment.
- * @FB_MQTT_MESSAGE_TYPE_UNSUBSCRIBE: Requests an unsubscription.
- * @FB_MQTT_MESSAGE_TYPE_UNSUBACK: Unsubscription acknowledgment.
- * @FB_MQTT_MESSAGE_TYPE_PINGREQ: Requests a ping response.
- * @FB_MQTT_MESSAGE_TYPE_PINGRESP: Ping response.
- * @FB_MQTT_MESSAGE_TYPE_DISCONNECT: Requests a disconnection.
- * The #FbMqttMessage types.
- FB_MQTT_MESSAGE_TYPE_CONNECT = 1,
- FB_MQTT_MESSAGE_TYPE_CONNACK = 2,
- FB_MQTT_MESSAGE_TYPE_PUBLISH = 3,
- FB_MQTT_MESSAGE_TYPE_PUBACK = 4,
- FB_MQTT_MESSAGE_TYPE_PUBREC = 5,
- FB_MQTT_MESSAGE_TYPE_PUBREL = 6,
- FB_MQTT_MESSAGE_TYPE_PUBCOMP = 7,
- FB_MQTT_MESSAGE_TYPE_SUBSCRIBE = 8,
- FB_MQTT_MESSAGE_TYPE_SUBACK = 9,
- FB_MQTT_MESSAGE_TYPE_UNSUBSCRIBE = 10,
- FB_MQTT_MESSAGE_TYPE_UNSUBACK = 11,
- FB_MQTT_MESSAGE_TYPE_PINGREQ = 12,
- FB_MQTT_MESSAGE_TYPE_PINGRESP = 13,
- FB_MQTT_MESSAGE_TYPE_DISCONNECT = 14
-G_DECLARE_FINAL_TYPE(FbMqtt, fb_mqtt, FB, MQTT, GObject)
-G_DECLARE_FINAL_TYPE(FbMqttMessage, fb_mqtt_message, FB, MQTT_MESSAGE,
- * Gets the #GQuark of the domain of MQTT errors.
- * Returns: The #GQuark of the domain.
-fb_mqtt_error_quark(void);
- * @gc: The #PurpleConnection.
- * Creates a new #FbMqtt. The returned #FbMqtt should be freed with
- * #g_object_unref() when no longer needed.
- * Returns: The new #FbMqtt.
-fb_mqtt_new(PurpleConnection *gc);
- * Closes the MQTT without sending the `DISCONNECT` message. The #FbMqtt
- * may be reopened after calling this.
-fb_mqtt_close(FbMqtt *mqtt);
- * @error: The #FbMqttError.
- * @format: The format string literal.
- * @...: The arguments for @format.
- * Emits an #FbMqttError and closes the #FbMqtt.
-fb_mqtt_error(FbMqtt *mqtt, FbMqttError error, const gchar *format, ...)
- * @msg: The #FbMqttMessage.
- * Reads an #FbMqttMessage into the #FbMqtt for processing.
-fb_mqtt_read(FbMqtt *mqtt, FbMqttMessage *msg);
- * @msg: The #FbMqttMessage.
- * Writes an #FbMqttMessage to the wire.
-fb_mqtt_write(FbMqtt *mqtt, FbMqttMessage *msg);
- * @host: The host name.
- * Opens an SSL connection to the remote server.
-fb_mqtt_open(FbMqtt *mqtt, const gchar *host, gint port);
- * @flags: The #FbMqttConnectFlags.
- * Sends a message of type #FB_MQTT_MESSAGE_TYPE_CONNECT.
-fb_mqtt_connect(FbMqtt *mqtt, guint8 flags, const GByteArray *pload);
- * @error: #TRUE to error with no connection, otherwise #FALSE.
- * Determines the connection state of the #FbMqtt, and optionally emits
- * Returns: #TRUE if the #FbMqtt is connected, otherwise #FALSE.
-fb_mqtt_connected(FbMqtt *mqtt, gboolean error);
- * Sends a message of type #FB_MQTT_MESSAGE_TYPE_DISCONNECT, and closes
-fb_mqtt_disconnect(FbMqtt *mqtt);
- * Sends a message of type #FB_MQTT_MESSAGE_TYPE_PUBLISH.
-fb_mqtt_publish(FbMqtt *mqtt, const gchar *topic, const GByteArray *pload);
- * @...: The %NULL-terminated list of topic/QoS pairs.
- * Sends a message of type #FB_MQTT_MESSAGE_TYPE_SUBSCRIBE.
-void fb_mqtt_subscribe(FbMqtt *mqtt, ...) G_GNUC_NULL_TERMINATED;
- * @topic1: The first topic.
- * @...: The %NULL-terminated list of topics.
- * Sends a message of type #FB_MQTT_MESSAGE_TYPE_UNSUBSCRIBE.
-fb_mqtt_unsubscribe(FbMqtt *mqtt, const gchar *topic1, ...)
- G_GNUC_NULL_TERMINATED;
- * @type: The #FbMqttMessageType.
- * @flags: The #FbMqttMessageFlags.
- * Creates a new #FbMqttMessage. The returned #FbMqttMessage should be
- * freed with #g_object_unref() when no longer needed.
- * Returns: The new #FbMqttMessage.
-fb_mqtt_message_new(FbMqttMessageType type, FbMqttMessageFlags flags);
- * fb_mqtt_message_new_bytes:
- * @bytes: The #GByteArray.
- * Creates a new #FbMqttMessage from a #GByteArray. The returned
- * #FbMqttMessage should be freed with #g_object_unref() when no
- * Returns: The new #FbMqttMessage.
-fb_mqtt_message_new_bytes(GByteArray *bytes);
- * fb_mqtt_message_reset:
- * @msg: The #FbMqttMessage.
- * Resets an #FbMqttMessage. This resets the cursor position, and
- * removes any sort of fixed header.
-fb_mqtt_message_reset(FbMqttMessage *msg);
- * fb_mqtt_message_bytes:
- * @msg: The #FbMqttMessage.
- * Formats the internal #GByteArray of the #FbMqttMessage with the
- * required fixed header. This resets the cursor position.
- * Returns: The internal #GByteArray.
-fb_mqtt_message_bytes(FbMqttMessage *msg);
- * fb_mqtt_message_read:
- * @msg: The #FbMqttMessage.
- * @data: The data buffer.
- * @size: The size of @buffer.
- * Reads data from the #FbMqttMessage into a buffer. If @data is #NULL,
- * this will simply advance the cursor position.
- * Returns: #TRUE if the data was read, otherwise #FALSE.
-fb_mqtt_message_read(FbMqttMessage *msg, gpointer data, guint size);
- * fb_mqtt_message_read_r:
- * @msg: The #FbMqttMessage.
- * @bytes: The #GByteArray.
- * Reads the remaining data from the #FbMqttMessage into a #GByteArray.
- * This is useful for obtaining the payload of a message.
- * Returns: #TRUE if the data was read, otherwise #FALSE.
-fb_mqtt_message_read_r(FbMqttMessage *msg, GByteArray *bytes);
- * fb_mqtt_message_read_byte:
- * @msg: The #FbMqttMessage.
- * @value: The return location for the value or #NULL.
- * Reads an 8-bit integer value from the #FbMqttMessage. If @value is
- * #NULL, this will simply advance the cursor position.
- * Returns: #TRUE if the value was read, otherwise #FALSE.
-fb_mqtt_message_read_byte(FbMqttMessage *msg, guint8 *value);
- * fb_mqtt_message_read_mid:
- * @msg: The #FbMqttMessage.
- * @value: The return location for the value or #NULL.
- * Reads a message identifier from the #FbMqttMessage. If @value is
- * #NULL, this will simply advance the cursor position.
- * Returns: #TRUE if the value was read, otherwise #FALSE.
-fb_mqtt_message_read_mid(FbMqttMessage *msg, guint16 *value);
- * fb_mqtt_message_read_u16:
- * @msg: The #FbMqttMessage.
- * @value: The return location for the value or #NULL.
- * Reads a 16-bit integer value from the #FbMqttMessage. If @value is
- * #NULL, this will simply advance the cursor position.
- * Returns: #TRUE if the value was read, otherwise #FALSE.
-fb_mqtt_message_read_u16(FbMqttMessage *msg, guint16 *value);
- * fb_mqtt_message_read_str:
- * @msg: The #FbMqttMessage.
- * @value: The return location for the value or #NULL.
- * Reads a string value from the #FbMqttMessage. The value returned to
- * @value should be freed with #g_free() when no longer needed. If
- * @value is #NULL, this will simply advance the cursor position.
- * Returns: #TRUE if the value was read, otherwise #FALSE.
-fb_mqtt_message_read_str(FbMqttMessage *msg, gchar **value);
- * fb_mqtt_message_write:
- * @msg: The #FbMqttMessage.
- * @data: The data buffer.
- * @size: The size of @buffer.
- * Writes data to the #FbMqttMessage.
-fb_mqtt_message_write(FbMqttMessage *msg, gconstpointer data, guint size);
- * fb_mqtt_message_write_byte:
- * @msg: The #FbMqttMessage.
- * Writes an 8-bit integer value to the #FbMqttMessage.
-fb_mqtt_message_write_byte(FbMqttMessage *msg, guint8 value);
- * fb_mqtt_message_write_mid:
- * @msg: The #FbMqttMessage.
- * Writes a message identifier to the #FbMqttMessage. This increments
- * @value for the next message.
-fb_mqtt_message_write_mid(FbMqttMessage *msg, guint16 *value);
- * fb_mqtt_message_write_u16:
- * @msg: The #FbMqttMessage.
- * Writes a 16-bit integer value to the #FbMqttMessage.
-fb_mqtt_message_write_u16(FbMqttMessage *msg, guint16 value);
- * fb_mqtt_message_write_str:
- * @msg: The #FbMqttMessage.
- * Writes a string value to the #FbMqttMessage.
-fb_mqtt_message_write_str(FbMqttMessage *msg, const gchar *value);
-#endif /* PURPLE_FACEBOOK_MQTT_H */
--- a/libpurple/protocols/facebook/resources/facebook.gresource.xml Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
- <gresource prefix="/im/pidgin/libpurple/facebook">
- <file>icons/16x16/apps/im-facebook.png</file>
- <file>icons/22x22/apps/im-facebook.png</file>
- <file>icons/48x48/apps/im-facebook.png</file>
Binary file libpurple/protocols/facebook/resources/icons/16x16/apps/im-facebook.png has changed
Binary file libpurple/protocols/facebook/resources/icons/22x22/apps/im-facebook.png has changed
Binary file libpurple/protocols/facebook/resources/icons/48x48/apps/im-facebook.png has changed
--- a/libpurple/protocols/facebook/thrift.c Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,675 +0,0 @@
- * 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
- * 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
- * Represents a reader/writer for compact Thrift data.
-G_DEFINE_TYPE(FbThrift, fb_thrift, G_TYPE_OBJECT);
-fb_thrift_dispose(GObject *obj)
- FbThrift* thft = FB_THRIFT(obj);
- g_byte_array_free(thft->bytes, TRUE);
- thft->internal = FALSE;
-fb_thrift_class_init(FbThriftClass *klass)
- GObjectClass *gklass = G_OBJECT_CLASS(klass);
- gklass->dispose = fb_thrift_dispose;
-fb_thrift_init(G_GNUC_UNUSED FbThrift *thft)
-fb_thrift_new(GByteArray *bytes, guint offset)
- thft = g_object_new(FB_TYPE_THRIFT, NULL);
- thft->bytes = g_byte_array_new();
-fb_thrift_get_bytes(FbThrift *thft)
- g_return_val_if_fail(FB_IS_THRIFT(thft), NULL);
-fb_thrift_get_pos(FbThrift *thft)
- g_return_val_if_fail(FB_IS_THRIFT(thft), 0);
-fb_thrift_set_pos(FbThrift *thft, guint pos)
- g_return_if_fail(FB_IS_THRIFT(thft));
-fb_thrift_reset(FbThrift *thft)
- g_return_if_fail(FB_IS_THRIFT(thft));
- thft->pos = thft->offset;
-fb_thrift_read(FbThrift *thft, gpointer data, guint size)
- g_return_val_if_fail(FB_IS_THRIFT(thft), FALSE);
- if ((thft->pos + size) > thft->bytes->len) {
- if ((data != NULL) && (size > 0)) {
- memcpy(data, thft->bytes->data + thft->pos, size);
-fb_thrift_read_bool(FbThrift *thft, gboolean *value)
- g_return_val_if_fail(FB_IS_THRIFT(thft), FALSE);
- if ((thft->lastbool & 0x03) != 0x01) {
- if (!fb_thrift_read_byte(thft, &byte)) {
- *value = (byte & 0x0F) == 0x01;
- *value = ((thft->lastbool & 0x04) >> 2) != 0;
-fb_thrift_read_byte(FbThrift *thft, guint8 *value)
- return fb_thrift_read(thft, value, sizeof *value);
-fb_thrift_read_dbl(FbThrift *thft, gdouble *value)
- /* Almost always 8, but check anyways */
- static const gsize size = MIN(sizeof value, sizeof i64);
- if (!fb_thrift_read_i64(thft, &i64)) {
- memcpy(value, &i64, size);
-fb_thrift_read_i16(FbThrift *thft, gint16 *value)
- if (!fb_thrift_read_i64(thft, &i64)) {
-fb_thrift_read_vi16(FbThrift *thft, guint16 *value)
- if (!fb_thrift_read_vi64(thft, &u64)) {
-fb_thrift_read_i32(FbThrift *thft, gint32 *value)
- if (!fb_thrift_read_i64(thft, &i64)) {
-fb_thrift_read_vi32(FbThrift *thft, guint32 *value)
- if (!fb_thrift_read_vi64(thft, &u64)) {
-fb_thrift_read_i64(FbThrift *thft, gint64 *value)
- if (!fb_thrift_read_vi64(thft, &u64)) {
- /* Convert from zigzag to integer */
- *value = (u64 >> 0x01) ^ -(u64 & 0x01);
-fb_thrift_read_vi64(FbThrift *thft, guint64 *value)
- if (!fb_thrift_read_byte(thft, &byte)) {
- u64 |= ((guint64) (byte & 0x7F)) << i;
- } while ((byte & 0x80) == 0x80);
-fb_thrift_read_str(FbThrift *thft, gchar **value)
- if (!fb_thrift_read_vi32(thft, &size)) {
- data = g_new(guint8, size + 1);
- if (!fb_thrift_read(thft, data, size)) {
- *value = (gchar *) data;
-fb_thrift_read_field(FbThrift *thft, FbThriftType *type, gint16 *id,
- g_return_val_if_fail(FB_IS_THRIFT(thft), FALSE);
- g_return_val_if_fail(type != NULL, FALSE);
- g_return_val_if_fail(id != NULL, FALSE);
- if (!fb_thrift_read_byte(thft, &byte)) {
- if (byte == FB_THRIFT_TYPE_STOP) {
- *type = FB_THRIFT_TYPE_STOP;
- *type = fb_thrift_ct2t(byte & 0x0F);
- i16 = (byte & 0xF0) >> 4;
- if (!fb_thrift_read_i16(thft, id)) {
- if (*type == FB_THRIFT_TYPE_BOOL) {
- if ((byte & 0x0F) == 0x01) {
- thft->lastbool |= 0x01 << 2;
-fb_thrift_read_stop(FbThrift *thft)
- return fb_thrift_read_byte(thft, &byte) &&
- (byte == FB_THRIFT_TYPE_STOP);
-fb_thrift_read_isstop(FbThrift *thft)
- g_return_val_if_fail(FB_IS_THRIFT(thft), FALSE);
- if (!fb_thrift_read_byte(thft, &byte)) {
- return byte == FB_THRIFT_TYPE_STOP;
-fb_thrift_read_list(FbThrift *thft, FbThriftType *type, guint *size)
- g_return_val_if_fail(type != NULL, FALSE);
- g_return_val_if_fail(size != NULL, FALSE);
- if (!fb_thrift_read_byte(thft, &byte)) {
- *type = fb_thrift_ct2t(byte & 0x0F);
- *size = (byte & 0xF0) >> 4;
- if (!fb_thrift_read_vi32(thft, &u32)) {
-fb_thrift_read_map(FbThrift *thft, FbThriftType *ktype, FbThriftType *vtype,
- g_return_val_if_fail(ktype != NULL, FALSE);
- g_return_val_if_fail(vtype != NULL, FALSE);
- g_return_val_if_fail(size != NULL, FALSE);
- if (!fb_thrift_read_i32(thft, &i32)) {
- if (!fb_thrift_read_byte(thft, &byte)) {
- *ktype = fb_thrift_ct2t((byte & 0xF0) >> 4);
- *vtype = fb_thrift_ct2t(byte & 0x0F);
-fb_thrift_read_set(FbThrift *thft, FbThriftType *type, guint *size)
- return fb_thrift_read_list(thft, type, size);
-fb_thrift_write(FbThrift *thft, gconstpointer data, guint size)
- g_return_if_fail(FB_IS_THRIFT(thft));
- g_byte_array_append(thft->bytes, data, size);
-fb_thrift_write_bool(FbThrift *thft, gboolean value)
- g_return_if_fail(FB_IS_THRIFT(thft));
- if ((thft->lastbool & 0x03) != 0x02) {
- fb_thrift_write_byte(thft, value ? 0x01 : 0x02);
- pos = thft->lastbool >> 3;
- if ((pos >= thft->offset) && (pos < thft->bytes->len)) {
- thft->bytes->data[pos] &= ~0x0F;
- thft->bytes->data[pos] |= value ? 0x01 : 0x02;
-fb_thrift_write_byte(FbThrift *thft, guint8 value)
- fb_thrift_write(thft, &value, sizeof value);
-fb_thrift_write_dbl(FbThrift *thft, gdouble value)
- /* Almost always 8, but check anyways */
- static const gsize size = MIN(sizeof value, sizeof i64);
- memcpy(&i64, &value, size);
- fb_thrift_write_i64(thft, i64);
-fb_thrift_write_i16(FbThrift *thft, gint16 value)
- fb_thrift_write_i64(thft, value);
-fb_thrift_write_vi16(FbThrift *thft, guint16 value)
- fb_thrift_write_vi64(thft, value);
-fb_thrift_write_i32(FbThrift *thft, gint32 value)
- value = (value << 1) ^ (value >> 31);
- fb_thrift_write_vi64(thft, value);
-fb_thrift_write_vi32(FbThrift *thft, guint32 value)
- fb_thrift_write_vi64(thft, value);
-fb_thrift_write_i64(FbThrift *thft, gint64 value)
- value = (value << 1) ^ (value >> 63);
- fb_thrift_write_vi64(thft, value);
-fb_thrift_write_vi64(FbThrift *thft, guint64 value)
- last = (value & ~0x7F) == 0;
- fb_thrift_write_byte(thft, byte);
-fb_thrift_write_str(FbThrift *thft, const gchar *value)
- g_return_if_fail(value != NULL);
- fb_thrift_write_vi32(thft, size);
- fb_thrift_write(thft, value, size);
-fb_thrift_write_field(FbThrift *thft, FbThriftType type, gint16 id,
- g_return_if_fail(FB_IS_THRIFT(thft));
- if (type == FB_THRIFT_TYPE_BOOL) {
- thft->lastbool = (thft->pos << 3) | 0x02;
- type = fb_thrift_t2ct(type);
- if ((id <= lastid) || (diff > 0x0F)) {
- fb_thrift_write_byte(thft, type);
- fb_thrift_write_i16(thft, id);
- fb_thrift_write_byte(thft, (diff << 4) | type);
-fb_thrift_write_stop(FbThrift *thft)
- fb_thrift_write_byte(thft, FB_THRIFT_TYPE_STOP);
-fb_thrift_write_list(FbThrift *thft, FbThriftType type, guint size)
- type = fb_thrift_t2ct(type);
- fb_thrift_write_byte(thft, (size << 4) | type);
- fb_thrift_write_vi32(thft, size);
- fb_thrift_write_byte(thft, 0xF0 | type);
-fb_thrift_write_map(FbThrift *thft, FbThriftType ktype, FbThriftType vtype,
- fb_thrift_write_byte(thft, 0);
- ktype = fb_thrift_t2ct(ktype);
- vtype = fb_thrift_t2ct(vtype);
- fb_thrift_write_vi32(thft, size);
- fb_thrift_write_byte(thft, (ktype << 4) | vtype);
-fb_thrift_write_set(FbThrift *thft, FbThriftType type, guint size)
- fb_thrift_write_list(thft, type, size);
-fb_thrift_t2ct(FbThriftType type)
- static const guint8 types[] = {
- [FB_THRIFT_TYPE_STOP] = 0,
- [FB_THRIFT_TYPE_VOID] = 0,
- [FB_THRIFT_TYPE_BOOL] = 2,
- [FB_THRIFT_TYPE_BYTE] = 3,
- [FB_THRIFT_TYPE_DOUBLE] = 7,
- [FB_THRIFT_TYPE_I16] = 4,
- [FB_THRIFT_TYPE_I32] = 5,
- [FB_THRIFT_TYPE_I64] = 6,
- [FB_THRIFT_TYPE_STRING] = 8,
- [FB_THRIFT_TYPE_STRUCT] = 12,
- [FB_THRIFT_TYPE_MAP] = 11,
- [FB_THRIFT_TYPE_SET] = 10,
- [FB_THRIFT_TYPE_LIST] = 9
- g_return_val_if_fail(type < G_N_ELEMENTS(types), 0);
-fb_thrift_ct2t(guint8 type)
- static const guint8 types[] = {
- [0] = FB_THRIFT_TYPE_STOP,
- [1] = FB_THRIFT_TYPE_BOOL,
- [2] = FB_THRIFT_TYPE_BOOL,
- [3] = FB_THRIFT_TYPE_BYTE,
- [4] = FB_THRIFT_TYPE_I16,
- [5] = FB_THRIFT_TYPE_I32,
- [6] = FB_THRIFT_TYPE_I64,
- [7] = FB_THRIFT_TYPE_DOUBLE,
- [8] = FB_THRIFT_TYPE_STRING,
- [9] = FB_THRIFT_TYPE_LIST,
- [10] = FB_THRIFT_TYPE_SET,
- [11] = FB_THRIFT_TYPE_MAP,
- [12] = FB_THRIFT_TYPE_STRUCT
- g_return_val_if_fail(type < G_N_ELEMENTS(types), 0);
--- a/libpurple/protocols/facebook/thrift.h Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,553 +0,0 @@
- * 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
- * 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_FACEBOOK_THRIFT_H
-#define PURPLE_FACEBOOK_THRIFT_H
-#include <glib-object.h>
-#define FB_TYPE_THRIFT fb_thrift_get_type()
- * @FB_THRIFT_TYPE_STOP: A stopper for certain types.
- * @FB_THRIFT_TYPE_VOID: A void or empty value.
- * @FB_THRIFT_TYPE_BOOL: A boolean (#TRUE or #FALSE).
- * @FB_THRIFT_TYPE_BYTE: A signed 8-bit integer.
- * @FB_THRIFT_TYPE_DOUBLE: A 64-bit floating point number.
- * @FB_THRIFT_TYPE_I16: A signed 16-bit integer.
- * @FB_THRIFT_TYPE_I32: A signed 32-bit integer.
- * @FB_THRIFT_TYPE_I64: A signed 64-bit integer.
- * @FB_THRIFT_TYPE_STRING: A UTF-8 encoded string.
- * @FB_THRIFT_TYPE_STRUCT: A set of typed fields.
- * @FB_THRIFT_TYPE_MAP: A map of unique keys to values.
- * @FB_THRIFT_TYPE_SET: A unique set of values.
- * @FB_THRIFT_TYPE_LIST: A ordered list of values.
- * @FB_THRIFT_TYPE_ENUM: A 32-bit enumerated list.
- * @FB_THRIFT_TYPE_UNKNOWN: An unknown type.
- * The Thrift data types.
- FB_THRIFT_TYPE_STOP = 0,
- FB_THRIFT_TYPE_VOID = 1,
- FB_THRIFT_TYPE_BOOL = 2,
- FB_THRIFT_TYPE_BYTE = 3,
- FB_THRIFT_TYPE_DOUBLE = 4,
- FB_THRIFT_TYPE_I16 = 6,
- FB_THRIFT_TYPE_I32 = 8,
- FB_THRIFT_TYPE_I64 = 10,
- FB_THRIFT_TYPE_STRING = 11,
- FB_THRIFT_TYPE_STRUCT = 12,
- FB_THRIFT_TYPE_MAP = 13,
- FB_THRIFT_TYPE_SET = 14,
- FB_THRIFT_TYPE_LIST = 15,
- FB_THRIFT_TYPE_ENUM = 16,
-G_DECLARE_FINAL_TYPE(FbThrift, fb_thrift, FB, THRIFT, GObject)
- * @bytes: The #GByteArray to read or write.
- * @offset: The offset in bytes of the data in @bytes.
- * Creates a new #FbThrift. The returned #FbThrift should be freed with
- * #g_object_unref() when no longer needed. This will optionally use a
- * #GByteArray at an offset, rather than a newly created and internal
- * Returns: The new #FbThrift.
-fb_thrift_new(GByteArray *bytes, guint offset);
- * @thft: The #FbThrift.
- * Gets the underlying #GByteArray of an #FbThrift.
- * Returns: The #GByteArray.
-fb_thrift_get_bytes(FbThrift *thft);
- * @thft: The #FbThrift.
- * Gets the cursor position of an #FbThrift.
- * Returns: The cursor position.
-fb_thrift_get_pos(FbThrift *thft);
- * @thft: The #FbThrift.
- * Sets the cursor position of an #FbThrift.
-fb_thrift_set_pos(FbThrift *thft, guint pos);
- * @thft: The #FbThrift.
- * Resets the cursor position of an #FbThrift.
-fb_thrift_reset(FbThrift *thft);
- * @thft: The #FbThrift.
- * @data: The data buffer.
- * @size: The size of @buffer.
- * Reads data from the #FbThrift into a buffer. If @data is #NULL, this
- * will simply advance the cursor position.
- * Returns: #TRUE if the data was read, otherwise #FALSE.
-fb_thrift_read(FbThrift *thft, gpointer data, guint size);
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- * Reads a boolean value from the #FbThrift. If @value is #NULL, this
- * will simply advance the cursor position.
- * Returns: #TRUE if the value was read, otherwise #FALSE.
-fb_thrift_read_bool(FbThrift *thft, gboolean *value);
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- * Reads an 8-bit integer value from the #FbThrift. If @value is #NULL,
- * this will simply advance the cursor position.
- * Returns: #TRUE if the value was read, otherwise #FALSE.
-fb_thrift_read_byte(FbThrift *thft, guint8 *value);
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- * Reads a 64-bit floating point value from the #FbThrift. If @value
- * is #NULL, this will simply advance the cursor position.
- * Returns: #TRUE if the value was read, otherwise #FALSE.
-fb_thrift_read_dbl(FbThrift *thft, gdouble *value);
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- * Reads a signed 16-bit integer value from the #FbThrift. This will
- * convert the integer from the zig-zag format. If @value is #NULL,
- * this will simply advance the cursor position.
- * Returns: #TRUE if the value was read, otherwise #FALSE.
-fb_thrift_read_i16(FbThrift *thft, gint16 *value);
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- * Reads a 16-bit integer value from the #FbThrift. This reads the raw
- * integer value without converting it from the zig-zag format. If
- * @value is #NULL, this will simply advance the cursor position.
- * Returns: #TRUE if the value was read, otherwise #FALSE.
-fb_thrift_read_vi16(FbThrift *thft, guint16 *value);
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- * Reads a signed 32-bit integer value from the #FbThrift. This will
- * convert the integer from the zig-zag format. If @value is #NULL,
- * this will simply advance the cursor position.
- * Returns: #TRUE if the value was read, otherwise #FALSE.
-fb_thrift_read_i32(FbThrift *thft, gint32 *value);
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- * Reads a 32-bit integer value from the #FbThrift. This reads the raw
- * integer value without converting it from the zig-zag format. If
- * @value is #NULL, this will simply advance the cursor position.
- * Returns: #TRUE if the value was read, otherwise #FALSE.
-fb_thrift_read_vi32(FbThrift *thft, guint32 *value);
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- * Reads a signed 64-bit integer value from the #FbThrift. This will
- * convert the integer from the zig-zag format. If @value is #NULL,
- * this will simply advance the cursor position.
- * Returns: #TRUE if the value was read, otherwise #FALSE.
-fb_thrift_read_i64(FbThrift *thft, gint64 *value);
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- * Reads a 64-bit integer value from the #FbThrift. This reads the raw
- * integer value without converting it from the zig-zag format. If
- * @value is #NULL, this will simply advance the cursor position.
- * Returns: #TRUE if the value was read, otherwise #FALSE.
-fb_thrift_read_vi64(FbThrift *thft, guint64 *value);
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- * Reads a string value from the #FbThrift. The value returned to
- * @value should be freed with #g_free() when no longer needed. If
- * @value is #NULL, this will simply advance the cursor position.
- * Returns: #TRUE if the value was read, otherwise #FALSE.
-fb_thrift_read_str(FbThrift *thft, gchar **value);
- * fb_thrift_read_field:
- * @thft: The #FbThrift.
- * @type: The return location for the #FbThriftType.
- * @id: The return location for the identifier.
- * @lastid: The identifier of the previous field.
- * Reads a field header from the #FbThrift.
- * Returns: #TRUE if the field header was read, otherwise #FALSE.
-fb_thrift_read_field(FbThrift *thft, FbThriftType *type, gint16 *id,
- * @thft: The #FbThrift.
- * Reads a field stop from the #FbThrift.
- * Returns: #TRUE if the field stop was read, otherwise #FALSE.
-fb_thrift_read_stop(FbThrift *thft);
- * fb_thrift_read_isstop:
- * @thft: The #FbThrift.
- * Determines if the next byte of the #FbThrift is a field stop.
- * Returns: #TRUE if the next byte is a field stop, otherwise #FALSE.
-fb_thrift_read_isstop(FbThrift *thft);
- * @thft: The #FbThrift.
- * @type: The return location for the #FbThriftType.
- * @size: The return location for the size.
- * Reads a list header from the #FbThrift.
- * Returns: #TRUE if the list header was read, otherwise #FALSE.
-fb_thrift_read_list(FbThrift *thft, FbThriftType *type, guint *size);
- * @thft: The #FbThrift.
- * @ktype: The return location for the key #FbThriftType.
- * @vtype: The return location for the value #FbThriftType.
- * @size: The return location for the size.
- * Reads a map header from the #FbThrift.
- * Returns: #TRUE if the map header was read, otherwise #FALSE.
-fb_thrift_read_map(FbThrift *thft, FbThriftType *ktype, FbThriftType *vtype,
- * @thft: The #FbThrift.
- * @type: The return location for the #FbThriftType.
- * @size: The return location for the size.
- * Reads a set header from the #FbThrift.
- * Returns: #TRUE if the set header was read, otherwise #FALSE.
-fb_thrift_read_set(FbThrift *thft, FbThriftType *type, guint *size);
- * @thft: The #FbThrift.
- * @data: The data buffer.
- * @size: The size of @buffer.
- * Writes data to the #FbThrift.
-fb_thrift_write(FbThrift *thft, gconstpointer data, guint size);
- * fb_thrift_write_bool:
- * @thft: The #FbThrift.
- * Writes a boolean value to the #FbThrift.
-fb_thrift_write_bool(FbThrift *thft, gboolean value);
- * fb_thrift_write_byte:
- * @thft: The #FbThrift.
- * Writes an 8-bit integer value to the #FbThrift.
-fb_thrift_write_byte(FbThrift *thft, guint8 value);
- * @thft: The #FbThrift.
- * Writes a 64-bit floating point value to the #FbThrift.
-fb_thrift_write_dbl(FbThrift *thft, gdouble value);
- * @thft: The #FbThrift.
- * Writes a signed 16-bit integer value to the #FbThrift. This will
- * convert the integer to the zig-zag format.
-fb_thrift_write_i16(FbThrift *thft, gint16 value);
- * fb_thrift_write_vi16:
- * @thft: The #FbThrift.
- * Writes a 16-bit integer value to the #FbThrift. This writes the raw
- * integer value without converting it to the zig-zag format.
-fb_thrift_write_vi16(FbThrift *thft, guint16 value);
- * @thft: The #FbThrift.
- * Writes a signed 32-bit integer value to the #FbThrift. This will
- * convert the integer to the zig-zag format.
-fb_thrift_write_i32(FbThrift *thft, gint32 value);
- * fb_thrift_write_vi32:
- * @thft: The #FbThrift.
- * Writes a 32-bit integer value to the #FbThrift. This writes the raw
- * integer value without converting it to the zig-zag format.
-fb_thrift_write_vi32(FbThrift *thft, guint32 value);
- * @thft: The #FbThrift.
- * Writes a signed 64-bit integer value to the #FbThrift. This will
- * convert the integer to the zig-zag format.
-fb_thrift_write_i64(FbThrift *thft, gint64 value);
- * fb_thrift_write_vi64:
- * @thft: The #FbThrift.
- * Writes a 64-bit integer value to the #FbThrift. This writes the raw
- * integer value without converting it to the zig-zag format.
-fb_thrift_write_vi64(FbThrift *thft, guint64 value);
- * @thft: The #FbThrift.
- * Writes a string value to the #FbThrift.
-fb_thrift_write_str(FbThrift *thft, const gchar *value);
- * fb_thrift_write_field:
- * @thft: The #FbThrift.
- * @type: The #FbThriftType.
- * @lastid: The identifier of the previous field.
- * Writes a field header to the #FbThrift.
-fb_thrift_write_field(FbThrift *thft, FbThriftType type, gint16 id,
- * fb_thrift_write_stop:
- * @thft: The #FbThrift.
- * Writes a field stop to the #FbThrift.
-fb_thrift_write_stop(FbThrift *thft);
- * fb_thrift_write_list:
- * @thft: The #FbThrift.
- * @type: The #FbThriftType.
- * Writes a list header to the #FbThrift.
-fb_thrift_write_list(FbThrift *thft, FbThriftType type, guint size);
- * @thft: The #FbThrift.
- * @ktype: The key #FbThriftType.
- * @vtype: The value #FbThriftType.
- * Writes a map header to the #FbThrift.
-fb_thrift_write_map(FbThrift *thft, FbThriftType ktype, FbThriftType vtype,
- * @thft: The #FbThrift.
- * @type: The #FbThriftType.
- * Writes a set header to the #FbThrift.
-fb_thrift_write_set(FbThrift *thft, FbThriftType type, guint size);
- * @type: The #FbThriftType.
- * Converts a #FbThriftType to a compact type.
- * Return: The equivalent compact type.
-fb_thrift_t2ct(FbThriftType type);
- * @type: The compact type.
- * Converts a compact type to an #FbThriftType.
- * Return: The equivalent #FbThriftType.
-fb_thrift_ct2t(guint8 type);
-#endif /* PURPLE_FACEBOOK_THRIFT_H */
--- a/libpurple/protocols/facebook/util.c Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,619 +0,0 @@
- * 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
- * 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 <glib/gi18n-lib.h>
-fb_util_error_quark(void)
- if (G_UNLIKELY(q == 0)) {
- q = g_quark_from_static_string("fb-util-error-quark");
-fb_util_account_find_buddy(PurpleAccount *acct, PurpleChatConversation *chat,
- const gchar *search, GError **error)
- PurpleBuddy *ret = NULL;
- g_return_val_if_fail(PURPLE_IS_ACCOUNT(acct), NULL);
- g_return_val_if_fail(search != NULL, NULL);
- buddies = purple_blist_find_buddies(acct, NULL);
- for (retc = 0, l = buddies; l != NULL; l = l->next) {
- name = purple_buddy_get_name(l->data);
- alias = purple_buddy_get_alias(l->data);
- !purple_chat_conversation_has_user(chat, name))
- if (g_ascii_strcasecmp(name, search) == 0) {
- if (g_ascii_strcasecmp(alias, search) == 0) {
- g_set_error(error, FB_UTIL_ERROR, FB_UTIL_ERROR_GENERAL,
- _("Buddy %s not found"), search);
- g_set_error(error, FB_UTIL_ERROR, FB_UTIL_ERROR_GENERAL,
- _("Buddy name %s is ambiguous"), search);
-fb_util_debug(PurpleDebugLevel level, const gchar *format, ...)
- fb_util_vdebug(level, format, ap);
-fb_util_vdebug(PurpleDebugLevel level, const gchar *format, va_list ap)
- g_return_if_fail(format != NULL);
- unsafe = (level & FB_UTIL_DEBUG_FLAG_UNSAFE) != 0;
- verbose = (level & FB_UTIL_DEBUG_FLAG_VERBOSE) != 0;
- if ((unsafe && !purple_debug_is_unsafe()) ||
- (verbose && !purple_debug_is_verbose()))
- /* Ensure all local flags are removed */
- level &= ~FB_UTIL_DEBUG_FLAG_ALL;
- str = g_strdup_vprintf(format, ap);
- purple_debug(level, "facebook", "%s", str);
-fb_util_debug_misc(const gchar *format, ...)
- fb_util_vdebug(PURPLE_DEBUG_MISC, format, ap);
-fb_util_debug_info(const gchar *format, ...)
- fb_util_vdebug(PURPLE_DEBUG_INFO, format, ap);
-fb_util_debug_warning(const gchar *format, ...)
- fb_util_vdebug(PURPLE_DEBUG_WARNING, format, ap);
-fb_util_debug_error(const gchar *format, ...)
- fb_util_vdebug(PURPLE_DEBUG_ERROR, format, ap);
-fb_util_debug_fatal(const gchar *format, ...)
- fb_util_vdebug(PURPLE_DEBUG_FATAL, format, ap);
-fb_util_debug_hexdump(PurpleDebugLevel level, const GByteArray *bytes,
- const gchar *format, ...)
- static const gchar *indent = " ";
- g_return_if_fail(bytes != NULL);
- fb_util_vdebug(level, format, ap);
- gstr = g_string_sized_new(80);
- for (i = 0; i < bytes->len; i += 16) {
- g_string_append_printf(gstr, "%s%08x ", indent, i);
- for (j = 0; j < 16; j++) {
- if ((i + j) < bytes->len) {
- g_string_append_printf(gstr, "%02x ",
- g_string_append(gstr, " ");
- g_string_append_c(gstr, ' ');
- g_string_append(gstr, " |");
- for (j = 0; (j < 16) && ((i + j) < bytes->len); j++) {
- c = bytes->data[i + j];
- if (!g_ascii_isprint(c) || g_ascii_isspace(c)) {
- g_string_append_c(gstr, c);
- g_string_append_c(gstr, '|');
- fb_util_debug(level, "%s", gstr->str);
- g_string_erase(gstr, 0, -1);
- g_string_append_printf(gstr, "%s%08x", indent, i);
- fb_util_debug(level, "%s", gstr->str);
- g_string_free(gstr, TRUE);
-fb_util_get_locale(void)
- const gchar * const *langs;
- static const gchar chrs[] = {'.', '@'};
- langs = g_get_language_names();
- if (purple_strequal(lang, "C")) {
- return g_strdup("en_US");
- for (i = 0; i < G_N_ELEMENTS(chrs); i++) {
- chr = strchr(lang, chrs[i]);
- return g_strndup(lang, chr - lang);
-fb_util_rand_alnum(guint len)
- static const gchar chars[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- static const gsize charc = G_N_ELEMENTS(chars) - 1;
- g_return_val_if_fail(len > 0, NULL);
- ret = g_new(gchar, len + 1);
- for (i = 0; i < len; i++) {
- j = g_rand_int_range(rand, 0, charc);
-fb_util_request_buddy_ok(gpointer *request_data, PurpleRequestPage *page) {
- FbUtilRequestBuddyFunc func = request_data[0];
- gpointer data = request_data[2];
- PurpleRequestFieldList *field;
- field = PURPLE_REQUEST_FIELD_LIST(purple_request_page_get_field(page,
- select = purple_request_field_list_get_selected(field);
- for (l = select; l != NULL; l = l->next) {
- bdy = purple_request_field_list_get_data(field, l->data);
- ret = g_slist_prepend(ret, bdy);
- ret = g_slist_reverse(ret);
-fb_util_request_buddy_cancel(gpointer *request_data,
- G_GNUC_UNUSED PurpleRequestPage *page)
- FbUtilRequestBuddyFunc func = request_data[1];
- gpointer data = request_data[2];
-fb_buddy_cmp(gconstpointer a, gconstpointer b)
- PurpleBuddy *pba, *pbb;
- gint alias_verdict, name_verdict;
- astr = g_utf8_casefold(purple_buddy_get_alias(pba), -1);
- bstr = g_utf8_casefold(purple_buddy_get_alias(pbb), -1);
- alias_verdict = g_utf8_collate(astr, bstr);
- if (alias_verdict != 0) {
- astr = g_utf8_casefold(purple_buddy_get_name(pba), -1);
- bstr = g_utf8_casefold(purple_buddy_get_name(pbb), -1);
- name_verdict = g_utf8_collate(astr, bstr);
-fb_util_request_buddy(PurpleConnection *gc, const gchar *title,
- const gchar *primary, const gchar *secondary,
- GSList *select, gboolean multi, GCallback ok_cb,
- GCallback cancel_cb, gpointer data)
- gpointer *request_data;
- PurpleRequestCommonParameters *cpar;
- PurpleRequestField *field;
- PurpleRequestFieldList *list;
- PurpleRequestGroup *group;
- PurpleRequestPage *page;
- request_data = g_new0(gpointer, 3);
- request_data[0] = ok_cb;
- request_data[1] = cancel_cb;
- request_data[2] = data;
- acct = purple_connection_get_account(gc);
- buddies = purple_blist_find_buddies(acct, NULL);
- buddies = g_slist_sort(buddies, fb_buddy_cmp);
- page = purple_request_page_new();
- group = purple_request_group_new(NULL);
- purple_request_page_add_group(page, group);
- field = purple_request_field_list_new("buddy", NULL);
- list = PURPLE_REQUEST_FIELD_LIST(field);
- purple_request_field_list_set_multi_select(list, multi);
- purple_request_field_set_required(field, TRUE);
- purple_request_group_add_field(group, field);
- for (l = buddies; l != NULL; l = l->next) {
- name = purple_buddy_get_name(l->data);
- alias = purple_buddy_get_alias(l->data);
- str = g_strdup_printf("%s (%s)", alias, name);
- purple_request_field_list_add_icon(list, str, NULL, l->data);
- for (l = select; l != NULL; l = l->next) {
- name = purple_buddy_get_name(l->data);
- alias = purple_buddy_get_alias(l->data);
- str = g_strdup_printf("%s (%s)", alias, name);
- items = g_list_append(items, str);
- purple_request_field_list_set_selected(list, items);
- g_list_free_full(items, g_free);
- cpar = purple_request_cpar_from_connection(gc);
- return purple_request_fields(gc, title, primary, secondary, page,
- G_CALLBACK(fb_util_request_buddy_ok),
- G_CALLBACK(fb_util_request_buddy_cancel),
-fb_util_serv_got_im(PurpleConnection *gc, const gchar *who, const gchar *text,
- PurpleMessageFlags flags, guint64 timestamp)
- const gchar *name, *me;
- PurpleContactInfo *info = NULL;
- PurpleConversation *conv;
- PurpleConversationManager *manager;
- if (!(flags & PURPLE_MESSAGE_SEND)) {
- purple_serv_got_im(gc, who, text, flags, timestamp);
- acct = purple_connection_get_account(gc);
- info = PURPLE_CONTACT_INFO(acct);
- manager = purple_conversation_manager_get_default();
- conv = purple_conversation_manager_find_im(manager, acct, who);
- conv = purple_im_conversation_new(acct, who);
- me = purple_contact_info_get_name_for_display(info);
- name = purple_contact_info_get_username(info);
- msg = purple_message_new_outgoing(acct, me, name, text, flags);
- dt = g_date_time_new_from_unix_local((gint64)timestamp);
- purple_message_set_timestamp(msg, dt);
- purple_conversation_write_message(conv, msg);
- g_object_unref(G_OBJECT(msg));
-fb_util_serv_got_chat_in(PurpleConnection *gc, gint id, const gchar *who,
- const gchar *text, PurpleMessageFlags flags,
- PurpleContactInfo *info = NULL;
- PurpleConversation *conv;
- PurpleConversationManager *manager;
- if (!(flags & PURPLE_MESSAGE_SEND)) {
- purple_serv_got_chat_in(gc, id, who, flags, text, timestamp);
- acct = purple_connection_get_account(gc);
- info = PURPLE_CONTACT_INFO(acct);
- manager = purple_conversation_manager_get_default();
- conv = purple_conversation_manager_find_chat_by_id(manager, acct, id);
- me = purple_contact_info_get_name_for_display(info);
- name = purple_contact_info_get_username(info);
- msg = purple_message_new_outgoing(acct, me, name, text, flags);
- dt = g_date_time_new_from_unix_local((gint64)timestamp);
- purple_message_set_timestamp(msg, dt);
- purple_conversation_write_message(conv, msg);
- g_object_unref(G_OBJECT(msg));
-fb_util_strtest(const gchar *str, GAsciiType type)
- g_return_val_if_fail(str != NULL, FALSE);
- for (i = 0; i < size; i++) {
- if ((g_ascii_table[c] & type) == 0) {
-fb_util_zlib_test(const GByteArray *bytes)
- g_return_val_if_fail(bytes != NULL, FALSE);
- b0 = *(bytes->data + 0);
- b1 = *(bytes->data + 1);
- return ((((b0 << 8) | b1) % 31) == 0) && /* Check the header */
- ((b0 & 0x0F) == 8 /* Z_DEFLATED */); /* Check the method */
-fb_util_zlib_conv(GConverter *conv, const GByteArray *bytes, GError **error)
- ret = g_byte_array_new();
- res = g_converter_convert(conv,
- G_CONVERTER_INPUT_AT_END,
- case G_CONVERTER_CONVERTED:
- g_byte_array_append(ret, data, wize);
- case G_CONVERTER_ERROR:
- g_byte_array_free(ret, TRUE);
- case G_CONVERTER_FINISHED:
- g_byte_array_append(ret, data, wize);
-fb_util_zlib_deflate(const GByteArray *bytes, GError **error)
- conv = g_zlib_compressor_new(G_ZLIB_COMPRESSOR_FORMAT_ZLIB, -1);
- ret = fb_util_zlib_conv(G_CONVERTER(conv), bytes, error);
-fb_util_zlib_inflate(const GByteArray *bytes, GError **error)
- GZlibDecompressor *conv;
- conv = g_zlib_decompressor_new(G_ZLIB_COMPRESSOR_FORMAT_ZLIB);
- ret = fb_util_zlib_conv(G_CONVERTER(conv), bytes, error);
--- a/libpurple/protocols/facebook/util.h Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,335 +0,0 @@
- * 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
- * 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_FACEBOOK_UTIL_H
-#define PURPLE_FACEBOOK_UTIL_H
- * Shortcut #PurpleDebugLevel for unsafe and verbose info messages.
-#define FB_UTIL_DEBUG_INFO ( \
- FB_UTIL_DEBUG_FLAG_UNSAFE | \
- FB_UTIL_DEBUG_FLAG_VERBOSE \
- * The #GQuark of the domain of utility errors.
-#define FB_UTIL_ERROR fb_util_error_quark()
- * FbUtilRequestBuddyFunc:
- * @buddies: The list of #PurpleBuddy's.
- * @data: The user-defined data.
- * The callback for requested buddies.
-typedef void (*FbUtilRequestBuddyFunc) (GSList *buddies, gpointer data);
- * @FB_UTIL_DEBUG_FLAG_UNSAFE: The message is unsafe.
- * @FB_UTIL_DEBUG_FLAG_VERBOSE: The message is verbose.
- * @FB_UTIL_DEBUG_FLAG_ALL: All of the flags.
- * The debugging message flags. These flags are inserted on top of
- FB_UTIL_DEBUG_FLAG_UNSAFE = 1 << 25,
- FB_UTIL_DEBUG_FLAG_VERBOSE = 1 << 26,
- FB_UTIL_DEBUG_FLAG_ALL = 3 << 25
- * @FB_UTIL_ERROR_GENERAL: General failure.
- * The error codes for the #FB_UTIL_ERROR domain.
- * Gets the #GQuark of the domain of utility errors.
- * Returns: The #GQuark of the domain.
-fb_util_error_quark(void);
- * fb_util_account_find_buddy:
- * @acct: The #PurpleAccount.
- * @chat: The #PurpleChatConversation.
- * @name: The name of the buddy.
- * @error: The return location for the #GError or #NULL.
- * Finds a buddy by their name or alias.
- * Returns: (transfer none): The #PurpleBuddy if found, otherwise #NULL.
-fb_util_account_find_buddy(PurpleAccount *acct, PurpleChatConversation *chat,
- const gchar *name, GError **error);
- * @level: The #PurpleDebugLevel.
- * @format: The format string literal.
- * @...: The arguments for @format.
- * Logs a debugging message. If the messages is unsafe or verbose,
- * apply the appropriate #FbUtilDebugFlags.
-fb_util_debug(PurpleDebugLevel level, const gchar *format, ...)
- * @level: The #PurpleDebugLevel.
- * @format: The format string literal.
- * Logs a debugging message. If the messages is unsafe or verbose,
- * apply the appropriate #FbUtilDebugFlags.
-fb_util_vdebug(PurpleDebugLevel level, const gchar *format, va_list ap);
- * @format: The format string literal.
- * @...: The arguments for @format.
- * Logs a debugging message with the level of #PURPLE_DEBUG_MISC.
-fb_util_debug_misc(const gchar *format, ...)
- * @format: The format string literal.
- * @...: The arguments for @format.
- * Logs a debugging message with the level of #PURPLE_DEBUG_INFO.
-fb_util_debug_info(const gchar *format, ...)
- * fb_util_debug_warning:
- * @format: The format string literal.
- * @...: The arguments for @format.
- * Logs a debugging message with the level of #PURPLE_DEBUG_WARNING.
-fb_util_debug_warning(const gchar *format, ...)
- * @format: The format string literal.
- * @...: The arguments for @format.
- * Logs a debugging message with the level of #PURPLE_DEBUG_ERROR.
-fb_util_debug_error(const gchar *format, ...)
- * @format: The format string literal.
- * @...: The arguments for @format.
- * Logs a debugging message with the level of #PURPLE_DEBUG_FATAL.
-fb_util_debug_fatal(const gchar *format, ...)
- * fb_util_debug_hexdump:
- * @level: The #PurpleDebugLevel.
- * @bytes: The #GByteArray.
- * @format: The format string literal.
- * @...: The arguments for @format.
- * Logs a hexdump of a #GByteArray. If the messages is unsafe or
- * verbose, apply the appropriate #FbUtilDebugFlags.
-fb_util_debug_hexdump(PurpleDebugLevel level, const GByteArray *bytes,
- const gchar *format, ...)
- * Gets the locale string (ex: en_US) from the system. The returned
- * string should be freed with #g_free() when no longer needed.
- * Returns: The locale string.
-fb_util_get_locale(void);
- * @len: The length of the string.
- * Gets a random alphanumeric (A-Za-z0-9) string. This function should
- * *not* be relied on for cryptographic operations. The returned string
- * should be freed with #g_free() when no longer needed.
- * Returns: The alphanumeric string.
-fb_util_rand_alnum(guint len);
- * fb_util_request_buddy:
- * @gc: The #PurpleConnection.
- * @title: The title of the message or #NULL.
- * @primary: The main point of the message or #NULL.
- * @secondary: The secondary information or #NULL.
- * @select: (element-type PurpleBuddy): A #GSList of selected buddies or #NULL.
- * @multi: #TRUE to for multiple buddy selections, otherwise #FALSE.
- * @ok_cb: (scope async): The callback for the `OK` button or #NULL.
- * @cancel_cb: (scope async): The callback for the `Cancel` button or #NULL.
- * @data: The user-defined data.
- * Displays a buddy list selection form.
- * Returns: The UI-specific handle.
-fb_util_request_buddy(PurpleConnection *gc, const gchar *title,
- const gchar *primary, const gchar *secondary,
- GSList *select, gboolean multi, GCallback ok_cb,
- GCallback cancel_cb, gpointer data);
- * @gc: The #PurpleConnection.
- * @who: The message sender or receiver.
- * @text: The message text.
- * @flags: The #PurpleMessageFlags.
- * @timestamp: The message timestamp.
- * Handles an incoming IM message. This function is special in that it
- * handles self messages. This function determines the direction of the
- * message from the #PurpleMessageFlags.
-fb_util_serv_got_im(PurpleConnection *gc, const gchar *who, const gchar *text,
- PurpleMessageFlags flags, guint64 timestamp);
- * fb_util_serv_got_chat_in:
- * @gc: The #PurpleConnection.
- * @id: The id of the chat.
- * @who: The message sender or receiver.
- * @text: The message text.
- * @flags: The #PurpleMessageFlags.
- * @timestamp: The message timestamp.
- * Handles an incoming chat message. This function is special in that
- * it handles self messages. This function determines the direction of
- * the message from the #PurpleMessageFlags.
-fb_util_serv_got_chat_in(PurpleConnection *gc, gint id, const gchar *who,
- const gchar *text, PurpleMessageFlags flags,
- * @type: The #GAsciiType.
- * Tests if the string only contains characters allowed by the
- * #GAsciiType. More than one type can be specified by ORing the types
- * Returns: #TRUE if the string only contains characters allowed by the
- * #GAsciiType, otherwise #FALSE.
-fb_util_strtest(const gchar *str, GAsciiType type);
- * @bytes: The #GByteArray.
- * Tests if the #GByteArray is zlib compressed.
- * Returns: #TRUE if the #GByteArray is compressed, otherwise #FALSE.
-fb_util_zlib_test(const GByteArray *bytes);
- * fb_util_zlib_deflate:
- * @bytes: The #GByteArray.
- * @error: The return location for the #GError or #NULL.
- * Deflates a #GByteArray with zlib. The returned #GByteArray should be
- * freed with #g_byte_array_free() when no longer needed.
- * Returns: (transfer full): The deflated #GByteArray or #NULL on error.
-fb_util_zlib_deflate(const GByteArray *bytes, GError **error);
- * fb_util_zlib_inflate:
- * @bytes: The #GByteArray.
- * @error: The return location for the #GError or #NULL.
- * Inflates a #GByteArray with zlib. The returned #GByteArray should be
- * freed with #g_byte_array_free() when no longer needed.
- * Returns: (transfer full): The inflated #GByteArray or #NULL on error.
-fb_util_zlib_inflate(const GByteArray *bytes, GError **error);
-#endif /* PURPLE_FACEBOOK_UTIL_H */
--- a/libpurple/protocols/meson.build Wed Mar 29 23:21:45 2023 -0500
+++ b/libpurple/protocols/meson.build Wed Mar 29 23:22:41 2023 -0500
@@ -1,6 +1,5 @@
--- a/po/POTFILES.in Wed Mar 29 23:21:45 2023 -0500
+++ b/po/POTFILES.in Wed Mar 29 23:22:41 2023 -0500
@@ -79,14 +79,6 @@
libpurple/protocols/demo/purpledemocontacts.c
libpurple/protocols/demo/purpledemoplugin.c
libpurple/protocols/demo/purpledemoprotocol.c
-libpurple/protocols/facebook/api.c
-libpurple/protocols/facebook/data.c
-libpurple/protocols/facebook/facebook.c
-libpurple/protocols/facebook/http.c
-libpurple/protocols/facebook/json.c
-libpurple/protocols/facebook/mqtt.c
-libpurple/protocols/facebook/thrift.c
-libpurple/protocols/facebook/util.c
libpurple/protocols/gg/avatar.c
libpurple/protocols/gg/blist.c
libpurple/protocols/gg/chat.c