summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomasz Wasilczyk <tomkiewicz@cpw.pidgin.im>2012-08-19 12:41:35 +0200
committerTomasz Wasilczyk <tomkiewicz@cpw.pidgin.im>2012-08-19 12:41:35 +0200
commit8855cd1744982294ae70b03ed143888d5d9a1f40 (patch)
tree2f88740687af6c1b6a4d471a5ede6b020c34cf54
parentef21b3967c08e98542e9b67190c084a7571b31a6 (diff)
downloadpidgin-8855cd1744982294ae70b03ed143888d5d9a1f40.tar.gz
Gadu-Gadu: extended OAuth support, initial support for gg10.5 public directory
-rw-r--r--libpurple/protocols/gg/Makefile.am2
-rw-r--r--libpurple/protocols/gg/avatar.c2
-rw-r--r--libpurple/protocols/gg/gg.c18
-rw-r--r--libpurple/protocols/gg/oauth/oauth-purple.c41
-rw-r--r--libpurple/protocols/gg/oauth/oauth-purple.h2
-rw-r--r--libpurple/protocols/gg/oauth/oauth.c4
-rw-r--r--libpurple/protocols/gg/pubdir-prpl.c213
-rw-r--r--libpurple/protocols/gg/pubdir-prpl.h28
-rw-r--r--libpurple/protocols/gg/xml.c41
-rw-r--r--libpurple/protocols/gg/xml.h2
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 */