Back to index

system-config-printer  1.3.9+20120706
udev-configure-printer.c
Go to the documentation of this file.
00001 /* -*- Mode: C; c-file-style: "gnu" -*-
00002  * udev-configure-printer - a udev callout to configure print queues
00003  * Copyright (C) 2009, 2010, 2011 Red Hat, Inc.
00004  * Author: Tim Waugh <twaugh@redhat.com>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00019  *
00020  */
00021 
00022 /*
00023  * The protocol for this program is:
00024  *
00025  * udev-configure-printer add {DEVPATH}
00026  * udev-configure-printer remove {DEVPATH}
00027  *
00028  * where DEVPATH is the path (%p) of the device
00029  */
00030 
00031 #define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE 1
00032 
00033 #include <cups/cups.h>
00034 #include <cups/http.h>
00035 #include <errno.h>
00036 #include <fcntl.h>
00037 #include <libudev.h>
00038 #include <limits.h>
00039 #include <stdio.h>
00040 #include <stdlib.h>
00041 #include <string.h>
00042 #include <sys/types.h>
00043 #include <sys/stat.h>
00044 #include <sys/wait.h>
00045 #include <ctype.h>
00046 #include <syslog.h>
00047 #include <unistd.h>
00048 #include <usb.h>
00049 #include <glib.h>
00050 
00051 #define DISABLED_REASON "Unplugged or turned off"
00052 #define MATCH_ONLY_DISABLED 1
00053 #define USB_URI_MAP "/var/run/udev-configure-printer/usb-uris"
00054 
00055 struct device_uris
00056 {
00057   size_t n_uris;
00058   char **uri;
00059 };
00060 
00061 struct usb_uri_map_entry
00062 {
00063   struct usb_uri_map_entry *next;
00064 
00065   /* The devpath of the ("usb","usb_device") device. */
00066   char *devpath;
00067 
00068   /* List of matching device URIs. */
00069   struct device_uris uris;
00070 };
00071 
00072 struct usb_uri_map
00073 {
00074   struct usb_uri_map_entry *entries;
00075 
00076   /* Open file descriptor for the map, or -1 if it has already been
00077    * written. */
00078   int fd;
00079 };
00080 
00081 struct device_id
00082 {
00083   char *full_device_id;
00084   char *mfg;
00085   char *mdl;
00086   char *sern;
00087 };
00088 
00089 /* Device URI schemes in decreasing order of preference. */
00090 static const char *device_uri_types[] =
00091   {
00092     "hp",
00093     "usb",
00094   };
00095 
00096 static int
00097 device_uri_type (const char *uri)
00098 {
00099   int slen = strcspn (uri, ":");
00100   int i;
00101   int n = sizeof (device_uri_types) / sizeof (device_uri_types[0]);
00102   for (i = 0; i < n; i++)
00103     if (!strncmp (uri, device_uri_types[i], slen) &&
00104        device_uri_types[i][slen] == '\0')
00105       break;
00106 
00107   return i;
00108 }
00109 
00110 static void
00111 add_device_uri (struct device_uris *uris,
00112               const char *uri)
00113 {
00114   char *uri_copy = strdup (uri);
00115   if (!uri_copy)
00116     {
00117       syslog (LOG_ERR, "out of memory");
00118       return;
00119     }
00120 
00121   if (uris->n_uris == 0)
00122     {
00123       uris->uri = malloc (sizeof (char *));
00124       if (uris->uri)
00125        {
00126          uris->n_uris = 1;
00127          uris->uri[0] = uri_copy;
00128        }
00129     }
00130   else
00131     {
00132       char **old = uris->uri;
00133       if (++uris->n_uris < UINT_MAX / sizeof (char *))
00134        {
00135          uris->uri = realloc (uris->uri,
00136                             sizeof (char *) * uris->n_uris);
00137          if (uris->uri)
00138            uris->uri[uris->n_uris - 1] = uri_copy;
00139          else
00140            {
00141              uris->uri = old;
00142              uris->n_uris--;
00143              free (uri_copy);
00144            }
00145        }
00146       else
00147        {
00148          uris->n_uris--;
00149          free (uri_copy);
00150        }
00151     }
00152 }
00153 
00154 static void
00155 free_device_uris (struct device_uris *uris)
00156 {
00157   size_t i;
00158   for (i = 0; i < uris->n_uris; i++)
00159     free (uris->uri[i]);
00160   free (uris->uri);
00161 }
00162 
00163 static void
00164 add_usb_uri_mapping (struct usb_uri_map **map,
00165                    const char *devpath,
00166                    const struct device_uris *uris)
00167 {
00168   struct usb_uri_map_entry *entry, **prev;
00169   size_t i;
00170   prev = &(*map)->entries;
00171   while (*prev)
00172     prev = &((*prev)->next);
00173 
00174   entry = malloc (sizeof (struct usb_uri_map_entry));
00175   if (!entry)
00176     {
00177       syslog (LOG_ERR, "out of memory");
00178       return;
00179     }
00180 
00181   entry->devpath = strdup (devpath);
00182   entry->uris.n_uris = uris->n_uris;
00183   entry->uris.uri = malloc (sizeof (char *) * uris->n_uris);
00184   for (i = 0; i < uris->n_uris; i++)
00185     entry->uris.uri[i] = strdup (uris->uri[i]);
00186   entry->next = NULL;
00187   *prev = entry;
00188 }
00189 
00190 static struct usb_uri_map *
00191 read_usb_uri_map (void)
00192 {
00193   int fd = open (USB_URI_MAP, O_RDWR);
00194   struct usb_uri_map *map = NULL;
00195   struct flock lock;
00196   struct stat st;
00197   char *buf, *line;
00198 
00199   if (fd == -1)
00200     {
00201       char dir[] = USB_URI_MAP;
00202       char *p = strrchr (dir, '/');
00203       if (p)
00204        {
00205          *p = '\0';
00206          mkdir (dir, 0755);
00207          fd = open (USB_URI_MAP, O_RDWR | O_TRUNC | O_CREAT, 0644);
00208          if (fd == -1)
00209            {
00210              syslog (LOG_ERR, "failed to create " USB_URI_MAP);
00211              exit (1);
00212            }
00213        }
00214     }
00215 
00216   map = malloc (sizeof (struct usb_uri_map));
00217   if (!map)
00218     {
00219       syslog (LOG_ERR, "out of memory");
00220       exit (1);
00221     }
00222 
00223   lock.l_type = F_WRLCK;
00224   lock.l_whence = SEEK_SET;
00225   lock.l_start = 0;
00226   lock.l_len = 0;
00227   if (fcntl (fd, F_SETLKW, &lock) == -1)
00228     {
00229       syslog (LOG_ERR, "failed to lock " USB_URI_MAP);
00230       exit (1);
00231     }
00232 
00233   map->entries = NULL;
00234   map->fd = fd;
00235   if (fstat (fd, &st) == -1)
00236     {
00237       syslog (LOG_ERR, "failed to fstat " USB_URI_MAP " (fd %d)", fd);
00238       exit (1);
00239     }
00240 
00241   /* Read the entire file into memory. */
00242   buf = malloc (1 + (sizeof (char) * st.st_size));
00243   if (!buf)
00244     {
00245       syslog (LOG_ERR, "out of memory");
00246       exit (1);
00247     }
00248 
00249   if (read (fd, buf, st.st_size) < 0)
00250     {
00251       syslog (LOG_ERR, "failed to read " USB_URI_MAP);
00252       exit (1);
00253     }
00254 
00255   buf[st.st_size] = '\0';
00256   line = buf;
00257   while (line)
00258     {
00259       char *saveptr = NULL;
00260       const char *devpath, *uri;
00261       struct device_uris uris;
00262       char *nextline = strchr (line, '\n');
00263       if (!nextline)
00264        break;
00265 
00266       *nextline++ = '\0';
00267       if (nextline >= buf + st.st_size)
00268        nextline = NULL;
00269 
00270       devpath = strtok_r (line, "\t", &saveptr);
00271       uri = strtok_r (NULL, "\t", &saveptr);
00272       if (!devpath || !uri)
00273        {
00274          syslog (LOG_DEBUG, "Incorrect line in " USB_URI_MAP ": %s",
00275                 line);
00276          continue;
00277        }
00278 
00279       uris.n_uris = 1;
00280       uris.uri = malloc (sizeof (char *));
00281       if (uris.uri == NULL)
00282        break;
00283 
00284       uris.uri[0] = strdup (uri);
00285       while ((uri = strtok_r (NULL, "\t", &saveptr)) != NULL)
00286        add_device_uri (&uris, uri);
00287 
00288       add_usb_uri_mapping (&map, devpath, &uris);
00289 
00290       line = nextline;
00291     }
00292 
00293   free (buf);
00294   return map;
00295 }
00296 
00297 static void
00298 write_usb_uri_map (struct usb_uri_map *map)
00299 {
00300   struct usb_uri_map_entry *entry;
00301   int fd = map->fd;
00302   FILE *f;
00303 
00304   lseek (fd, SEEK_SET, 0);
00305   if (ftruncate (fd, 0) == -1)
00306     {
00307       syslog (LOG_ERR, "failed to ftruncate " USB_URI_MAP " (fd %d, errno %d)",
00308              fd, errno);
00309       exit (1);
00310     }
00311 
00312   f = fdopen (fd, "w");
00313   if (!f)
00314     {
00315       syslog (LOG_ERR, "failed to fdopen " USB_URI_MAP " (fd %d, errno %d)",
00316              fd, errno);
00317       exit (1);
00318     }
00319 
00320   for (entry = map->entries; entry; entry = entry->next)
00321     {
00322       size_t i;
00323       fprintf (f, "%s\t%s", entry->devpath, entry->uris.uri[0]);
00324       for (i = 1; i < entry->uris.n_uris; i++)
00325        {
00326          if (fprintf (f, "\t%s", entry->uris.uri[i]) < 0)
00327            {
00328              syslog (LOG_ERR, "failed to fprintf " USB_URI_MAP " (errno %d)",
00329                     errno);
00330              exit (1);
00331            }
00332        }
00333 
00334       if (fwrite ("\n", 1, 1, f) < 1)
00335        {
00336          syslog (LOG_ERR, "failed to fwrite " USB_URI_MAP " (errno %d)",
00337                 errno);
00338          exit (1);
00339        }
00340     }
00341 
00342   if (fclose (f) == EOF)
00343     syslog (LOG_ERR, "error closing " USB_URI_MAP " (errno %d)", errno);
00344 
00345   map->fd = -1;
00346 }
00347 
00348 static void
00349 free_usb_uri_map (struct usb_uri_map *map)
00350 {
00351   struct usb_uri_map_entry *entry, *next;
00352   for (entry = map->entries; entry; entry = next)
00353     {
00354       next = entry->next;
00355       free (entry->devpath);
00356       free_device_uris (&entry->uris);
00357       free (entry);
00358     }
00359 
00360   if (map->fd != -1)
00361     close (map->fd);
00362 
00363   free (map);
00364 }
00365 
00366 static void
00367 free_device_id (struct device_id *id)
00368 {
00369   free (id->full_device_id);
00370   free (id->mfg);
00371   free (id->mdl);
00372   free (id->sern);
00373 }
00374 
00375 static void
00376 parse_device_id (const char *device_id,
00377                struct device_id *id)
00378 {
00379   char *fieldname;
00380   char *start, *end;
00381   size_t len;
00382 
00383   len = strlen (device_id);
00384   if (len == 0)
00385     return;
00386 
00387   if (device_id[len - 1] == '\n')
00388     len--;
00389 
00390   id->full_device_id = malloc (len + 1);
00391   fieldname = malloc (len + 1);
00392   if (!id->full_device_id || !fieldname)
00393     {
00394       syslog (LOG_ERR, "out of memory");
00395       exit (1);
00396     }
00397 
00398   memcpy (id->full_device_id, device_id, len);
00399   id->full_device_id[len] = '\0';
00400   fieldname[0] = '\0';
00401   start = id->full_device_id;
00402   while (*start != '\0')
00403     {
00404       /* New field. */
00405 
00406       end = start;
00407       while (*end != '\0' && *end != ':')
00408        end++;
00409 
00410       if (*end == '\0')
00411        break;
00412 
00413       len = end - start;
00414       memcpy (fieldname, start, len);
00415       fieldname[len] = '\0';
00416 
00417       start = end + 1;
00418       while (*end != '\0' && *end != ';')
00419        end++;
00420 
00421       len = end - start;
00422 
00423       if (!id->mfg &&
00424          (!strncasecmp (fieldname, "MANUFACTURER", 12) ||
00425           !strncasecmp (fieldname, "MFG", 3)))
00426        id->mfg = strndup (start, len);
00427       else if (!id->mdl &&
00428               (!strncasecmp (fieldname, "MODEL", 5) ||
00429               !strncasecmp (fieldname, "MDL", 3)))
00430        id->mdl = strndup (start, len);
00431       else if (!id->sern &&
00432               (!strncasecmp (fieldname, "SERIALNUMBER", 12) ||
00433               !strncasecmp (fieldname, "SERN", 4) ||
00434               !strncasecmp (fieldname, "SN", 2)))
00435        id->sern = strndup (start, len);
00436 
00437       if (*end != '\0')
00438        start = end + 1;
00439     }
00440 
00441   free (fieldname);
00442 }
00443 
00444 static char *
00445 device_id_from_devpath (const char *devpath,
00446                      const struct usb_uri_map *map,
00447                      struct device_id *id,
00448                      char *usbserial, size_t usbseriallen,
00449                      char *usblpdev, size_t usblpdevlen)
00450 {
00451   struct usb_uri_map_entry *entry;
00452   struct udev *udev;
00453   struct udev_device *dev, *parent_dev = NULL;
00454   const char *idVendorStr, *idProductStr, *serial;
00455   char *end;
00456   unsigned long idVendor, idProduct;
00457   size_t syslen, devpathlen;
00458   char *syspath;
00459   struct usb_bus *bus;
00460   struct usb_dev_handle *handle = NULL;
00461   char ieee1284_id[1024];
00462   const char *device_id = NULL;
00463   int conf = 0, iface = 0;
00464   int got = 0;
00465   char *usb_device_devpath;
00466   char *usblpdevpos, *dest;
00467 
00468   id->full_device_id = id->mfg = id->mdl = id->sern = NULL;
00469 
00470   udev = udev_new ();
00471   if (udev == NULL)
00472     {
00473       syslog (LOG_ERR, "udev_new failed");
00474       exit (1);
00475     }
00476 
00477   /* For devices discovered via the usblp kernel module we read out the number
00478    * of the /dev/usb/lp* device file, as there can be queues set up with 
00479    * non-standard CUPS backends based on the /dev/usb/lp* device file and
00480    * we want to avoid that an additional queue with a standard CUPS backend
00481    * gets set up.
00482    */
00483   usblpdevpos = strstr(devpath, "/usb/lp");
00484   if (usblpdevpos != NULL)
00485     usblpdevpos += 7;
00486   else
00487     {
00488       usblpdevpos = strstr(devpath, "/usblp");
00489       if (usblpdevpos != NULL)
00490        usblpdevpos += 6;
00491     }
00492   if (usblpdevpos != NULL)
00493     {
00494       for (dest = usblpdev;
00495           (*usblpdevpos >= '0') && (*usblpdevpos <= '9') &&
00496             (dest - usblpdev < usblpdevlen);
00497           usblpdevpos ++, dest ++)
00498        *dest = *usblpdevpos;
00499       *dest = '\0';
00500     }
00501 
00502   syslen = strlen ("/sys");
00503   devpathlen = strlen (devpath);
00504   syspath = malloc (syslen + devpathlen + 1);
00505   if (syspath == NULL)
00506     {
00507       udev_unref (udev);
00508       syslog (LOG_ERR, "out of memory");
00509       exit (1);
00510     }
00511 
00512   memcpy (syspath, "/sys", syslen);
00513   memcpy (syspath + syslen, devpath, devpathlen);
00514   syspath[syslen + devpathlen] = '\0';
00515 
00516   dev = udev_device_new_from_syspath (udev, syspath);
00517   if (dev == NULL)
00518     {
00519       udev_device_unref (dev);
00520       udev_unref (udev);
00521       syslog (LOG_ERR, "unable to access %s", syspath);
00522       return NULL;
00523     }
00524 
00525   parent_dev = udev_device_get_parent_with_subsystem_devtype (dev,
00526                                                        "usb",
00527                                                        "usb_device");
00528   if (!parent_dev)
00529     {
00530       udev_unref (udev);
00531       syslog (LOG_ERR, "Failed to get parent");
00532       return NULL;
00533     }
00534 
00535   usb_device_devpath = strdup (udev_device_get_devpath (parent_dev));
00536   syslog (LOG_DEBUG, "device devpath is %s", usb_device_devpath);
00537 
00538   for (entry = map->entries; entry; entry = entry->next)
00539     if (!strcmp (entry->devpath, usb_device_devpath))
00540       break;
00541 
00542   if (entry)
00543     {
00544       /* The map already had an entry so has already been dealt
00545        * with.  This can happen because there are two "add"
00546        * triggers: one for the usb_device device and the other for
00547        * the usblp device.  We have most likely been triggered by
00548        * the usblp device, so the usb_device rule got there before
00549        * us and succeeded.
00550        *
00551        * Pretend we didn't find any device URIs that matched, and
00552        * exit.
00553        */
00554       syslog (LOG_DEBUG, "Device already handled");
00555       return NULL;
00556     }
00557 
00558   serial = udev_device_get_sysattr_value (parent_dev, "serial");
00559   if (serial)
00560     {
00561       strncpy (usbserial, serial, usbseriallen);
00562       usbserial[usbseriallen - 1] = '\0';
00563     }
00564   else
00565     usbserial[0] = '\0';
00566 
00567   /* See if we were triggered by a usblp add event. */
00568   device_id = udev_device_get_sysattr_value (dev, "device/ieee1284_id");
00569   if (device_id)
00570     {
00571       got = 1;
00572       goto got_deviceid;
00573     }
00574 
00575   /* This is a low-level USB device.  Use libusb to fetch the Device ID. */
00576   idVendorStr = udev_device_get_sysattr_value (parent_dev, "idVendor");
00577   idProductStr = udev_device_get_sysattr_value (parent_dev, "idProduct");
00578 
00579   if (!idVendorStr || !idProductStr)
00580     {
00581       udev_device_unref (dev);
00582       udev_unref (udev);
00583       syslog (LOG_ERR, "Missing sysattr %s",
00584              idVendorStr ?
00585              (idProductStr ? "serial" : "idProduct") : "idVendor");
00586       return NULL;
00587     }
00588 
00589   idVendor = strtoul (idVendorStr, &end, 16);
00590   if (end == idVendorStr)
00591     {
00592       syslog (LOG_ERR, "Invalid idVendor: %s", idVendorStr);
00593       return NULL;
00594     }
00595 
00596   idProduct = strtoul (idProductStr, &end, 16);
00597   if (end == idProductStr)
00598     {
00599       syslog (LOG_ERR, "Invalid idProduct: %s", idProductStr);
00600       return NULL;
00601     }
00602 
00603   syslog (LOG_DEBUG, "Device vendor/product is %04zX:%04zX",
00604          idVendor, idProduct);
00605 
00606   usb_init ();
00607   usb_find_busses ();
00608   usb_find_devices ();
00609   for (bus = usb_get_busses (); bus && !got; bus = bus->next)
00610     {
00611       struct usb_device *device;
00612       for (device = bus->devices; device && !got; device = device->next)
00613        {
00614          struct usb_config_descriptor *confptr;
00615          if (device->descriptor.idVendor != idVendor ||
00616              device->descriptor.idProduct != idProduct ||
00617              !device->config)
00618            continue;
00619 
00620          conf = 0;
00621          for (confptr = device->config;
00622               conf < device->descriptor.bNumConfigurations && !got;
00623               conf++, confptr++)
00624            {
00625              struct usb_interface *ifaceptr;
00626              iface = 0;
00627              for (ifaceptr = confptr->interface;
00628                  iface < confptr->bNumInterfaces && !got;
00629                  iface++, ifaceptr++)
00630               {
00631                 struct usb_interface_descriptor *altptr;
00632                 int altset = 0;
00633                 for (altptr = ifaceptr->altsetting;
00634                      altset < ifaceptr->num_altsetting && !got;
00635                      altset++, altptr++)
00636                   {
00637                     if (altptr->bInterfaceClass == USB_CLASS_PRINTER &&
00638                        altptr->bInterfaceSubClass == 1)
00639                      {
00640                        int n;
00641                        handle = usb_open (device);
00642                        if (!handle)
00643                          {
00644                            syslog (LOG_DEBUG, "failed to open device");
00645                            continue;
00646                          }
00647 
00648                        n = altptr->bInterfaceNumber;
00649                        if (usb_claim_interface (handle, n) < 0)
00650                          {
00651                            usb_close (handle);
00652                            handle = NULL;
00653                            syslog (LOG_DEBUG, "failed to claim interface");
00654                            continue;
00655                          }
00656 
00657                        if (n != 0 && usb_claim_interface (handle, 0) < 0)
00658                          {
00659                            usb_close (handle);
00660                            handle = NULL;
00661                            syslog (LOG_DEBUG, "failed to claim interface 0");
00662                            continue;
00663                          }
00664 
00665                        n = altptr->bAlternateSetting;
00666                        if (usb_set_altinterface (handle, n) < 0)
00667                          {
00668                            usb_close (handle);
00669                            handle = NULL;
00670                            syslog (LOG_DEBUG, "failed set altinterface");
00671                            continue;
00672                          }
00673 
00674                        memset (ieee1284_id, '\0', sizeof (ieee1284_id));
00675                        if (usb_control_msg (handle,
00676                                           USB_TYPE_CLASS |
00677                                           USB_ENDPOINT_IN |
00678                                           USB_RECIP_INTERFACE,
00679                                           0, conf, iface,
00680                                           ieee1284_id,
00681                                           sizeof (ieee1284_id),
00682                                           5000) < 0)
00683                          {
00684                            usb_close (handle);
00685                            handle = NULL;
00686                            syslog (LOG_ERR, "Failed to fetch Device ID");
00687                            continue;
00688                          }
00689 
00690                        got = 1;
00691                        usb_close (handle);
00692                        break;
00693                      }
00694                   }
00695               }
00696            }
00697        }
00698     }
00699 
00700  got_deviceid:
00701   if (got)
00702     {
00703       if (!device_id)
00704        device_id = ieee1284_id + 2;
00705       parse_device_id (device_id, id);
00706     }
00707 
00708   udev_device_unref (dev);
00709   udev_unref (udev);
00710   return usb_device_devpath;
00711 }
00712 
00713 static void
00714 device_id_from_bluetooth (const char *bdaddr, struct device_id *id)
00715 {
00716   gint exit_status;
00717   char *device_id;
00718   gchar *argv[4];
00719 
00720   id->full_device_id = id->mfg = id->mdl = id->sern = NULL;
00721   argv[0] = g_strdup ("/usr/lib/cups/backend/bluetooth");
00722   argv[1] = g_strdup ("--get-deviceid");
00723   argv[2] = g_strdup (bdaddr);
00724   argv[3] = NULL;
00725   if (g_spawn_sync (NULL, argv, NULL,
00726                   G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL,
00727                   &device_id, NULL, &exit_status, NULL) == FALSE) {
00728     g_free (argv[0]);
00729     g_free (argv[1]);
00730     g_free (argv[2]);
00731     return;
00732   }
00733   g_free (argv[0]);
00734   g_free (argv[1]);
00735   g_free (argv[2]);
00736 
00737   if (WEXITSTATUS(exit_status) == 0)
00738     parse_device_id (device_id, id);
00739 
00740   g_free (device_id);
00741 }
00742 
00743 static char *
00744 uri_from_bdaddr (const char *devpath)
00745 {
00746   return g_strdup_printf("bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c",
00747                       devpath[0], devpath[1],
00748                       devpath[3], devpath[4],
00749                       devpath[6], devpath[7],
00750                       devpath[9], devpath[10],
00751                       devpath[12], devpath[13],
00752                       devpath[15], devpath[16]);
00753 }
00754 
00755 static const char *
00756 no_password (const char *prompt)
00757 {
00758   return "";
00759 }
00760 
00761 static ipp_t *
00762 cupsDoRequestOrDie (http_t *http,
00763                   ipp_t *request,
00764                   const char *resource)
00765 {
00766   ipp_t *answer = cupsDoRequest (http, request, resource);
00767   if (answer == NULL)
00768     {
00769       syslog (LOG_ERR, "failed to send IPP request %d",
00770              request->request.op.operation_id);
00771       exit (1);
00772     }
00773 
00774   if (answer->request.status.status_code > IPP_OK_CONFLICT)
00775     {
00776       syslog (LOG_ERR, "IPP request %d failed (%d)",
00777              request->request.op.operation_id,
00778              answer->request.status.status_code);
00779       exit (1);
00780     }
00781 
00782   return answer;
00783 }
00784 
00785 static int
00786 find_matching_device_uris (struct device_id *id,
00787                         const char *usbserial,
00788                         struct device_uris *uris,
00789                         const char *devpath,
00790                         struct usb_uri_map *map)
00791 {
00792   http_t *cups;
00793   ipp_t *request, *answer;
00794   ipp_attribute_t *attr;
00795   struct device_uris uris_noserial;
00796   struct device_uris all_uris;
00797   size_t i, n;
00798   const char *exclude_schemes[] = {
00799     "beh",
00800     "cups-pdf",
00801     "bluetooth",
00802     "dnssd",
00803     "http",
00804     "https",
00805     "ipp",
00806     "lpd",
00807     "ncp",
00808     "parallel",
00809     "scsi",
00810     "smb",
00811     "snmp",
00812     "socket",
00813   };
00814 
00815   uris->n_uris = uris_noserial.n_uris = all_uris.n_uris = 0;
00816   uris->uri = uris_noserial.uri = all_uris.uri = NULL;
00817 
00818   /* Leave the bus to settle. */
00819   sleep (1);
00820 
00821   cups = httpConnectEncrypt (cupsServer (), ippPort(), cupsEncryption ());
00822   if (cups == NULL)
00823     {
00824       /* Don't bother retrying here.  We've probably been run from
00825         udev before the cups.socket systemd unit is running.  We'll
00826         get run again, as the systemd service
00827         udev-configure-printer.service, after cups.socket.  For more
00828         information:
00829         http://0pointer.de/blog/projects/socket-activation2.html
00830       */
00831 
00832       syslog (LOG_DEBUG, "failed to connect to CUPS server; giving up");
00833       exit (1);
00834     }
00835 
00836   request = ippNewRequest (CUPS_GET_DEVICES);
00837   ippAddStrings (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "exclude-schemes",
00838                sizeof (exclude_schemes) / sizeof(exclude_schemes[0]),
00839                NULL, exclude_schemes);
00840   ippAddInteger (request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "timeout",
00841                  2);
00842 
00843   answer = cupsDoRequestOrDie (cups, request, "/");
00844   httpClose (cups);
00845 
00846   for (attr = answer->attrs; attr; attr = attr->next)
00847     {
00848       const char *device_uri = NULL;
00849       struct device_id this_id;
00850       this_id.full_device_id = this_id.mfg = this_id.mdl = this_id.sern = NULL;
00851 
00852       while (attr && attr->group_tag != IPP_TAG_PRINTER)
00853        attr = attr->next;
00854 
00855       if (!attr)
00856        break;
00857 
00858       for (; attr && attr->group_tag == IPP_TAG_PRINTER; attr = attr->next)
00859        {
00860          if (attr->value_tag == IPP_TAG_URI &&
00861              !strcmp (attr->name, "device-uri"))
00862            device_uri = attr->values[0].string.text;
00863          else if (attr->value_tag == IPP_TAG_TEXT &&
00864                  !strcmp (attr->name, "device-id"))
00865            parse_device_id (attr->values[0].string.text, &this_id);
00866        }
00867 
00868       /* Only use device schemes in our preference order for matching
00869        * against the IEEE 1284 Device ID. */
00870 
00871       for (i = 0;
00872           device_uri &&
00873           i < sizeof (device_uri_types) / sizeof (device_uri_types[0]);
00874           i++)
00875        {
00876          size_t len = strlen (device_uri_types[i]);
00877          if (!strncmp (device_uri_types[i], device_uri, len) &&
00878              device_uri[len] == ':')
00879            break;
00880        }
00881 
00882       if (device_uri)
00883        add_device_uri (&all_uris, device_uri);
00884 
00885       if (i == sizeof (device_uri_types) / sizeof (device_uri_types[0]))
00886        /* Not what we want to match against.  Ignore this one. */
00887        device_uri = NULL;
00888 
00889       /* Now check the manufacturer and model names. */
00890       if (device_uri && this_id.mfg && this_id.mdl &&
00891          !strcasecmp (this_id.mfg, id->mfg) &&
00892          !strcasecmp (this_id.mdl, id->mdl))
00893        {
00894          /* We've checked everything except the serial numbers.  This
00895           * is more complicated.  Some devices include a serial
00896           * number (SERN) field in their IEEE 1284 Device ID.  Others
00897           * don't -- this was not a mandatory field in the
00898           * specification.
00899           *
00900           * If the device includes SERN field in its, it must match
00901           * what the device-id attribute has.
00902           *
00903           * Otherwise, the only means we have of knowing which device
00904           * is meant is the USB serial number.
00905           *
00906           * CUPS backends may choose to insert the USB serial number
00907           * into the SERN field when reporting a device-id attribute.
00908           * HPLIP does this, and it seems not to stray too far from
00909           * the intent of that field.  We accommodate this.
00910           *
00911           * Alternatively, CUPS backends may include the USB serial
00912           * number somewhere in their reported device-uri attributes.
00913           * For instance, the CUPS 1.4 usb backend, when compiled
00914           * with libusb support, gives device URIs containing the USB
00915           * serial number for devices without a SERN field, like
00916           * this: usb://HP/DESKJET%20990C?serial=US05M1D20CIJ
00917           *
00918           * To accommodate this we examine tokens between '?', '='
00919           * and '&' delimiters to check for USB serial number
00920           * matches.
00921           *
00922           * CUPS 1.3, and CUPS 1.4 without libusb support, doesn't do this.
00923           * As a result we also need to deal with devices that don't report a
00924           * SERN field where the backends that don't add a SERN field from
00925           * the USB serial number and also don't include the USB serial
00926           * number in the URI.
00927           */
00928 
00929          int match = 0;
00930          if ((id->sern && this_id.sern && !strcmp (id->sern, this_id.sern)))
00931            {
00932              syslog (LOG_DEBUG, "SERN fields match");
00933              match = 1;
00934            }
00935 
00936          if (!match && usbserial[0] != '\0')
00937            {
00938              if (!id->sern)
00939               {
00940                 if (this_id.sern && !strcmp (usbserial, this_id.sern))
00941                   {
00942                     syslog (LOG_DEBUG,
00943                            "SERN field matches USB serial number");
00944                     match = 1;
00945                   }
00946               }
00947 
00948              if (!match)
00949               {
00950                 char *saveptr, *uri = strdup (device_uri);
00951                 const char *token;
00952                 const char *sep = "?=&/";
00953                 for (token = strtok_r (uri, sep, &saveptr);
00954                      token;
00955                      token = strtok_r (NULL, sep, &saveptr))
00956                   if (!strcmp (token, usbserial))
00957                     {
00958                      syslog (LOG_DEBUG, "URI contains USB serial number");
00959                      match = 1;
00960                      break;
00961                     }
00962 
00963                 free (uri);
00964               }
00965            }
00966 
00967          if (match)
00968            {
00969              syslog (LOG_DEBUG, "URI match: %s", device_uri);
00970              add_device_uri (uris, device_uri);
00971            }
00972          else if (!id->sern)
00973            {
00974              syslog (LOG_DEBUG, "URI matches without serial number: %s",
00975                     device_uri);
00976              add_device_uri (&uris_noserial, device_uri);
00977            }
00978        }
00979 
00980       if (!attr)
00981        break;
00982     }
00983 
00984   ippDelete (answer);
00985 
00986   /* Decide what to do about device URIs that did not match a serial
00987    * number.  The device had no SERN field, and the USB serial number
00988    * was nowhere to be found from the device URI or device-id field.
00989    *
00990    * Device URIs with no reference to serial number can only each ever
00991    * work when only one printer of that model is connected.
00992    * Accordingly, it is safe to disable queues using such URIs, as we
00993    * know the removed/added device is that lone printer.
00994    *
00995    * When adding queues it is best to avoid URIs that don't
00996    * distinguish serial numbers.
00997    *
00998    * What we'll do, then, is concatenate the list of "non-serial" URIs
00999    * onto the end of the list of "serial" URIs.
01000    */
01001 
01002   if (uris->n_uris == 0 && uris_noserial.n_uris > 0)
01003     {
01004       syslog (LOG_DEBUG, "No serial number URI matches so using those without");
01005       uris->n_uris = uris_noserial.n_uris;
01006       uris->uri = uris_noserial.uri;
01007       uris_noserial.n_uris = 0;
01008       uris_noserial.uri = NULL;
01009     }
01010   else if (uris_noserial.n_uris > 0)
01011     {
01012       char **old = uris->uri;
01013       uris->uri = realloc (uris->uri,
01014                         sizeof (char *) * (uris->n_uris +
01015                                          uris_noserial.n_uris));
01016       if (!uris->uri)
01017        uris->uri = old;
01018       else
01019        {
01020          for (i = 0; i < uris_noserial.n_uris; i++)
01021            uris->uri[uris->n_uris + i] = uris_noserial.uri[i];
01022          uris->n_uris += uris_noserial.n_uris;
01023        }
01024 
01025       uris_noserial.n_uris = 0;
01026       uris_noserial.uri = NULL;
01027     }
01028 
01029   free_device_uris (&uris_noserial);
01030 
01031   /* Having decided which device URIs match based on IEEE 1284 Device
01032    * ID, we now need to look for "paired" URIs for other functions of
01033    * a multi-function device.  This are the same except for the
01034    * scheme. */
01035 
01036   n = uris->n_uris;
01037   for (i = 0; i < n; i++)
01038     {
01039       size_t j;
01040       char *me = uris->uri[i];
01041       char *my_rest = strchr (me, ':');
01042       size_t my_schemelen;
01043       if (!my_rest)
01044        continue;
01045 
01046       my_schemelen = my_rest - me;
01047       for (j = 0; j < all_uris.n_uris; j++)
01048        {
01049          char *twin = all_uris.uri[j];
01050          char *twin_rest = strchr (twin, ':');
01051          size_t twin_schemelen;
01052          if (!twin_rest)
01053            continue;
01054 
01055          twin_schemelen = twin_rest - twin;
01056          if (my_schemelen == twin_schemelen &&
01057              !strncmp (me, twin, my_schemelen))
01058            /* This is the one we are looking for the twin of. */
01059            continue;
01060 
01061          if (!strcmp (my_rest, twin_rest))
01062            {
01063              syslog (LOG_DEBUG, "%s twinned with %s", me, twin);
01064              add_device_uri (uris, twin);
01065            }
01066        }
01067     }
01068 
01069   free_device_uris (&all_uris);
01070   if (uris->n_uris > 0)
01071     {
01072       add_usb_uri_mapping (&map, devpath, uris);
01073       write_usb_uri_map (map);
01074       free_usb_uri_map (map);
01075     }
01076 
01077   return uris->n_uris;
01078 }
01079 
01080 char *
01081 normalize_device_uri(const char *str_orig)
01082 {
01083   int i, j;
01084   int havespace = 0;
01085   char *str;
01086 
01087   if (str_orig == NULL)
01088     return NULL;
01089 
01090   str = strdup(str_orig);
01091   for (i = 0, j = 0; i < strlen(str); i++, j++)
01092     {
01093       if (((str[i] >= 'A') && (str[i] <= 'Z')) ||
01094          ((str[i] >= 'a') && (str[i] <= 'z')) ||
01095          ((str[i] >= '0') && (str[i] <= '9')))
01096        {
01097          /* Letter or number, keep it */
01098          havespace = 0;
01099          str[j] = tolower(str[i]);
01100        }
01101       else
01102        {
01103          if ((str[i] == '%') && (i <= strlen(str)-3) &&
01104              (((str[i+1] >= 'A') && (str[i+1] <= 'F')) ||
01105               ((str[i+1] >= 'a') && (str[i+1] <= 'f')) ||
01106               ((str[i+1] >= '0') && (str[i+1] <= '9'))) &&
01107            (((str[i+2] >= 'A') && (str[i+2] <= 'F')) ||
01108             ((str[i+2] >= 'a') && (str[i+2] <= 'f')) ||
01109             ((str[i+2] >= '0') && (str[i+2] <= '9'))))
01110            /* Hex-encoded special characters replace by a single space if the
01111               last character is not already a space */
01112            i += 2;
01113          if (havespace == 1)
01114            j --;
01115          else
01116            {
01117              havespace = 1;
01118              str[j] = ' ';
01119            }
01120        }
01121     }
01122   /* Add terminating zero */
01123   str[j] = '\0';
01124   /* Cut off trailing white space */
01125   while (str[strlen(str)-1] == ' ')
01126     str[strlen(str)-1] = '\0';
01127   /* Cut off all before model name */
01128   while ((strstr(str, "hp ") == str) ||
01129         (strstr(str, "hewlett ") == str) ||
01130         (strstr(str, "packard ") == str) ||
01131         (strstr(str, "apollo ") == str) ||
01132         (strstr(str, "usb ") == str))
01133     str = strchr(str, ' ') + 1;
01134 
01135   return str;
01136 }
01137 
01138 /* Call a function for each queue with the given device-uri and printer-state.
01139  * Returns the number of queues with a matching device-uri. */
01140 static size_t
01141 for_each_matching_queue (struct device_uris *device_uris,
01142                       int flags,
01143                       void (*fn) (const char *, void *),
01144                       void *context,
01145                       char *usblpdev, size_t usblpdevlen)
01146 {
01147   size_t matched = 0;
01148   http_t *cups = httpConnectEncrypt (cupsServer (), ippPort (),
01149                                  cupsEncryption ());
01150   ipp_t *request, *answer;
01151   ipp_attribute_t *attr;
01152   const char *attributes[] = {
01153     "printer-uri-supported",
01154     "device-uri",
01155     "printer-state",
01156     "printer-state-message",
01157   };
01158   char usblpdevstr1[32] = "", usblpdevstr2[32] = "";
01159 
01160   if (cups == NULL)
01161     return 0;
01162 
01163   request = ippNewRequest (CUPS_GET_PRINTERS);
01164   ippAddStrings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
01165                "requested-attributes",
01166                sizeof (attributes) / sizeof (attributes[0]),
01167                NULL, attributes);
01168   answer = cupsDoRequest (cups, request, "/");
01169   httpClose (cups);
01170   if (answer == NULL)
01171     {
01172       syslog (LOG_ERR, "failed to send CUPS-Get-Printers request");
01173       exit (1);
01174     }
01175 
01176   if (answer->request.status.status_code > IPP_OK_CONFLICT)
01177     {
01178       if (answer->request.status.status_code == IPP_NOT_FOUND)
01179        {
01180          /* No printer queues configured. */
01181          ippDelete (answer);
01182          return 0;
01183        }
01184 
01185       syslog (LOG_ERR, "CUPS-Get-Printers request failed (%d)",
01186              answer->request.status.status_code);
01187       exit (1);
01188     }
01189 
01190   if (strlen(usblpdev) > 0)
01191     {
01192       /* If one of these strings is contained in one of the existing queue's
01193         device URIs, consider the printer as already configured. Some
01194         non-standard CUPS backend use the (obsolete) reference to the
01195         usblp device file. This avoids that in such a case a second queue
01196         with a standard CUPS backend is auto-created. */
01197       snprintf(usblpdevstr1, sizeof(usblpdevstr1), "/usb/lp%s",
01198               usblpdev);
01199       snprintf(usblpdevstr2, sizeof(usblpdevstr2), "/usblp%s",
01200               usblpdev);
01201       syslog (LOG_DEBUG,
01202              "Consider also queues with \"%s\" or \"%s\" in their URIs as matching",
01203              usblpdevstr1, usblpdevstr2);
01204     }
01205 
01206   for (attr = answer->attrs; attr; attr = attr->next)
01207     {
01208       const char *this_printer_uri = NULL;
01209       const char *this_device_uri = NULL;
01210       const char *printer_state_message = NULL;
01211       int state = 0;
01212       size_t i, l;
01213       char *this_device_uri_n, *device_uri_n;
01214       const char *ps1, *ps2, *pi1, *pi2;
01215 
01216       while (attr && attr->group_tag != IPP_TAG_PRINTER)
01217        attr = attr->next;
01218 
01219       if (!attr)
01220        break;
01221 
01222       for (; attr && attr->group_tag == IPP_TAG_PRINTER; attr = attr->next)
01223        {
01224          if (attr->value_tag == IPP_TAG_URI)
01225            {
01226              if (!strcmp (attr->name, "device-uri"))
01227               this_device_uri = attr->values[0].string.text;
01228              else if (!strcmp (attr->name, "printer-uri-supported"))
01229               this_printer_uri = attr->values[0].string.text;
01230            }
01231          else if (attr->value_tag == IPP_TAG_TEXT &&
01232                  !strcmp (attr->name, "printer-state-message"))
01233            printer_state_message = attr->values[0].string.text;
01234          else if (attr->value_tag == IPP_TAG_ENUM &&
01235                  !strcmp (attr->name, "printer-state"))
01236            state = attr->values[0].integer;
01237        }
01238 
01239       if (!this_device_uri)
01240        /* CUPS didn't include a device-uri attribute in the response
01241           for this printer (shouldn't happen). */
01242        goto skip;
01243 
01244       this_device_uri_n = normalize_device_uri(this_device_uri);
01245       syslog (LOG_DEBUG, "URI of print queue: %s, normalized: %s",
01246              this_device_uri, this_device_uri_n);
01247       pi1 = strstr (this_device_uri, "interface=");
01248       ps1 = strstr (this_device_uri, "serial=");
01249       for (i = 0; i < device_uris->n_uris; i++)
01250        {
01251          device_uri_n = normalize_device_uri(device_uris->uri[i]);
01252          /* As for the same device different URIs can come out when the
01253             device is accessed via the usblp kernel module or via low-
01254             level USB (libusb) we cannot simply compare URIs, must
01255             consider also URIs as equal if one has an "interface"
01256             or "serial" attribute and the other not. If both have
01257             the attribute it must naturally match. We check which attributes 
01258              are there and this way determine up to which length the two URIs 
01259              must match. Here we can assume that if a URI has an "interface"
01260             attribute it has also a "serial" attribute, as this URI is
01261             an URI obtained via libusb and these always have a "serial"
01262             attribute. usblp-based URIs never have an "interface"
01263             attribute.*/
01264          pi2 = strstr (device_uris->uri[i], "interface=");
01265          ps2 = strstr (device_uris->uri[i], "serial=");
01266          if (pi1 && !pi2)
01267            l = strlen(device_uris->uri[i]);
01268          else if (!pi1 && pi2)
01269            l = strlen(this_device_uri);
01270          else if (ps1 && !ps2)
01271            l = strlen(device_uris->uri[i]);
01272          else if (!ps1 && ps2)
01273            l = strlen(this_device_uri);
01274          else if (strlen(this_device_uri) > strlen(device_uris->uri[i]))
01275            l = strlen(this_device_uri);
01276          else
01277            l = strlen(device_uris->uri[i]);
01278          syslog (LOG_DEBUG, "URI of detected printer: %s, normalized: %s",
01279                 device_uris->uri[i], device_uri_n);
01280          if ((!strncmp (device_uris->uri[i], this_device_uri, l)) ||
01281              (strstr (device_uri_n, this_device_uri_n) == 
01282               device_uri_n) ||
01283              (strstr (this_device_uri_n, device_uri_n) == 
01284               this_device_uri_n) ||
01285              ((strlen(usblpdev) > 0) &&
01286               ((strstr (this_device_uri, usblpdevstr1) != NULL) ||
01287               (strstr (this_device_uri, usblpdevstr2) != NULL)))) 
01288            {
01289              matched++;
01290              syslog (LOG_DEBUG, "Queue %s has matching device URI",
01291                     this_printer_uri);
01292              if (((flags & MATCH_ONLY_DISABLED) &&
01293                  state == IPP_PRINTER_STOPPED &&
01294                  !strcmp (printer_state_message, DISABLED_REASON)) ||
01295                 (flags & MATCH_ONLY_DISABLED) == 0)
01296               {
01297                 (*fn) (this_printer_uri, context);
01298               }
01299            }
01300        }
01301 
01302     skip:
01303       if (!attr)
01304        break;
01305     }
01306 
01307   ippDelete (answer);
01308   return matched;
01309 }
01310 
01311 static void
01312 enable_queue (const char *printer_uri, void *context)
01313 {
01314   /* Enable it. */
01315   http_t *cups = httpConnectEncrypt (cupsServer (), ippPort (),
01316                                  cupsEncryption ());
01317   ipp_t *request, *answer;
01318 
01319   if (cups == NULL)
01320     return;
01321 
01322   request = ippNewRequest (IPP_RESUME_PRINTER);
01323   ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
01324               "printer-uri", NULL, printer_uri);
01325   answer = cupsDoRequest (cups, request, "/admin/");
01326   if (!answer)
01327     {
01328       syslog (LOG_ERR, "Failed to send IPP-Resume-Printer request");
01329       httpClose (cups);
01330       return;
01331     }
01332 
01333   if (answer->request.status.status_code > IPP_OK_CONFLICT)
01334     syslog (LOG_ERR, "IPP-Resume-Printer request failed");
01335   else
01336     syslog (LOG_INFO, "Re-enabled printer %s", printer_uri);
01337 
01338   ippDelete (answer);
01339   httpClose (cups);
01340 }
01341 
01342 static gboolean
01343 bluetooth_verify_address (const char *bdaddr)
01344 {
01345   gboolean retval = TRUE;
01346   char **elems;
01347   guint i;
01348 
01349   g_return_val_if_fail (bdaddr != NULL, FALSE);
01350 
01351   if (strlen (bdaddr) != 17)
01352     return FALSE;
01353 
01354   elems = g_strsplit (bdaddr, ":", -1);
01355   if (elems == NULL)
01356     return FALSE;
01357   if (g_strv_length (elems) != 6) {
01358     g_strfreev (elems);
01359     return FALSE;
01360   }
01361   for (i = 0; i < 6; i++) {
01362     if (strlen (elems[i]) != 2 ||
01363         g_ascii_isxdigit (elems[i][0]) == FALSE ||
01364         g_ascii_isxdigit (elems[i][1]) == FALSE) {
01365          retval = FALSE;
01366          break;
01367     }
01368   }
01369 
01370   g_strfreev (elems);
01371   return retval;
01372 }
01373 
01374 static int
01375 do_add (const char *cmd, const char *devpath, int detach)
01376 {
01377   pid_t pid;
01378   int f;
01379   struct device_id id;
01380   struct device_uris device_uris;
01381   struct usb_uri_map *map;
01382   char *usb_device_devpath = NULL;
01383   char usbserial[256];
01384   char usblpdev[8] = "";
01385   gboolean is_bluetooth;
01386 
01387   if (detach && getenv ("DEBUG") == NULL)
01388     {
01389       if ((pid = fork ()) == -1)
01390        syslog (LOG_ERR, "Failed to fork process");
01391       else if (pid != 0)
01392        /* Parent. */
01393        exit (0);
01394 
01395       close (STDIN_FILENO);
01396       close (STDOUT_FILENO);
01397       close (STDERR_FILENO);
01398       f = open ("/dev/null", O_RDWR);
01399       if (f != STDIN_FILENO)
01400        dup2 (f, STDIN_FILENO);
01401       if (f != STDOUT_FILENO)
01402        dup2 (f, STDOUT_FILENO);
01403       if (f != STDERR_FILENO)
01404        dup2 (f, STDERR_FILENO);
01405 
01406       setsid ();
01407     }
01408 
01409   syslog (LOG_DEBUG, "add %s", devpath);
01410 
01411   is_bluetooth = bluetooth_verify_address (devpath);
01412 
01413   map = read_usb_uri_map ();
01414   if (is_bluetooth) {
01415     usbserial[0] = '\0';
01416     device_id_from_bluetooth (devpath, &id);
01417   } else {
01418     usb_device_devpath = device_id_from_devpath (devpath, map, &id,
01419                                            usbserial, sizeof (usbserial),
01420                                            usblpdev, sizeof (usblpdev));
01421   }
01422 
01423   if (!id.mfg || !id.mdl)
01424     return 1;
01425 
01426   syslog (LOG_DEBUG, "MFG:%s MDL:%s SERN:%s serial:%s", id.mfg, id.mdl,
01427          id.sern ? id.sern : "-", usbserial[0] ? usbserial : "-");
01428 
01429   if (!is_bluetooth)
01430     {
01431       find_matching_device_uris (&id, usbserial, &device_uris, usb_device_devpath,
01432                              map);
01433       free (usb_device_devpath);
01434     } else {
01435       char *device_uri;
01436 
01437       device_uri = uri_from_bdaddr (devpath);
01438       add_device_uri (&device_uris, device_uri);
01439       g_free (device_uri);
01440     }
01441 
01442   if (device_uris.n_uris == 0)
01443     {
01444       syslog (LOG_ERR, "no corresponding CUPS device found");
01445       free_device_id (&id);
01446       return 0;
01447     }
01448 
01449   /* Re-enable any queues we'd previously disabled. */
01450   if (for_each_matching_queue (&device_uris, MATCH_ONLY_DISABLED,
01451                             enable_queue, NULL,
01452                             usblpdev, sizeof (usblpdev)) == 0)
01453     {
01454       size_t i;
01455       int type;
01456       char argv0[PATH_MAX];
01457       char *p;
01458       char **argv = malloc (sizeof (char *) * (3 + device_uris.n_uris));
01459 
01460       /* No queue is configured for this device yet.
01461         Decide on a URI to use. */
01462       type = device_uri_type (device_uris.uri[0]);
01463       for (i = 1; i < device_uris.n_uris; i++)
01464        {
01465          int new_type = device_uri_type (device_uris.uri[i]);
01466          if (new_type < type)
01467            {
01468              char *swap = device_uris.uri[0];
01469              device_uris.uri[0] = device_uris.uri[i];
01470              device_uris.uri[i] = swap;
01471              type = new_type;
01472            }
01473        }
01474 
01475       argv[0] = argv0;
01476       argv[1] = id.full_device_id;
01477       for (i = 0; i < device_uris.n_uris; i++)
01478        argv[i + 2] = device_uris.uri[i];
01479       argv[i + 2] = NULL;
01480 
01481       syslog (LOG_DEBUG, "About to add queue for %s", argv[2]);
01482       strcpy (argv0, cmd);
01483       p = strrchr (argv0, '/');
01484       if (p++ == NULL)
01485        p = argv0;
01486 
01487       strcpy (p, "udev-add-printer");
01488 
01489       execv (argv0, argv);
01490       syslog (LOG_ERR, "Failed to execute %s", argv0);
01491     }
01492 
01493   free_device_id (&id);
01494   free_device_uris (&device_uris);
01495   return 0;
01496 }
01497 
01498 static void
01499 remove_queue (const char *printer_uri)
01500 {
01501   /* Disable it. */
01502   http_t *cups = httpConnectEncrypt (cupsServer (), ippPort (),
01503                                  cupsEncryption ());
01504   ipp_t *request, *answer;
01505 
01506   if (cups == NULL)
01507     return;
01508 
01509   request = ippNewRequest (CUPS_DELETE_PRINTER);
01510   ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
01511               "printer-uri", NULL, printer_uri);
01512   answer = cupsDoRequest (cups, request, "/admin/");
01513   if (!answer)
01514     {
01515       syslog (LOG_ERR, "Failed to send IPP-Delete-Printer request");
01516       httpClose (cups);
01517       return;
01518     }
01519 
01520   if (answer->request.status.status_code > IPP_OK_CONFLICT)
01521     syslog (LOG_ERR, "IPP-Delete-Printer request failed");
01522   else
01523     syslog (LOG_INFO, "Deleted printer %s as the corresponding device "
01524            "was unpaired", printer_uri);
01525 
01526   ippDelete (answer);
01527   httpClose (cups);
01528 }
01529 
01530 static void
01531 disable_queue (const char *printer_uri, void *context)
01532 {
01533   /* Disable it. */
01534   http_t *cups = httpConnectEncrypt (cupsServer (), ippPort (),
01535                                  cupsEncryption ());
01536   ipp_t *request, *answer;
01537 
01538   if (cups == NULL)
01539     return;
01540 
01541   request = ippNewRequest (IPP_PAUSE_PRINTER);
01542   ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
01543               "printer-uri", NULL, printer_uri);
01544   ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
01545               "printer-state-message", NULL, DISABLED_REASON);
01546   answer = cupsDoRequest (cups, request, "/admin/");
01547   if (!answer)
01548     {
01549       syslog (LOG_ERR, "Failed to send IPP-Pause-Printer request");
01550       httpClose (cups);
01551       return;
01552     }
01553 
01554   if (answer->request.status.status_code > IPP_OK_CONFLICT)
01555     syslog (LOG_ERR, "IPP-Pause-Printer request failed");
01556   else
01557     syslog (LOG_INFO, "Disabled printer %s as the corresponding device "
01558            "was unplugged or turned off", printer_uri);
01559 
01560   ippDelete (answer);
01561   httpClose (cups);
01562 }
01563 
01564 static int
01565 do_remove (const char *devpath)
01566 {
01567   struct usb_uri_map *map;
01568   struct usb_uri_map_entry *entry, **prev;
01569   struct device_uris *uris = NULL;
01570   char usblpdev[8] = "";
01571   syslog (LOG_DEBUG, "remove %s", devpath);
01572 
01573   if (bluetooth_verify_address (devpath))
01574     {
01575       char *device_uri;
01576 
01577       device_uri = uri_from_bdaddr (devpath);
01578       remove_queue (devpath);
01579       g_free (device_uri);
01580       return 0;
01581     }
01582 
01583   map = read_usb_uri_map ();
01584   prev = &map->entries;
01585   for (entry = map->entries; entry; entry = entry->next)
01586     {
01587       if (!strcmp (entry->devpath, devpath))
01588        {
01589          uris = &entry->uris;
01590          break;
01591        }
01592 
01593       prev = &(entry->next);
01594     }
01595 
01596   if (uris)
01597     {
01598       /* Find the relevant queues and disable them if they are enabled. */
01599       for_each_matching_queue (uris, 0, disable_queue, NULL,
01600                             usblpdev, sizeof (usblpdev));
01601       *prev = entry->next;
01602       write_usb_uri_map (map);
01603     }
01604 
01605   free_usb_uri_map (map);
01606   return 0;
01607 }
01608 
01609 static int
01610 do_enumerate (const char *argv0)
01611 {
01612   struct udev *udev;
01613   struct udev_enumerate *e;
01614   struct udev_list_entry *item = NULL, *first = NULL;
01615   int r = 0;
01616 
01617   udev = udev_new ();
01618   if (udev == NULL)
01619     {
01620       syslog (LOG_ERR, "udev_new failed");
01621       exit (1);
01622     }
01623 
01624   e = udev_enumerate_new (udev);
01625   if (e == NULL)
01626     {
01627       udev_unref (udev);
01628       syslog (LOG_ERR, "udev_enumerate_new failed");
01629       exit (1);
01630     }
01631 
01632   if (udev_enumerate_add_match_tag (e, "udev-configure-printer") < 0)
01633     {
01634       udev_unref (udev);
01635       udev_enumerate_unref (e);
01636       syslog (LOG_ERR, "udev_enumerate_add_match_tag failed");
01637       exit (1);
01638     }
01639 
01640   if (udev_enumerate_scan_devices (e) < 0)
01641     {
01642       udev_unref (udev);
01643       udev_enumerate_unref (e);
01644       syslog (LOG_ERR, "udev_enumerate_scan_devices failed");
01645       exit (1);
01646     }
01647 
01648   first = udev_enumerate_get_list_entry (e);
01649   udev_list_entry_foreach (item, first)
01650     {
01651       int k;
01652       const char *p;
01653       struct udev_device *d;
01654 
01655       d = udev_device_new_from_syspath (udev, udev_list_entry_get_name(item));
01656       if (!d)
01657         continue;
01658 
01659       p = udev_device_get_devpath (d);
01660       if (p)
01661         {
01662           k = do_add (argv0, p, 0);
01663           if (k != 0)
01664             r = k;
01665         }
01666 
01667       udev_device_unref (d);
01668   }
01669 
01670   udev_enumerate_unref (e);
01671   udev_unref (udev);
01672 
01673   return r;
01674 }
01675 
01676 int
01677 main (int argc, char **argv)
01678 {
01679   int add = 0;
01680   int enumerate = 0;
01681 
01682   if (argc > 1)
01683     {
01684       add = !strcmp (argv[1], "add");
01685       enumerate = !strcmp (argv[1], "enumerate");
01686     }
01687 
01688   if (!(argc == 3 &&
01689         (add || !strcmp (argv[1], "remove"))) &&
01690       !(argc == 2 && enumerate))
01691     {
01692       fprintf (stderr,
01693               "Syntax: %s add {USB device path}\n"
01694               "        %s remove {USB device path}\n"
01695                "        %s enumerate\n",
01696               argv[0], argv[0], argv[0]);
01697       return 1;
01698     }
01699 
01700   openlog ("udev-configure-printer", 0, LOG_LPR);
01701   cupsSetPasswordCB (no_password);
01702   if (add)
01703     return do_add (argv[0], argv[2], 1);
01704   if (enumerate)
01705     return do_enumerate (argv[0]);
01706 
01707   return do_remove (argv[2]);
01708 }