]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - backend/ieee1284.c
Import CUPS v1.7.1
[thirdparty/cups.git] / backend / ieee1284.c
index 2e0f2b242b8d87af35804548044d5c2de7a682f7..fc5ad1d09a81aaa4e3f896a3aa035b36772565cc 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * "$Id: ieee1284.c 6649 2007-07-11 21:46:42Z mike $"
+ * "$Id: ieee1284.c 10996 2013-05-29 11:51:34Z msweet $"
  *
- *   IEEE-1284 support functions for the Common UNIX Printing System (CUPS).
+ *   IEEE-1284 support functions for CUPS.
  *
- *   Copyright 2007 by Apple Inc.
+ *   Copyright 2007-2011 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
  */
 
 #include "backend-private.h"
-
-#ifdef __linux
-#  include <sys/ioctl.h>
-#  include <linux/lp.h>
-#  define IOCNR_GET_DEVICE_ID          1
-#  define LPIOC_GET_DEVICE_ID(len)     _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)
-#endif /* __linux */
-
-#ifdef __sun
-#  ifdef __sparc
-#    include <sys/ecppio.h>
-#  else
-#    include <sys/ioccom.h>
-#    include <sys/ecppsys.h>
-#  endif /* __sparc */
-#endif /* __sun */
+#include <cups/cups-private.h>
 
 
 /*
@@ -60,18 +45,27 @@ backendGetDeviceID(
     char       *uri,                   /* O - Device URI */
     int        uri_size)               /* I - Size of buffer */
 {
-  char *attr,                          /* 1284 attribute */
-       *delim,                         /* 1284 delimiter */
-       *uriptr,                        /* Pointer into URI */
-       manufacturer[256],              /* Manufacturer string */
-       serial_number[1024];            /* Serial number string */
-  int  manulen;                        /* Length of manufacturer string */
-#ifdef __linux
+#ifdef __APPLE__ /* This function is a no-op */
+  (void)fd;
+  (void)device_id;
+  (void)device_id_size;
+  (void)make_model;
+  (void)make_model_size;
+  (void)scheme;
+  (void)uri;
+  (void)uri_size;
+
+  return (-1);
+
+#else /* Get the device ID from the specified file descriptor... */
+#  ifdef __linux
   int  length;                         /* Length of device ID info */
-#endif /* __linux */
-#if defined(__sun) && defined(ECPPIOC_GETDEVID)
+  int   got_id = 0;
+#  endif /* __linux */
+#  if defined(__sun) && defined(ECPPIOC_GETDEVID)
   struct ecpp_device_id did;           /* Device ID buffer */
-#endif /* __sun && ECPPIOC_GETDEVID */
+#  endif /* __sun && ECPPIOC_GETDEVID */
+  char *ptr;                           /* Pointer into device ID */
 
 
   DEBUG_printf(("backendGetDeviceID(fd=%d, device_id=%p, device_id_size=%d, "
@@ -93,9 +87,6 @@ backendGetDeviceID(
   if (make_model)
     *make_model = '\0';
 
-  if (uri)
-    *uri = '\0';
-
   if (fd >= 0)
   {
    /*
@@ -104,8 +95,83 @@ backendGetDeviceID(
 
     *device_id = '\0';
 
-#ifdef __linux
-    if (!ioctl(fd, LPIOC_GET_DEVICE_ID(device_id_size), device_id))
+#  ifdef __linux
+    if (ioctl(fd, LPIOC_GET_DEVICE_ID(device_id_size), device_id))
+    {
+     /*
+      * Linux has to implement things differently for every device it seems.
+      * Since the standard parallel port driver does not provide a simple
+      * ioctl() to get the 1284 device ID, we have to open the "raw" parallel
+      * device corresponding to this port and do some negotiation trickery
+      * to get the current device ID.
+      */
+
+      if (uri && !strncmp(uri, "parallel:/dev/", 14))
+      {
+       char    devparport[16];         /* /dev/parportN */
+       int     devparportfd,           /* File descriptor for raw device */
+                 mode;                 /* Port mode */
+
+
+       /*
+       * Since the Linux parallel backend only supports 4 parallel port
+       * devices, just grab the trailing digit and use it to construct a
+       * /dev/parportN filename...
+       */
+
+       snprintf(devparport, sizeof(devparport), "/dev/parport%s",
+                uri + strlen(uri) - 1);
+
+       if ((devparportfd = open(devparport, O_RDWR | O_NOCTTY)) != -1)
+       {
+        /*
+         * Claim the device...
+         */
+
+         if (!ioctl(devparportfd, PPCLAIM))
+         {
+           fcntl(devparportfd, F_SETFL, fcntl(devparportfd, F_GETFL) | O_NONBLOCK);
+
+           mode = IEEE1284_MODE_COMPAT;
+
+           if (!ioctl(devparportfd, PPNEGOT, &mode))
+           {
+            /*
+             * Put the device into Device ID mode...
+             */
+
+             mode = IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID;
+
+             if (!ioctl(devparportfd, PPNEGOT, &mode))
+             {
+              /*
+               * Read the 1284 device ID...
+               */
+
+               if ((length = read(devparportfd, device_id,
+                                  device_id_size - 1)) >= 2)
+               {
+                 device_id[length] = '\0';
+                 got_id = 1;
+               }
+             }
+           }
+
+          /*
+           * Release the device...
+           */
+
+           ioctl(devparportfd, PPRELEASE);
+         }
+
+         close(devparportfd);
+       }
+      }
+    }
+    else
+      got_id = 1;
+
+    if (got_id)
     {
      /*
       * Extract the length of the device ID string from the first two
@@ -121,28 +187,53 @@ backendGetDeviceID(
       * and then limit the length to the size of our buffer...
       */
 
-      if (length > (device_id_size - 2))
+      if (length > device_id_size || length < 14)
        length = (((unsigned)device_id[1] & 255) << 8) +
                 ((unsigned)device_id[0] & 255);
 
-      if (length > (device_id_size - 2))
-       length = device_id_size - 2;
+      if (length > device_id_size)
+       length = device_id_size;
 
      /*
-      * Copy the device ID text to the beginning of the buffer and
-      * nul-terminate.
+      * The length field counts the number of bytes in the string
+      * including the length field itself (2 bytes).  The minimum
+      * length for a valid/usable device ID is 14 bytes:
+      *
+      *     <LENGTH> MFG: <MFG> ;MDL: <MDL> ;
+      *        2  +   4  +  1  +  5 +  1 +  1
       */
 
-      memmove(device_id, device_id + 2, length);
-      device_id[length] = '\0';
+      if (length < 14)
+      {
+       /*
+       * Can't use this device ID, so don't try to copy it...
+       */
+
+       device_id[0] = '\0';
+       got_id       = 0;
+      }
+      else
+      {
+       /*
+       * Copy the device ID text to the beginning of the buffer and
+       * nul-terminate.
+       */
+
+       length -= 2;
+
+       memmove(device_id, device_id + 2, length);
+       device_id[length] = '\0';
+      }
     }
-#  ifdef DEBUG
     else
-      printf("backendGetDeviceID: ioctl failed - %s\n", strerror(errno));
-#  endif /* DEBUG */
-#endif /* __linux */
+    {
+      DEBUG_printf(("backendGetDeviceID: ioctl failed - %s\n",
+                    strerror(errno)));
+      *device_id = '\0';
+    }
+#  endif /* __linux */
 
-#if defined(__sun) && defined(ECPPIOC_GETDEVID)
+#   if defined(__sun) && defined(ECPPIOC_GETDEVID)
     did.mode = ECPP_CENTRONICS;
     did.len  = device_id_size - 1;
     did.rlen = 0;
@@ -159,15 +250,35 @@ backendGetDeviceID(
       else
        device_id[device_id_size - 1] = '\0';
     }
-#  ifdef DEBUG
+#    ifdef DEBUG
     else
-      printf("backendGetDeviceID: ioctl failed - %s\n", strerror(errno));
-#  endif /* DEBUG */
-#endif /* __sun && ECPPIOC_GETDEVID */
+      DEBUG_printf(("backendGetDeviceID: ioctl failed - %s\n",
+                    strerror(errno)));
+#    endif /* DEBUG */
+#  endif /* __sun && ECPPIOC_GETDEVID */
   }
 
+ /*
+  * Check whether device ID is valid. Turn line breaks and tabs to spaces and
+  * reject device IDs with non-printable characters.
+  */
+
+  for (ptr = device_id; *ptr; ptr ++)
+    if (_cups_isspace(*ptr))
+      *ptr = ' ';
+    else if ((*ptr & 255) < ' ' || *ptr == 127)
+    {
+      DEBUG_printf(("backendGetDeviceID: Bad device_id character %d.",
+                    *ptr & 255));
+      *device_id = '\0';
+      break;
+    }
+
   DEBUG_printf(("backendGetDeviceID: device_id=\"%s\"\n", device_id));
 
+  if (scheme && uri)
+    *uri = '\0';
+
   if (!*device_id)
     return (-1);
 
@@ -184,111 +295,72 @@ backendGetDeviceID(
 
   if (scheme && uri && uri_size > 32)
   {
-   /*
-    * Look for the serial number field...
-    */
-
-    if ((attr = strstr(device_id, "SERN:")) != NULL)
-      attr += 5;
-    else if ((attr = strstr(device_id, "SERIALNUMBER:")) != NULL)
-      attr += 13;
-    else if ((attr = strstr(device_id, ";SN:")) != NULL)
-      attr += 4;
+    int                        num_values;     /* Number of keys and values */
+    cups_option_t      *values;        /* Keys and values in device ID */
+    const char         *mfg,           /* Manufacturer */
+                       *mdl,           /* Model */
+                       *sern;          /* Serial number */
+    char               temp[256],      /* Temporary manufacturer string */
+                       *tempptr;       /* Pointer into temp string */
 
-    if (attr)
-    {
-      strlcpy(serial_number, attr, sizeof(serial_number));
-
-      if ((delim = strchr(serial_number, ';')) != NULL)
-       *delim = '\0';
-    }
-    else
-      serial_number[0] = '\0';
 
    /*
-    * Generate the device URI from the manufacturer, make_model, and
-    * serial number strings.
+    * Get the make, model, and serial numbers...
     */
 
-    snprintf(uri, uri_size, "%s://", scheme);
+    num_values = _cupsGet1284Values(device_id, &values);
 
-    if ((attr = strstr(device_id, "MANUFACTURER:")) != NULL)
-      attr += 13;
-    else if ((attr = strstr(device_id, "Manufacturer:")) != NULL)
-      attr += 13;
-    else if ((attr = strstr(device_id, "MFG:")) != NULL)
-      attr += 4;
+    if ((sern = cupsGetOption("SERIALNUMBER", num_values, values)) == NULL)
+      if ((sern = cupsGetOption("SERN", num_values, values)) == NULL)
+        sern = cupsGetOption("SN", num_values, values);
 
-    if (attr)
-    {
-      strlcpy(manufacturer, attr, sizeof(manufacturer));
+    if ((mfg = cupsGetOption("MANUFACTURER", num_values, values)) == NULL)
+      mfg = cupsGetOption("MFG", num_values, values);
 
-      if ((delim = strchr(manufacturer, ';')) != NULL)
-        *delim = '\0';
+    if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL)
+      mdl = cupsGetOption("MDL", num_values, values);
 
-      if (!strcasecmp(manufacturer, "Hewlett-Packard"))
-        strcpy(manufacturer, "HP");
-      else if (!strcasecmp(manufacturer, "Lexmark International"))
-        strcpy(manufacturer, "Lexmark");
+    if (mfg)
+    {
+      if (!_cups_strcasecmp(mfg, "Hewlett-Packard"))
+        mfg = "HP";
+      else if (!_cups_strcasecmp(mfg, "Lexmark International"))
+        mfg = "Lexmark";
     }
     else
     {
-      strlcpy(manufacturer, make_model, sizeof(manufacturer));
+      strlcpy(temp, make_model, sizeof(temp));
 
-      if ((delim = strchr(manufacturer, ' ')) != NULL)
-        *delim = '\0';
-    }
+      if ((tempptr = strchr(temp, ' ')) != NULL)
+        *tempptr = '\0';
 
-    manulen = strlen(manufacturer);
-
-    for (uriptr = uri + strlen(uri), delim = manufacturer;
-        *delim && uriptr < (uri + uri_size - 3);
-        delim ++)
-      if (*delim == ' ')
-      {
-       *uriptr++ = '%';
-       *uriptr++ = '2';
-       *uriptr++ = '0';
-      }
-      else
-       *uriptr++ = *delim;
+      mfg = temp;
+    }
 
-    *uriptr++ = '/';
+    if (!mdl)
+      mdl = "";
 
-    if (!strncasecmp(make_model, manufacturer, manulen))
+    if (!_cups_strncasecmp(mdl, mfg, strlen(mfg)))
     {
-      delim = make_model + manulen;
+      mdl += strlen(mfg);
 
-      while (isspace(*delim & 255))
-        delim ++;
+      while (isspace(*mdl & 255))
+        mdl ++;
     }
-    else
-      delim = make_model;
 
-    for (; *delim && uriptr < (uri + uri_size - 3); delim ++)
-      if (*delim == ' ')
-      {
-       *uriptr++ = '%';
-       *uriptr++ = '2';
-       *uriptr++ = '0';
-      }
-      else
-       *uriptr++ = *delim;
+   /*
+    * Generate the device URI from the manufacturer, make_model, and
+    * serial number strings.
+    */
 
-    if (serial_number[0])
-    {
-     /*
-      * Add the serial number to the URI...
-      */
+    httpAssembleURIf(HTTP_URI_CODING_ALL, uri, uri_size, scheme, NULL, mfg, 0,
+                     "/%s%s%s", mdl, sern ? "?serial=" : "", sern ? sern : "");
 
-      strlcpy(uriptr, "?serial=", uri_size - (uriptr - uri));
-      strlcat(uriptr, serial_number, uri_size - (uriptr - uri));
-    }
-    else
-      *uriptr = '\0';
+    cupsFreeOptions(num_values, values);
   }
 
   return (0);
+#endif /* __APPLE__ */
 }
 
 
@@ -302,10 +374,11 @@ backendGetMakeModel(
     char       *make_model,            /* O - Make/model */
     int        make_model_size)                /* I - Size of buffer */
 {
-  char *attr,                          /* 1284 attribute */
-       *delim,                         /* 1284 delimiter */
-       *mfg,                           /* Manufacturer string */
-       *mdl;                           /* Model string */
+  int          num_values;             /* Number of keys and values */
+  cups_option_t        *values;                /* Keys and values */
+  const char   *mfg,                   /* Manufacturer string */
+               *mdl,                   /* Model string */
+               *des;                   /* Description string */
 
 
   DEBUG_printf(("backendGetMakeModel(device_id=\"%s\", "
@@ -328,135 +401,77 @@ backendGetMakeModel(
   * Look for the description field...
   */
 
-  if ((attr = strstr(device_id, "DES:")) != NULL)
-    attr += 4;
-  else if ((attr = strstr(device_id, "DESCRIPTION:")) != NULL)
-    attr += 12;
+  num_values = _cupsGet1284Values(device_id, &values);
+
+  if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL)
+    mdl = cupsGetOption("MDL", num_values, values);
 
-  if (attr)
+  if (mdl)
   {
    /*
-    * Make sure the description contains something useful, since some
-    * printer manufacturers (HP) apparently don't follow the standards
-    * they helped to define...
-    *
-    * Here we require the description to be 8 or more characters in length,
-    * containing at least one space and one letter.
+    * Build a make-model string from the manufacturer and model attributes...
     */
 
-    if ((delim = strchr(attr, ';')) == NULL)
-      delim = attr + strlen(attr);
+    if ((mfg = cupsGetOption("MANUFACTURER", num_values, values)) == NULL)
+      mfg = cupsGetOption("MFG", num_values, values);
 
-    if ((delim - attr) < 8)
-      attr = NULL;
-    else
+    if (!mfg || !_cups_strncasecmp(mdl, mfg, strlen(mfg)))
     {
-      char     *ptr;                   /* Pointer into description */
-      int      letters,                /* Number of letters seen */
-               spaces;                 /* Number of spaces seen */
+     /*
+      * Just copy the model string, since it has the manufacturer...
+      */
 
+      _ppdNormalizeMakeAndModel(mdl, make_model, make_model_size);
+    }
+    else
+    {
+     /*
+      * Concatenate the make and model...
+      */
 
-      for (ptr = attr, letters = 0, spaces = 0; ptr < delim; ptr ++)
-      {
-        if (isspace(*ptr & 255))
-         spaces ++;
-       else if (isalpha(*ptr & 255))
-         letters ++;
+      char     temp[1024];             /* Temporary make and model */
 
-        if (spaces && letters)
-         break;
-      }
+      snprintf(temp, sizeof(temp), "%s %s", mfg, mdl);
 
-      if (!spaces || !letters)
-        attr = NULL;
+      _ppdNormalizeMakeAndModel(temp, make_model, make_model_size);
     }
   }
-
-  if ((mfg = strstr(device_id, "MANUFACTURER:")) != NULL)
-    mfg += 13;
-  else if ((mfg = strstr(device_id, "Manufacturer:")) != NULL)
-    mfg += 13;
-  else if ((mfg = strstr(device_id, "MFG:")) != NULL)
-    mfg += 4;
-
-  if ((mdl = strstr(device_id, "MODEL:")) != NULL)
-    mdl += 6;
-  else if ((mdl = strstr(device_id, "Model:")) != NULL)
-    mdl += 6;
-  else if ((mdl = strstr(device_id, "MDL:")) != NULL)
-    mdl += 4;
-
-  if (mdl)
+  else if ((des = cupsGetOption("DESCRIPTION", num_values, values)) != NULL ||
+           (des = cupsGetOption("DES", num_values, values)) != NULL)
   {
    /*
-    * Build a make-model string from the manufacturer and model attributes...
+    * Make sure the description contains something useful, since some
+    * printer manufacturers (HP) apparently don't follow the standards
+    * they helped to define...
+    *
+    * Here we require the description to be 8 or more characters in length,
+    * containing at least one space and one letter.
     */
 
-    if (mfg)
+    if (strlen(des) >= 8)
     {
-      if (!strncasecmp(mfg, "Hewlett-Packard", 15))
-       strlcpy(make_model, "HP", make_model_size);
-      else if (!strncasecmp(mfg, "Lexmark International", 21))
-       strlcpy(make_model, "Lexmark", make_model_size);
-      else
-       strlcpy(make_model, mfg, make_model_size);
+      const char       *ptr;           /* Pointer into description */
+      int              letters,        /* Number of letters seen */
+                       spaces;         /* Number of spaces seen */
 
-      if ((delim = strchr(make_model, ';')) != NULL)
-       *delim = '\0';
 
-      if (!strncasecmp(make_model, mdl, strlen(make_model)))
+      for (ptr = des, letters = 0, spaces = 0; *ptr; ptr ++)
       {
-       /*
-       * Just copy model string, since it has the manufacturer...
-       */
-
-       strlcpy(make_model, mdl, make_model_size);
-      }
-      else
-      {
-       /*
-       * Concatenate the make and model...
-       */
+       if (isspace(*ptr & 255))
+         spaces ++;
+       else if (isalpha(*ptr & 255))
+         letters ++;
 
-       strlcat(make_model, " ", make_model_size);
-       strlcat(make_model, mdl, make_model_size);
+       if (spaces && letters)
+         break;
       }
-    }
-    else
-    {
-     /*
-      * Just copy model string, since it has the manufacturer...
-      */
 
-      strlcpy(make_model, mdl, make_model_size);
+      if (spaces && letters)
+        _ppdNormalizeMakeAndModel(des, make_model, make_model_size);
     }
   }
-  else if (attr)
-  {
-   /*
-    * Use description...
-    */
 
-    if (!strncasecmp(attr, "Hewlett-Packard hp ", 19))
-    {
-     /*
-      * Check for a common HP bug...
-      */
-
-      strlcpy(make_model, "HP ", make_model_size);
-      strlcpy(make_model + 3, attr + 19, make_model_size - 3);
-    }
-    else if (!strncasecmp(attr, "Hewlett-Packard ", 16))
-    {
-      strlcpy(make_model, "HP ", make_model_size);
-      strlcpy(make_model + 3, attr + 16, make_model_size - 3);
-    }
-    else
-    {
-      strlcpy(make_model, attr, make_model_size);
-    }
-  }
-  else
+  if (!make_model[0])
   {
    /*
     * Use "Unknown" as the printer make and model...
@@ -465,34 +480,12 @@ backendGetMakeModel(
     strlcpy(make_model, "Unknown", make_model_size);
   }
 
- /*
-  * Strip trailing data...
-  */
-
-  if ((delim = strchr(make_model, ';')) != NULL)
-    *delim = '\0';
+  cupsFreeOptions(num_values, values);
 
- /*
-  * Strip trailing whitespace...
-  */
-
-  for (delim = make_model + strlen(make_model) - 1; delim >= make_model; delim --)
-    if (isspace(*delim & 255))
-      *delim = '\0';
-    else
-      break;
-
- /*
-  * Return...
-  */
-
-  if (make_model[0])
-    return (0);
-  else
-    return (-1);
+  return (0);
 }
 
 
 /*
- * End of "$Id: ieee1284.c 6649 2007-07-11 21:46:42Z mike $".
+ * End of "$Id: ieee1284.c 10996 2013-05-29 11:51:34Z msweet $".
  */