diff options
author | Matthias Clasen <matthiasc@src.gnome.org> | 2008-07-31 23:56:17 +0000 |
---|---|---|
committer | Matthias Clasen <matthiasc@src.gnome.org> | 2008-07-31 23:56:17 +0000 |
commit | e9d978dff9f9b18eaac6c4920fb5abf7245d839d (patch) | |
tree | 11e1d6864cfc988203ba48ffad98851b1820e011 /modules/printbackends | |
parent | c04c884f3516ca7408fd737536a2721554dc7f71 (diff) | |
download | gtk+-e9d978dff9f9b18eaac6c4920fb5abf7245d839d.tar.gz |
Bug 424207 – printing hangs on unreachable cups server
svn path=/trunk/; revision=20923
Diffstat (limited to 'modules/printbackends')
-rw-r--r-- | modules/printbackends/cups/gtkcupsutils.c | 119 | ||||
-rw-r--r-- | modules/printbackends/cups/gtkcupsutils.h | 82 | ||||
-rw-r--r-- | modules/printbackends/cups/gtkprintbackendcups.c | 57 |
3 files changed, 217 insertions, 41 deletions
diff --git a/modules/printbackends/cups/gtkcupsutils.c b/modules/printbackends/cups/gtkcupsutils.c index 06e8ca8661..09cd6906cf 100644 --- a/modules/printbackends/cups/gtkcupsutils.c +++ b/modules/printbackends/cups/gtkcupsutils.c @@ -29,6 +29,8 @@ #include <sys/stat.h> #include <stdlib.h> #include <time.h> +#include <fcntl.h> +#include <sys/socket.h> typedef void (*GtkCupsRequestStateFunc) (GtkCupsRequest *request); @@ -1195,3 +1197,120 @@ gtk_cups_result_get_error_string (GtkCupsResult *result) return result->error_msg; } +/* This function allocates new instance of GtkCupsConnectionTest() and creates + * a socket for communication with a CUPS server 'server'. + */ +GtkCupsConnectionTest * +gtk_cups_connection_test_new (const char *server) +{ + GtkCupsConnectionTest *result = NULL; + gchar *port_str = NULL; + + result = g_new (GtkCupsConnectionTest, 1); + + port_str = g_strdup_printf ("%d", ippPort ()); + + if (server != NULL) + result->addrlist = httpAddrGetList (server, AF_UNSPEC, port_str); + else + result->addrlist = httpAddrGetList (cupsServer (), AF_UNSPEC, port_str); + + g_free (port_str); + + result->socket = -1; + result->current_addr = NULL; + result->success_at_init = FALSE; + + result->success_at_init = gtk_cups_connection_test_is_server_available (result); + + return result; +} + + +/* A non-blocking test whether it is possible to connect to a CUPS server specified + * inside of GtkCupsConnectionTest structure. + * - you need to check it more then once. + * The connection is closed after a successful connection. + */ +gboolean +gtk_cups_connection_test_is_server_available (GtkCupsConnectionTest *test) +{ + http_addrlist_t *iter; + gboolean result = FALSE; + gint flags; + gint code; + + if (test == NULL) + return FALSE; + + if (test->success_at_init) + { + test->success_at_init = FALSE; + return TRUE; + } + else + { + if (test->socket == -1) + { + iter = test->addrlist; + while (iter) + { + test->socket = socket (iter->addr.addr.sa_family, + SOCK_STREAM, + 0); + + if (test->socket >= 0) + { + flags = fcntl (test->socket, F_GETFL); + + if (flags != -1) + flags |= O_NONBLOCK; + + fcntl (test->socket, F_SETFL, flags); + + test->current_addr = iter; + + break; + } + iter = iter->next; + } + } + + if (test->socket >= 0) + { + code = connect (test->socket, + &test->current_addr->addr.addr, + httpAddrLength (&test->current_addr->addr)); + + if (code == 0) + { + close (test->socket); + test->socket = -1; + test->current_addr = NULL; + result = TRUE; + } + else + result = FALSE; + } + + return result; + } +} + +/* This function frees memory used by the GtkCupsConnectionTest structure. + */ +void +gtk_cups_connection_test_free (GtkCupsConnectionTest *test) +{ + if (test == NULL) + return FALSE; + + test->current_addr = NULL; + httpAddrFreeList (test->addrlist); + if (test->socket != -1) + { + close (test->socket); + test->socket = -1; + } + g_free (test); +} diff --git a/modules/printbackends/cups/gtkcupsutils.h b/modules/printbackends/cups/gtkcupsutils.h index 6ea80e78d0..7dfe387f91 100644 --- a/modules/printbackends/cups/gtkcupsutils.h +++ b/modules/printbackends/cups/gtkcupsutils.h @@ -28,8 +28,9 @@ G_BEGIN_DECLS -typedef struct _GtkCupsRequest GtkCupsRequest; -typedef struct _GtkCupsResult GtkCupsResult; +typedef struct _GtkCupsRequest GtkCupsRequest; +typedef struct _GtkCupsResult GtkCupsResult; +typedef struct _GtkCupsConnectionTest GtkCupsConnectionTest; typedef enum { @@ -80,6 +81,14 @@ struct _GtkCupsRequest gint own_http : 1; }; +struct _GtkCupsConnectionTest +{ + http_addrlist_t *addrlist; + http_addrlist_t *current_addr; + gboolean success_at_init; + gint socket; +}; + #define GTK_CUPS_REQUEST_START 0 #define GTK_CUPS_REQUEST_DONE 500 @@ -105,39 +114,42 @@ enum GTK_CUPS_GET_DONE = GTK_CUPS_REQUEST_DONE }; -GtkCupsRequest * gtk_cups_request_new (http_t *connection, - GtkCupsRequestType req_type, - gint operation_id, - GIOChannel *data_io, - const char *server, - const char *resource); -void gtk_cups_request_ipp_add_string (GtkCupsRequest *request, - ipp_tag_t group, - ipp_tag_t tag, - const char *name, - const char *charset, - const char *value); -void gtk_cups_request_ipp_add_strings (GtkCupsRequest *request, - ipp_tag_t group, - ipp_tag_t tag, - const char *name, - int num_values, - const char *charset, - const char * const *values); -gboolean gtk_cups_request_read_write (GtkCupsRequest *request); -GtkCupsPollState gtk_cups_request_get_poll_state (GtkCupsRequest *request); -void gtk_cups_request_free (GtkCupsRequest *request); -GtkCupsResult * gtk_cups_request_get_result (GtkCupsRequest *request); -gboolean gtk_cups_request_is_done (GtkCupsRequest *request); -void gtk_cups_request_encode_option (GtkCupsRequest *request, - const gchar *option, - const gchar *value); -gboolean gtk_cups_result_is_error (GtkCupsResult *result); -ipp_t * gtk_cups_result_get_response (GtkCupsResult *result); -GtkCupsErrorType gtk_cups_result_get_error_type (GtkCupsResult *result); -int gtk_cups_result_get_error_status (GtkCupsResult *result); -int gtk_cups_result_get_error_code (GtkCupsResult *result); -const char * gtk_cups_result_get_error_string (GtkCupsResult *result); +GtkCupsRequest * gtk_cups_request_new (http_t *connection, + GtkCupsRequestType req_type, + gint operation_id, + GIOChannel *data_io, + const char *server, + const char *resource); +void gtk_cups_request_ipp_add_string (GtkCupsRequest *request, + ipp_tag_t group, + ipp_tag_t tag, + const char *name, + const char *charset, + const char *value); +void gtk_cups_request_ipp_add_strings (GtkCupsRequest *request, + ipp_tag_t group, + ipp_tag_t tag, + const char *name, + int num_values, + const char *charset, + const char * const *values); +gboolean gtk_cups_request_read_write (GtkCupsRequest *request); +GtkCupsPollState gtk_cups_request_get_poll_state (GtkCupsRequest *request); +void gtk_cups_request_free (GtkCupsRequest *request); +GtkCupsResult * gtk_cups_request_get_result (GtkCupsRequest *request); +gboolean gtk_cups_request_is_done (GtkCupsRequest *request); +void gtk_cups_request_encode_option (GtkCupsRequest *request, + const gchar *option, + const gchar *value); +gboolean gtk_cups_result_is_error (GtkCupsResult *result); +ipp_t * gtk_cups_result_get_response (GtkCupsResult *result); +GtkCupsErrorType gtk_cups_result_get_error_type (GtkCupsResult *result); +int gtk_cups_result_get_error_status (GtkCupsResult *result); +int gtk_cups_result_get_error_code (GtkCupsResult *result); +const char * gtk_cups_result_get_error_string (GtkCupsResult *result); +GtkCupsConnectionTest * gtk_cups_connection_test_new (const char *server); +gboolean gtk_cups_connection_test_is_server_available (GtkCupsConnectionTest *test); +void gtk_cups_connection_test_free (GtkCupsConnectionTest *test); G_END_DECLS #endif diff --git a/modules/printbackends/cups/gtkprintbackendcups.c b/modules/printbackends/cups/gtkprintbackendcups.c index f493063b7d..1a3ebae8a1 100644 --- a/modules/printbackends/cups/gtkprintbackendcups.c +++ b/modules/printbackends/cups/gtkprintbackendcups.c @@ -106,6 +106,8 @@ struct _GtkPrintBackendCups guint list_printers_poll; guint list_printers_pending : 1; guint got_default_printer : 1; + guint default_printer_poll; + GtkCupsConnectionTest *default_printer_connection_test; char **covers; char *default_cover_before; @@ -120,6 +122,7 @@ static void gtk_print_backend_cups_init (GtkPrintBack static void gtk_print_backend_cups_finalize (GObject *object); static void gtk_print_backend_cups_dispose (GObject *object); static void cups_get_printer_list (GtkPrintBackend *print_backend); +static void cups_get_default_printer (GtkPrintBackendCups *print_backend); static void cups_request_execute (GtkPrintBackendCups *print_backend, GtkCupsRequest *request, GtkPrintCupsResponseCallbackFunc callback, @@ -141,7 +144,7 @@ static void cups_printer_prepare_for_print (GtkPrinter static GList * cups_printer_list_papers (GtkPrinter *printer); static GtkPageSetup * cups_printer_get_default_page_size (GtkPrinter *printer); static void cups_printer_request_details (GtkPrinter *printer); -static void cups_request_default_printer (GtkPrintBackendCups *print_backend); +static gboolean cups_request_default_printer (GtkPrintBackendCups *print_backend); static void cups_request_ppd (GtkPrinter *printer); static void cups_printer_get_hard_margins (GtkPrinter *printer, double *top, @@ -509,7 +512,10 @@ gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups) backend_cups->default_cover_after = NULL; backend_cups->number_of_covers = 0; - cups_request_default_printer (backend_cups); + backend_cups->default_printer_poll = 0; + backend_cups->default_printer_connection_test = NULL; + + cups_get_default_printer (backend_cups); } static void @@ -530,6 +536,8 @@ gtk_print_backend_cups_finalize (GObject *object) g_free (backend_cups->default_cover_before); g_free (backend_cups->default_cover_after); + + gtk_cups_connection_test_free (backend_cups->default_printer_connection_test); backend_parent_class->finalize (object); } @@ -548,6 +556,10 @@ gtk_print_backend_cups_dispose (GObject *object) g_source_remove (backend_cups->list_printers_poll); backend_cups->list_printers_poll = 0; + if (backend_cups->default_printer_poll > 0) + g_source_remove (backend_cups->default_printer_poll); + backend_cups->default_printer_poll = 0; + backend_parent_class->dispose (object); } @@ -1812,6 +1824,27 @@ cups_get_user_options (const char *printer_name, return num_options; } +/* This function requests default printer from a CUPS server in regular intervals. + * In the case of unreachable CUPS server the request is repeated later. + * The default printer is not requested in the case of previous success. + */ +static void +cups_get_default_printer (GtkPrintBackendCups *backend) +{ + GtkPrintBackendCups *cups_backend; + + cups_backend = backend; + + cups_backend->default_printer_connection_test = gtk_cups_connection_test_new (NULL); + if (cups_backend->default_printer_poll == 0) + { + if (cups_request_default_printer (cups_backend)) + cups_backend->default_printer_poll = gdk_threads_add_timeout_seconds (1, + (GSourceFunc) cups_request_default_printer, + backend); + } +} + static void cups_request_default_printer_cb (GtkPrintBackendCups *print_backend, GtkCupsResult *result, @@ -1820,6 +1853,8 @@ cups_request_default_printer_cb (GtkPrintBackendCups *print_backend, ipp_t *response; ipp_attribute_t *attr; + GDK_THREADS_ENTER (); + response = gtk_cups_result_get_response (result); if ((attr = ippFindAttribute (response, "printer-name", IPP_TAG_NAME)) != NULL) @@ -1832,27 +1867,35 @@ cups_request_default_printer_cb (GtkPrintBackendCups *print_backend, */ if (print_backend->list_printers_poll != 0) cups_request_printer_list (print_backend); + + GDK_THREADS_LEAVE (); } -static void +static gboolean cups_request_default_printer (GtkPrintBackendCups *print_backend) { GtkCupsRequest *request; const char *str; char *name = NULL; + if (!gtk_cups_connection_test_is_server_available (print_backend->default_printer_connection_test)) + return TRUE; + + gtk_cups_connection_test_free (print_backend->default_printer_connection_test); + print_backend->default_printer_connection_test = NULL; + if ((str = g_getenv ("LPDEST")) != NULL) { print_backend->default_printer = g_strdup (str); print_backend->got_default_printer = TRUE; - return; + return FALSE; } else if ((str = g_getenv ("PRINTER")) != NULL && strcmp (str, "lp") != 0) { print_backend->default_printer = g_strdup (str); print_backend->got_default_printer = TRUE; - return; + return FALSE; } /* Figure out user setting for default printer */ @@ -1861,7 +1904,7 @@ cups_request_default_printer (GtkPrintBackendCups *print_backend) { print_backend->default_printer = name; print_backend->got_default_printer = TRUE; - return; + return FALSE; } request = gtk_cups_request_new (NULL, @@ -1876,6 +1919,8 @@ cups_request_default_printer (GtkPrintBackendCups *print_backend) (GtkPrintCupsResponseCallbackFunc) cups_request_default_printer_cb, g_object_ref (print_backend), g_object_unref); + + return FALSE; } static void |