diff --git a/udev/udev-add-printer b/udev/udev-add-printer index 03d301e..2e4d933 100755 --- a/udev/udev-add-printer +++ b/udev/udev-add-printer @@ -27,13 +27,11 @@ import sys import traceback from syslog import * -def create_queue (c, name, device_uri, ppdname, info): +def create_queue (c, printernames, name, device_uri, ppdname, info): # Make sure the name is unique. - printers = cupshelpers.getPrinters (c) - names = printers.keys () - if name in names: + if name in printernames: suffix = 2 - while (name + "-" + str (suffix)) in names: + while (name + "-" + str (suffix)) in printernames: suffix += 1 if suffix == 100: break @@ -83,7 +81,10 @@ def add_queue (device_id, device_uris, is_fax=False): name = name.replace ("/", "-") name = name.replace ("#", "-") - create_queue (c, name, device_uris[0], ppdname, + printers = cupshelpers.getPrinters (c) + printernames = printers.keys () + + create_queue (c, printernames, name, device_uris[0], ppdname, "%s %s" % (id_dict["MFG"], id_dict["MDL"])) if not is_fax: @@ -93,24 +94,8 @@ def add_queue (device_id, device_uris, is_fax=False): # find one whose scheme ends in "fax", use that as a fax # queue. Note that the HPLIP backends do follow this # pattern (hp and hpfax). - not_fax_schemes=["beh", - "bluetooth", - "http", - "https", - "ipp", - "lpd", - "parallel", - "serial", - "smb", - "snmp", - "socket", - "scsi", - "usb"] - devices = c.getDevices (exclude_schemes=not_fax_schemes) - for uri, device_dict in devices.iteritems (): - if uri in device_uris: - continue - + used_uris = map (lambda x: x.device_uri, printers.values ()) + for uri in device_uris[1:]: if uri.find (":") == -1: continue @@ -119,8 +104,20 @@ def add_queue (device_id, device_uris, is_fax=False): # Now see if the non-scheme parts of the URI match # any of the URIs we were given. for each_uri in device_uris: + if each_uri == uri: + continue (s, device_uri_rest) = each_uri.split (":", 1) if rest == device_uri_rest: + # This one matches. Check there is not + # already a queue using this URI. + if uri in used_uris: + break + + devices = c.getDevices (include_schemes=[scheme]) + device_dict = devices.get (uri) + if device_dict == None: + break + add_queue (device_dict.get ("device-id", ""), [uri], is_fax=True) else: diff --git a/udev/udev-configure-printer.c b/udev/udev-configure-printer.c index a3c87dc..37a8682 100644 --- a/udev/udev-configure-printer.c +++ b/udev/udev-configure-printer.c @@ -708,7 +708,7 @@ cupsDoRequestOrDie (http_t *http, static int find_matching_device_uris (struct device_id *id, - const char *serial, + const char *usbserial, struct device_uris *uris, const char *devpath) { @@ -716,21 +716,34 @@ find_matching_device_uris (struct device_id *id, ipp_t *request, *answer; ipp_attribute_t *attr; struct device_uris uris_noserial; + struct device_uris all_uris; + size_t i, n; + const char *exclude_schemes[] = { + "beh", + "bluetooth", + "http", + "https", + "ipp", + "lpd", + "ncp", + "parallel", + "scsi", + "smb", + "snmp", + "socket", + }; - uris->n_uris = 0; - uris->uri = NULL; - - uris_noserial.n_uris = 0; - uris_noserial.uri = NULL; + uris->n_uris = uris_noserial.n_uris = all_uris.n_uris = 0; + uris->uri = uris_noserial.uri = all_uris.uri = NULL; /* Leave the bus to settle. */ sleep (1); cups = cups_connection (); request = ippNewRequest (CUPS_GET_DEVICES); - ippAddStrings (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "include-schemes", - sizeof (device_uri_types) / sizeof(device_uri_types[0]), - NULL, device_uri_types); + ippAddStrings (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "exclude-schemes", + sizeof (exclude_schemes) / sizeof(exclude_schemes[0]), + NULL, exclude_schemes); answer = cupsDoRequestOrDie (cups, request, "/"); httpClose (cups); @@ -757,6 +770,28 @@ find_matching_device_uris (struct device_id *id, parse_device_id (attr->values[0].string.text, &this_id); } + /* Only use device schemes in our preference order for matching + * against the IEEE 1284 Device ID. */ + + for (i = 0; + device_uri && + i < sizeof (device_uri_types) / sizeof (device_uri_types[0]); + i++) + { + size_t len = strlen (device_uri_types[i]); + if (!strncmp (device_uri_types[i], device_uri, len) && + device_uri[len] == ':') + break; + } + + if (device_uri) + add_device_uri (&all_uris, device_uri); + + if (i == sizeof (device_uri_types) / sizeof (device_uri_types[0])) + /* Not what we want to match against. Ignore this one. */ + device_uri = NULL; + + /* Now check the manufacturer and model names. */ if (device_uri && this_id.mfg && this_id.mdl && !strcmp (this_id.mfg, id->mfg) && !strcmp (this_id.mdl, id->mdl)) @@ -803,11 +838,11 @@ find_matching_device_uris (struct device_id *id, match = 1; } - if (!match && strlen (serial) >= 12) + if (!match && usbserial[0] != '\0') { if (!id->sern) { - if (this_id.sern && !strcmp (serial, this_id.sern)) + if (this_id.sern && !strcmp (usbserial, this_id.sern)) { syslog (LOG_DEBUG, "SERN field matches USB serial number"); @@ -819,10 +854,11 @@ find_matching_device_uris (struct device_id *id, { char *saveptr, *uri = strdup (device_uri); const char *token; - for (token = strtok_r (uri, "?=&", &saveptr); + const char *sep = "?=&/"; + for (token = strtok_r (uri, sep, &saveptr); token; - token = strtok_r (NULL, "?=&", &saveptr)) - if (!strcmp (token, serial)) + token = strtok_r (NULL, sep, &saveptr)) + if (!strcmp (token, usbserial)) { syslog (LOG_DEBUG, "URI contains USB serial number"); match = 1; @@ -886,14 +922,56 @@ find_matching_device_uris (struct device_id *id, uris->uri = old; else { - size_t i; for (i = 0; i < uris_noserial.n_uris; i++) uris->uri[uris->n_uris + i] = uris_noserial.uri[i]; uris->n_uris += uris_noserial.n_uris; } + + uris_noserial.n_uris = 0; + uris_noserial.uri = NULL; } free_device_uris (&uris_noserial); + + /* Having decided which device URIs match based on IEEE 1284 Device + * ID, we now need to look for "paired" URIs for other functions of + * a multi-function device. This are the same except for the + * scheme. */ + + n = uris->n_uris; + for (i = 0; i < n; i++) + { + size_t j; + char *me = uris->uri[i]; + char *my_rest = strchr (me, ':'); + size_t my_schemelen; + if (!my_rest) + continue; + + my_schemelen = my_rest - me; + for (j = 0; j < all_uris.n_uris; j++) + { + char *twin = all_uris.uri[j]; + char *twin_rest = strchr (twin, ':'); + size_t twin_schemelen; + if (!twin_rest) + continue; + + twin_schemelen = twin_rest - twin; + if (my_schemelen == twin_schemelen && + !strncmp (me, twin, my_schemelen)) + /* This is the one we are looking for the twin of. */ + continue; + + if (!strcmp (my_rest, twin_rest)) + { + syslog (LOG_DEBUG, "%s twinned with %s", me, twin); + add_device_uri (uris, twin); + } + } + } + + free_device_uris (&all_uris); if (uris->n_uris > 0) { struct usb_uri_map *map = read_usb_uri_map (); @@ -1048,12 +1126,12 @@ do_add (const char *cmd, const char *devpath) struct device_id id; struct device_uris device_uris; char *usb_device_devpath; - char serial[256]; + char usbserial[256]; syslog (LOG_DEBUG, "add %s", devpath); usb_device_devpath = device_id_from_devpath (devpath, &id, - serial, sizeof (serial)); + usbserial, sizeof (usbserial)); if (!id.mfg || !id.mdl) { syslog (LOG_ERR, "invalid or missing IEEE 1284 Device ID%s%s", @@ -1063,28 +1141,31 @@ do_add (const char *cmd, const char *devpath) } syslog (LOG_DEBUG, "MFG:%s MDL:%s SERN:%s serial:%s", id.mfg, id.mdl, - id.sern ? id.sern : "-", serial); - - if ((pid = fork ()) == -1) - syslog (LOG_ERR, "Failed to fork process"); - else if (pid != 0) - /* Parent. */ - exit (0); - - close (STDIN_FILENO); - close (STDOUT_FILENO); - close (STDERR_FILENO); - f = open ("/dev/null", O_RDWR); - if (f != STDIN_FILENO) - dup2 (f, STDIN_FILENO); - if (f != STDOUT_FILENO) - dup2 (f, STDOUT_FILENO); - if (f != STDERR_FILENO) - dup2 (f, STDERR_FILENO); - - setsid (); - - find_matching_device_uris (&id, serial, &device_uris, usb_device_devpath); + id.sern ? id.sern : "-", usbserial); + + if (getenv ("DEBUG") == NULL) + { + if ((pid = fork ()) == -1) + syslog (LOG_ERR, "Failed to fork process"); + else if (pid != 0) + /* Parent. */ + exit (0); + + close (STDIN_FILENO); + close (STDOUT_FILENO); + close (STDERR_FILENO); + f = open ("/dev/null", O_RDWR); + if (f != STDIN_FILENO) + dup2 (f, STDIN_FILENO); + if (f != STDOUT_FILENO) + dup2 (f, STDOUT_FILENO); + if (f != STDERR_FILENO) + dup2 (f, STDERR_FILENO); + + setsid (); + } + + find_matching_device_uris (&id, usbserial, &device_uris, usb_device_devpath); free (usb_device_devpath); if (device_uris.n_uris == 0) {