diff options
author | Tomasz Wasilczyk <tomkiewicz@cpw.pidgin.im> | 2012-08-19 12:41:35 +0200 |
---|---|---|
committer | Tomasz Wasilczyk <tomkiewicz@cpw.pidgin.im> | 2012-08-19 12:41:35 +0200 |
commit | 8855cd1744982294ae70b03ed143888d5d9a1f40 (patch) | |
tree | 2f88740687af6c1b6a4d471a5ede6b020c34cf54 | |
parent | ef21b3967c08e98542e9b67190c084a7571b31a6 (diff) | |
download | pidgin-8855cd1744982294ae70b03ed143888d5d9a1f40.tar.gz |
Gadu-Gadu: extended OAuth support, initial support for gg10.5 public directory
-rw-r--r-- | libpurple/protocols/gg/Makefile.am | 2 | ||||
-rw-r--r-- | libpurple/protocols/gg/avatar.c | 2 | ||||
-rw-r--r-- | libpurple/protocols/gg/gg.c | 18 | ||||
-rw-r--r-- | libpurple/protocols/gg/oauth/oauth-purple.c | 41 | ||||
-rw-r--r-- | libpurple/protocols/gg/oauth/oauth-purple.h | 2 | ||||
-rw-r--r-- | libpurple/protocols/gg/oauth/oauth.c | 4 | ||||
-rw-r--r-- | libpurple/protocols/gg/pubdir-prpl.c | 213 | ||||
-rw-r--r-- | libpurple/protocols/gg/pubdir-prpl.h | 28 | ||||
-rw-r--r-- | libpurple/protocols/gg/xml.c | 41 | ||||
-rw-r--r-- | libpurple/protocols/gg/xml.h | 2 |
10 files changed, 339 insertions, 14 deletions
diff --git a/libpurple/protocols/gg/Makefile.am b/libpurple/protocols/gg/Makefile.am index dc4d8eec75..f002df5f80 100644 --- a/libpurple/protocols/gg/Makefile.am +++ b/libpurple/protocols/gg/Makefile.am @@ -88,6 +88,8 @@ GGSOURCES = \ status.h \ servconn.c \ servconn.h \ + pubdir-prpl.c \ + pubdir-prpl.h \ oauth/oauth.c \ oauth/oauth.h \ oauth/oauth-parameter.c \ diff --git a/libpurple/protocols/gg/avatar.c b/libpurple/protocols/gg/avatar.c index 117691bf06..90adb2d557 100644 --- a/libpurple/protocols/gg/avatar.c +++ b/libpurple/protocols/gg/avatar.c @@ -300,7 +300,7 @@ void ggp_avatar_own_set(PurpleConnection *gc, PurpleStoredImage *img) own_data->img = img; - ggp_oauth_request(gc, ggp_avatar_own_got_token, img); + ggp_oauth_request(gc, ggp_avatar_own_got_token, img, NULL, NULL); } static void ggp_avatar_own_got_token(PurpleConnection *gc, const gchar *token, diff --git a/libpurple/protocols/gg/gg.c b/libpurple/protocols/gg/gg.c index 60244e2be2..ae25f47078 100644 --- a/libpurple/protocols/gg/gg.c +++ b/libpurple/protocols/gg/gg.c @@ -1670,6 +1670,21 @@ static void ggp_action_status_broadcasting(PurplePluginAction *action) ggp_status_broadcasting_dialog((PurpleConnection *)action->context); } +#include "pubdir-prpl.h" + +static void ggp_pubdir_debug_cb(PurpleConnection *gc, int records_count, const ggp_pubdir_record *records, void *user_data) +{ + purple_debug_info("gg", "ggp_action_debug_got: [%d]\n", records_count); +} + +static void ggp_action_debug(PurplePluginAction *action) +{ + PurpleConnection *gc = action->context; + purple_debug_info("gg", "ggp_action_debug\n"); + + ggp_pubdir_get_info(gc, 5110, ggp_pubdir_debug_cb, NULL); +} + static GList *ggp_actions(PurplePlugin *plugin, gpointer context) { GList *m = NULL; @@ -1697,6 +1712,9 @@ static GList *ggp_actions(PurplePlugin *plugin, gpointer context) ggp_action_buddylist_load); m = g_list_append(m, act); + act = purple_plugin_action_new("Debug action", ggp_action_debug); + m = g_list_append(m, act); + return m; } diff --git a/libpurple/protocols/gg/oauth/oauth-purple.c b/libpurple/protocols/gg/oauth/oauth-purple.c index 7ea2c19a86..42d25fc1cb 100644 --- a/libpurple/protocols/gg/oauth/oauth-purple.c +++ b/libpurple/protocols/gg/oauth/oauth-purple.c @@ -15,6 +15,8 @@ typedef struct gpointer user_data; gchar *token; gchar *token_secret; + + gchar *sign_method, *sign_url; } ggp_oauth_data; static void ggp_oauth_data_free(ggp_oauth_data *data); @@ -35,11 +37,13 @@ static void ggp_oauth_data_free(ggp_oauth_data *data) { g_free(data->token); g_free(data->token_secret); + g_free(data->sign_method); + g_free(data->sign_url); g_free(data); } void ggp_oauth_request(PurpleConnection *gc, ggp_oauth_request_cb callback, - gpointer user_data) + gpointer user_data, const gchar *sign_method, const gchar *sign_url) { PurpleAccount *account = purple_connection_get_account(gc); char *auth; @@ -48,6 +52,8 @@ void ggp_oauth_request(PurpleConnection *gc, ggp_oauth_request_cb callback, gchar *request; ggp_oauth_data *data; + g_return_if_fail((method == NULL) == (url == NULL)); + purple_debug_misc("gg", "ggp_oauth_request: requesting token...\n"); auth = gg_oauth_generate_header(method, url, @@ -66,6 +72,8 @@ void ggp_oauth_request(PurpleConnection *gc, ggp_oauth_request_cb callback, data->gc = gc; data->callback = callback; data->user_data = user_data; + data->sign_method = g_strdup(sign_method); + data->sign_url = g_strdup(sign_url); purple_util_fetch_url_request(account, url, FALSE, NULL, TRUE, request, FALSE, GGP_OAUTH_RESPONSE_MAX, ggp_oauth_request_token_got, @@ -192,7 +200,7 @@ static void ggp_oauth_access_token_got(PurpleUtilFetchUrlData *url_data, const gchar *error_message) { ggp_oauth_data *data = user_data; - gchar *token; + gchar *token, *token_secret; xmlnode *xml; gboolean succ = TRUE; @@ -206,6 +214,8 @@ static void ggp_oauth_access_token_got(PurpleUtilFetchUrlData *url_data, } succ &= ggp_xml_get_string(xml, "oauth_token", &token); + succ &= ggp_xml_get_string(xml, "oauth_token_secret", + &token_secret); xmlnode_free(xml); if (!succ || strlen(token) < 10) { @@ -215,11 +225,30 @@ static void ggp_oauth_access_token_got(PurpleUtilFetchUrlData *url_data, return; } - purple_debug_misc("gg", "ggp_oauth_access_token_got: " - "got access token\n"); - - data->callback(data->gc, token, data->user_data); + if (data->sign_url) + { + PurpleAccount *account; + gchar *auth; + + purple_debug_misc("gg", "ggp_oauth_access_token_got: " + "got access token, returning signed url\n"); + + account = purple_connection_get_account(data->gc); + auth = gg_oauth_generate_header( + data->sign_method, data->sign_url, + purple_account_get_username(account), + purple_account_get_password(account), + token, token_secret); + data->callback(data->gc, auth, data->user_data); + } + else + { + purple_debug_misc("gg", "ggp_oauth_access_token_got: " + "got access token, returning it\n"); + data->callback(data->gc, token, data->user_data); + } g_free(token); + g_free(token_secret); ggp_oauth_data_free(data); } diff --git a/libpurple/protocols/gg/oauth/oauth-purple.h b/libpurple/protocols/gg/oauth/oauth-purple.h index 10115f5824..0471e13803 100644 --- a/libpurple/protocols/gg/oauth/oauth-purple.h +++ b/libpurple/protocols/gg/oauth/oauth-purple.h @@ -8,6 +8,6 @@ typedef void (*ggp_oauth_request_cb)(PurpleConnection *gc, const gchar *token, gpointer user_data); void ggp_oauth_request(PurpleConnection *gc, ggp_oauth_request_cb callback, - gpointer user_data); + gpointer user_data, const gchar *sign_method, const gchar *sign_url); #endif /* _GGP_OAUTH_PURPLE_H */ diff --git a/libpurple/protocols/gg/oauth/oauth.c b/libpurple/protocols/gg/oauth/oauth.c index dfaf824fa3..ccc1ce9e0a 100644 --- a/libpurple/protocols/gg/oauth/oauth.c +++ b/libpurple/protocols/gg/oauth/oauth.c @@ -68,8 +68,8 @@ static char *gg_oauth_generate_signature(const char *method, const char *url, co g_free(request_e); consumer_secret_e = g_uri_escape_string(consumer_secret, NULL, FALSE); - token_secret_e = g_uri_escape_string(token_secret, NULL, FALSE); - key = g_strdup_printf("%s&%s", consumer_secret, token_secret ? token_secret : ""); + token_secret_e = token_secret ? g_uri_escape_string(token_secret, NULL, FALSE) : NULL; + key = g_strdup_printf("%s&%s", consumer_secret_e, token_secret ? token_secret_e : ""); g_free(consumer_secret_e); g_free(token_secret_e); diff --git a/libpurple/protocols/gg/pubdir-prpl.c b/libpurple/protocols/gg/pubdir-prpl.c new file mode 100644 index 0000000000..88dc3efa92 --- /dev/null +++ b/libpurple/protocols/gg/pubdir-prpl.c @@ -0,0 +1,213 @@ +#include "pubdir-prpl.h" + +#include <debug.h> + +#include "oauth/oauth-purple.h" +#include "xml.h" +#include "utils.h" + +typedef struct +{ + PurpleConnection *gc; + ggp_pubdir_request_cb cb; + void *user_data; + union + { + struct + { + uin_t uin; + } user_info; + } params; +} ggp_pubdir_request; + +void ggp_pubdir_request_free(ggp_pubdir_request *request); +void ggp_pubdir_record_free(ggp_pubdir_record *records, int count); + +static void ggp_pubdir_get_info_got_token(PurpleConnection *gc, + const gchar *token, gpointer _request); +static void ggp_pubdir_get_info_got_data(PurpleUtilFetchUrlData *url_data, + gpointer user_data, const gchar *url_text, gsize len, + const gchar *error_message); + +/******************************************************************************/ + +void ggp_pubdir_record_free(ggp_pubdir_record *records, int count) +{ + int i; + for (i = 0; i < count; i++) + { + g_free(records[i].label); + g_free(records[i].city); + } + g_free(records); +} + +void ggp_pubdir_request_free(ggp_pubdir_request *request) +{ + g_free(request); +} + +void ggp_pubdir_get_info(PurpleConnection *gc, uin_t uin, + ggp_pubdir_request_cb cb, void *user_data) +{ + ggp_pubdir_request *request = g_new0(ggp_pubdir_request, 1); + gchar *url; + + request->gc = gc; + request->cb = cb; + request->user_data = user_data; + request->params.user_info.uin = uin; + + url = g_strdup_printf("http://api.gadu-gadu.pl/users/%u", uin); + ggp_oauth_request(gc, ggp_pubdir_get_info_got_token, request, + "GET", url); + g_free(url); +} + +static void ggp_pubdir_get_info_got_token(PurpleConnection *gc, + const gchar *token, gpointer _request) +{ + gchar *http_request; + ggp_pubdir_request *request = _request; + gchar *url; + + if (!token || !PURPLE_CONNECTION_IS_VALID(gc)) + { + request->cb(gc, -1, NULL, request->user_data); + ggp_pubdir_request_free(request); + return; + } + + url = g_strdup_printf("http://api.gadu-gadu.pl/users/%u", + request->params.user_info.uin); + http_request = g_strdup_printf( + "GET /users/%u HTTP/1.1\r\n" + "Host: api.gadu-gadu.pl\r\n" + "%s\r\n" + "\r\n", + request->params.user_info.uin, + token); + + purple_util_fetch_url_request(purple_connection_get_account(gc), url, + FALSE, NULL, TRUE, http_request, FALSE, -1, + ggp_pubdir_get_info_got_data, request); + + g_free(url); + g_free(http_request); +} + +static void ggp_pubdir_get_info_got_data(PurpleUtilFetchUrlData *url_data, + gpointer _request, const gchar *url_text, gsize len, + const gchar *error_message) +{ + ggp_pubdir_request *request = _request; + PurpleConnection *gc = request->gc; + gboolean succ = TRUE; + xmlnode *xml; + unsigned int status, nextOffset; + int record_count, i; + ggp_pubdir_record *records; + + purple_debug_misc("gg", "ggp_pubdir_get_info_got_data: [%s]\n", url_text); + + xml = xmlnode_from_str(url_text, -1); + if (xml == NULL) + { + purple_debug_error("gg", "ggp_pubdir_get_info_got_data: " + "invalid xml\n"); + request->cb(gc, -1, NULL, request->user_data); + ggp_pubdir_request_free(request); + return; + } + + succ &= ggp_xml_get_uint(xml, "status", &status); + if (!ggp_xml_get_uint(xml, "nextOffset", &nextOffset)) + nextOffset = 0; + xml = xmlnode_get_child(xml, "users"); + if (!succ || status != 0 || !xml) + { + purple_debug_error("gg", "ggp_pubdir_get_info_got_data: " + "invalid reply\n"); + request->cb(gc, -1, NULL, request->user_data); + ggp_pubdir_request_free(request); + return; + } + + record_count = ggp_xml_child_count(xml, "user"); + records = g_new0(ggp_pubdir_record, record_count); + + purple_debug_info("gg", "ggp_pubdir_get_info_got_data: got %d\n", record_count); + + xml = xmlnode_get_child(xml, "user"); + i = 0; + while (xml) + { + ggp_pubdir_record *record = &records[i++]; + gchar *label = NULL, *nick = NULL, *name = NULL, + *surname = NULL, *city = NULL, *birth_s = NULL; + unsigned int gender = 0; + GTimeVal birth_g; + g_assert(i <= record_count); + + record->uin = ggp_str_to_uin(xmlnode_get_attrib(xml, "uin")); + + ggp_xml_get_string(xml, "label", &label); + ggp_xml_get_string(xml, "nick", &nick); + ggp_xml_get_string(xml, "name", &name); + ggp_xml_get_string(xml, "surname", &surname); + ggp_xml_get_string(xml, "city", &city); + ggp_xml_get_string(xml, "birth", &birth_s); + ggp_xml_get_uint(xml, "gender", &gender); + ggp_xml_get_uint(xml, "age", &record->age); + + if (label) + record->label = g_strdup(label); + else if (nick) + record->label = g_strdup(nick); + else if (name && surname) + record->label = g_strdup_printf("%s %s", name, surname); + else if (name) + record->label = g_strdup(name); + else if (surname) + record->label = g_strdup(surname); + else + { + purple_debug_warning("gg", + "ggp_pubdir_get_info_got_data: " + "invalid record\n"); + record->label = g_strdup(""); + } + + if (gender == 1) + record->gender = GGP_PUBDIR_GENDER_FEMALE; + else if (gender == 2) + record->gender = GGP_PUBDIR_GENDER_MALE; + else + record->gender = GGP_PUBDIR_GENDER_UNSPECIFIED; + + if (city && city[0] != '\0') + record->city = g_strdup(city); + + if (birth_s && g_time_val_from_iso8601(birth_s, &birth_g)) + record->birth = birth_g.tv_sec; + //TODO: calculate age from birth + + purple_debug_info("gg", "ggp_pubdir_get_info_got_data: [%d][%s][%s][%d]\n", + record->uin, record->label, record->city, record->gender); + purple_debug_info("gg", "ggp_pubdir_get_info_got_data: birth[%s][%lu]\n", + birth_s, birth); + + g_free(label); + g_free(nick); + g_free(name); + g_free(surname); + g_free(city); + + xml = xmlnode_get_next_twin(xml); + } + + request->cb(gc, record_count, records, request->user_data); + + ggp_pubdir_request_free(request); + ggp_pubdir_record_free(records, record_count); +} diff --git a/libpurple/protocols/gg/pubdir-prpl.h b/libpurple/protocols/gg/pubdir-prpl.h new file mode 100644 index 0000000000..e93df39007 --- /dev/null +++ b/libpurple/protocols/gg/pubdir-prpl.h @@ -0,0 +1,28 @@ +#ifndef _GGP_PUBDIR_PRPL_H +#define _GGP_PUBDIR_PRPL_H + +#include <internal.h> +#include <libgadu.h> + +typedef struct +{ + uin_t uin; + gchar *label; + enum + { + GGP_PUBDIR_GENDER_UNSPECIFIED, + GGP_PUBDIR_GENDER_FEMALE, + GGP_PUBDIR_GENDER_MALE, + } gender; + gchar *city; + time_t birth; + int age; +} ggp_pubdir_record; + +typedef void (*ggp_pubdir_request_cb)(PurpleConnection *gc, int records_count, + const ggp_pubdir_record *records, void *user_data); + +void ggp_pubdir_get_info(PurpleConnection *gc, uin_t uin, + ggp_pubdir_request_cb cb, void *user_data); + +#endif /* _GGP_PUBDIR_PRPL_H */ diff --git a/libpurple/protocols/gg/xml.c b/libpurple/protocols/gg/xml.c index 9cd8e79bdb..52f8099a05 100644 --- a/libpurple/protocols/gg/xml.c +++ b/libpurple/protocols/gg/xml.c @@ -12,11 +12,13 @@ gboolean ggp_xml_get_string(const xmlnode *xml, gchar *childName, gchar **var) if (childName != NULL) { xml = xmlnode_get_child(xml, childName); - g_return_val_if_fail(xml != NULL, FALSE); + if (xml == NULL) + return FALSE; } str = xmlnode_get_data(xml); - g_return_val_if_fail(str != NULL, FALSE); + if (str == NULL) + return FALSE; *var = str; return TRUE; @@ -28,7 +30,8 @@ gboolean ggp_xml_get_bool(const xmlnode *xml, gchar *childName, gboolean *var) gboolean succ; succ = ggp_xml_get_string(xml, childName, &str); - g_return_val_if_fail(succ, FALSE); + if (!succ) + return FALSE; *var = (strcmp(str, "true") == 0 || strcmp(str, "True") == 0 || @@ -46,7 +49,8 @@ gboolean ggp_xml_get_uint(const xmlnode *xml, gchar *childName, unsigned int *va unsigned int val; succ = ggp_xml_get_string(xml, childName, &str); - g_return_val_if_fail(succ, FALSE); + if (!succ) + return FALSE; errno = 0; val = strtoul(str, &endptr, 10); @@ -101,3 +105,32 @@ void ggp_xmlnode_remove_children(xmlnode *xml) child = next; } } + +unsigned int ggp_xml_child_count(xmlnode *xml, const gchar *childName) +{ + xmlnode *child; + unsigned int count = 0; + + g_return_val_if_fail(xml != NULL, 0); + + if (childName) + { + child = xmlnode_get_child(xml, childName); + while (child) + { + child = xmlnode_get_next_twin(child); + count++; + } + } + else + { + child = xml->child; + while (child) + { + child = child->next; + count++; + } + } + + return count; +} diff --git a/libpurple/protocols/gg/xml.h b/libpurple/protocols/gg/xml.h index dc1fa49557..7d775a8abb 100644 --- a/libpurple/protocols/gg/xml.h +++ b/libpurple/protocols/gg/xml.h @@ -14,4 +14,6 @@ gboolean ggp_xml_set_uint(xmlnode *xml, gchar *childName, unsigned int val); void ggp_xmlnode_remove_children(xmlnode *xml); +unsigned int ggp_xml_child_count(xmlnode *xml, const gchar *childName); + #endif /* _GGP_XML_H */ |