Hi, Matthias Clasen and I have been working on adding an asynchronous API (vaguely modeled after GnomeVFS) to libgnomecups, and making the internals use this. Right now it's fairly naïve; it creates a new thread for every request. I'm working on moving it to a model where it has a thread per server. But anyways, we just wanted to get feedback on the API as it stands now, and the approach in general.
cvs server: Diffing . Index: configure.in =================================================================== RCS file: /cvs/gnome/libgnomecups/configure.in,v retrieving revision 1.27 diff -u -d -r1.27 configure.in --- configure.in 4 Jun 2004 20:01:46 -0000 1.27 +++ configure.in 18 Jun 2004 17:57:57 -0000 @@ -20,7 +20,7 @@ GLIB_REQUIRED=2.0.0 AC_SUBST(GLIB_REQUIRED) -PKG_CHECK_MODULES(LIBGNOMECUPS, glib-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED) +PKG_CHECK_MODULES(LIBGNOMECUPS, glib-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED gthread-2.0 >= $GLIB_REQUIRED) AC_SUBST(LIBGNOMECUPS_CFLAGS) AC_SUBST(LIBGNOMECUPS_LIBS) cvs server: Diffing libgnomecups Index: libgnomecups/gnome-cups-init.c =================================================================== RCS file: /cvs/gnome/libgnomecups/libgnomecups/gnome-cups-init.c,v retrieving revision 1.3 diff -u -d -r1.3 gnome-cups-init.c --- libgnomecups/gnome-cups-init.c 14 Jan 2004 22:14:52 -0000 1.3 +++ libgnomecups/gnome-cups-init.c 18 Jun 2004 17:57:57 -0000 @@ -2,39 +2,7 @@ #include <cups/cups.h> #include "gnome-cups-init.h" #include "gnome-cups-printer.h" - -/* Should be per thread with push/pop/user_data etc. (clearly) */ -static GnomeCupsAuthFunction global_auth = NULL; - -static const char * -cups_password_cb (const char *prompt) -{ - static char *hazard = NULL; - - g_free (hazard); - hazard = NULL; - - if (global_auth) { - char *password = NULL; - char *username = g_strdup (g_get_user_name ()); - - if (global_auth (prompt, &username, &password, NULL)) { - - if (username) { - cupsSetUser (username); - } else { - cupsSetUser (g_get_user_name ()); - } - hazard = password; - } - g_free (username); - - } else { - g_warning ("Cannot prompt for password: '%s'", prompt); - } - - return hazard; -} +#include "gnome-cups-request.h" /** * gnome_cups_init: @@ -48,9 +16,12 @@ { g_type_init (); - global_auth = opt_auth_fn; - cupsSetPasswordCB (cups_password_cb); - + _gnome_cups_request_init (opt_auth_fn); _gnome_cups_printer_init (); } +void +gnome_cups_shutdown (void) +{ + _gnome_cups_request_shutdown (); +} Index: libgnomecups/gnome-cups-init.h =================================================================== RCS file: /cvs/gnome/libgnomecups/libgnomecups/gnome-cups-init.h,v retrieving revision 1.2 diff -u -d -r1.2 gnome-cups-init.h --- libgnomecups/gnome-cups-init.h 2 May 2003 10:03:39 -0000 1.2 +++ libgnomecups/gnome-cups-init.h 18 Jun 2004 17:57:57 -0000 @@ -13,6 +13,7 @@ GnomeCupsAuthContext *ctxt); void gnome_cups_init (GnomeCupsAuthFunction opt_auth_fn); +void gnome_cups_shutdown (void); G_END_DECLS Index: libgnomecups/gnome-cups-printer.c =================================================================== RCS file: /cvs/gnome/libgnomecups/libgnomecups/gnome-cups-printer.c,v retrieving revision 1.18 diff -u -d -r1.18 gnome-cups-printer.c --- libgnomecups/gnome-cups-printer.c 17 Jun 2004 17:21:03 -0000 1.18 +++ libgnomecups/gnome-cups-printer.c 18 Jun 2004 17:57:57 -0000 @@ -46,6 +46,8 @@ guint is_gone : 1; guint is_local : 1; + guint attributes_request_id; + /* Option management */ guint options_invalid : 1; GHashTable *ppd_options; @@ -207,34 +209,23 @@ return printer->details->info; } -static void -update_attributes (GnomeCupsPrinter *printer) -{ #define MAP_INT(v,a) {if (!g_ascii_strcasecmp (attr->name, (a))) { if ((v) != attr->values[0].integer) { changed = TRUE; } (v) = attr->values[0].integer; }} #define MAP_STRING(v,a) {if (!g_ascii_strcasecmp (attr->name, (a))) { if (!v || strcmp (v, attr->values[0].string.text)) { g_free (v); changed = TRUE; (v) = g_strdup (attr->values[0].string.text); }}} - ipp_t *request; - ipp_t *response; +static void +attributes_update_cb (guint id, + ipp_t *request, + const char *path, + ipp_t *response, + GError **error, + gpointer cb_data) +{ + GnomeCupsPrinter *printer; ipp_attribute_t *attr; gboolean changed; - GError *error = NULL; - static const char *attributes[] = { - "printer-state", "queued-job-count", - "printer-location", "printer-info", - "printer-state-message", "device-uri", - "printer-state-reasons", "printer-info", - "printer-make-and-model", "printer-uri-supported" - }; - - request = gnome_cups_request_new_for_printer (IPP_GET_PRINTER_ATTRIBUTES, - printer->details->printer_name); - gnome_cups_request_add_requested_attributes (request, - IPP_TAG_OPERATION, - G_N_ELEMENTS (attributes), - (char**)attributes); - response = gnome_cups_request_execute (request, "/", &error); - + printer = GNOME_CUPS_PRINTER (cb_data); + changed = FALSE; if (!error && response) { @@ -260,9 +251,7 @@ } } ippDelete (response); - if (error) { - g_error_free (error); - } + g_clear_error (error); if (changed) { g_free (printer->details->full_state); @@ -270,8 +259,42 @@ g_signal_emit (printer, signals[ATTRIBUTES_CHANGED], 0); } + printer->details->attributes_request_id = 0; +} + #undef MAP_INT #undef MAP_STRING + + +static void +update_attributes (GnomeCupsPrinter *printer) +{ + ipp_t *request; + static const char *attributes[] = { + "printer-state", "queued-job-count", + "printer-location", "printer-info", + "printer-state-message", "device-uri", + "printer-state-reasons", "printer-info", + "printer-make-and-model", "printer-uri-supported" + }; + + if (printer->details->attributes_request_id > 0) { + return; + } + + request = gnome_cups_request_new_for_printer (IPP_GET_PRINTER_ATTRIBUTES, + printer->details->printer_name); + + gnome_cups_request_add_requested_attributes (request, + IPP_TAG_OPERATION, + G_N_ELEMENTS (attributes), + (char**)attributes); + printer->details->attributes_request_id = + gnome_cups_request_execute_async (request, NULL, "/", + (GnomeCupsAsyncRequestCallback) attributes_update_cb, + g_object_ref (printer), + g_object_unref); + } static char * @@ -311,7 +334,7 @@ cupsFreeDests (num_dests, dests); request = gnome_cups_request_new (CUPS_GET_DEFAULT); - response = gnome_cups_request_execute (request, "/", &error); + response = gnome_cups_request_execute (request, NULL, "/", &error); if (error) { ippDelete (response); @@ -428,7 +451,7 @@ request = gnome_cups_request_new (CUPS_GET_PRINTERS); - response = gnome_cups_request_execute (request, "/", &error); + response = gnome_cups_request_execute (request, NULL, "/", &error); if (error) { ippDelete (response); @@ -602,7 +625,7 @@ request = gnome_cups_request_new_for_printer (IPP_GET_PRINTER_ATTRIBUTES, printer); - response = gnome_cups_request_execute (request, "/", &error); + response = gnome_cups_request_execute (request, NULL, "/", &error); ippDelete (response); @@ -797,7 +820,7 @@ printer->details->printer_name); ippAddString (request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", NULL, description); - response = gnome_cups_request_execute (request, "/admin/", error); + response = gnome_cups_request_execute (request, NULL, "/admin/", error); ippDelete (response); update_attributes (printer); } @@ -829,7 +852,7 @@ printer->details->printer_name); ippAddString (request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location", NULL, location); - response = gnome_cups_request_execute (request, "/admin/", error); + response = gnome_cups_request_execute (request, NULL, "/admin/", error); ippDelete (response); update_attributes (printer); } @@ -845,7 +868,7 @@ request = gnome_cups_request_new_for_printer (IPP_PAUSE_PRINTER, printer->details->printer_name); - response = gnome_cups_request_execute (request, "/admin/", error); + response = gnome_cups_request_execute (request, NULL, "/admin/", error); ippDelete (response); update_attributes (printer); } @@ -861,7 +884,7 @@ request = gnome_cups_request_new_for_printer (IPP_RESUME_PRINTER, printer->details->printer_name); - response = gnome_cups_request_execute (request, "/admin/", error); + response = gnome_cups_request_execute (request, NULL, "/admin/", error); ippDelete (response); update_attributes (printer); } @@ -877,7 +900,7 @@ request = gnome_cups_request_new_for_printer (CUPS_DELETE_PRINTER, printer->details->printer_name); - response = gnome_cups_request_execute (request, "/admin/", error); + response = gnome_cups_request_execute (request, NULL, "/admin/", error); ippDelete (response); } @@ -1233,6 +1256,9 @@ gnome_cups_printer_finalize (GObject *object) { GnomeCupsPrinter *printer = GNOME_CUPS_PRINTER (object); + + if (printer->details->attributes_request_id > 0) + gnome_cups_request_cancel (printer->details->attributes_request_id > 0); if (printer->details->ppd_options) { g_hash_table_destroy (printer->details->ppd_options); @@ -1471,6 +1497,29 @@ printer->details->dest_options) { printer->details->options_invalid = TRUE; } +} + +gchar *_gnome_cups_printer_get_host (GnomeCupsPrinter *printer) +{ + gchar *host = NULL; + if (printer->details->printer_uri) + { + gchar *x, *y; + + x = strstr (printer->details->printer_uri, "://"); + + if (x) + { + x += 3; + y = strpbrk (x, ":/"); + if (y) + host = g_strndup (x, y - x); + else + host = g_strdup (x); + } + } + + return host; } char * Index: libgnomecups/gnome-cups-queue.c =================================================================== RCS file: /cvs/gnome/libgnomecups/libgnomecups/gnome-cups-queue.c,v retrieving revision 1.11 diff -u -d -r1.11 gnome-cups-queue.c --- libgnomecups/gnome-cups-queue.c 10 Jun 2004 15:55:44 -0000 1.11 +++ libgnomecups/gnome-cups-queue.c 18 Jun 2004 17:57:57 -0000 @@ -9,6 +9,7 @@ #include "util.h" #include "gnome-cups-request.h" +#include "gnome-cups-util.h" #include "gnome-cups-i18n.h" #define UPDATE_TIMEOUT 3000 @@ -17,6 +18,8 @@ char *queue_name; GList *jobs; gboolean is_gone; + + guint get_jobs_request_id; }; enum { @@ -198,26 +201,34 @@ #define MAP_STR(dest, src) { if (!g_ascii_strcasecmp (attr->name, (src))) { if ((dest) != NULL) g_free (dest); (dest) = g_strdup (attr->values[0].string.text);}} #define MAP_INT(dest, src) { if (!g_ascii_strcasecmp (attr->name, (src))) { (dest) = attr->values[0].integer; } } -static GList * -get_jobs (const char *printer_name) +static void +get_jobs_cb (guint id, + ipp_t *request, + const char *path, + ipp_t *response, + GError **error, + gpointer cb_data) { - GError *error = NULL; - ipp_t *request; - ipp_t *response; - ipp_attribute_t *attr; + GnomeCupsQueue *queue; GList *jobs; GnomeCupsJob *job; + ipp_attribute_t *attr; + GList *old_jobs; + GList *added_jobs; + GList *removed_jobs; + GList *changed_jobs; - request = gnome_cups_request_new_for_printer (IPP_GET_JOBS, - printer_name); - response = gnome_cups_request_execute (request, "/", &error); if (error) { ippDelete (response); - g_error_free (error); - return NULL; + g_clear_error (error); + return; } - + + queue = GNOME_CUPS_QUEUE (cb_data); + + old_jobs = queue->details->jobs; jobs = NULL; + if (response) { job = g_new0 (GnomeCupsJob, 1); for (attr = response->attrs; attr != NULL; attr = attr->next) { @@ -235,8 +246,8 @@ if (!g_ascii_strcasecmp (attr->name, "attributes-charset") || !g_ascii_strcasecmp (attr->name, "attributes-charset")) { continue; + } - MAP_STR (job->name, "job-name"); MAP_INT (job->id, "job-id"); MAP_STR (job->owner, "job-originating-user-name"); @@ -257,12 +268,50 @@ gnome_cups_job_free (job); } - jobs = g_list_reverse (jobs); + queue->details->jobs = g_list_reverse (jobs); ippDelete (response); } + + compare_queues (old_jobs, queue->details->jobs, + &added_jobs, &removed_jobs, &changed_jobs); - return jobs; + if (added_jobs) { + g_signal_emit (queue, signals[JOBS_ADDED], 0, added_jobs); + g_list_free (added_jobs); + } + if (changed_jobs) { + g_signal_emit (queue, signals[JOBS_CHANGED], 0, changed_jobs); + g_list_free (changed_jobs); + } + if (removed_jobs) { + g_signal_emit (queue, signals[JOBS_REMOVED], 0, removed_jobs); + g_list_free (removed_jobs); + } + + gnome_cups_job_list_free (old_jobs); + + queue->details->get_jobs_request_id = 0; +} + +static void +get_jobs_on_server (GnomeCupsQueue *queue, const char *server) +{ + ipp_t *request; + const char *printer_name; + + if (queue->details->get_jobs_request_id > 0) + return; + + printer_name = queue->details->queue_name; + + request = gnome_cups_request_new_for_printer (IPP_GET_JOBS, + printer_name); + queue->details->get_jobs_request_id = + gnome_cups_request_execute_async (request, server, "/", + (GnomeCupsAsyncRequestCallback) get_jobs_cb, + g_object_ref (queue), + (GDestroyNotify) g_object_unref); } static GnomeCupsJob * @@ -273,11 +322,27 @@ ipp_t *request; ipp_t *response; ipp_attribute_t *attr; + GnomeCupsPrinter *printer; GnomeCupsJob *job; + char *server; + + printer = gnome_cups_printer_get (queue->details->queue_name); + + if (!printer) + return NULL; + + server = _gnome_cups_printer_get_host (printer); + + g_object_unref (G_OBJECT (printer)); request = gnome_cups_request_new_for_job (IPP_GET_JOB_ATTRIBUTES, job_id); - response = gnome_cups_request_execute (request, "/", &error); + + if (gnome_cups_printer_get_is_local (printer)) + response = gnome_cups_request_execute (request, NULL, "/", &error); + else + response = gnome_cups_request_execute (request, server, "/", &error); + g_free (server); if (error) { ippDelete (response); g_error_free (error); @@ -357,32 +422,25 @@ static void update_queue (GnomeCupsQueue *queue) { - GList *old_jobs; + GnomeCupsPrinter *printer; + gchar *printer_host = NULL; - GList *added_jobs; - GList *removed_jobs; - GList *changed_jobs; + printer = gnome_cups_printer_get_existing (queue->details->queue_name); - old_jobs = queue->details->jobs; - queue->details->jobs = get_jobs (queue->details->queue_name); + if (printer) { + printer_host = _gnome_cups_printer_get_host (printer); + g_object_unref (printer); + } - compare_queues (old_jobs, queue->details->jobs, - &added_jobs, &removed_jobs, &changed_jobs); + if (!printer_host) + return; - if (added_jobs) { - g_signal_emit (queue, signals[JOBS_ADDED], 0, added_jobs); - g_list_free (added_jobs); - } - if (changed_jobs) { - g_signal_emit (queue, signals[JOBS_CHANGED], 0, changed_jobs); - g_list_free (changed_jobs); - } - if (removed_jobs) { - g_signal_emit (queue, signals[JOBS_REMOVED], 0, removed_jobs); - g_list_free (removed_jobs); - } + if (gnome_cups_printer_get_is_local (printer)) + get_jobs_on_server (queue, NULL); + else + get_jobs_on_server (queue, printer_host); - gnome_cups_job_list_free (old_jobs); + g_free (printer_host); } static gboolean @@ -513,7 +571,7 @@ request = gnome_cups_request_new_for_printer (IPP_GET_PRINTER_ATTRIBUTES, queue); - response = gnome_cups_request_execute (request, "/", &error); + response = gnome_cups_request_execute (request, NULL, "/", &error); ippDelete (response); @@ -598,7 +656,7 @@ g_return_if_fail (GNOME_CUPS_IS_QUEUE (queue)); request = gnome_cups_request_new_for_job (IPP_HOLD_JOB, job_id); - response = gnome_cups_request_execute (request, "/jobs", error); + response = gnome_cups_request_execute (request, NULL, "/jobs", error); ippDelete (response); update_queue (queue); @@ -615,7 +673,7 @@ g_return_if_fail (GNOME_CUPS_IS_QUEUE (queue)); request = gnome_cups_request_new_for_job (IPP_RELEASE_JOB, job_id); - response = gnome_cups_request_execute (request, "/jobs", error); + response = gnome_cups_request_execute (request, NULL, "/jobs", error); ippDelete (response); update_queue (queue); @@ -632,7 +690,7 @@ g_return_if_fail (GNOME_CUPS_IS_QUEUE (queue)); request = gnome_cups_request_new_for_job (IPP_CANCEL_JOB, job_id); - response = gnome_cups_request_execute (request, "/jobs", error); + response = gnome_cups_request_execute (request, NULL, "/jobs", error); ippDelete (response); update_queue (queue); @@ -642,6 +700,9 @@ gnome_cups_queue_finalize (GObject *object) { GnomeCupsQueue *queue = GNOME_CUPS_QUEUE (object); + + if (queue->details->get_jobs_request_id > 0) + gnome_cups_request_cancel (queue->details->get_jobs_request_id > 0); if (queue->details->jobs) { gnome_cups_job_list_free (queue->details->jobs); Index: libgnomecups/gnome-cups-request.c =================================================================== RCS file: /cvs/gnome/libgnomecups/libgnomecups/gnome-cups-request.c,v retrieving revision 1.11 diff -u -d -r1.11 gnome-cups-request.c --- libgnomecups/gnome-cups-request.c 17 May 2004 16:46:18 -0000 1.11 +++ libgnomecups/gnome-cups-request.c 18 Jun 2004 17:57:57 -0000 @@ -10,6 +10,15 @@ #include "gnome-cups-util.h" #include "gnome-cups-i18n.h" +static guint +gnome_cups_request_execute_async_internal (ipp_t *request, + const char *server, + const char *path, + gboolean direct_callback, + GnomeCupsAsyncRequestCallback callback, + gpointer cb_data, + GDestroyNotify destroy_notify); + static const char * get_error_string (ipp_status_t error) { @@ -77,6 +86,179 @@ return _("Unknown error"); } +/* Should be per thread with push/pop/user_data etc. (clearly) */ +static GnomeCupsAuthFunction global_auth = NULL; + +static const char * +cups_password_cb (const char *prompt) +{ + static char *hazard = NULL; + + g_free (hazard); + hazard = NULL; + + if (global_auth) { + char *password = NULL; + char *username = g_strdup (g_get_user_name ()); + + if (global_auth (prompt, &username, &password, NULL)) { + + if (username) { + cupsSetUser (username); + } else { + cupsSetUser (g_get_user_name ()); + } + hazard = password; + } + g_free (username); + + } else { + g_warning ("Cannot prompt for password: '%s'", prompt); + } + + return hazard; +} + +typedef struct +{ + gboolean cancelled; + gboolean direct_callback; + guint id; + + ipp_t *response; + GError **error; + char *server; + GnomeCupsAsyncRequestCallback callback; + gpointer cb_data; + GDestroyNotify destroy_notify; + + ipp_t *request; + char *path; +} GnomeCupsRequest; + +GStaticMutex request_mutex = G_STATIC_MUTEX_INIT; +static guint request_serial_number = 0; +static guint request_map_refcount = 0; +static GHashTable *request_map = 0; + +void +_gnome_cups_request_init (GnomeCupsAuthFunction auth_fn) +{ + global_auth = auth_fn; + cupsSetPasswordCB (cups_password_cb); + + g_static_mutex_lock (&request_mutex); + if (request_map_refcount == 0) + request_map = g_hash_table_new (NULL, NULL); + request_map_refcount++; + g_static_mutex_unlock (&request_mutex); +} + +void +_gnome_cups_request_shutdown (void) +{ + g_static_mutex_lock (&request_mutex); + request_map_refcount--; + if (request_map_refcount == 0) + g_hash_table_destroy (request_map); + g_static_mutex_unlock (&request_mutex); +} + +static void +gnome_cups_request_struct_free (GnomeCupsRequest *request) +{ + g_free (request->server); + g_free (request->path); + if (request->error && *request->error) + g_error_free (*request->error); + g_free (request); +} + +static gboolean +idle_signal_request_complete (GnomeCupsRequest *request) +{ + if (!request->cancelled && request->callback) + request->callback (request->id, request->request, + request->path, + request->response, + request->error, + request->cb_data); + else { + ippDelete (request->request); + ippDelete (request->response); + } + + g_static_mutex_lock (&request_mutex); + g_assert (g_hash_table_remove (request_map, GUINT_TO_POINTER (request->id))); + g_static_mutex_unlock (&request_mutex); + + if (request->destroy_notify) + request->destroy_notify (request->cb_data); + + gnome_cups_request_struct_free (request); + + return FALSE; +} + +static void +do_signal_complete (GnomeCupsRequest *request) +{ + if (request->direct_callback) + idle_signal_request_complete (request); + else + g_idle_add ((GSourceFunc) idle_signal_request_complete, request); +} + +static gpointer +request_thread_main (GnomeCupsRequest *request) +{ + http_t *http; + ipp_t *response; + ipp_status_t status; + const char *server; + + if (request->cancelled) { + do_signal_complete (request); + return NULL; + } + + if (!request->server) + server = cupsServer(); + else + server = request->server; + + http = httpConnectEncrypt (server, ippPort(), cupsEncryption()); + + response = cupsDoRequest (http, request->request, + request->path ? request->path : "/"); + + status = cupsLastError (); + + httpClose (http); + + if (status > IPP_OK_CONFLICT && request->error != NULL) { + *(request->error) = g_error_new (GNOME_CUPS_ERROR, + status, + get_error_string (status)); + } + + request->response = response; + do_signal_complete (request); + + return NULL; +} + +gboolean +_gnome_cups_request_is_executing (void) +{ + gboolean ret; + + g_static_mutex_lock (&request_mutex); + ret = g_hash_table_size (request_map) > 0; + g_static_mutex_unlock (&request_mutex); + return ret; +} + ipp_t * gnome_cups_request_new (int operation_id) { @@ -105,7 +287,7 @@ { ipp_t *request; char *printer_uri; - + request = gnome_cups_request_new (operation_id); printer_uri = gnome_cups_get_printer_uri (printer_name); @@ -155,71 +337,132 @@ IPP_TAG_KEYWORD, "requested-attributes", n_attributes, NULL, NULL); - + for (i = 0; i < n_attributes; i++) { attr->values[i].string.text = gnome_cups_strdup (attributes[i]); } } -static gboolean request_executing = FALSE; +typedef struct +{ + GMutex *mutex; + GCond *cond; + gboolean done; + ipp_t *response; + GError **error; +} GnomeCupsAsyncWrapperData; -gboolean -_gnome_cups_request_is_executing (void) +static void +async_wrapper_cb (guint id, ipp_t *request, const char *path, + ipp_t *response, GError **error, + GnomeCupsAsyncWrapperData *data) { - return request_executing; + g_mutex_lock (data->mutex); + data->done = TRUE; + data->response = response; + if (data->error && error && *error) + g_propagate_error (data->error, *error); + g_cond_signal (data->cond); + g_mutex_unlock (data->mutex); } ipp_t * -gnome_cups_request_execute (ipp_t *request, const char *path, GError **err) +gnome_cups_request_execute (ipp_t *request, + const char *server, + const char *path, GError **err) { - static http_t *main_http = NULL; - http_t *single_http = NULL; - http_t *http; - ipp_t *response; - ipp_status_t status; + guint id; + GnomeCupsAsyncWrapperData data; - g_return_val_if_fail (err == NULL || *err == NULL, NULL); + data.mutex = g_mutex_new (); + data.cond = g_cond_new (); + data.done = FALSE; + data.response = NULL; + data.error = err; - /* FIXME: This sucks. We want to try to keep everything on - * one http connection, but due to reentrancy problems, we - * can't always do that (if the request goes back to the main - * loop during authentication, we can be called again, and - * can't issue a new request on that connection. - * - * For right now, we keep a main http connection around, and use that - * if it's available. Otherwise we do a connection per request. */ + id = gnome_cups_request_execute_async_internal (request, server, path, + TRUE, + (GnomeCupsAsyncRequestCallback) async_wrapper_cb, + &data, + NULL); + if (id == 0) + goto out; - cupsSetUser (g_get_user_name ()); + g_mutex_lock (data.mutex); + while (!data.done) + g_cond_wait (data.cond, data.mutex); + g_mutex_unlock (data.mutex); - if (!main_http) { - main_http = httpConnectEncrypt (cupsServer(), ippPort(), cupsEncryption()); - } +out: + g_mutex_free (data.mutex); + g_cond_free (data.cond); + + return data.response; +} - if (!request_executing) { - http = main_http; - } else { - http = single_http = httpConnectEncrypt (cupsServer (), - ippPort(), - cupsEncryption()); - } +guint +gnome_cups_request_execute_async (ipp_t *request, + const char *server, + const char *path, + GnomeCupsAsyncRequestCallback callback, + gpointer cb_data, + GDestroyNotify destroy_notify) +{ + return gnome_cups_request_execute_async_internal (request, server, + path, FALSE, + callback, cb_data, + destroy_notify); +} - request_executing = TRUE; +static guint +gnome_cups_request_execute_async_internal (ipp_t *request, + const char *server, + const char *path, + gboolean direct_callback, + GnomeCupsAsyncRequestCallback callback, + gpointer cb_data, + GDestroyNotify destroy_notify) +{ + GnomeCupsRequest *req; + GError *thread_err = NULL; - response = cupsDoRequest (http, request, path ? path : "/"); + req = g_new0 (GnomeCupsRequest, 1); + req->cancelled = FALSE; + req->server = g_strdup (server); + req->request = request; + req->callback = callback; + req->cb_data = cb_data; + req->destroy_notify = destroy_notify; + req->path = g_strdup (path); + req->direct_callback = direct_callback; + req->error = NULL; - status = cupsLastError (); + g_static_mutex_lock (&request_mutex); + req->id = ++request_serial_number; + g_static_mutex_unlock (&request_mutex); - if (single_http) { - httpClose (single_http); + g_thread_create ((GThreadFunc) request_thread_main, req, FALSE, &thread_err); + if (thread_err != NULL) { + g_error_free (thread_err); + gnome_cups_request_struct_free (req); + return 0; } + g_static_mutex_lock (&request_mutex); + g_hash_table_insert (request_map, GUINT_TO_POINTER (req->id), req); + g_static_mutex_unlock (&request_mutex); - request_executing = FALSE; + return req->id; + +} - if (status > IPP_OK_CONFLICT && err != NULL) { - *err = g_error_new (GNOME_CUPS_ERROR, - status, - get_error_string (status)); - } +void +gnome_cups_request_cancel (guint request_id) +{ + GnomeCupsRequest *request; - return response; + g_static_mutex_lock (&request_mutex); + if ((request = g_hash_table_lookup (request_map, GUINT_TO_POINTER (request_id))) != NULL) { + request->cancelled = TRUE; + } + g_static_mutex_unlock (&request_mutex); } Index: libgnomecups/gnome-cups-request.h =================================================================== RCS file: /cvs/gnome/libgnomecups/libgnomecups/gnome-cups-request.h,v retrieving revision 1.4 diff -u -d -r1.4 gnome-cups-request.h --- libgnomecups/gnome-cups-request.h 6 May 2003 22:14:27 -0000 1.4 +++ libgnomecups/gnome-cups-request.h 18 Jun 2004 17:57:57 -0000 @@ -3,6 +3,14 @@ #include <cups/ipp.h> #include <glib.h> +#include <gnome-cups-init.h> + +typedef void (*GnomeCupsAsyncRequestCallback) (guint id, + ipp_t *request, + const char *path, + ipp_t *response, + GError **error, + gpointer cb_data); ipp_t *gnome_cups_request_new (int operation_id); ipp_t *gnome_cups_request_new_for_printer (int operation_id, @@ -14,11 +22,22 @@ int n_attributes, char **attributes); ipp_t *gnome_cups_request_execute (ipp_t *request, + const char *server, const char *path, GError **err); +guint gnome_cups_request_execute_async (ipp_t *request, + const char *server, + const char *path, + GnomeCupsAsyncRequestCallback callback, + gpointer cb_data, + GDestroyNotify destroy_notify); + +void gnome_cups_request_cancel (guint request_id); /* private */ gboolean _gnome_cups_request_is_executing (void); +void _gnome_cups_request_init (GnomeCupsAuthFunction authfn); +void _gnome_cups_request_shutdown (void); cvs server: Diffing po
Attachment:
signature.asc
Description: This is a digitally signed message part