Blame cups-filters-browsepoll-notifications.patch

Tim Waugh db83b8
diff -up cups-filters-1.0.38/utils/cups-browsed.c.browsepoll-notifications cups-filters-1.0.38/utils/cups-browsed.c
Tim Waugh db83b8
--- cups-filters-1.0.38/utils/cups-browsed.c.browsepoll-notifications	2013-08-14 10:24:38.000000000 +0100
Tim Waugh db83b8
+++ cups-filters-1.0.38/utils/cups-browsed.c	2013-10-01 17:12:54.257126326 +0100
Tim Waugh db83b8
@@ -100,6 +100,16 @@ typedef struct allow_s {
Tim Waugh db83b8
   http_addr_t mask;
Tim Waugh db83b8
 } allow_t;
Tim Waugh db83b8
 
Tim Waugh db83b8
+/* Data structure for a BrowsePoll server */
Tim Waugh db83b8
+typedef struct browsepoll_s {
Tim Waugh db83b8
+  char *server;
Tim Waugh db83b8
+  int port;
Tim Waugh db83b8
+  int major;
Tim Waugh db83b8
+  int minor;
Tim Waugh db83b8
+  gboolean can_subscribe;
Tim Waugh db83b8
+  int subscription_id;
Tim Waugh db83b8
+} browsepoll_t;
Tim Waugh db83b8
+
Tim Waugh db83b8
 cups_array_t *remote_printers;
Tim Waugh db83b8
 static cups_array_t *netifs;
Tim Waugh db83b8
 static cups_array_t *browseallow;
Tim Waugh db83b8
@@ -118,7 +128,7 @@ static unsigned int BrowseRemoteProtocol
Tim Waugh db83b8
 static unsigned int BrowseInterval = 60;
Tim Waugh db83b8
 static unsigned int BrowseTimeout = 300;
Tim Waugh db83b8
 static uint16_t BrowsePort = 631;
Tim Waugh db83b8
-static char **BrowsePoll = NULL;
Tim Waugh db83b8
+static browsepoll_t **BrowsePoll = NULL;
Tim Waugh db83b8
 static size_t NumBrowsePoll = 0;
Tim Waugh db83b8
 static char *DomainSocket = NULL;
Tim Waugh db83b8
 
Tim Waugh db83b8
@@ -234,6 +244,16 @@ void debug_printf(const char *format, ..
Tim Waugh db83b8
   }
Tim Waugh db83b8
 }
Tim Waugh db83b8
 
Tim Waugh db83b8
+static const char *
Tim Waugh db83b8
+password_callback (const char *prompt,
Tim Waugh db83b8
+		   http_t *http,
Tim Waugh db83b8
+		   const char *method,
Tim Waugh db83b8
+		   const char *resource,
Tim Waugh db83b8
+		   void *user_data)
Tim Waugh db83b8
+{
Tim Waugh db83b8
+  return NULL;
Tim Waugh db83b8
+}
Tim Waugh db83b8
+
Tim Waugh db83b8
 static remote_printer_t *
Tim Waugh db83b8
 create_local_queue (const char *name,
Tim Waugh db83b8
 		    const char *uri,
Tim Waugh db83b8
@@ -1469,66 +1489,22 @@ send_browse_data (gpointer data)
Tim Waugh db83b8
   return FALSE;
Tim Waugh db83b8
 }
Tim Waugh db83b8
 
Tim Waugh db83b8
-gboolean
Tim Waugh db83b8
-browse_poll (gpointer data)
Tim Waugh db83b8
+static void
Tim Waugh db83b8
+browse_poll_get_printers (browsepoll_t *context, http_t *conn)
Tim Waugh db83b8
 {
Tim Waugh db83b8
   static const char * const rattrs[] = { "printer-uri-supported" };
Tim Waugh db83b8
-  char *server = strdup (data);
Tim Waugh db83b8
   ipp_t *request, *response = NULL;
Tim Waugh db83b8
   ipp_attribute_t *attr;
Tim Waugh db83b8
-  http_t *conn;
Tim Waugh db83b8
-  int port = BrowsePort;
Tim Waugh db83b8
-  char *colon,*slash;
Tim Waugh db83b8
-  int major = 0;
Tim Waugh db83b8
-  int minor = 0;
Tim Waugh db83b8
-
Tim Waugh db83b8
-  slash = strchr (server, '/');
Tim Waugh db83b8
-  if (slash) {
Tim Waugh db83b8
-    *slash++ = '\0';
Tim Waugh db83b8
-    if (!strcmp(slash, "version=1.0")) {
Tim Waugh db83b8
-      major = 1;
Tim Waugh db83b8
-      minor = 0;
Tim Waugh db83b8
-    } else if (!strcmp(slash, "version=1.1")) {
Tim Waugh db83b8
-      major = 1;
Tim Waugh db83b8
-      minor = 1;
Tim Waugh db83b8
-    } else if (!strcmp(slash, "version=2.0")) {
Tim Waugh db83b8
-      major = 2;
Tim Waugh db83b8
-      minor = 0;
Tim Waugh db83b8
-    } else if (!strcmp(slash, "version=2.1")) {
Tim Waugh db83b8
-      major = 2;
Tim Waugh db83b8
-      minor = 1;
Tim Waugh db83b8
-    } else if (!strcmp(slash, "version=2.2")) {
Tim Waugh db83b8
-      major = 2;
Tim Waugh db83b8
-      minor = 2;
Tim Waugh db83b8
-    } else {
Tim Waugh db83b8
-      debug_printf ("ignoring unknown server option: %s\n", slash);
Tim Waugh db83b8
-    }
Tim Waugh db83b8
-  }
Tim Waugh db83b8
-
Tim Waugh db83b8
-  debug_printf ("cups-browsed: browse polling %s\n", server);
Tim Waugh db83b8
-
Tim Waugh db83b8
-  colon = strchr (server, ':');
Tim Waugh db83b8
-  if (colon) {
Tim Waugh db83b8
-    char *endptr;
Tim Waugh db83b8
-    unsigned long n;
Tim Waugh db83b8
-    *colon++ = '\0';
Tim Waugh db83b8
-    n = strtoul (colon, &endptr, 10);
Tim Waugh db83b8
-    if (endptr != colon && n < INT_MAX)
Tim Waugh db83b8
-      port = (int) n;
Tim Waugh db83b8
-  }
Tim Waugh db83b8
-
Tim Waugh db83b8
-  res_init ();
Tim Waugh db83b8
-  conn = httpConnectEncrypt (server, port, HTTP_ENCRYPT_IF_REQUESTED);
Tim Waugh db83b8
 
Tim Waugh db83b8
-  if (conn == NULL) {
Tim Waugh db83b8
-    debug_printf("cups-browsed: browse poll failed to connect to %s\n", server);
Tim Waugh db83b8
-    goto fail;
Tim Waugh db83b8
-  }
Tim Waugh db83b8
+  debug_printf ("cups-browsed [BrowsePoll %s:%d]: CUPS-Get-Printers\n",
Tim Waugh db83b8
+		context->server, context->port);
Tim Waugh db83b8
 
Tim Waugh db83b8
   request = ippNewRequest(CUPS_GET_PRINTERS);
Tim Waugh db83b8
-  if (major > 0) {
Tim Waugh db83b8
-    debug_printf("cups-browsed: setting IPP version %d.%d\n", major, minor);
Tim Waugh db83b8
-    ippSetVersion (request, major, minor);
Tim Waugh db83b8
+  if (context->major > 0) {
Tim Waugh db83b8
+    debug_printf("cups-browsed [BrowsePoll %s:%d]: setting IPP version %d.%d\n",
Tim Waugh db83b8
+		 context->server, context->port, context->major,
Tim Waugh db83b8
+		 context->minor);
Tim Waugh db83b8
+    ippSetVersion (request, context->major, context->minor);
Tim Waugh db83b8
   }
Tim Waugh db83b8
 
Tim Waugh db83b8
   ippAddStrings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
Tim Waugh db83b8
@@ -1550,8 +1526,8 @@ browse_poll (gpointer data)
Tim Waugh db83b8
 
Tim Waugh db83b8
   response = cupsDoRequest(conn, request, "/");
Tim Waugh db83b8
   if (cupsLastError() > IPP_OK_CONFLICT) {
Tim Waugh db83b8
-    debug_printf("cups-browsed: browse poll failed for server %s: %s\n",
Tim Waugh db83b8
-		 server, cupsLastErrorString ());
Tim Waugh db83b8
+    debug_printf("cups-browsed [BrowsePoll %s:%d]: failed: %s\n",
Tim Waugh db83b8
+		 context->server, context->port, cupsLastErrorString ());
Tim Waugh db83b8
     goto fail;
Tim Waugh db83b8
   }
Tim Waugh db83b8
 
Tim Waugh db83b8
@@ -1579,7 +1555,7 @@ browse_poll (gpointer data)
Tim Waugh db83b8
     }
Tim Waugh db83b8
 
Tim Waugh db83b8
     if (uri)
Tim Waugh db83b8
-      found_cups_printer (server, uri, info);
Tim Waugh db83b8
+      found_cups_printer (context->server, uri, info);
Tim Waugh db83b8
 
Tim Waugh db83b8
     if (!attr)
Tim Waugh db83b8
       break;
Tim Waugh db83b8
@@ -1590,12 +1566,226 @@ browse_poll (gpointer data)
Tim Waugh db83b8
 fail:
Tim Waugh db83b8
   if (response)
Tim Waugh db83b8
     ippDelete(response);
Tim Waugh db83b8
+}
Tim Waugh db83b8
 
Tim Waugh db83b8
-  if (conn)
Tim Waugh db83b8
-    httpClose (conn);
Tim Waugh db83b8
+static void
Tim Waugh db83b8
+browse_poll_create_subscription (browsepoll_t *context, http_t *conn)
Tim Waugh db83b8
+{
Tim Waugh db83b8
+  static const char * const events[] = { "printer-added",
Tim Waugh db83b8
+					 "printer-changed",
Tim Waugh db83b8
+					 "printer-config-changed",
Tim Waugh db83b8
+					 "printer-modified",
Tim Waugh db83b8
+					 "printer-deleted",
Tim Waugh db83b8
+					 "printer-state-changed" };
Tim Waugh db83b8
+  ipp_t *request, *response = NULL;
Tim Waugh db83b8
+  ipp_attribute_t *attr;
Tim Waugh db83b8
+
Tim Waugh db83b8
+  debug_printf ("cups-browsed [BrowsePoll %s:%d]: IPP-Create-Subscription\n",
Tim Waugh db83b8
+		context->server, context->port);
Tim Waugh db83b8
+
Tim Waugh db83b8
+  request = ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION);
Tim Waugh db83b8
+  if (context->major > 0) {
Tim Waugh db83b8
+    debug_printf("cups-browsed [BrowsePoll %s:%d]: setting IPP version %d.%d\n",
Tim Waugh db83b8
+		 context->server, context->port, context->major,
Tim Waugh db83b8
+		 context->minor);
Tim Waugh db83b8
+    ippSetVersion (request, context->major, context->minor);
Tim Waugh db83b8
+  }
Tim Waugh db83b8
+
Tim Waugh db83b8
+  ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
Tim Waugh db83b8
+		"printer-uri", NULL, "/");
Tim Waugh db83b8
+  ippAddString (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD,
Tim Waugh db83b8
+		"notify-pull-method", NULL, "ippget");
Tim Waugh db83b8
+  ippAddString (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_CHARSET,
Tim Waugh db83b8
+		"notify-charset", NULL, "utf-8");
Tim Waugh db83b8
+  ippAddString (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_NAME,
Tim Waugh db83b8
+		"requesting-user-name", NULL, cupsUser ());
Tim Waugh db83b8
+  ippAddStrings (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD,
Tim Waugh db83b8
+		 "notify-events", sizeof (events) / sizeof (events[0]),
Tim Waugh db83b8
+		 NULL, events);
Tim Waugh db83b8
+  ippAddInteger (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
Tim Waugh db83b8
+		 "notify-time-interval", BrowseInterval);
Tim Waugh db83b8
+
Tim Waugh db83b8
+  response = cupsDoRequest (conn, request, "/");
Tim Waugh db83b8
+  if (!response || ippGetStatusCode (response) > IPP_OK_CONFLICT) {
Tim Waugh db83b8
+    debug_printf("cupsd-browsed [BrowsePoll %s:%d]: failed: %s\n",
Tim Waugh db83b8
+		 context->server, context->port, cupsLastErrorString ());
Tim Waugh db83b8
+    context->subscription_id = -1;
Tim Waugh db83b8
+    context->can_subscribe = FALSE;
Tim Waugh db83b8
+    goto fail;
Tim Waugh db83b8
+  }
Tim Waugh db83b8
+
Tim Waugh db83b8
+  for (attr = ippFirstAttribute(response); attr;
Tim Waugh db83b8
+       attr = ippNextAttribute(response)) {
Tim Waugh db83b8
+    if (ippGetGroupTag (attr) == IPP_TAG_SUBSCRIPTION) {
Tim Waugh db83b8
+      if (ippGetValueTag (attr) == IPP_TAG_INTEGER &&
Tim Waugh db83b8
+	  !strcmp (ippGetName (attr), "notify-subscription-id")) {
Tim Waugh db83b8
+	context->subscription_id = ippGetInteger (attr, 0);
Tim Waugh db83b8
+	debug_printf("cups-browsed [BrowsePoll %s:%d]: subscription ID=%d\n",
Tim Waugh db83b8
+		     context->server, context->port, context->subscription_id);
Tim Waugh db83b8
+	break;
Tim Waugh db83b8
+      }
Tim Waugh db83b8
+    }
Tim Waugh db83b8
+  }
Tim Waugh db83b8
+
Tim Waugh db83b8
+  if (!attr) {
Tim Waugh db83b8
+    debug_printf("cups-browsed [BrowsePoll %s:%d]: no ID returned\n",
Tim Waugh db83b8
+		 context->server, context->port);
Tim Waugh db83b8
+    context->subscription_id = -1;
Tim Waugh db83b8
+    context->can_subscribe = FALSE;
Tim Waugh db83b8
+  }
Tim Waugh db83b8
+
Tim Waugh db83b8
+fail:
Tim Waugh db83b8
+  if (response)
Tim Waugh db83b8
+    ippDelete(response);
Tim Waugh db83b8
+}
Tim Waugh db83b8
+
Tim Waugh db83b8
+static void
Tim Waugh db83b8
+browse_poll_cancel_subscription (browsepoll_t *context)
Tim Waugh db83b8
+{
Tim Waugh db83b8
+  ipp_t *request, *response = NULL;
Tim Waugh db83b8
+  http_t *conn = httpConnectEncrypt (context->server, context->port,
Tim Waugh db83b8
+				     HTTP_ENCRYPT_IF_REQUESTED);
Tim Waugh db83b8
+
Tim Waugh db83b8
+  if (conn == NULL) {
Tim Waugh db83b8
+    debug_printf("cups-browsed [BrowsePoll %s:%d]: connection failure "
Tim Waugh db83b8
+		 "attempting to cancel\n", context->server, context->port);
Tim Waugh db83b8
+    return;
Tim Waugh db83b8
+  }
Tim Waugh db83b8
+
Tim Waugh db83b8
+  debug_printf ("cups-browsed [BrowsePoll %s:%d] IPP-Cancel-Subscription\n",
Tim Waugh db83b8
+		context->server, context->port);
Tim Waugh db83b8
+
Tim Waugh db83b8
+  request = ippNewRequest(IPP_CANCEL_SUBSCRIPTION);
Tim Waugh db83b8
+  if (context->major > 0) {
Tim Waugh db83b8
+    debug_printf("cups-browsed [BrowsePoll %s:%d]: setting IPP version %d.%d\n",
Tim Waugh db83b8
+		 context->server, context->port, context->major,
Tim Waugh db83b8
+		 context->minor);
Tim Waugh db83b8
+    ippSetVersion (request, context->major, context->minor);
Tim Waugh db83b8
+  }
Tim Waugh db83b8
+
Tim Waugh db83b8
+  ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
Tim Waugh db83b8
+		"printer-uri", NULL, "/");
Tim Waugh db83b8
+  ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
Tim Waugh db83b8
+		"requesting-user-name", NULL, cupsUser ());
Tim Waugh db83b8
+  ippAddInteger (request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
Tim Waugh db83b8
+		 "notify-subscription-id", context->subscription_id);
Tim Waugh db83b8
+
Tim Waugh db83b8
+  response = cupsDoRequest (conn, request, "/");
Tim Waugh db83b8
+  if (!response || ippGetStatusCode (response) > IPP_OK_CONFLICT)
Tim Waugh db83b8
+    debug_printf("cupsd-browsed [BrowsePoll %s:%d]: failed: %s\n",
Tim Waugh db83b8
+		 context->server, context->port, cupsLastErrorString ());
Tim Waugh db83b8
 
Tim Waugh db83b8
-  if (server)
Tim Waugh db83b8
-    free (server);
Tim Waugh db83b8
+  if (response)
Tim Waugh db83b8
+    ippDelete(response);
Tim Waugh db83b8
+}
Tim Waugh db83b8
+
Tim Waugh db83b8
+static gboolean
Tim Waugh db83b8
+browse_poll_get_notifications (browsepoll_t *context, http_t *conn)
Tim Waugh db83b8
+{
Tim Waugh db83b8
+  ipp_t *request, *response = NULL;
Tim Waugh db83b8
+  ipp_attribute_t *attr;
Tim Waugh db83b8
+  ipp_status_t status;
Tim Waugh db83b8
+  gboolean get_printers = FALSE;
Tim Waugh db83b8
+
Tim Waugh db83b8
+  debug_printf ("cups-browsed [BrowsePoll %s:%d] IPP-Get-Notifications\n",
Tim Waugh db83b8
+		context->server, context->port);
Tim Waugh db83b8
+
Tim Waugh db83b8
+  request = ippNewRequest(IPP_GET_NOTIFICATIONS);
Tim Waugh db83b8
+  if (context->major > 0) {
Tim Waugh db83b8
+    debug_printf("cups-browsed [BrowsePoll %s:%d]: setting IPP version %d.%d\n",
Tim Waugh db83b8
+		 context->server, context->port, context->major,
Tim Waugh db83b8
+		 context->minor);
Tim Waugh db83b8
+    ippSetVersion (request, context->major, context->minor);
Tim Waugh db83b8
+  }
Tim Waugh db83b8
+
Tim Waugh db83b8
+  ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
Tim Waugh db83b8
+		"printer-uri", NULL, "/");
Tim Waugh db83b8
+  ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
Tim Waugh db83b8
+		"requesting-user-name", NULL, cupsUser ());
Tim Waugh db83b8
+  ippAddInteger (request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
Tim Waugh db83b8
+		 "notify-subscription-ids", context->subscription_id);
Tim Waugh db83b8
+
Tim Waugh db83b8
+  response = cupsDoRequest (conn, request, "/");
Tim Waugh db83b8
+  if (!response)
Tim Waugh db83b8
+    status = cupsLastError ();
Tim Waugh db83b8
+  else
Tim Waugh db83b8
+    status = ippGetStatusCode (response);
Tim Waugh db83b8
+
Tim Waugh db83b8
+  if (status == IPP_NOT_FOUND) {
Tim Waugh db83b8
+    /* Subscription lease has expired. */
Tim Waugh db83b8
+    debug_printf ("cups-browsed [BrowsePoll %s:%d] Lease expired\n",
Tim Waugh db83b8
+		  context->server, context->port);
Tim Waugh db83b8
+    browse_poll_create_subscription (context, conn);
Tim Waugh db83b8
+    get_printers = TRUE;
Tim Waugh db83b8
+  } else if (status > IPP_OK_CONFLICT) {
Tim Waugh db83b8
+    debug_printf("cupsd-browsed [BrowsePoll %s:%d]: failed: %s\n",
Tim Waugh db83b8
+		 context->server, context->port, cupsLastErrorString ());
Tim Waugh db83b8
+    context->can_subscribe = FALSE;
Tim Waugh db83b8
+    browse_poll_cancel_subscription (context);
Tim Waugh db83b8
+    context->subscription_id = -1;
Tim Waugh db83b8
+    get_printers = TRUE;
Tim Waugh db83b8
+    goto fail;
Tim Waugh db83b8
+  }
Tim Waugh db83b8
+
Tim Waugh db83b8
+  for (attr = ippFirstAttribute(response); attr;
Tim Waugh db83b8
+       attr = ippNextAttribute(response))
Tim Waugh db83b8
+    if (ippGetGroupTag (attr) == IPP_TAG_EVENT_NOTIFICATION)
Tim Waugh db83b8
+      /* There is a printer-* event here. */
Tim Waugh db83b8
+      break;
Tim Waugh db83b8
+
Tim Waugh db83b8
+  if (attr) {
Tim Waugh db83b8
+    debug_printf("cups-browsed [BrowsePoll %s:%d]: printer-* event\n",
Tim Waugh db83b8
+		 context->server, context->port);
Tim Waugh db83b8
+    get_printers = TRUE;
Tim Waugh db83b8
+  } else
Tim Waugh db83b8
+    debug_printf("cups-browsed [BrowsePoll %s:%d]: no events\n",
Tim Waugh db83b8
+		 context->server, context->port);
Tim Waugh db83b8
+
Tim Waugh db83b8
+fail:
Tim Waugh db83b8
+  if (response)
Tim Waugh db83b8
+    ippDelete(response);
Tim Waugh db83b8
+
Tim Waugh db83b8
+  return get_printers;
Tim Waugh db83b8
+}
Tim Waugh db83b8
+
Tim Waugh db83b8
+gboolean
Tim Waugh db83b8
+browse_poll (gpointer data)
Tim Waugh db83b8
+{
Tim Waugh db83b8
+  browsepoll_t *context = data;
Tim Waugh db83b8
+  http_t *conn = NULL;
Tim Waugh db83b8
+  gboolean get_printers = FALSE;
Tim Waugh db83b8
+
Tim Waugh db83b8
+  debug_printf ("cups-browsed: browse polling %s:%d\n",
Tim Waugh db83b8
+		context->server, context->port);
Tim Waugh db83b8
+
Tim Waugh db83b8
+  res_init ();
Tim Waugh db83b8
+
Tim Waugh db83b8
+  conn = httpConnectEncrypt (context->server, context->port,
Tim Waugh db83b8
+			     HTTP_ENCRYPT_IF_REQUESTED);
Tim Waugh db83b8
+  if (conn == NULL) {
Tim Waugh db83b8
+    debug_printf("cups-browsed [BrowsePoll %s:%d]: failed to connect\n",
Tim Waugh db83b8
+		 context->server, context->port);
Tim Waugh db83b8
+    goto fail;
Tim Waugh db83b8
+  }
Tim Waugh db83b8
+
Tim Waugh db83b8
+  if (context->can_subscribe) {
Tim Waugh db83b8
+    if (context->subscription_id == -1) {
Tim Waugh db83b8
+      /* The first time this callback is run we need to create the IPP
Tim Waugh db83b8
+       * subscription to watch to printer-* events. */
Tim Waugh db83b8
+      browse_poll_create_subscription (context, conn);
Tim Waugh db83b8
+      get_printers = TRUE;
Tim Waugh db83b8
+    } else
Tim Waugh db83b8
+      /* On subsequent runs, check for notifications using our
Tim Waugh db83b8
+       * subscription. */
Tim Waugh db83b8
+      get_printers = browse_poll_get_notifications (context, conn);
Tim Waugh db83b8
+  }
Tim Waugh db83b8
+  else
Tim Waugh db83b8
+    get_printers = TRUE;
Tim Waugh db83b8
+
Tim Waugh db83b8
+  if (get_printers)
Tim Waugh db83b8
+    browse_poll_get_printers (context, conn);
Tim Waugh db83b8
+
Tim Waugh db83b8
+fail:
Tim Waugh db83b8
 
Tim Waugh db83b8
   /* Call a new timeout handler so that we run again */
Tim Waugh db83b8
   g_timeout_add_seconds (BrowseInterval, browse_poll, data);
Tim Waugh db83b8
@@ -1723,14 +1913,61 @@ read_configuration (const char *filename
Tim Waugh db83b8
       else
Tim Waugh db83b8
 	BrowseLocalProtocols = BrowseRemoteProtocols = protocols;
Tim Waugh db83b8
     } else if (!strcasecmp(line, "BrowsePoll") && value) {
Tim Waugh db83b8
-      char **old = BrowsePoll;
Tim Waugh db83b8
-      BrowsePoll = realloc (BrowsePoll, (NumBrowsePoll + 1) * sizeof (char *));
Tim Waugh db83b8
+      browsepoll_t **old = BrowsePoll;
Tim Waugh db83b8
+      BrowsePoll = realloc (BrowsePoll,
Tim Waugh db83b8
+			    (NumBrowsePoll + 1) *
Tim Waugh db83b8
+			    sizeof (browsepoll_t));
Tim Waugh db83b8
       if (!BrowsePoll) {
Tim Waugh db83b8
 	debug_printf("cups-browsed: unable to realloc: ignoring BrowsePoll line\n");
Tim Waugh db83b8
 	BrowsePoll = old;
Tim Waugh db83b8
       } else {
Tim Waugh db83b8
-	debug_printf("cups-browsed: Adding BrowsePoll server: %s\n", value);
Tim Waugh db83b8
-	BrowsePoll[NumBrowsePoll++] = strdup (value);
Tim Waugh db83b8
+	char *colon, *slash;
Tim Waugh db83b8
+	browsepoll_t *b = malloc (sizeof (browsepoll_t));
Tim Waugh db83b8
+	if (!b) {
Tim Waugh db83b8
+	  debug_printf("cups-browsed: unable to malloc: ignoring BrowsePoll line\n");
Tim Waugh db83b8
+	  BrowsePoll = old;
Tim Waugh db83b8
+	} else {
Tim Waugh db83b8
+	  debug_printf("cups-browsed: Adding BrowsePoll server: %s\n", value);
Tim Waugh db83b8
+	  b->server = strdup (value);
Tim Waugh db83b8
+	  b->port = BrowsePort;
Tim Waugh db83b8
+	  b->can_subscribe = TRUE; /* first assume subscriptions work */
Tim Waugh db83b8
+	  b->subscription_id = -1;
Tim Waugh db83b8
+	  slash = strchr (b->server, '/');
Tim Waugh db83b8
+	  if (slash) {
Tim Waugh db83b8
+	    *slash++ = '\0';
Tim Waugh db83b8
+	    if (!strcmp (slash, "version=1.0")) {
Tim Waugh db83b8
+	      b->major = 1;
Tim Waugh db83b8
+	      b->minor = 0;
Tim Waugh db83b8
+	    } else if (!strcmp (slash, "version=1.1")) {
Tim Waugh db83b8
+	      b->major = 1;
Tim Waugh db83b8
+	      b->minor = 1;
Tim Waugh db83b8
+	    } else if (!strcmp (slash, "version=2.0")) {
Tim Waugh db83b8
+	      b->major = 2;
Tim Waugh db83b8
+	      b->minor = 0;
Tim Waugh db83b8
+	    } else if (!strcmp (slash, "version=2.1")) {
Tim Waugh db83b8
+	      b->major = 2;
Tim Waugh db83b8
+	      b->minor = 1;
Tim Waugh db83b8
+	    } else if (!strcmp (slash, "version=2.2")) {
Tim Waugh db83b8
+	      b->major = 2;
Tim Waugh db83b8
+	      b->minor = 2;
Tim Waugh db83b8
+	    } else {
Tim Waugh db83b8
+	      debug_printf ("ignoring unknown server option: %s\n", slash);
Tim Waugh db83b8
+	    }
Tim Waugh db83b8
+	  } else
Tim Waugh db83b8
+	    b->major = 0;
Tim Waugh db83b8
+
Tim Waugh db83b8
+	  colon = strchr (b->server, ':');
Tim Waugh db83b8
+	  if (colon) {
Tim Waugh db83b8
+	    char *endptr;
Tim Waugh db83b8
+	    unsigned long n;
Tim Waugh db83b8
+	    *colon++ = '\0';
Tim Waugh db83b8
+	    n = strtoul (colon, &endptr, 10);
Tim Waugh db83b8
+	    if (endptr != colon && n < INT_MAX)
Tim Waugh db83b8
+	      b->port = (int) n;
Tim Waugh db83b8
+	  }
Tim Waugh db83b8
+
Tim Waugh db83b8
+	  BrowsePoll[NumBrowsePoll++] = b;
Tim Waugh db83b8
+	}
Tim Waugh db83b8
       }
Tim Waugh db83b8
     } else if (!strcasecmp(line, "BrowseAllow") && value) {
Tim Waugh db83b8
       if (read_browseallow_value (value))
Tim Waugh db83b8
@@ -1972,6 +2209,10 @@ int main(int argc, char*argv[]) {
Tim Waugh db83b8
     goto fail;
Tim Waugh db83b8
   }
Tim Waugh db83b8
 
Tim Waugh db83b8
+  /* Override the default password callback so we don't end up
Tim Waugh db83b8
+   * prompting for it. */
Tim Waugh db83b8
+  cupsSetPasswordCB2 (password_callback, NULL);
Tim Waugh db83b8
+
Tim Waugh db83b8
   /* Run the main loop */
Tim Waugh db83b8
   gmainloop = g_main_loop_new (NULL, FALSE);
Tim Waugh db83b8
   recheck_timer ();
Tim Waugh db83b8
@@ -1994,7 +2235,7 @@ int main(int argc, char*argv[]) {
Tim Waugh db83b8
 	 index < NumBrowsePoll;
Tim Waugh db83b8
 	 index++) {
Tim Waugh db83b8
       debug_printf ("cups-browsed: will browse poll %s every %ds\n",
Tim Waugh db83b8
-		    BrowsePoll[index], BrowseInterval);
Tim Waugh db83b8
+		    BrowsePoll[index]->server, BrowseInterval);
Tim Waugh db83b8
       g_idle_add (browse_poll, BrowsePoll[index]);
Tim Waugh db83b8
     }
Tim Waugh db83b8
   }
Tim Waugh db83b8
@@ -2018,6 +2259,21 @@ fail:
Tim Waugh db83b8
   }
Tim Waugh db83b8
   handle_cups_queues(NULL);
Tim Waugh db83b8
 
Tim Waugh db83b8
+  if (BrowsePoll) {
Tim Waugh db83b8
+    size_t index;
Tim Waugh db83b8
+    for (index = 0;
Tim Waugh db83b8
+	 index < NumBrowsePoll;
Tim Waugh db83b8
+	 index++) {
Tim Waugh db83b8
+      if (BrowsePoll[index]->can_subscribe &&
Tim Waugh db83b8
+	  BrowsePoll[index]->subscription_id != -1)
Tim Waugh db83b8
+	browse_poll_cancel_subscription (BrowsePoll[index]);
Tim Waugh db83b8
+
Tim Waugh db83b8
+      free (BrowsePoll[index]->server);
Tim Waugh db83b8
+      free (BrowsePoll[index]);
Tim Waugh db83b8
+    }
Tim Waugh db83b8
+
Tim Waugh db83b8
+    free (BrowsePoll);
Tim Waugh db83b8
+  }
Tim Waugh db83b8
 #ifdef HAVE_AVAHI
Tim Waugh db83b8
   /* Free the data structures for Bonjour browsing */
Tim Waugh db83b8
   if (sb1)