adium: 7fdc885e: applied changes from f8ec537d9500e49f390...
evands at pidgin.im
evands at pidgin.im
Sat Nov 13 09:42:57 EST 2010
----------------------------------------------------------------------
Revision: 7fdc885e727b6167fa8238bce645b6c021a91e32
Parent: 3ce0bc8e8aa53725cf63a582be307a16a5602906
Author: evands at pidgin.im
Date: 11/01/10 23:37:04
Branch: im.pidgin.adium
URL: http://d.pidgin.im/viewmtn/revision/info/7fdc885e727b6167fa8238bce645b6c021a91e32
Changelog:
applied changes from f8ec537d9500e49f390edd63f33de0d22a2c7e56
through b749d0705821b037f8e05755779d8a10c1b093c3
Changes against parent 3ce0bc8e8aa53725cf63a582be307a16a5602906
added libpurple/protocols/jabber/auth_fb.c
added libpurple/protocols/jabber/fbapi.c
added libpurple/protocols/jabber/fbapi.h
patched libpurple/protocols/jabber/Makefile.am
patched libpurple/protocols/jabber/auth.c
patched libpurple/protocols/jabber/auth.h
-------------- next part --------------
============================================================
--- libpurple/protocols/jabber/Makefile.am 9c9c664e7262b61ad796bba3066f6813dcf5c613
+++ libpurple/protocols/jabber/Makefile.am 476bea6906d6274c395997cc38eeff26468f1e52
@@ -11,6 +11,7 @@ JABBERSOURCES = \
auth.c \
auth.h \
auth_digest_md5.c \
+ auth_fb.c \
auth_plain.c \
auth_scram.c \
auth_scram.h \
@@ -26,6 +27,8 @@ JABBERSOURCES = \
data.h \
disco.c \
disco.h \
+ fbapi.c \
+ fbapi.h \
google/gmail.c \
google/gmail.h \
google/google.c \
============================================================
--- libpurple/protocols/jabber/auth.c 8bbd39c21dc1df5ca43ebf50f24777174713981b
+++ libpurple/protocols/jabber/auth.c a5c6eb8d3129570cf362d5d4ef1ac5957ceea139
@@ -513,6 +513,9 @@ void jabber_auth_init(void)
auth_mechs = g_slist_insert_sorted(auth_mechs, jabber_auth_get_cyrus_mech(), compare_mech);
#endif
+ /* Facebook */
+ auth_mechs = g_slist_insert_sorted(auth_mechs, jabber_auth_get_fb_mech(), compare_mech);
+
tmp = jabber_auth_get_scram_mechs(&count);
for (i = 0; i < count; ++i)
auth_mechs = g_slist_insert_sorted(auth_mechs, tmp[i], compare_mech);
============================================================
--- libpurple/protocols/jabber/auth.h 6d90cee7211707669e36c0a25f003c8e0c7c5bc3
+++ libpurple/protocols/jabber/auth.h 8ed6e72b0ded4367703f0a7c095d61ceae4a5ece
@@ -57,6 +57,7 @@ JabberSaslMech *jabber_auth_get_cyrus_me
#ifdef HAVE_CYRUS_SASL
JabberSaslMech *jabber_auth_get_cyrus_mech(void);
#endif
+JabberSaslMech *jabber_auth_get_fb_mech(void);
void jabber_auth_init(void);
void jabber_auth_uninit(void);
============================================================
--- /dev/null
+++ libpurple/protocols/jabber/auth_fb.c 19a37944c2c3aad11208be00d18ed6972b0bddb5
@@ -0,0 +1,156 @@
+/*
+ * purple - Jabber Protocol Plugin
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ */
+#include "internal.h"
+
+#include "account.h"
+#include "debug.h"
+#include "request.h"
+#include "util.h"
+#include "xmlnode.h"
+
+#include "jabber.h"
+#include "auth.h"
+
+#include "fbapi.h"
+
+static JabberSaslState
+fb_handle_challenge(JabberStream *js, xmlnode *packet,
+ xmlnode **response, char **msg)
+{
+ xmlnode *reply = NULL;
+ gchar *challenge;
+ guchar *decoded;
+ gsize decoded_len;
+ gchar **pairs, *method, *nonce;
+ gsize i;
+ GString *request;
+ gchar *enc_out;
+
+ /* Get base64-encoded challenge from XML */
+ challenge = xmlnode_get_data(packet);
+ if (challenge == NULL) {
+ *msg = g_strdup(_("Invalid response from server"));
+ return JABBER_SASL_STATE_FAIL;
+ }
+
+ /* Decode challenge */
+ decoded = purple_base64_decode(challenge, &decoded_len);
+ if (decoded == NULL) {
+ purple_debug_error("jabber", "X-FACEBOOK-PLATFORM challenge "
+ "wasn't valid base64: %s\n", challenge);
+
+ *msg = g_strdup(_("Invalid response from server"));
+
+ g_free(challenge);
+ return JABBER_SASL_STATE_FAIL;
+ }
+ g_free(challenge);
+
+ /* NULL-terminate the challenge so we can parse it */
+ challenge = g_strndup((const gchar *)decoded, decoded_len);
+ g_free(decoded);
+ purple_debug_misc("jabber", "X-FACEBOOK-PLATFORM decoded "
+ "challenge is %s\n", challenge);
+
+ /* Get method and nonce */
+ method = NULL;
+ nonce = NULL;
+ pairs = g_strsplit(challenge, "&", 0);
+ for (i = 0; pairs[i] != NULL; i++) {
+ if (g_str_has_prefix(pairs[i], "method=")) {
+ g_free(method);
+ // TODO: Should url decode this value
+ method = g_strdup(strchr(pairs[i], '=') + 1);
+ } else if (g_str_has_prefix(pairs[i], "nonce=")) {
+ g_free(nonce);
+ // TODO: Should url decode this value
+ nonce = g_strdup(strchr(pairs[i], '=') + 1);
+ }
+ }
+ g_strfreev(pairs);
+ if (!method || !nonce) {
+ purple_debug_error("jabber", "X-FACEBOOK-PLATFORM challenge "
+ "is missing method or nonce: %s\n", challenge);
+ *msg = g_strdup(_("Invalid response from server"));
+
+ g_free(method);
+ g_free(nonce);
+ g_free(challenge);
+ return JABBER_SASL_STATE_FAIL;
+ }
+ g_free(challenge);
+
+ request = purple_fbapi_construct_request(purple_connection_get_account(js->gc),
+ method,
+ "v", "1.0",
+ "session_key", purple_connection_get_password(js->gc),
+ "nonce", nonce,
+ NULL);
+ g_free(method);
+ g_free(nonce);
+
+ purple_debug_misc("jabber", "X-FACEBOOK-PLATFORM response before "
+ "encoding is %s\n", request->str);
+ enc_out = purple_base64_encode((const guchar *)request->str, request->len);
+ g_string_free(request, TRUE);
+
+ reply = xmlnode_new("response");
+ xmlnode_set_namespace(reply, NS_XMPP_SASL);
+ xmlnode_insert_data(reply, enc_out, -1);
+
+ g_free(enc_out);
+
+ *response = reply;
+
+ return JABBER_SASL_STATE_CONTINUE;
+}
+
+static JabberSaslState
+fb_start(JabberStream *js, xmlnode *packet, xmlnode **response, char **error)
+{
+
+ /* When connecting with X-FACEBOOK-PLATFORM, the password field must be set to the
+ * OAUTH 2.0 session key.
+ */
+ xmlnode *auth = xmlnode_new("auth");
+ xmlnode_set_namespace(auth, "urn:ietf:params:xml:ns:xmpp-sasl");
+ xmlnode_set_attrib(auth, "mechanism", "X-FACEBOOK-PLATFORM");
+
+ *response = auth;
+ return JABBER_SASL_STATE_CONTINUE;
+}
+
+static JabberSaslMech fb_mech = {
+ 255, /* priority */
+ "X-FACEBOOK-PLATFORM", /* name */
+ fb_start,
+ fb_handle_challenge, /* handle_challenge */
+ NULL, /* handle_success */
+ NULL, /* handle_failure */
+ NULL /* dispose */
+};
+
+JabberSaslMech *jabber_auth_get_fb_mech(void)
+{
+ return &fb_mech;
+}
============================================================
--- /dev/null
+++ libpurple/protocols/jabber/fbapi.c 0542e3b2cf3e85c89d308bc6589382a74ef0e542
@@ -0,0 +1,377 @@
+/*
+ * This is the property of its developers. See the COPYRIGHT file
+ * for more details.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/time.h>
+
+#include "internal.h"
+#include "cipher.h"
+#include "debug.h"
+#include "util.h"
+
+#include "fbapi.h"
+
+#define API_URL "http://api.facebook.com/restserver.php"
+#define API_SECRET "INSERT_SECRET_HERE"
+#define MAX_CONNECTION_ATTEMPTS 3
+
+struct _PurpleFbApiCall {
+ gchar *request;
+ PurpleUtilFetchUrlData *url_data;
+ PurpleFbApiCallback callback;
+ gpointer user_data;
+ GDestroyNotify user_data_destroy_func;
+ unsigned int attempt_number;
+};
+
+static GSList *apicalls = NULL;
+
+/*
+ * Try to strip characters that are not valid XML. The string is
+ * changed in-place. This was needed because of this bug:
+ * http://bugs.developers.facebook.com/show_bug.cgi?id=2840
+ * That bug has been fixed, so it's possible this isn't necessary
+ * anymore.
+ *
+ * This page lists which characters are valid:
+ * http://www.w3.org/TR/2008/REC-xml-20081126/#charsets
+ *
+ * Valid XML characters are:
+ * #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
+ *
+ * Invalid XML characters are:
+ * [#x0-#x8] | #xB | #xC | [#xE-#x1F] | [#xD800-#xDFFF] | #xFFFE | #xFFFF
+ * | [#x110000-#xFFFFFFFF]
+ *
+ * Note: We could maybe use purple_utf8_strip_unprintables() for this (that
+ * function was added after we had already started using this), but
+ * we know this function works and changing it is scary.
+ */
+static void purple_fbapi_xml_salvage(char *str)
+{
+ gchar *tmp;
+ gunichar unichar;
+
+ for (tmp = str; tmp[0] != '\0'; tmp = g_utf8_next_char(tmp))
+ {
+ unichar = g_utf8_get_char(tmp);
+ if ((unichar >= 0x1 && unichar <= 0x8)
+ || unichar == 0xb
+ || unichar == 0xc
+ || (unichar >= 0xe && unichar <= 0x1f)
+ || (unichar >= 0xd800 && unichar <= 0xdfff)
+ || unichar == 0xfffe
+ || unichar == 0xffff
+ || unichar >= 0x110000)
+ {
+ /* This character is not valid XML so replace it with question marks */
+ purple_debug_error("fbapi", "Replacing invalid "
+ "XML character %08x with question marks\n",
+ unichar);
+
+ tmp[0] = '?';
+ if (unichar & 0x0000ff00)
+ tmp[1] = '?';
+ if (unichar & 0x00ff0000)
+ tmp[2] = '?';
+ if (unichar & 0xff000000)
+ tmp[3] = '?';
+ }
+ }
+}
+
+static void purple_fbapi_request_fetch_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, gsize len, const gchar *error_message)
+{
+ PurpleFbApiCall *apicall;
+ xmlnode *response;
+ PurpleConnectionError error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
+ char *error_message2 = NULL;
+
+ apicall = user_data;
+
+ if (error_message != NULL) {
+ /* Request failed */
+
+ if (apicall->attempt_number < MAX_CONNECTION_ATTEMPTS) {
+ /* Retry! */
+ apicall->url_data = purple_util_fetch_url_request(API_URL,
+ TRUE, NULL, FALSE, apicall->request, FALSE,
+ purple_fbapi_request_fetch_cb, apicall);
+ apicall->attempt_number++;
+ return;
+ }
+
+ response = NULL;
+ error_message2 = g_strdup(error_message);
+ error = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
+ } else if (url_text != NULL && len > 0) {
+ /* Parse the response as XML */
+ response = xmlnode_from_str(url_text, len);
+
+ if (response == NULL)
+ {
+ gchar *salvaged;
+
+ if (g_utf8_validate(url_text, len, NULL)) {
+ salvaged = g_strdup(url_text);
+ } else {
+ /* Facebook responded with invalid UTF-8. Bastards. */
+ purple_debug_error("fbapi", "Response is not valid UTF-8\n");
+ salvaged = purple_utf8_salvage(url_text);
+ }
+
+ purple_fbapi_xml_salvage(salvaged);
+ response = xmlnode_from_str(salvaged, -1);
+ g_free(salvaged);
+ }
+
+ if (response == NULL) {
+ purple_debug_error("fbapi", "Could not parse response as XML: %*s\n",
+ (int)len, url_text);
+ error_message2 = g_strdup(_("Invalid response from server"));
+ } else if (g_str_equal(response->name, "error_response")) {
+ /*
+ * The response is an error message, in the standard format
+ * for errors from API calls.
+ */
+ xmlnode *tmp;
+ char *tmpstr;
+
+ tmp = xmlnode_get_child(response, "error_code");
+ if (tmp != NULL) {
+ tmpstr = xmlnode_get_data_unescaped(tmp);
+ if (tmpstr != NULL && strcmp(tmpstr, "293") == 0) {
+ error_message2 = g_strdup(_("Need chat permission"));
+ error = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
+ }
+ g_free(tmpstr);
+ }
+ if (error_message2 == NULL) {
+ error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
+ tmp = xmlnode_get_child(response, "error_msg");
+ if (tmp != NULL)
+ error_message2 = xmlnode_get_data_unescaped(tmp);
+ }
+ if (error_message2 == NULL)
+ error_message2 = g_strdup(_("Unknown"));
+ } else {
+ error_message2 = NULL;
+ }
+ } else {
+ /* Response body was empty */
+ response = NULL;
+ error_message2 = NULL;
+ }
+
+ if (apicall->attempt_number > 1 || error_message2 != NULL)
+ purple_debug_error("fbapi", "Request '%s' %s after %u attempts: %s\n",
+ apicall->request,
+ error_message == NULL ? "succeeded" : "failed",
+ apicall->attempt_number, error_message2);
+
+ /*
+ * The request either succeeded or failed the maximum number of
+ * times. In either case, pass control off to the callback
+ * function and let them decide what to do.
+ */
+ apicall->callback(apicall, apicall->user_data, response, error, error_message2);
+ apicall->url_data = NULL;
+ purple_fbapi_request_destroy(apicall);
+
+ xmlnode_free(response);
+ g_free(error_message2);
+}
+
+static gboolean concat_params(gpointer key, gpointer value, gpointer data)
+{
+ GString *tmp;
+
+ tmp = data;
+ g_string_append_printf(tmp, "%s=%s", (const char *)key, (const char *)value);
+
+ return FALSE;
+}
+
+/**
+ * @return A Newly allocated base16 encoded version of the md5
+ * signature calculated using the algorithm described on the
+ * Facebook developer wiki. This string must be g_free'd.
+ */
+static char *generate_signature(const char *api_secret, const GTree *params)
+{
+ GString *tmp;
+ unsigned char hashval[16];
+
+ tmp = g_string_new(NULL);
+ g_tree_foreach((GTree *)params, concat_params, tmp);
+ g_string_append(tmp, api_secret);
+
+ purple_cipher_digest_region("md5", (const unsigned char *)tmp->str,
+ tmp->len, sizeof(hashval), hashval, NULL);
+ g_string_free(tmp, TRUE);
+
+ return purple_base16_encode(hashval, sizeof(hashval));
+}
+
+static gboolean append_params_to_body(gpointer key, gpointer value, gpointer data)
+{
+ GString *body;
+
+ body = data;
+
+ if (body->len > 0)
+ g_string_append_c(body, '&');
+
+ g_string_append(body, purple_url_encode(key));
+ g_string_append_c(body, '=');
+ g_string_append(body, purple_url_encode(value));
+
+ return FALSE;
+}
+
+static GString *purple_fbapi_construct_request_vargs(PurpleAccount *account, const char *method, va_list args)
+{
+ GTree *params;
+ const char *api_key, *api_secret;
+ const char *key, *value;
+ char call_id[21];
+ char *signature;
+ GString *body;
+
+ /* Read all paramters into a sorted tree */
+ params = g_tree_new((GCompareFunc)strcmp);
+ while ((key = va_arg(args, const char *)) != NULL)
+ {
+ value = va_arg(args, const char *);
+ g_tree_insert(params, (char *)key, (char *)value);
+
+ /* If we have a session_key then we need a call_id */
+ if (g_str_equal(key, "session_key")) {
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL) != 0) {
+ time_t now;
+ purple_debug_error("fbapi",
+ "Error calling gettimeofday(): %s\n",
+ g_strerror(errno));
+ now = time(NULL);
+ strftime(call_id, sizeof(call_id), "%s000000", localtime(&now));
+ } else {
+ char tmp[22];
+ strftime(tmp, sizeof(tmp), "%s", localtime(&tv.tv_sec));
+ sprintf(call_id, "%s%06lu", tmp, tv.tv_usec);
+ }
+ g_tree_insert(params, "call_id", call_id);
+ }
+ }
+
+ api_key = purple_account_get_string(account, "fb_api_key", PURPLE_FBAPI_KEY);
+ api_secret = purple_account_get_string(account, "fb_api_secret", API_SECRET);
+
+ /* Add the method and api_key parameters to the list */
+ g_tree_insert(params, "method", (char *)method);
+ g_tree_insert(params, "api_key", (char *)api_key);
+
+ /* Add the signature parameter to the list */
+ signature = generate_signature((char *)api_secret, params);
+ g_tree_insert(params, "sig", signature);
+
+ /* Construct the body of the HTTP POST request */
+ body = g_string_new(NULL);
+ g_tree_foreach(params, append_params_to_body, body);
+ g_tree_destroy(params);
+ g_free(signature);
+
+ return body;
+}
+
+GString *purple_fbapi_construct_request(PurpleAccount *account, const char *method, ...)
+{
+ va_list args;
+ GString *body;
+
+ va_start(args, method);
+ body = purple_fbapi_construct_request_vargs(account, method, args);
+ va_end(args);
+
+ return body;
+}
+
+PurpleFbApiCall *purple_fbapi_request_vargs(PurpleAccount *account, PurpleFbApiCallback callback, gpointer user_data, GDestroyNotify user_data_destroy_func, const char *method, va_list args)
+{
+ GString *body;
+ PurpleFbApiCall *apicall;
+
+ body = purple_fbapi_construct_request_vargs(account, method, args);
+
+ /* Construct an HTTP POST request */
+ apicall = g_new(PurpleFbApiCall, 1);
+ apicall->callback = callback;
+ apicall->user_data = user_data;
+ apicall->user_data_destroy_func = user_data_destroy_func;
+ apicall->attempt_number = 1;
+
+ apicall->request = g_strdup_printf("POST /restserver.php HTTP/1.0\r\n"
+ "Connection: close\r\n"
+ "Accept: */*\r\n"
+ "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n"
+ "Content-Length: %zu\r\n\r\n%s", body->len, body->str);
+ g_string_free(body, TRUE);
+
+ apicall->url_data = purple_util_fetch_url_request(API_URL,
+ TRUE, NULL, FALSE, apicall->request, FALSE,
+ purple_fbapi_request_fetch_cb, apicall);
+
+ apicalls = g_slist_prepend(apicalls, apicall);
+
+ return apicall;
+}
+
+PurpleFbApiCall *purple_fbapi_request(PurpleAccount *account, PurpleFbApiCallback callback, gpointer user_data, GDestroyNotify user_data_destroy_func, const char *method, ...)
+{
+ va_list args;
+ PurpleFbApiCall *apicall;
+
+ va_start(args, method);
+ apicall = purple_fbapi_request_vargs(account, callback, user_data, user_data_destroy_func, method, args);
+ va_end(args);
+
+ return apicall;
+}
+
+void purple_fbapi_request_destroy(PurpleFbApiCall *apicall)
+{
+ apicalls = g_slist_remove(apicalls, apicall);
+
+ if (apicall->url_data != NULL)
+ purple_util_fetch_url_cancel(apicall->url_data);
+
+ if (apicall->user_data != NULL && apicall->user_data_destroy_func != NULL)
+ apicall->user_data_destroy_func(apicall->user_data);
+
+ g_free(apicall->request);
+ g_free(apicall);
+}
+
+void purple_fbapi_uninit(void)
+{
+ while (apicalls != NULL)
+ purple_fbapi_request_destroy(apicalls->data);
+}
============================================================
--- /dev/null
+++ libpurple/protocols/jabber/fbapi.h 577175234144e0463a77f0a69f7ff2d8cb5c49c4
@@ -0,0 +1,106 @@
+/*
+ * libfacebook
+ *
+ * libfacebook is the property of its developers. See the COPYRIGHT file
+ * for more details.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FBAPI_H
+#define FBAPI_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <glib.h>
+
+#include "connection.h"
+
+#define PURPLE_FBAPI_KEY "INSERT_KEY_HERE"
+
+typedef struct _PurpleFbApiCall PurpleFbApiCall;
+
+/**
+ * This is the callback function when a response is received to an API
+ * request. The response will always be parsed as XML.
+ *
+ * error_message will be set if the physical TCP connection failed, or
+ * if the API call returned <error_response> as the top level node in
+ * the document.
+ *
+ * error will be set if and only if error_message is set.
+ *
+ * response will be null if error_message is non-null or if the
+ * response was not valid XML. So if error_message == NULL &&
+ * response == NULL then you know the body was malformed XML.
+ */
+typedef void (*PurpleFbApiCallback)(PurpleFbApiCall *apicall, gpointer user_data, const xmlnode *response, PurpleConnectionError error, const gchar *error_message);
+
+/**
+ * Construct the body of a Facebook API request.
+ *
+ * @param account PurpleAccount of the user
+ * @param method The API method to call. For example, auth.getSession or
+ * events.get.
+ * @param attrs key/value pairs of request arguments. The list must be
+ * terminated with a NULL. It should not contain the method,
+ * api_key, call_id, or sig parameters--these will be appended
+ * for you.
+ */
+GString *purple_fbapi_construct_request(PurpleAccount *account, const char *method, ...) G_GNUC_NULL_TERMINATED;
+
+/**
+ * @param account PurpleAccount of the user
+ * @param args key/value pairs that will be POSTed to the API URL. The
+ * list must be terminated with a NULL. It should not contain
+ * the method, api_key, call_id, or sig parameters--these will be
+ * appended for you.
+ * @see purple_fbapi_request
+ */
+PurpleFbApiCall *purple_fbapi_request_vargs(PurpleAccount *account, PurpleFbApiCallback callback, gpointer user_data, GDestroyNotify user_data_destroy_func, const char *method, va_list args);
+
+/**
+ * @param account PurpleAccount of the user
+ * @param callback The callback function that should be called when we
+ * receive a response from the server.
+ * @param user_data Optional data to pass to the callback function.
+ * @param user_data_destroy_func An option function to be called and
+ * passed user_data to free it after this request has finished
+ * or been canceled.
+ * @param method The API method to call. For example, auth.getSession or
+ * events.get.
+ * @param attrs key/value pairs that will be POSTed to the API URL. The
+ * list must be terminated with a NULL. It should not contain
+ * the method, api_key, call_id, or sig parameters--these will be
+ * appended for you.
+ */
+PurpleFbApiCall *purple_fbapi_request(PurpleAccount *account, PurpleFbApiCallback callback, gpointer user_data, GDestroyNotify user_data_destroy_func, const char *method, ...) G_GNUC_NULL_TERMINATED;
+
+/*
+ * Destroy a single pending API request.
+ */
+void purple_fbapi_request_destroy(PurpleFbApiCall *apicall);
+
+/**
+ * Destroy all pending API requests.
+ */
+void purple_fbapi_uninit(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FBAPI_H */
More information about the Commits
mailing list