gtk+ r20923 - in trunk: . modules/printbackends/cups



Author: matthiasc
Date: Thu Jul 31 23:56:17 2008
New Revision: 20923
URL: http://svn.gnome.org/viewvc/gtk+?rev=20923&view=rev

Log:
Bug 424207 â printing hangs on unreachable cups server


Modified:
   trunk/ChangeLog
   trunk/modules/printbackends/cups/gtkcupsutils.c
   trunk/modules/printbackends/cups/gtkcupsutils.h
   trunk/modules/printbackends/cups/gtkprintbackendcups.c

Modified: trunk/modules/printbackends/cups/gtkcupsutils.c
==============================================================================
--- trunk/modules/printbackends/cups/gtkcupsutils.c	(original)
+++ trunk/modules/printbackends/cups/gtkcupsutils.c	Thu Jul 31 23:56:17 2008
@@ -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 @@
   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);
+}

Modified: trunk/modules/printbackends/cups/gtkcupsutils.h
==============================================================================
--- trunk/modules/printbackends/cups/gtkcupsutils.h	(original)
+++ trunk/modules/printbackends/cups/gtkcupsutils.h	Thu Jul 31 23:56:17 2008
@@ -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 @@
   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 @@
   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 

Modified: trunk/modules/printbackends/cups/gtkprintbackendcups.c
==============================================================================
--- trunk/modules/printbackends/cups/gtkprintbackendcups.c	(original)
+++ trunk/modules/printbackends/cups/gtkprintbackendcups.c	Thu Jul 31 23:56:17 2008
@@ -106,6 +106,8 @@
   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_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 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 @@
   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 @@
 
   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 @@
     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 @@
   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 @@
   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 @@
    */
   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 @@
     {
        print_backend->default_printer = name;
        print_backend->got_default_printer = TRUE;
-       return;
+       return FALSE;
     }
 
   request = gtk_cups_request_new (NULL,
@@ -1876,6 +1919,8 @@
                         (GtkPrintCupsResponseCallbackFunc) cups_request_default_printer_cb,
 		        g_object_ref (print_backend),
 		        g_object_unref);
+
+  return FALSE;
 }
 
 static void



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]