Fri, 11 Oct 2019 05:45:14 -0400
Re-arrange GG edisc file to avoid prototypes.
| libpurple/protocols/gg/edisc.c | file | annotate | diff | comparison | revisions |
--- a/libpurple/protocols/gg/edisc.c Wed Oct 09 21:05:42 2019 -0400 +++ b/libpurple/protocols/gg/edisc.c Fri Oct 11 05:45:14 2019 -0400 @@ -46,8 +46,6 @@ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" \ " [](){}-+=_;'<>,.&$!" -typedef struct _ggp_edisc_auth_data ggp_edisc_auth_data; - typedef struct _ggp_edisc_xfer ggp_edisc_xfer; struct _ggp_edisc_session_data @@ -88,37 +86,6 @@ typedef void (*ggp_ggdrive_auth_cb)(PurpleConnection *gc, gboolean success, gpointer user_data); -/* Setting up. */ -static inline ggp_edisc_session_data * -ggp_edisc_get_sdata(PurpleConnection *gc); - -/* Misc. */ -static void ggp_edisc_set_defaults(PurpleHttpRequest *req); -static int ggp_edisc_parse_error(const gchar *data); - -/* General xfer functions. */ -static void ggp_edisc_xfer_error(PurpleXfer *xfer, const gchar *msg); -static const gchar * ggp_edisc_xfer_ticket_url(const gchar *ticket_id); -static void ggp_edisc_xfer_progress_watcher(PurpleHttpConnection *hc, - gboolean reading_state, int processed, int total, gpointer _xfer); -static ggp_edisc_xfer_ack_status -ggp_edisc_xfer_parse_ack_status(const gchar *str); - - -/* Sending a file. */ -static void ggp_edisc_xfer_send_ticket_changed(PurpleConnection *gc, - PurpleXfer *xfer, gboolean is_allowed); - -/* Receiving a file. */ -static void ggp_edisc_xfer_recv_reject(PurpleXfer *xfer); -static void ggp_edisc_xfer_recv_ticket_got(PurpleConnection *gc, - const gchar *ticket_id); -static void ggp_edisc_xfer_recv_ticket_completed(PurpleXfer *xfer); - -/* Authentication. */ -static void ggp_ggdrive_auth(PurpleConnection *gc, ggp_ggdrive_auth_cb cb, - gpointer user_data); - /******************************************************************************* * Setting up. ******************************************************************************/ @@ -210,10 +177,41 @@ return error_id; } +static ggp_edisc_xfer_ack_status +ggp_edisc_xfer_parse_ack_status(const gchar *str) +{ + g_return_val_if_fail(str != NULL, GGP_EDISC_XFER_ACK_STATUS_UNKNOWN); + + if (g_strcmp0("unknown", str) == 0) { + return GGP_EDISC_XFER_ACK_STATUS_UNKNOWN; + } + if (g_strcmp0("allowed", str) == 0) { + return GGP_EDISC_XFER_ACK_STATUS_ALLOWED; + } + if (g_strcmp0("rejected", str) == 0) { + return GGP_EDISC_XFER_ACK_STATUS_REJECTED; + } + + purple_debug_warning( + "gg", "ggp_edisc_xfer_parse_ack_status: unknown status (%s)", str); + return GGP_EDISC_XFER_ACK_STATUS_UNKNOWN; +} + /******************************************************************************* * General xfer functions. ******************************************************************************/ +static const gchar * +ggp_edisc_xfer_ticket_url(const gchar *ticket_id) +{ + static gchar ticket_url[150]; + + g_snprintf(ticket_url, sizeof(ticket_url), + "https://drive.mpa.gg.pl/send_ticket/%s", ticket_id); + + return ticket_url; +} + static void ggp_edisc_xfer_error(PurpleXfer *xfer, const gchar *msg) { if (purple_xfer_is_cancelled(xfer)) @@ -228,74 +226,6 @@ purple_xfer_end(xfer); } -void ggp_edisc_xfer_ticket_changed(PurpleConnection *gc, const char *data) -{ - ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); - PurpleXfer *xfer; - JsonParser *parser; - JsonObject *ticket; - const gchar *ticket_id, *send_status; - ggp_edisc_xfer_ack_status ack_status; - gboolean is_completed; - - g_return_if_fail(sdata != NULL); - - parser = ggp_json_parse(data); - ticket = json_node_get_object(json_parser_get_root(parser)); - ticket_id = json_object_get_string_member(ticket, "id"); - ack_status = ggp_edisc_xfer_parse_ack_status( - json_object_get_string_member(ticket, "ack_status")); - send_status = json_object_get_string_member(ticket, "send_status"); - - if (ticket_id == NULL) - ticket_id = ""; - xfer = g_hash_table_lookup(sdata->xfers_initialized, ticket_id); - if (xfer == NULL) { - purple_debug_misc("gg", "ggp_edisc_event_ticket_changed: " - "ticket %s not found, updating it...\n", - purple_debug_is_unsafe() ? ticket_id : ""); - ggp_edisc_xfer_recv_ticket_got(gc, ticket_id); - g_object_unref(parser); - return; - } - - is_completed = FALSE; - if (g_strcmp0("in_progress", send_status) == 0) { - /* do nothing */ - } else if (g_strcmp0("completed", send_status) == 0) { - is_completed = TRUE; - } else if (g_strcmp0("expired", send_status) == 0) - ggp_edisc_xfer_error(xfer, _("File transfer expired.")); - else { - purple_debug_warning("gg", "ggp_edisc_event_ticket_changed: " - "unknown send_status=%s\n", send_status); - g_object_unref(parser); - return; - } - - g_object_unref(parser); - - if (purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_RECEIVE) { - if (is_completed) - ggp_edisc_xfer_recv_ticket_completed(xfer); - } else { - if (ack_status != GGP_EDISC_XFER_ACK_STATUS_UNKNOWN) - ggp_edisc_xfer_send_ticket_changed(gc, xfer, ack_status - == GGP_EDISC_XFER_ACK_STATUS_ALLOWED); - } - -} - -static const gchar * ggp_edisc_xfer_ticket_url(const gchar *ticket_id) -{ - static gchar ticket_url[150]; - - g_snprintf(ticket_url, sizeof(ticket_url), - "https://drive.mpa.gg.pl/send_ticket/%s", ticket_id); - - return ticket_url; -} - static void ggp_edisc_xfer_progress_watcher(PurpleHttpConnection *hc, gboolean reading_state, int processed, int total, gpointer _xfer) { @@ -320,41 +250,200 @@ purple_xfer_update_progress(xfer); } -static ggp_edisc_xfer_ack_status -ggp_edisc_xfer_parse_ack_status(const gchar *str) +/******************************************************************************* + * Authentication. + ******************************************************************************/ + +typedef struct _ggp_edisc_auth_data { + ggp_ggdrive_auth_cb cb; + gpointer user_data; +} ggp_edisc_auth_data; + +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", gc, success); + + g_return_if_fail(sdata != NULL); + + 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) { - g_return_val_if_fail(str != NULL, GGP_EDISC_XFER_ACK_STATUS_UNKNOWN); + PurpleConnection *gc = purple_http_conn_get_purple_connection(hc); + ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); + JsonParser *parser; + JsonObject *result; + int status = -1; + + g_return_if_fail(sdata != NULL); + + sdata->auth_request = NULL; + + if (!purple_http_response_is_successful(response)) { + purple_debug_misc("gg", + "ggp_ggdrive_auth_done: authentication failed due to " + "unsuccessful request (code = %d)", + purple_http_response_get_code(response)); + ggp_ggdrive_auth_results(gc, FALSE); + return; + } + + parser = ggp_json_parse(purple_http_response_get_data(response, NULL)); + result = json_node_get_object(json_parser_get_root(parser)); + result = json_object_get_object_member(result, "result"); + if (json_object_has_member(result, "status")) + status = json_object_get_int_member(result, "status"); + g_object_unref(parser); + + if (status != 0) { + purple_debug_misc("gg", + "ggp_ggdrive_auth_done: authentication failed due to " + "bad result (status=%d)", + status); + if (purple_debug_is_verbose()) { + purple_debug_misc("gg", "ggp_ggdrive_auth_done: result = %s", + purple_http_response_get_data(response, NULL)); + } + 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) { + purple_debug_misc("gg", "ggp_ggdrive_auth_done: authentication failed " + "due to missing security token header"); + ggp_ggdrive_auth_results(gc, FALSE); + return; + } + + if (purple_debug_is_unsafe()) { + purple_debug_misc("gg", "ggp_ggdrive_auth_done: security_token=%s", + sdata->security_token); + } + ggp_ggdrive_auth_results(gc, TRUE); +} - if (g_strcmp0("unknown", str) == 0) - return GGP_EDISC_XFER_ACK_STATUS_UNKNOWN; - if (g_strcmp0("allowed", str) == 0) - return GGP_EDISC_XFER_ACK_STATUS_ALLOWED; - if (g_strcmp0("rejected", str) == 0) - return GGP_EDISC_XFER_ACK_STATUS_REJECTED; +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; + + g_return_if_fail(sdata != NULL); + + 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)", gc); + + req = purple_http_request_new("https://drive.mpa.gg.pl/signin"); + purple_http_request_set_method(req, "PUT"); + + ggp_edisc_set_defaults(req); + purple_http_request_set_cookie_jar(req, sdata->cookies); - purple_debug_warning("gg", "ggp_edisc_xfer_parse_ack_status: " - "unknown status (%s)\n", str); - return GGP_EDISC_XFER_ACK_STATUS_UNKNOWN; + metadata = + g_strdup_printf("{" + "\"id\": \"%032x\", " + "\"name\": \"%s\", " + "\"os_version\": \"" GGP_EDISC_OS "\", " + "\"client_version\": \"%s\", " + "\"type\": \"" GGP_EDISC_TYPE "\"}", + g_random_int_range(1, 1 << 16), + purple_get_host_name(), 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); + g_free(metadata); + + sdata->auth_request = + purple_http_request(gc, req, ggp_ggdrive_auth_done, NULL); + purple_http_request_unref(req); +} + +static void +ggp_edisc_xfer_send_ticket_changed(PurpleConnection *gc, PurpleXfer *xfer, + gboolean is_allowed) +{ + GGPXfer *edisc_xfer = GGP_XFER(xfer); + if (!edisc_xfer) { + purple_debug_fatal( + "gg", + "ggp_edisc_event_ticket_changed: transfer %p already free'd", + xfer); + return; + } + + if (!is_allowed) { + purple_debug_info( + "gg", "ggp_edisc_event_ticket_changed: transfer %p rejected", + xfer); + purple_xfer_cancel_remote(xfer); + return; + } + + if (edisc_xfer->allowed) { + purple_debug_misc( + "gg", + "ggp_edisc_event_ticket_changed: transfer %p already allowed", + xfer); + return; + } + edisc_xfer->allowed = TRUE; + + purple_xfer_start(xfer, -1, NULL, 0); } /******************************************************************************* * Sending a file. ******************************************************************************/ -static void ggp_edisc_xfer_send_init(PurpleXfer *xfer); -static void ggp_edisc_xfer_send_init_authenticated(PurpleConnection *gc, - gboolean success, gpointer _xfer); -static void ggp_edisc_xfer_send_init_ticket_created(PurpleHttpConnection *hc, - PurpleHttpResponse *response, gpointer _xfer); -static void ggp_edisc_xfer_send_reader(PurpleHttpConnection *hc, - gchar *buffer, size_t offset, size_t length, gpointer _xfer, - PurpleHttpContentReaderCb cb); -static void ggp_edisc_xfer_send_start(PurpleXfer *xfer); -static void ggp_edisc_xfer_send_done(PurpleHttpConnection *hc, - PurpleHttpResponse *response, gpointer _xfer); - -gboolean ggp_edisc_xfer_can_receive_file(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, - const char *who) +gboolean +ggp_edisc_xfer_can_receive_file(PurpleProtocolXfer *prplxfer, + PurpleConnection *gc, const char *who) { PurpleBuddy *buddy; @@ -362,71 +451,15 @@ g_return_val_if_fail(who != NULL, FALSE); buddy = purple_blist_find_buddy(purple_connection_get_account(gc), who); - if (buddy == NULL) + if (buddy == NULL) { return FALSE; + } /* TODO: check, if this buddy have us on his list */ return PURPLE_BUDDY_IS_ONLINE(buddy); } -static void ggp_edisc_xfer_send_init(PurpleXfer *xfer) -{ - GGPXfer *edisc_xfer = GGP_XFER(xfer); - - purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_NOT_STARTED); - - edisc_xfer->filename = g_strdup(purple_xfer_get_filename(xfer)); - g_strcanon(edisc_xfer->filename, GGP_EDISC_FNAME_ALLOWED, '_'); - - ggp_ggdrive_auth(edisc_xfer->gc, ggp_edisc_xfer_send_init_authenticated, - xfer); -} - -static void ggp_edisc_xfer_send_init_authenticated(PurpleConnection *gc, - gboolean success, gpointer _xfer) -{ - ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); - PurpleHttpRequest *req; - PurpleXfer *xfer = _xfer; - GGPXfer *edisc_xfer = GGP_XFER(xfer); - gchar *data; - - if (purple_xfer_is_cancelled(xfer)) - return; - - if (!success) { - ggp_edisc_xfer_error(xfer, _("Authentication failed")); - return; - } - - g_return_if_fail(sdata != NULL); - - req = purple_http_request_new("https://drive.mpa.gg.pl/send_ticket"); - purple_http_request_set_method(req, "PUT"); - - ggp_edisc_set_defaults(req); - purple_http_request_set_cookie_jar(req, sdata->cookies); - - purple_http_request_header_set(req, "X-gged-security-token", - sdata->security_token); - - data = g_strdup_printf("{\"send_ticket\":{" - "\"recipient\":\"%s\"," - "\"file_name\":\"%s\"," - "\"file_size\":\"%u\"" - "}}", - purple_xfer_get_remote_user(xfer), - edisc_xfer->filename, - (int)purple_xfer_get_size(xfer)); - purple_http_request_set_contents(req, data, -1); - g_free(data); - - edisc_xfer->hc = purple_http_request(gc, req, - ggp_edisc_xfer_send_init_ticket_created, xfer); - purple_http_request_unref(req); -} - static void ggp_edisc_xfer_send_init_ticket_created(PurpleHttpConnection *hc, PurpleHttpResponse *response, gpointer _xfer) { @@ -492,31 +525,64 @@ ack_status == GGP_EDISC_XFER_ACK_STATUS_ALLOWED); } -void ggp_edisc_xfer_send_ticket_changed(PurpleConnection *gc, PurpleXfer *xfer, - gboolean is_allowed) +static void +ggp_edisc_xfer_send_init_authenticated(PurpleConnection *gc, gboolean success, + gpointer _xfer) { + ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); + PurpleHttpRequest *req; + PurpleXfer *xfer = _xfer; GGPXfer *edisc_xfer = GGP_XFER(xfer); - if (!edisc_xfer) { - purple_debug_fatal("gg", "ggp_edisc_event_ticket_changed: " - "transfer %p already free'd\n", xfer); + gchar *data; + + if (purple_xfer_is_cancelled(xfer)) { + return; + } + + if (!success) { + ggp_edisc_xfer_error(xfer, _("Authentication failed")); return; } - if (!is_allowed) { - purple_debug_info("gg", "ggp_edisc_event_ticket_changed: " - "transfer %p rejected\n", xfer); - purple_xfer_cancel_remote(xfer); - return; - } + g_return_if_fail(sdata != NULL); + + req = purple_http_request_new("https://drive.mpa.gg.pl/send_ticket"); + purple_http_request_set_method(req, "PUT"); + + ggp_edisc_set_defaults(req); + purple_http_request_set_cookie_jar(req, sdata->cookies); + + purple_http_request_header_set(req, "X-gged-security-token", + sdata->security_token); - if (edisc_xfer->allowed) { - purple_debug_misc("gg", "ggp_edisc_event_ticket_changed: " - "transfer %p already allowed\n", xfer); - return; - } - edisc_xfer->allowed = TRUE; + data = g_strdup_printf("{\"send_ticket\":{" + "\"recipient\":\"%s\"," + "\"file_name\":\"%s\"," + "\"file_size\":\"%u\"" + "}}", + purple_xfer_get_remote_user(xfer), + edisc_xfer->filename, + (int)purple_xfer_get_size(xfer)); + purple_http_request_set_contents(req, data, -1); + g_free(data); - purple_xfer_start(xfer, -1, NULL, 0); + edisc_xfer->hc = purple_http_request( + gc, req, ggp_edisc_xfer_send_init_ticket_created, xfer); + purple_http_request_unref(req); +} + +static void +ggp_edisc_xfer_send_init(PurpleXfer *xfer) +{ + GGPXfer *edisc_xfer = GGP_XFER(xfer); + + purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_NOT_STARTED); + + edisc_xfer->filename = g_strdup(purple_xfer_get_filename(xfer)); + g_strcanon(edisc_xfer->filename, GGP_EDISC_FNAME_ALLOWED, '_'); + + ggp_ggdrive_auth(edisc_xfer->gc, ggp_edisc_xfer_send_init_authenticated, + xfer); } static void ggp_edisc_xfer_send_reader(PurpleHttpConnection *hc, @@ -553,6 +619,46 @@ cb(hc, success, eof, stored); } +static void +ggp_edisc_xfer_send_done(PurpleHttpConnection *hc, PurpleHttpResponse *response, + gpointer _xfer) +{ + PurpleXfer *xfer = _xfer; + GGPXfer *edisc_xfer = GGP_XFER(xfer); + const gchar *data = purple_http_response_get_data(response, NULL); + JsonParser *parser; + JsonObject *result; + int result_status = -1; + + if (purple_xfer_is_cancelled(xfer)) { + return; + } + + g_return_if_fail(edisc_xfer != NULL); + + edisc_xfer->hc = NULL; + + if (!purple_http_response_is_successful(response)) { + ggp_edisc_xfer_error(xfer, _("Error while sending a file")); + return; + } + + parser = ggp_json_parse(data); + result = json_node_get_object(json_parser_get_root(parser)); + result = json_object_get_object_member(result, "result"); + if (json_object_has_member(result, "status")) { + result_status = json_object_get_int_member(result, "status"); + } + g_object_unref(parser); + + if (result_status == 0) { + purple_xfer_set_completed(xfer, TRUE); + purple_xfer_end(xfer); + } else { + ggp_edisc_xfer_error(xfer, _("Error while sending a file")); + } +} + static void ggp_edisc_xfer_send_start(PurpleXfer *xfer) { ggp_edisc_session_data *sdata; @@ -596,44 +702,6 @@ ggp_edisc_xfer_progress_watcher, xfer, 250000); } -static void ggp_edisc_xfer_send_done(PurpleHttpConnection *hc, - PurpleHttpResponse *response, gpointer _xfer) -{ - PurpleXfer *xfer = _xfer; - GGPXfer *edisc_xfer = GGP_XFER(xfer); - const gchar *data = purple_http_response_get_data(response, NULL); - JsonParser *parser; - JsonObject *result; - int result_status = -1; - - if (purple_xfer_is_cancelled(xfer)) - return; - - g_return_if_fail(edisc_xfer != NULL); - - edisc_xfer->hc = NULL; - - if (!purple_http_response_is_successful(response)) { - ggp_edisc_xfer_error(xfer, _("Error while sending a file")); - return; - } - - parser = ggp_json_parse(data); - result = json_node_get_object(json_parser_get_root(parser)); - result = json_object_get_object_member(result, "result"); - if (json_object_has_member(result, "status")) { - result_status = json_object_get_int_member(result, "status"); - } - g_object_unref(parser); - - if (result_status == 0) { - purple_xfer_set_completed(xfer, TRUE); - purple_xfer_end(xfer); - } else { - ggp_edisc_xfer_error(xfer, _("Error while sending a file")); - } -} - PurpleXfer * ggp_edisc_xfer_send_new(PurpleProtocolXfer *prplxfer, PurpleConnection *gc, const char *who) { GGPXfer *xfer; @@ -676,199 +744,44 @@ * Receiving a file. ******************************************************************************/ -static void ggp_edisc_xfer_recv_ticket_update_authenticated( - PurpleConnection *gc, gboolean success, gpointer _ticket); -static void ggp_edisc_xfer_recv_ticket_update_got(PurpleHttpConnection *hc, - PurpleHttpResponse *response, gpointer user_data); -static PurpleXfer * ggp_edisc_xfer_recv_new(PurpleConnection *gc, - const char *who); -static void ggp_edisc_xfer_recv_accept(PurpleXfer *xfer); -static void ggp_edisc_xfer_recv_start(PurpleXfer *xfer); -static void ggp_edisc_xfer_recv_ack(PurpleXfer *xfer, gboolean accept); -static void ggp_edisc_xfer_recv_ack_done(PurpleHttpConnection *hc, - PurpleHttpResponse *response, gpointer _xfer); -static gboolean ggp_edisc_xfer_recv_writer(PurpleHttpConnection *http_conn, - PurpleHttpResponse *response, const gchar *buffer, size_t offset, - size_t length, gpointer user_data); -static void ggp_edisc_xfer_recv_done(PurpleHttpConnection *hc, - PurpleHttpResponse *response, gpointer _xfer); - -static void ggp_edisc_xfer_recv_ticket_got(PurpleConnection *gc, - const gchar *ticket_id) -{ - ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); - - g_return_if_fail(sdata != NULL); - - if (g_hash_table_lookup(sdata->xfers_history, ticket_id)) - return; - - ggp_ggdrive_auth(gc, ggp_edisc_xfer_recv_ticket_update_authenticated, - g_strdup(ticket_id)); -} - -static void ggp_edisc_xfer_recv_ticket_update_authenticated( - PurpleConnection *gc, gboolean success, gpointer _ticket) -{ - ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); - PurpleHttpRequest *req; - gchar *ticket = _ticket; - - g_return_if_fail(sdata != NULL); - - if (!success) { - purple_debug_warning("gg", - "ggp_edisc_xfer_recv_ticket_update_authenticated: " - "update of ticket %s aborted due to authentication " - "failure\n", ticket); - g_free(ticket); - return; - } - - req = purple_http_request_new(ggp_edisc_xfer_ticket_url(ticket)); - g_free(ticket); - - ggp_edisc_set_defaults(req); - purple_http_request_set_cookie_jar(req, sdata->cookies); - - purple_http_request_header_set(req, "X-gged-security-token", - sdata->security_token); - - purple_http_request(gc, req, ggp_edisc_xfer_recv_ticket_update_got, - NULL); - purple_http_request_unref(req); -} - -static void ggp_edisc_xfer_recv_ticket_update_got(PurpleHttpConnection *hc, - PurpleHttpResponse *response, gpointer user_data) -{ - PurpleConnection *gc = purple_http_conn_get_purple_connection(hc); - PurpleXfer *xfer; - GGPXfer *edisc_xfer; - JsonParser *parser; - JsonObject *result; - int status = -1; - ggp_edisc_session_data *sdata; - - const gchar *ticket_id, *file_name, *send_mode_str; - uin_t sender, recipient; - int file_size; - - if (!purple_http_response_is_successful(response)) { - purple_debug_error("gg", - "ggp_edisc_xfer_recv_ticket_update_got: " - "cannot fetch update for ticket (code=%d)\n", - purple_http_response_get_code(response)); - return; - } - - sdata = ggp_edisc_get_sdata(gc); - g_return_if_fail(sdata != NULL); - - parser = ggp_json_parse(purple_http_response_get_data(response, NULL)); - result = json_node_get_object(json_parser_get_root(parser)); - result = json_object_get_object_member(result, "result"); - if (json_object_has_member(result, "status")) - status = json_object_get_int_member(result, "status"); - result = json_object_get_object_member(result, "send_ticket"); - - if (status != 0) { - purple_debug_warning("gg", - "ggp_edisc_xfer_recv_ticket_update_got: failed to get " - "update (status=%d)\n", status); - g_object_unref(parser); - return; - } - - ticket_id = json_object_get_string_member(result, "id"); - sender = ggp_str_to_uin(json_object_get_string_member(result, - "sender")); - recipient = ggp_str_to_uin(json_object_get_string_member(result, - "recipient")); - file_size = g_ascii_strtoll(json_object_get_string_member(result, - "file_size"), NULL, 10); - file_name = json_object_get_string_member(result, "file_name"); - - /* GG11: normal - * AQQ 2.4.2.10: direct_inbox - */ - send_mode_str = json_object_get_string_member(result, "send_mode"); - - /* more fields: - * send_progress (float), ack_status, send_status - */ - - if (purple_debug_is_verbose() && purple_debug_is_unsafe()) - purple_debug_info("gg", "Got ticket update: id=%s, sender=%u, " - "recipient=%u, file name=\"%s\", file size=%d, " - "send mode=%s)\n", - ticket_id, - sender, recipient, - file_name, file_size, - send_mode_str); - - xfer = g_hash_table_lookup(sdata->xfers_initialized, ticket_id); - if (xfer != NULL) { - purple_debug_misc("gg", "ggp_edisc_xfer_recv_ticket_update_got:" - " ticket %s already updated\n", - purple_debug_is_unsafe() ? ticket_id : ""); - g_object_unref(parser); - return; - } - - if (recipient != ggp_get_my_uin(gc)) { - purple_debug_misc("gg", "ggp_edisc_xfer_recv_ticket_update_got:" - " ticket %s is not for incoming transfer " - "(its from %u to %u)\n", - purple_debug_is_unsafe() ? ticket_id : "", - sender, recipient); - g_object_unref(parser); - return; - } - - xfer = ggp_edisc_xfer_recv_new(gc, ggp_uin_to_str(sender)); - purple_xfer_set_filename(xfer, file_name); - purple_xfer_set_size(xfer, file_size); - purple_xfer_request(xfer); - edisc_xfer = GGP_XFER(xfer); - edisc_xfer->ticket_id = g_strdup(ticket_id); - g_hash_table_insert(sdata->xfers_initialized, - edisc_xfer->ticket_id, xfer); - g_hash_table_insert(sdata->xfers_history, - g_strdup(ticket_id), GINT_TO_POINTER(1)); - - g_object_unref(parser); -} - -static PurpleXfer * ggp_edisc_xfer_recv_new(PurpleConnection *gc, - const char *who) +static PurpleXfer * +ggp_edisc_xfer_recv_new(PurpleConnection *gc, const char *who) { GGPXfer *xfer; g_return_val_if_fail(gc != NULL, NULL); g_return_val_if_fail(who != NULL, NULL); - xfer = g_object_new( - GGP_TYPE_XFER, - "account", purple_connection_get_account(gc), - "type", PURPLE_XFER_TYPE_RECEIVE, - "remote-user", who, - NULL - ); + xfer = g_object_new(GGP_TYPE_XFER, "account", + purple_connection_get_account(gc), "type", + PURPLE_XFER_TYPE_RECEIVE, "remote-user", who, NULL); xfer->gc = gc; return PURPLE_XFER(xfer); } -static void ggp_edisc_xfer_recv_reject(PurpleXfer *xfer) +static void +ggp_edisc_xfer_recv_ack_done(PurpleHttpConnection *hc, + PurpleHttpResponse *response, gpointer _xfer) { - ggp_edisc_xfer_recv_ack(xfer, FALSE); -} + PurpleXfer *xfer = _xfer; + GGPXfer *edisc_xfer; + + if (purple_xfer_is_cancelled(xfer)) { + g_return_if_reached(); + } -static void ggp_edisc_xfer_recv_accept(PurpleXfer *xfer) -{ - ggp_edisc_xfer_recv_ack(xfer, TRUE); + edisc_xfer = GGP_XFER(xfer); + edisc_xfer->hc = NULL; + + if (!purple_http_response_is_successful(response)) { + ggp_edisc_xfer_error(xfer, _("Cannot confirm file transfer.")); + return; + } + + purple_debug_info("gg", "ggp_edisc_xfer_recv_ack_done: [%s]\n", + purple_http_response_get_data(response, NULL)); } static void ggp_edisc_xfer_recv_ack(PurpleXfer *xfer, gboolean accept) @@ -902,25 +815,16 @@ } } -static void ggp_edisc_xfer_recv_ack_done(PurpleHttpConnection *hc, - PurpleHttpResponse *response, gpointer _xfer) +static void +ggp_edisc_xfer_recv_reject(PurpleXfer *xfer) { - PurpleXfer *xfer = _xfer; - GGPXfer *edisc_xfer; - - if (purple_xfer_is_cancelled(xfer)) - g_return_if_reached(); + ggp_edisc_xfer_recv_ack(xfer, FALSE); +} - edisc_xfer = GGP_XFER(xfer); - edisc_xfer->hc = NULL; - - if (!purple_http_response_is_successful(response)) { - ggp_edisc_xfer_error(xfer, _("Cannot confirm file transfer.")); - return; - } - - purple_debug_info("gg", "ggp_edisc_xfer_recv_ack_done: [%s]\n", - purple_http_response_get_data(response, NULL)); +static void +ggp_edisc_xfer_recv_accept(PurpleXfer *xfer) +{ + ggp_edisc_xfer_recv_ack(xfer, TRUE); } static void ggp_edisc_xfer_recv_ticket_completed(PurpleXfer *xfer) @@ -934,43 +838,6 @@ purple_xfer_start(xfer, -1, NULL, 0); } -static void ggp_edisc_xfer_recv_start(PurpleXfer *xfer) -{ - ggp_edisc_session_data *sdata; - GGPXfer *edisc_xfer; - gchar *upload_url; - PurpleHttpRequest *req; - - g_return_if_fail(xfer != NULL); - edisc_xfer = GGP_XFER(xfer); - g_return_if_fail(edisc_xfer != NULL); - sdata = ggp_edisc_get_sdata(edisc_xfer->gc); - g_return_if_fail(sdata != NULL); - - upload_url = g_strdup_printf("https://drive.mpa.gg.pl/me/file/inbox/" - "%s,%s?api_version=%s&security_token=%s", - edisc_xfer->ticket_id, purple_url_encode(purple_xfer_get_filename(xfer)), - GGP_EDISC_API, sdata->security_token); - req = purple_http_request_new(upload_url); - g_free(upload_url); - - purple_http_request_set_timeout(req, -1); - - ggp_edisc_set_defaults(req); - purple_http_request_set_max_len(req, purple_xfer_get_size(xfer) + 1); - purple_http_request_set_cookie_jar(req, sdata->cookies); - - purple_http_request_set_response_writer(req, ggp_edisc_xfer_recv_writer, - xfer); - - edisc_xfer->hc = purple_http_request(edisc_xfer->gc, req, - ggp_edisc_xfer_recv_done, xfer); - purple_http_request_unref(req); - - purple_http_conn_set_progress_watcher(edisc_xfer->hc, - ggp_edisc_xfer_progress_watcher, xfer, 250000); -} - static gboolean ggp_edisc_xfer_recv_writer(PurpleHttpConnection *http_conn, PurpleHttpResponse *response, const gchar *buffer, size_t offset, size_t length, gpointer _xfer) @@ -1031,157 +898,264 @@ } } -/******************************************************************************* - * Authentication. - ******************************************************************************/ - -struct _ggp_edisc_auth_data +static void +ggp_edisc_xfer_recv_start(PurpleXfer *xfer) { - 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; + ggp_edisc_session_data *sdata; + GGPXfer *edisc_xfer; + gchar *upload_url; PurpleHttpRequest *req; + g_return_if_fail(xfer != NULL); + edisc_xfer = GGP_XFER(xfer); + g_return_if_fail(edisc_xfer != NULL); + sdata = ggp_edisc_get_sdata(edisc_xfer->gc); g_return_if_fail(sdata != NULL); - imtoken = ggp_get_imtoken(gc); - if (!imtoken) { - cb(gc, FALSE, user_data); - return; - } + upload_url = + g_strdup_printf("https://drive.mpa.gg.pl/me/file/inbox/" + "%s,%s?api_version=%s&security_token=%s", + edisc_xfer->ticket_id, + purple_url_encode(purple_xfer_get_filename(xfer)), + GGP_EDISC_API, sdata->security_token); + req = purple_http_request_new(upload_url); + g_free(upload_url); + + purple_http_request_set_timeout(req, -1); + + ggp_edisc_set_defaults(req); + purple_http_request_set_max_len(req, purple_xfer_get_size(xfer) + 1); + purple_http_request_set_cookie_jar(req, sdata->cookies); + + purple_http_request_set_response_writer(req, ggp_edisc_xfer_recv_writer, + xfer); + + edisc_xfer->hc = purple_http_request(edisc_xfer->gc, req, + ggp_edisc_xfer_recv_done, xfer); + purple_http_request_unref(req); - if (sdata->auth_done) { - cb(gc, sdata->security_token != NULL, user_data); + purple_http_conn_set_progress_watcher( + edisc_xfer->hc, ggp_edisc_xfer_progress_watcher, xfer, 250000); +} + +static void +ggp_edisc_xfer_recv_ticket_update_got(PurpleHttpConnection *hc, + PurpleHttpResponse *response, + gpointer user_data) +{ + PurpleConnection *gc = purple_http_conn_get_purple_connection(hc); + PurpleXfer *xfer; + GGPXfer *edisc_xfer; + JsonParser *parser; + JsonObject *result; + int status = -1; + ggp_edisc_session_data *sdata; + + const gchar *ticket_id, *file_name, *send_mode_str; + uin_t sender, recipient; + int file_size; + + if (!purple_http_response_is_successful(response)) { + purple_debug_error("gg", + "ggp_edisc_xfer_recv_ticket_update_got: cannot " + "fetch update for ticket (code=%d)", + purple_http_response_get_code(response)); 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"); - - ggp_edisc_set_defaults(req); - purple_http_request_set_cookie_jar(req, sdata->cookies); - - metadata = g_strdup_printf("{" - "\"id\": \"%032x\", " - "\"name\": \"%s\", " - "\"os_version\": \"" GGP_EDISC_OS "\", " - "\"client_version\": \"%s\", " - "\"type\": \"" GGP_EDISC_TYPE "\"}", - g_random_int_range(1, 1 << 16), - purple_get_host_name(), - 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); - 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); - + sdata = ggp_edisc_get_sdata(gc); g_return_if_fail(sdata != NULL); - 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); - JsonParser *parser; - JsonObject *result; - int status = -1; - - g_return_if_fail(sdata != NULL); - - sdata->auth_request = NULL; - - if (!purple_http_response_is_successful(response)) { - purple_debug_misc("gg", "ggp_ggdrive_auth_done: authentication " - "failed due to unsuccessful request (code = %d)\n", - purple_http_response_get_code(response)); - ggp_ggdrive_auth_results(gc, FALSE); - return; - } - parser = ggp_json_parse(purple_http_response_get_data(response, NULL)); result = json_node_get_object(json_parser_get_root(parser)); result = json_object_get_object_member(result, "result"); if (json_object_has_member(result, "status")) status = json_object_get_int_member(result, "status"); - g_object_unref(parser); + result = json_object_get_object_member(result, "send_ticket"); + + if (status != 0) { + purple_debug_warning("gg", + "ggp_edisc_xfer_recv_ticket_update_got: failed to " + "get update (status=%d)", + status); + g_object_unref(parser); + return; + } + + ticket_id = json_object_get_string_member(result, "id"); + sender = ggp_str_to_uin(json_object_get_string_member(result, "sender")); + recipient = + ggp_str_to_uin(json_object_get_string_member(result, "recipient")); + file_size = g_ascii_strtoll( + json_object_get_string_member(result, "file_size"), NULL, 10); + file_name = json_object_get_string_member(result, "file_name"); + + /* GG11: normal + * AQQ 2.4.2.10: direct_inbox + */ + send_mode_str = json_object_get_string_member(result, "send_mode"); + + /* more fields: + * send_progress (float), ack_status, send_status + */ + + if (purple_debug_is_verbose() && purple_debug_is_unsafe()) { + purple_debug_info("gg", + "Got ticket update: id=%s, sender=%u, recipient=%u, " + "file name=\"%s\", file size=%d, send mode=%s)", + ticket_id, sender, recipient, file_name, file_size, + send_mode_str); + } - if (status != 0 ) { - purple_debug_misc("gg", "ggp_ggdrive_auth_done: authentication " - "failed due to bad result (status=%d)\n", status); - if (purple_debug_is_verbose()) - purple_debug_misc("gg", "ggp_ggdrive_auth_done: " - "result = %s\n", - purple_http_response_get_data(response, NULL)); - ggp_ggdrive_auth_results(gc, FALSE); + xfer = g_hash_table_lookup(sdata->xfers_initialized, ticket_id); + if (xfer != NULL) { + purple_debug_misc("gg", + "ggp_edisc_xfer_recv_ticket_update_got: ticket %s " + "already updated", + purple_debug_is_unsafe() ? ticket_id : ""); + g_object_unref(parser); + return; + } + + if (recipient != ggp_get_my_uin(gc)) { + purple_debug_misc("gg", + "ggp_edisc_xfer_recv_ticket_update_got: ticket %s is " + "not for incoming transfer (its from %u to %u)", + purple_debug_is_unsafe() ? ticket_id : "", sender, + recipient); + g_object_unref(parser); + return; + } + + xfer = ggp_edisc_xfer_recv_new(gc, ggp_uin_to_str(sender)); + purple_xfer_set_filename(xfer, file_name); + purple_xfer_set_size(xfer, file_size); + purple_xfer_request(xfer); + edisc_xfer = GGP_XFER(xfer); + edisc_xfer->ticket_id = g_strdup(ticket_id); + g_hash_table_insert(sdata->xfers_initialized, edisc_xfer->ticket_id, xfer); + g_hash_table_insert(sdata->xfers_history, g_strdup(ticket_id), + GINT_TO_POINTER(1)); + + g_object_unref(parser); +} + +static void +ggp_edisc_xfer_recv_ticket_update_authenticated(PurpleConnection *gc, + gboolean success, + gpointer _ticket) +{ + ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); + PurpleHttpRequest *req; + gchar *ticket = _ticket; + + g_return_if_fail(sdata != NULL); + + if (!success) { + purple_debug_warning( + "gg", + "ggp_edisc_xfer_recv_ticket_update_authenticated: update of " + "ticket %s aborted due to authentication failure", + ticket); + g_free(ticket); return; } - sdata->security_token = g_strdup(purple_http_response_get_header( - response, "X-gged-security-token")); - if (!sdata->security_token) { - purple_debug_misc("gg", "ggp_ggdrive_auth_done: authentication " - "failed due to missing security token header\n"); - ggp_ggdrive_auth_results(gc, FALSE); + req = purple_http_request_new(ggp_edisc_xfer_ticket_url(ticket)); + g_free(ticket); + + ggp_edisc_set_defaults(req); + purple_http_request_set_cookie_jar(req, sdata->cookies); + + purple_http_request_header_set(req, "X-gged-security-token", + sdata->security_token); + + purple_http_request(gc, req, ggp_edisc_xfer_recv_ticket_update_got, NULL); + purple_http_request_unref(req); +} + +static void +ggp_edisc_xfer_recv_ticket_got(PurpleConnection *gc, const gchar *ticket_id) +{ + ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); + + g_return_if_fail(sdata != NULL); + + if (g_hash_table_lookup(sdata->xfers_history, ticket_id)) { 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); + ggp_ggdrive_auth(gc, ggp_edisc_xfer_recv_ticket_update_authenticated, + g_strdup(ticket_id)); } +void +ggp_edisc_xfer_ticket_changed(PurpleConnection *gc, const char *data) +{ + ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); + PurpleXfer *xfer; + JsonParser *parser; + JsonObject *ticket; + const gchar *ticket_id, *send_status; + ggp_edisc_xfer_ack_status ack_status; + gboolean is_completed; + + g_return_if_fail(sdata != NULL); + + parser = ggp_json_parse(data); + ticket = json_node_get_object(json_parser_get_root(parser)); + ticket_id = json_object_get_string_member(ticket, "id"); + ack_status = ggp_edisc_xfer_parse_ack_status( + json_object_get_string_member(ticket, "ack_status")); + send_status = json_object_get_string_member(ticket, "send_status"); + + if (ticket_id == NULL) { + ticket_id = ""; + } + xfer = g_hash_table_lookup(sdata->xfers_initialized, ticket_id); + if (xfer == NULL) { + purple_debug_misc("gg", + "ggp_edisc_event_ticket_changed: ticket %s not " + "found, updating it...", + purple_debug_is_unsafe() ? ticket_id : ""); + ggp_edisc_xfer_recv_ticket_got(gc, ticket_id); + g_object_unref(parser); + return; + } + + is_completed = FALSE; + if (g_strcmp0("in_progress", send_status) == 0) { + /* do nothing */ + } else if (g_strcmp0("completed", send_status) == 0) { + is_completed = TRUE; + } else if (g_strcmp0("expired", send_status) == 0) + ggp_edisc_xfer_error(xfer, _("File transfer expired.")); + else { + purple_debug_warning( + "gg", "ggp_edisc_event_ticket_changed: unknown send_status=%s", + send_status); + g_object_unref(parser); + return; + } + + g_object_unref(parser); + + if (purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_RECEIVE) { + if (is_completed) { + ggp_edisc_xfer_recv_ticket_completed(xfer); + } + } else { + if (ack_status != GGP_EDISC_XFER_ACK_STATUS_UNKNOWN) { + ggp_edisc_xfer_send_ticket_changed( + gc, xfer, ack_status == GGP_EDISC_XFER_ACK_STATUS_ALLOWED); + } + } +} + +/******************************************************************************* + * GObject implementation + ******************************************************************************/ + G_DEFINE_DYNAMIC_TYPE(GGPXfer, ggp_xfer, PURPLE_TYPE_XFER); static void