From ed342f169cb4ddce9394542eebfb4cc361470ac7 Mon Sep 17 00:00:00 2001 From: Stefan Becker Date: Fri, 12 Apr 2013 08:04:44 +0300 Subject: [PATCH] request: provide complete implementation Just not setting the UI ops is not enough, because if a purple request has been generated the caller can be blocked waiting for a callback. Implement all requests UI ops by simply calling the cancel or default action callback. --- configure.ac | 5 -- src/request.c | 204 +++++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 137 insertions(+), 72 deletions(-) diff --git a/configure.ac b/configure.ac index 811dc01..9895552 100644 --- a/configure.ac +++ b/configure.ac @@ -66,11 +66,6 @@ AC_SUBST(ERROR_CFLAGS) AC_CHECK_HEADERS_ONCE([libintl.h]) -AC_ARG_ENABLE(leaky-request-stubs, - AC_HELP_STRING([--enable-leaky-request-stubs],[print debugging information when libpurple attempts to use the request API (warning: very leaky)]), - AC_DEFINE(ENABLE_LEAKY_REQUEST_STUBS, [], [Enable the leaky stub implementation of the request API for debugging purposes])) -AC_SUBST(ENABLE_LEAKY_REQUEST_STUBS) - PKG_CHECK_MODULES(PURPLE,[purple >= 2.7]) PKG_CHECK_MODULES(TP_GLIB,[telepathy-glib >= 0.15.1]) PKG_CHECK_MODULES(GLIB,[glib-2.0 >= 2.22, gobject-2.0, gio-2.0]) diff --git a/src/request.c b/src/request.c index 8aa7bc9..be6f302 100644 --- a/src/request.c +++ b/src/request.c @@ -18,7 +18,7 @@ * */ -#include "config.h" +#include #include @@ -29,7 +29,54 @@ #include "request.h" #include "connection.h" -#ifdef ENABLE_LEAKY_REQUEST_STUBS +struct request_data { + /* request resources */ + PurpleRequestType type; + gpointer resource; /* data type depends on "type" */ + + /* callback resources */ + PurpleRequestFieldsCb ok_cb; + PurpleRequestFieldsCb cancel_cb; + void *user_data; + + /* for purple_account_request_password() */ + PurpleAccount *account; + PurpleRequestField *password; +}; + +static void +haze_close_request (PurpleRequestType type, + void *ui_handle) +{ + struct request_data *rd = ui_handle; + + if (type == PURPLE_REQUEST_FIELDS) + { + if (rd->account) + { + haze_connection_cancel_password_request (rd->account); + } + purple_request_fields_destroy (rd->resource); + } + + g_slice_free (struct request_data, rd); +} + +static gboolean +haze_request_destroy (gpointer user_data) +{ + struct request_data *rd = user_data; + + if (rd->cancel_cb) + { + (rd->cancel_cb) (rd->user_data, NULL); + } + + purple_request_close (rd->type, user_data); + + return FALSE; +} + static gpointer haze_request_input (const char *title, const char *primary, @@ -47,13 +94,23 @@ haze_request_input (const char *title, PurpleConversation *conv, void *user_data) { + struct request_data *rd = g_slice_new0 (struct request_data); + + /* it is our responsibility to destroy this data */ + rd->type = PURPLE_REQUEST_INPUT; + rd->cancel_cb = (PurpleRequestFieldsCb) cancel_cb; + rd->user_data = user_data; + DEBUG ("ignoring request:"); DEBUG (" title: %s", (title ? title : "(null)")); DEBUG (" primary: %s", (primary ? primary : "(null)")); DEBUG (" secondary: %s", (secondary ? secondary : "(null)")); DEBUG (" default_value: %s", default_value ? default_value : "(null)"); - return NULL; + /* Avoid leaking of "user_data" */ + g_idle_add (haze_request_destroy, rd); + + return rd; } static gpointer @@ -71,13 +128,23 @@ haze_request_choice (const char *title, void *user_data, va_list choices) { + struct request_data *rd = g_slice_new0 (struct request_data); + + /* it is our responsibility to destroy this data */ + rd->type = PURPLE_REQUEST_CHOICE; + rd->cancel_cb = (PurpleRequestFieldsCb) cancel_cb; + rd->user_data = user_data; + DEBUG ("ignoring request:"); DEBUG (" title: %s", (title ? title : "(null)")); DEBUG (" primary: %s", (primary ? primary : "(null)")); DEBUG (" secondary: %s", (secondary ? secondary : "(null)")); DEBUG (" default_value: %i", default_value); - return NULL; + /* Avoid leaking of "user_data" */ + g_idle_add (haze_request_destroy, rd); + + return rd; } static gpointer @@ -92,73 +159,59 @@ haze_request_action (const char *title, size_t action_count, va_list actions) { + struct request_data *rd = g_slice_new0 (struct request_data); + size_t i; + + /* it is our responsibility to destroy this data */ + rd->type = PURPLE_REQUEST_ACTION; + rd->user_data = user_data; + + /* find the default action callback */ + for (i = 0; i < action_count; i++) + { + const gchar *text = va_arg(actions, char *); + GCallback cb = va_arg(actions, GCallback); + + /* keep compiler happy */ + (void) text; + + if (i == (size_t) default_action) + { + rd->cancel_cb = (PurpleRequestFieldsCb) cb; + break; + } + } + DEBUG ("ignoring request:"); DEBUG (" title: %s", (title ? title : "(null)")); DEBUG (" primary: %s", (primary ? primary : "(null)")); DEBUG (" secondary: %s", (secondary ? secondary : "(null)")); - return NULL; -} -#endif + /* Avoid leaking of "user_data" */ + g_idle_add (haze_request_destroy, rd); -struct fields_data { - PurpleAccount *account; - PurpleRequestFields *fields; - PurpleRequestField *password; - PurpleRequestFieldsCb ok_cb; - PurpleRequestFieldsCb cancel_cb; - void *user_data; -}; - -static void -haze_close_request (PurpleRequestType type, - void *ui_handle) -{ - struct fields_data *fd = ui_handle; - - haze_connection_cancel_password_request (fd->account); - purple_request_fields_destroy (fd->fields); - g_slice_free (struct fields_data, fd); + return rd; } void haze_request_password_cb (gpointer user_data, const gchar *password) { - struct fields_data *fd = user_data; + struct request_data *rd = user_data; if (password) { - purple_request_field_string_set_value (fd->password, password); - if (fd->ok_cb) + purple_request_field_string_set_value (rd->password, password); + if (rd->ok_cb) { - (fd->ok_cb) (fd->user_data, fd->fields); + (rd->ok_cb) (rd->user_data, rd->resource); } + purple_request_close (rd->type, user_data); } else { - if (fd->cancel_cb) - { - (fd->cancel_cb) (fd->user_data, fd->fields); - } + haze_request_destroy(user_data); } - - purple_request_close (PURPLE_REQUEST_FIELDS, fd); -} - -static gboolean -haze_request_fields_destroy (gpointer user_data) -{ - struct fields_data *fd = user_data; - - if (fd->cancel_cb) - { - (fd->cancel_cb) (fd->user_data, fd->fields); - } - - purple_request_close (PURPLE_REQUEST_FIELDS, user_data); - - return FALSE; } /* @@ -180,13 +233,13 @@ haze_request_fields (const char *title, PurpleConversation *conv, void *user_data) { - struct fields_data *fd = g_slice_new0 (struct fields_data); + struct request_data *rd = g_slice_new0 (struct request_data); /* it is our responsibility to destroy this data */ - fd->account = account; - fd->fields = fields; - fd->cancel_cb = (PurpleRequestFieldsCb) cancel_cb; - fd->user_data = user_data; + rd->type = PURPLE_REQUEST_FIELDS; + rd->resource = fields; + rd->cancel_cb = (PurpleRequestFieldsCb) cancel_cb; + rd->user_data = user_data; if (purple_request_fields_exists (fields, "password") && purple_request_fields_exists (fields, "remember")) @@ -194,10 +247,11 @@ haze_request_fields (const char *title, DEBUG ("triggering password request"); - fd->password = purple_request_fields_get_field (fields, "password"); - fd->ok_cb = (PurpleRequestFieldsCb) ok_cb; + rd->account = account; + rd->password = purple_request_fields_get_field (fields, "password"); + rd->ok_cb = (PurpleRequestFieldsCb) ok_cb; - haze_connection_request_password (account, fd); + haze_connection_request_password (account, rd); } else @@ -208,13 +262,12 @@ haze_request_fields (const char *title, DEBUG (" secondary: %s", (secondary ? secondary : "(null)")); /* Avoid leaking of "fields" and "user_data" */ - g_idle_add (haze_request_fields_destroy, fd); + g_idle_add (haze_request_destroy, rd); } - return fd; + return rd; } -#ifdef ENABLE_LEAKY_REQUEST_STUBS static gpointer haze_request_file (const char *title, const char *filename, @@ -226,11 +279,21 @@ haze_request_file (const char *title, PurpleConversation *conv, void *user_data) { + struct request_data *rd = g_slice_new0 (struct request_data); + + /* it is our responsibility to destroy this data */ + rd->type = PURPLE_REQUEST_FILE; + rd->cancel_cb = (PurpleRequestFieldsCb) cancel_cb; + rd->user_data = user_data; + DEBUG ("ignoring request:"); DEBUG (" title: %s", (title ? title : "(null)")); DEBUG (" filename: %s", (filename ? filename : "(null)")); - return NULL; + /* Avoid leaking of "user_data" */ + g_idle_add (haze_request_destroy, rd); + + return rd; } static gpointer @@ -243,24 +306,31 @@ haze_request_folder (const char *title, PurpleConversation *conv, void *user_data) { + struct request_data *rd = g_slice_new0 (struct request_data); + + /* it is our responsibility to destroy this data */ + rd->type = PURPLE_REQUEST_FOLDER; + rd->cancel_cb = (PurpleRequestFieldsCb) cancel_cb; + rd->user_data = user_data; + DEBUG ("ignoring request:"); DEBUG (" title: %s", (title ? title : "(null)")); DEBUG (" dirname: %s", (dirname ? dirname : "(null)")); - return NULL; + /* Avoid leaking of "user_data" */ + g_idle_add (haze_request_destroy, rd); + + return rd; } -#endif static PurpleRequestUiOps request_uiops = { -#ifdef ENABLE_LEAKY_REQUEST_STUBS .request_input = haze_request_input, .request_choice = haze_request_choice, .request_action = haze_request_action, + .request_fields = haze_request_fields, .request_file = haze_request_file, .request_folder = haze_request_folder, -#endif - .request_fields = haze_request_fields, .close_request = haze_close_request }; -- 1.8.1.4