[gtk+] printing: Don't wake up Avahi printers unnecessarily



commit 376e2c003d02405cb0a62b90f4e2a0cab88f9650
Author: Marek Kasik <mkasik redhat com>
Date:   Thu Nov 21 15:27:33 2013 +0100

    printing: Don't wake up Avahi printers unnecessarily
    
    Use info available in Avahi TXT records for creation of gtk printer
    and request details when needed (through gtk_printer_request_details()).
    If there is a printer advertised on Avahi by a remote CUPS server
    try to get its PPD file at first or get its capabilities through an IPP
    request if it fails.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=712751

 modules/printbackends/cups/gtkprintbackendcups.c |  317 +++++++++++++++-------
 1 files changed, 220 insertions(+), 97 deletions(-)
---
diff --git a/modules/printbackends/cups/gtkprintbackendcups.c 
b/modules/printbackends/cups/gtkprintbackendcups.c
index 9090733..53c7de1 100644
--- a/modules/printbackends/cups/gtkprintbackendcups.c
+++ b/modules/printbackends/cups/gtkprintbackendcups.c
@@ -2365,28 +2365,6 @@ set_default_printer (GtkPrintBackendCups *cups_backend,
 }
 
 #ifdef HAVE_CUPS_API_1_6
-typedef struct
-{
-  gchar *name;
-  gchar *type;
-  gchar *domain;
-  gchar *host;
-  gint   port;
-} AvahiService;
-
-void
-avahi_service_free (AvahiService *service)
-{
-  if (service)
-    {
-      g_free (service->name);
-      g_free (service->type);
-      g_free (service->domain);
-      g_free (service->host);
-      g_free (service);
-    }
-}
-
 static void
 cups_request_avahi_printer_info_cb (GtkPrintBackendCups *cups_backend,
                                     GtkCupsResult       *result,
@@ -2395,9 +2373,7 @@ cups_request_avahi_printer_info_cb (GtkPrintBackendCups *cups_backend,
   PrinterSetupInfo *info = g_slice_new0 (PrinterSetupInfo);
   GtkPrintBackend  *backend = GTK_PRINT_BACKEND (cups_backend);
   ipp_attribute_t  *attr;
-  AvahiService     *service = (AvahiService *) user_data;
   GtkPrinter       *printer;
-  gboolean          list_has_changed = FALSE;
   gboolean          status_changed = FALSE;
   ipp_t            *response;
 
@@ -2432,42 +2408,28 @@ cups_request_avahi_printer_info_cb (GtkPrintBackendCups *cups_backend,
 
       if (info->printer_name && info->printer_uri)
         {
-          info->avahi_printer = TRUE;
-
-          if (info->got_printer_type &&
-              info->default_printer &&
-              cups_backend->avahi_default_printer == NULL)
-            cups_backend->avahi_default_printer = g_strdup (info->printer_name);
-
           set_info_state_message (info);
 
           printer = gtk_print_backend_find_printer (backend, info->printer_name);
-          if (!printer)
+          if (printer != NULL &&
+              GTK_PRINTER_CUPS (printer)->avahi_browsed)
             {
-              printer = cups_create_printer (cups_backend, info);
-              list_has_changed = TRUE;
+              g_object_ref (printer);
             }
           else
             {
-              g_object_ref (printer);
+              goto done;
             }
 
+          if (info->got_printer_type &&
+              info->default_printer &&
+              cups_backend->avahi_default_printer == NULL)
+            cups_backend->avahi_default_printer = g_strdup (info->printer_name);
+
           gtk_printer_set_is_paused (printer, info->is_paused);
           gtk_printer_set_is_accepting_jobs (printer, info->is_accepting_jobs);
 
-          if (!gtk_printer_is_active (printer))
-            {
-              gtk_printer_set_is_active (printer, TRUE);
-              gtk_printer_set_is_new (printer, TRUE);
-              list_has_changed = TRUE;
-            }
-
           GTK_PRINTER_CUPS (printer)->remote = info->remote_printer;
-          GTK_PRINTER_CUPS (printer)->avahi_name = g_strdup (service->name);
-          GTK_PRINTER_CUPS (printer)->avahi_type = g_strdup (service->type);
-          GTK_PRINTER_CUPS (printer)->avahi_domain = g_strdup (service->domain);
-          GTK_PRINTER_CUPS (printer)->hostname = g_strdup (service->host);
-          GTK_PRINTER_CUPS (printer)->port = service->port;
           GTK_PRINTER_CUPS (printer)->state = info->state;
           GTK_PRINTER_CUPS (printer)->ipp_version_major = info->ipp_version_major;
           GTK_PRINTER_CUPS (printer)->ipp_version_minor = info->ipp_version_minor;
@@ -2482,11 +2444,8 @@ cups_request_avahi_printer_info_cb (GtkPrintBackendCups *cups_backend,
 
           set_printer_icon_name_from_info (printer, info);
 
-          if (gtk_printer_is_new (printer))
-            {
-              g_signal_emit_by_name (backend, "printer-added", printer);
-              gtk_printer_set_is_new (printer, FALSE);
-            }
+          gtk_printer_set_has_details (printer, TRUE);
+          g_signal_emit_by_name (printer, "details-acquired", TRUE);
 
           if (status_changed)
             g_signal_emit_by_name (GTK_PRINT_BACKEND (backend),
@@ -2498,9 +2457,6 @@ cups_request_avahi_printer_info_cb (GtkPrintBackendCups *cups_backend,
     }
 
 done:
-  if (list_has_changed)
-    g_signal_emit_by_name (backend, "printer-list-changed");
-
   if (!cups_backend->got_default_printer &&
       gtk_print_backend_printer_list_is_done (backend) &&
       cups_backend->avahi_default_printer != NULL)
@@ -2508,6 +2464,7 @@ done:
       set_default_printer (cups_backend, cups_backend->avahi_default_printer);
     }
 
+  g_free (info->state_msg);
   g_slice_free (PrinterSetupInfo, info);
 
   gdk_threads_leave ();
@@ -2517,25 +2474,14 @@ static void
 cups_request_avahi_printer_info (const gchar         *printer_uri,
                                  const gchar         *host,
                                  gint                 port,
-                                 const gchar         *name,
-                                 const gchar         *type,
-                                 const gchar         *domain,
                                  GtkPrintBackendCups *backend)
 {
   GtkCupsRequest *request;
-  AvahiService   *service;
   http_t         *http;
 
   http = httpConnect (host, port);
   if (http)
     {
-      service = (AvahiService *) g_new0 (AvahiService, 1);
-      service->name = g_strdup (name);
-      service->type = g_strdup (type);
-      service->domain = g_strdup (domain);
-      service->host = g_strdup (host);
-      service->port = port;
-
       request = gtk_cups_request_new_with_username (http,
                                                     GTK_CUPS_POST,
                                                     IPP_GET_PRINTER_ATTRIBUTES,
@@ -2556,22 +2502,118 @@ cups_request_avahi_printer_info (const gchar         *printer_uri,
       cups_request_execute (backend,
                             request,
                             (GtkPrintCupsResponseCallbackFunc) cups_request_avahi_printer_info_cb,
-                            service,
-                            (GDestroyNotify) avahi_service_free);
+                            NULL,
+                            NULL);
     }
 }
 
 typedef struct
 {
   gchar               *printer_uri;
+  gchar               *location;
   gchar               *host;
   gint                 port;
+  gchar               *printer_name;
   gchar               *name;
+  gboolean             got_printer_type;
+  guint                printer_type;
+  gboolean             got_printer_state;
+  guint                printer_state;
   gchar               *type;
   gchar               *domain;
   GtkPrintBackendCups *backend;
 } AvahiConnectionTestData;
 
+/*
+ *  Create new GtkPrinter from informations included in TXT records.
+ */
+static void
+create_cups_printer_from_avahi_data (AvahiConnectionTestData *data)
+{
+  PrinterSetupInfo *info = g_slice_new0 (PrinterSetupInfo);
+  GtkPrinter       *printer;
+
+  info->avahi_printer = TRUE;
+  info->printer_name = data->printer_name;
+  info->printer_uri = data->printer_uri;
+
+  if (data->got_printer_state)
+    info->state = data->printer_state;
+
+  info->got_printer_type = data->got_printer_type;
+  if (data->got_printer_type)
+    {
+      if (data->printer_type & CUPS_PRINTER_DEFAULT)
+        info->default_printer = TRUE;
+      else
+        info->default_printer = FALSE;
+
+      if (data->printer_type & CUPS_PRINTER_REMOTE)
+        info->remote_printer = TRUE;
+      else
+        info->remote_printer = FALSE;
+
+      if (data->printer_type & CUPS_PRINTER_REJECTING)
+        info->is_accepting_jobs = FALSE;
+      else
+        info->is_accepting_jobs = TRUE;
+
+      if (info->default_printer &&
+          data->backend->avahi_default_printer == NULL)
+        data->backend->avahi_default_printer = g_strdup (info->printer_name);
+    }
+
+  set_info_state_message (info);
+
+  printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (data->backend), data->printer_name);
+  if (printer == NULL)
+    {
+      printer = cups_create_printer (data->backend, info);
+
+      if (data->got_printer_type)
+        {
+          gtk_printer_set_is_accepting_jobs (printer, info->is_accepting_jobs);
+          GTK_PRINTER_CUPS (printer)->remote = info->remote_printer;
+
+          if (info->default_printer &&
+              data->backend->avahi_default_printer == NULL)
+            data->backend->avahi_default_printer = g_strdup (info->printer_name);
+        }
+
+      if (data->got_printer_state)
+        GTK_PRINTER_CUPS (printer)->state = info->state;
+
+      GTK_PRINTER_CUPS (printer)->avahi_name = g_strdup (data->name);
+      GTK_PRINTER_CUPS (printer)->avahi_type = g_strdup (data->type);
+      GTK_PRINTER_CUPS (printer)->avahi_domain = g_strdup (data->domain);
+      g_free (GTK_PRINTER_CUPS (printer)->hostname);
+      GTK_PRINTER_CUPS (printer)->hostname = g_strdup (data->host);
+      GTK_PRINTER_CUPS (printer)->port = data->port;
+      gtk_printer_set_location (printer, data->location);
+      gtk_printer_set_state_message (printer, info->state_msg);
+
+      set_printer_icon_name_from_info (printer, info);
+
+      if (!gtk_printer_is_active (printer))
+        gtk_printer_set_is_active (printer, TRUE);
+
+      g_signal_emit_by_name (data->backend, "printer-added", printer);
+      gtk_printer_set_is_new (printer, FALSE);
+      g_signal_emit_by_name (data->backend, "printer-list-changed");
+
+      if (!data->backend->got_default_printer &&
+          gtk_print_backend_printer_list_is_done (GTK_PRINT_BACKEND (data->backend)) &&
+          data->backend->avahi_default_printer != NULL)
+        set_default_printer (data->backend, data->backend->avahi_default_printer);
+
+      /* The ref is held by GtkPrintBackend, in add_printer() */
+      g_object_unref (printer);
+    }
+
+  g_free (info->state_msg);
+  g_slice_free (PrinterSetupInfo, info);
+}
+
 static void
 avahi_connection_test_cb (GObject      *source_object,
                           GAsyncResult *res,
@@ -2590,23 +2632,46 @@ avahi_connection_test_cb (GObject      *source_object,
       g_io_stream_close (G_IO_STREAM (connection), NULL, NULL);
       g_object_unref (connection);
 
-      cups_request_avahi_printer_info (data->printer_uri,
-                                       data->host,
-                                       data->port,
-                                       data->name,
-                                       data->type,
-                                       data->domain,
-                                       data->backend);
+      create_cups_printer_from_avahi_data (data);
     }
 
   g_free (data->printer_uri);
+  g_free (data->location);
   g_free (data->host);
+  g_free (data->printer_name);
   g_free (data->name);
   g_free (data->type);
   g_free (data->domain);
   g_free (data);
 }
 
+gboolean
+avahi_txt_get_key_value_pair (const gchar  *entry,
+                              gchar       **key,
+                              gchar       **value)
+{
+  const gchar *equal_sign;
+
+  *key = NULL;
+  *value = NULL;
+
+  if (entry != NULL)
+    {
+      /* See RFC 6763 section 6.3 */
+      equal_sign = strstr (entry, "=");
+
+      if (equal_sign != NULL)
+        {
+          *key = g_strndup (entry, equal_sign - entry);
+          *value = g_strdup (equal_sign + 1);
+
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
 static void
 avahi_service_resolver_cb (GObject      *source_object,
                            GAsyncResult *res,
@@ -2626,8 +2691,12 @@ avahi_service_resolver_cb (GObject      *source_object,
   guint32                  flags;
   guint16                  port;
   GError                  *error = NULL;
-  gchar                   *suffix = NULL;
+  gchar                   *queue_name = NULL;
   gchar                   *tmp;
+  gchar                   *printer_name;
+  gchar                   *endptr;
+  gchar                   *key;
+  gchar                   *value;
   gint                     interface;
   gint                     protocol;
   gint                     aprotocol;
@@ -2653,6 +2722,8 @@ avahi_service_resolver_cb (GObject      *source_object,
                      &txt,
                      &flags);
 
+      data = g_new0 (AvahiConnectionTestData, 1);
+
       for (i = 0; i < g_variant_n_children (txt); i++)
         {
           child = g_variant_get_child_value (txt, i);
@@ -2663,32 +2734,61 @@ avahi_service_resolver_cb (GObject      *source_object,
               tmp[j] = g_variant_get_byte (g_variant_get_child_value (child, j));
             }
 
-          if (g_str_has_prefix (tmp, "rp="))
+          if (!avahi_txt_get_key_value_pair (tmp, &key, &value))
             {
-              suffix = g_strdup (tmp + 3);
               g_free (tmp);
-              break;
+              continue;
             }
 
+          if (g_strcmp0 (key, "rp") == 0)
+            {
+              queue_name = g_strdup (value);
+
+              printer_name = g_strrstr (queue_name, "/");
+              if (printer_name != NULL)
+                data->printer_name = g_strdup (printer_name + 1);
+              else
+                data->printer_name = g_strdup (queue_name);
+            }
+          else if (g_strcmp0 (key, "note") == 0)
+            {
+              data->location = g_strdup (value);
+            }
+          else if (g_strcmp0 (key, "printer-type") == 0)
+            {
+              endptr = NULL;
+              data->printer_type = g_ascii_strtoull (value, &endptr, 16);
+              if (data->printer_type != 0 || endptr != value)
+                data->got_printer_type = TRUE;
+            }
+          else if (g_strcmp0 (key, "printer-state") == 0)
+            {
+              endptr = NULL;
+              data->printer_state = g_ascii_strtoull (value, &endptr, 10);
+              if (data->printer_state != 0 || endptr != value)
+                data->got_printer_state = TRUE;
+            }
+
+          g_clear_pointer (&key, g_free);
+          g_clear_pointer (&value, g_free);
           g_free (tmp);
         }
 
-      if (suffix)
+      if (queue_name)
         {
           if (g_strcmp0 (type, "_ipp._tcp") == 0)
             protocol_string = "ipp";
           else
             protocol_string = "ipps";
 
-          data = g_new0 (AvahiConnectionTestData, 1);
-
           if (aprotocol == AVAHI_PROTO_INET6)
-            data->printer_uri = g_strdup_printf ("%s://[%s]:%u/%s", protocol_string, address, port, suffix);
+            data->printer_uri = g_strdup_printf ("%s://[%s]:%u/%s", protocol_string, address, port, 
queue_name);
           else
-            data->printer_uri = g_strdup_printf ("%s://%s:%u/%s", protocol_string, address, port, suffix);
+            data->printer_uri = g_strdup_printf ("%s://%s:%u/%s", protocol_string, address, port, 
queue_name);
 
           data->host = g_strdup (address);
           data->port = port;
+
           data->name = g_strdup (name);
           data->type = g_strdup (type);
           data->domain = g_strdup (domain);
@@ -2701,7 +2801,13 @@ avahi_service_resolver_cb (GObject      *source_object,
                                                  backend->avahi_cancellable,
                                                  avahi_connection_test_cb,
                                                  data);
-          g_free (suffix);
+          g_free (queue_name);
+        }
+      else
+        {
+          g_free (data->printer_name);
+          g_free (data->location);
+          g_free (data);
         }
 
       g_variant_unref (output);
@@ -3326,21 +3432,30 @@ cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
     {
       gboolean success = FALSE;
 
-      /* If we get a 404 then it is just a raw printer without a ppd
-         and not an error. Standalone Avahi printers also don't have
-         PPD files. */
-      if (((gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_HTTP) &&
-           (gtk_cups_result_get_error_status (result) == HTTP_NOT_FOUND))
 #ifdef HAVE_CUPS_API_1_6
-           || GTK_PRINTER_CUPS (printer)->avahi_browsed
+      /* Standalone Avahi printers don't have PPD files. */
+      if (GTK_PRINTER_CUPS (printer)->avahi_browsed)
+        {
+          cups_request_avahi_printer_info (GTK_PRINTER_CUPS (printer)->printer_uri,
+                                           GTK_PRINTER_CUPS (printer)->hostname,
+                                           GTK_PRINTER_CUPS (printer)->port,
+                                           GTK_PRINT_BACKEND_CUPS (gtk_printer_get_backend (printer)));
+        }
+      else
 #endif
-           )
         {
-          gtk_printer_set_has_details (printer, TRUE);
-          success = TRUE;
+          /* If we get a 404 then it is just a raw printer without a ppd
+             and not an error. */
+          if ((gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_HTTP) &&
+              (gtk_cups_result_get_error_status (result) == HTTP_NOT_FOUND))
+            {
+              gtk_printer_set_has_details (printer, TRUE);
+              success = TRUE;
+            }
+
+          g_signal_emit_by_name (printer, "details-acquired", success);
         }
 
-      g_signal_emit_by_name (printer, "details-acquired", success);
       goto done;
     }
 
@@ -3377,7 +3492,11 @@ cups_request_ppd (GtkPrinter *printer)
   GTK_NOTE (PRINTING,
             g_print ("CUPS Backend: %s\n", G_STRFUNC));
 
-  if (cups_printer->remote)
+  if (cups_printer->remote
+#ifdef HAVE_CUPS_API_1_6
+      && !cups_printer->avahi_browsed
+#endif
+      )
     {
       GtkCupsConnectionState state;
 
@@ -3788,7 +3907,11 @@ cups_printer_request_details (GtkPrinter *printer)
   if (!cups_printer->reading_ppd &&
       gtk_printer_cups_get_ppd (cups_printer) == NULL)
     {
-      if (cups_printer->remote)
+      if (cups_printer->remote
+#ifdef HAVE_CUPS_API_1_6
+          && !cups_printer->avahi_browsed
+#endif
+          )
         {
           if (cups_printer->get_remote_ppd_poll == 0)
             {


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