libpurple/protocols/gg/edisc.c

changeset 34380
2179667660bc
parent 34378
63439e75c0b1
child 34383
4b1a106bbf1d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/gg/edisc.c	Mon Oct 22 01:26:22 2012 +0200
@@ -0,0 +1,317 @@
+#include "edisc.h"
+
+#include <debug.h>
+
+#include "gg.h"
+#include "libgaduw.h"
+#include <http.h>
+
+#define GGP_EDISC_HOSTNAME "MyComputer"
+#define GGP_EDISC_OS "WINNT x86-msvc"
+#define GGP_EDISC_TYPE "desktop"
+
+#define GGP_EDISC_RESPONSE_MAX 10240
+
+typedef struct _ggp_edisc_auth_data ggp_edisc_auth_data;
+
+typedef struct _ggp_edisc_xfer ggp_edisc_xfer;
+
+struct _ggp_edisc_session_data
+{
+	PurpleHttpCookieJar *cookies;
+	gchar *security_token;
+
+	PurpleHttpConnection *auth_request;
+	gboolean auth_done;
+	GList *auth_pending;
+};
+
+struct _ggp_edisc_xfer
+{
+	PurpleConnection *gc;
+};
+
+typedef void (*ggp_ggdrive_auth_cb)(PurpleConnection *gc, gboolean success,
+	gpointer user_data);
+
+static void ggp_ggdrive_auth(PurpleConnection *gc, ggp_ggdrive_auth_cb cb,
+	gpointer user_data);
+
+static void ggp_edisc_xfer_free(PurpleXfer *xfer);
+
+/*******************************************************************************
+ * Setting up.
+ ******************************************************************************/
+
+static inline ggp_edisc_session_data *
+ggp_edisc_get_sdata(PurpleConnection *gc)
+{
+	GGPInfo *accdata = purple_connection_get_protocol_data(gc);
+	return accdata->edisc_data;
+}
+
+void ggp_edisc_setup(PurpleConnection *gc)
+{
+	GGPInfo *accdata = purple_connection_get_protocol_data(gc);
+	ggp_edisc_session_data *sdata = g_new0(ggp_edisc_session_data, 1);
+
+	accdata->edisc_data = sdata;
+
+	sdata->cookies = purple_http_cookie_jar_new();
+}
+
+void ggp_edisc_cleanup(PurpleConnection *gc)
+{
+	ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc);
+
+	purple_http_conn_cancel(sdata->auth_request);
+	g_list_free_full(sdata->auth_pending, g_free);
+	g_free(sdata->security_token);
+
+	purple_http_cookie_jar_unref(sdata->cookies);
+
+	g_free(sdata);
+}
+
+/*******************************************************************************
+ * Sending a file.
+ ******************************************************************************/
+
+static void ggp_edisc_xfer_init(PurpleXfer *xfer);
+static void ggp_edisc_xfer_init_authenticated(PurpleConnection *gc,
+	gboolean success, gpointer _xfer);
+
+static void ggp_edisc_xfer_error(PurpleXfer *xfer, const gchar *msg);
+
+static void ggp_edisc_xfer_free(PurpleXfer *xfer)
+{
+	ggp_edisc_xfer *edisc_xfer = purple_xfer_get_protocol_data(xfer);
+
+	if (edisc_xfer == NULL)
+		return;
+
+	g_free(edisc_xfer);
+	purple_xfer_set_protocol_data(xfer, NULL);
+}
+
+static void ggp_edisc_xfer_error(PurpleXfer *xfer, const gchar *msg)
+{
+	purple_xfer_error(
+		purple_xfer_get_type(xfer),
+		purple_xfer_get_account(xfer),
+		purple_xfer_get_remote_user(xfer),
+		msg);
+	ggp_edisc_xfer_free(xfer);
+}
+
+gboolean ggp_edisc_xfer_can_receive_file(PurpleConnection *gc, const char *who)
+{
+	return TRUE; /* TODO: only online, buddies (?) */
+}
+
+static void ggp_edisc_xfer_init(PurpleXfer *xfer)
+{
+	ggp_edisc_xfer *edisc_xfer = purple_xfer_get_protocol_data(xfer);
+
+	if (purple_xfer_get_type(xfer) != PURPLE_XFER_SEND) {
+		purple_debug_error("gg", "ggp_edisc_xfer_init: "
+			"Not yet implemented\n");
+		return;
+	}
+
+	ggp_ggdrive_auth(edisc_xfer->gc, ggp_edisc_xfer_init_authenticated, xfer);
+}
+
+static void ggp_edisc_xfer_init_authenticated(PurpleConnection *gc,
+	gboolean success, gpointer _xfer)
+{
+	PurpleXfer *xfer = _xfer;
+
+	if (!success) {
+		ggp_edisc_xfer_error(xfer, _("Authentication failed"));
+		return;
+	}
+
+	/* TODO: requesting a ticket */
+
+	purple_xfer_start(xfer, -1, NULL, 0);
+}
+
+static void ggp_edisc_xfer_start(PurpleXfer *xfer)
+{
+	g_return_if_fail(xfer != NULL);
+
+	if (purple_xfer_get_type(xfer) != PURPLE_XFER_SEND) {
+		purple_debug_error("gg", "ggp_edisc_xfer_start: "
+			"Not yet implemented\n");
+		return;
+	}
+
+	purple_debug_info("gg", "Starting a file transfer...\n");
+}
+
+PurpleXfer * ggp_edisc_xfer_new(PurpleConnection *gc, const char *who)
+{
+	PurpleXfer *xfer;
+	ggp_edisc_xfer *edisc_xfer;
+
+	g_return_val_if_fail(gc != NULL, NULL);
+	g_return_val_if_fail(who != NULL, NULL);
+
+	xfer = purple_xfer_new(purple_connection_get_account(gc),
+		PURPLE_XFER_SEND, who);
+	edisc_xfer = g_new0(ggp_edisc_xfer, 1);
+	purple_xfer_set_protocol_data(xfer, edisc_xfer);
+
+	edisc_xfer->gc = gc;
+
+	purple_xfer_set_init_fnc(xfer, ggp_edisc_xfer_init);
+	purple_xfer_set_start_fnc(xfer, ggp_edisc_xfer_start);
+
+	//purple_xfer_set_cancel_send_fnc(xfer, bonjour_xfer_cancel_send);
+	//purple_xfer_set_end_fnc(xfer, bonjour_xfer_end);
+
+	return xfer;
+}
+
+void ggp_edisc_xfer_send_file(PurpleConnection *gc, const char *who,
+	const char *filename)
+{
+	PurpleXfer *xfer;
+
+	g_return_if_fail(gc != NULL);
+	g_return_if_fail(who != NULL);
+
+	/* Nothing interesting here, this code is common among prpls.
+	 * See ggp_edisc_new_xfer. */
+
+	xfer = ggp_edisc_xfer_new(gc, who);
+	if (filename)
+		purple_xfer_request_accepted(xfer, filename);
+	else
+		purple_xfer_request(xfer);
+}
+
+/*******************************************************************************
+ * Authentication
+ ******************************************************************************/
+
+struct _ggp_edisc_auth_data
+{
+	ggp_ggdrive_auth_cb cb;
+	gpointer user_data;
+};
+
+static void ggp_ggdrive_auth_done(PurpleHttpConnection *hc,
+	PurpleHttpResponse *response, gpointer user_data);
+
+static void ggp_ggdrive_auth(PurpleConnection *gc, ggp_ggdrive_auth_cb cb,
+	gpointer user_data)
+{
+	GGPInfo *accdata = purple_connection_get_protocol_data(gc);
+	ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc);
+	ggp_edisc_auth_data *auth;
+	const gchar *imtoken;
+	gchar *metadata;
+	PurpleHttpRequest *req;
+
+	imtoken = ggp_get_imtoken(gc);
+	if (!imtoken)
+	{
+		cb(gc, FALSE, user_data);
+		return;
+	}
+
+	if (sdata->auth_done)
+	{
+		cb(gc, sdata->security_token != NULL, user_data);
+		return;
+	}
+
+	auth = g_new0(ggp_edisc_auth_data, 1);
+	auth->cb = cb;
+	auth->user_data = user_data;
+	sdata->auth_pending = g_list_prepend(sdata->auth_pending, auth);
+
+	if (sdata->auth_request)
+		return;
+
+	purple_debug_info("gg", "ggp_ggdrive_auth(gc=%p)\n", gc);
+
+	req = purple_http_request_new("https://drive.mpa.gg.pl/signin");
+	purple_http_request_set_method(req, "PUT");
+
+	/* TODO: defaults (browser name, etc) */
+	purple_http_request_set_max_len(req, GGP_EDISC_RESPONSE_MAX);
+	purple_http_request_set_cookie_jar(req, sdata->cookies);
+
+	metadata = g_strdup_printf("{"
+		"\"id\": \"%032x\", "
+		"\"name\": \"" GGP_EDISC_HOSTNAME "\", "
+		"\"os_version\": \"" GGP_EDISC_OS "\", "
+		"\"client_version\": \"%s\", "
+		"\"type\": \"" GGP_EDISC_TYPE "\"}",
+		g_random_int_range(1, 1 << 16),
+		ggp_libgaduw_version(gc));
+
+	purple_http_request_header_set_printf(req, "Authorization",
+		"IMToken %s", imtoken);
+	purple_http_request_header_set_printf(req, "X-gged-user",
+		"gg/pl:%u", accdata->session->uin);
+	purple_http_request_header_set(req, "X-gged-client-metadata", metadata);
+	purple_http_request_header_set(req, "X-gged-api-version", "6");
+	g_free(metadata);
+
+	sdata->auth_request = purple_http_request(gc, req,
+		ggp_ggdrive_auth_done, NULL);
+	purple_http_request_unref(req);
+}
+
+static void ggp_ggdrive_auth_results(PurpleConnection *gc, gboolean success)
+{
+	ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc);
+	GList *it;
+
+	purple_debug_info("gg", "ggp_ggdrive_auth_results(gc=%p): %d\n",
+		gc, success);
+
+	it = g_list_first(sdata->auth_pending);
+	while (it) {
+		ggp_edisc_auth_data *auth = it->data;
+		it = g_list_next(it);
+
+		auth->cb(gc, success, auth->user_data);
+		g_free(auth);
+	}
+	g_list_free(sdata->auth_pending);
+	sdata->auth_pending = NULL;
+	sdata->auth_done = TRUE;
+}
+
+static void ggp_ggdrive_auth_done(PurpleHttpConnection *hc,
+	PurpleHttpResponse *response, gpointer user_data)
+{
+	PurpleConnection *gc = purple_http_conn_get_purple_connection(hc);
+	ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc);
+
+	sdata->auth_request = NULL;
+
+	if (!purple_http_response_is_successfull(response) ||
+		0 != strcmp(purple_http_response_get_data(response),
+		"{\"result\":{\"status\":0}}")) {
+		ggp_ggdrive_auth_results(gc, FALSE);
+		return;
+	}
+
+	sdata->security_token = g_strdup(purple_http_response_get_header(
+		response, "X-gged-security-token"));
+	if (!sdata->security_token) {
+		ggp_ggdrive_auth_results(gc, FALSE);
+		return;
+	}
+
+	if (purple_debug_is_unsafe())
+		purple_debug_misc("gg", "ggp_ggdrive_auth_done: "
+			"security_token=%s\n", sdata->security_token);
+	ggp_ggdrive_auth_results(gc, TRUE);
+}

mercurial