]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/ipp-file.c
Update ipp documentation to reflect the behavior of configuring WiFi on IPP USB printers.
[thirdparty/cups.git] / cups / ipp-file.c
index 14918125cd039bbd9cfc8ee08b52dd649970a690..5483a607df600c4752114e6745d978dc8086449d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * IPP data file parsing functions.
  *
- * Copyright © 2007-2018 by Apple Inc.
+ * Copyright © 2007-2019 by Apple Inc.
  * Copyright © 1997-2007 by Easy Software Products.
  *
  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
@@ -14,7 +14,7 @@
 
 #include "ipp-private.h"
 #include "string-private.h"
-#include "debug-private.h"
+#include "debug-internal.h"
 
 
 /*
@@ -23,7 +23,7 @@
 
 static ipp_t   *parse_collection(_ipp_file_t *f, _ipp_vars_t *v, void *user_data);
 static int     parse_value(_ipp_file_t *f, _ipp_vars_t *v, void *user_data, ipp_t *ipp, ipp_attribute_t **attr, int element);
-static void    report_error(_ipp_file_t *f, _ipp_vars_t *v, void *user_data, const char *message, ...) __attribute((__format__ (__printf__, 4, 5)));
+static void    report_error(_ipp_file_t *f, _ipp_vars_t *v, void *user_data, const char *message, ...) _CUPS_FORMAT(4, 5);
 
 
 /*
@@ -81,8 +81,11 @@ _ippFileParse(
 
       if (_ippFileReadToken(&f, name, sizeof(name)) && _ippFileReadToken(&f, temp, sizeof(temp)))
       {
-        _ippVarsExpand(v, value, temp, sizeof(value));
-        _ippVarsSet(v, name, value);
+        if (_cups_strcasecmp(token, "DEFINE-DEFAULT") || !_ippVarsGet(v, name))
+        {
+         _ippVarsExpand(v, value, temp, sizeof(value));
+         _ippVarsSet(v, name, value);
+       }
       }
       else
       {
@@ -214,6 +217,8 @@ _ippFileReadToken(_ipp_file_t *f,   /* I - File to read from */
   * Skip whitespace and comments...
   */
 
+  DEBUG_printf(("1_ippFileReadToken: linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
+
   while ((ch = cupsFileGetChar(f->fp)) != EOF)
   {
     if (_cups_isspace(ch))
@@ -223,7 +228,10 @@ _ippFileReadToken(_ipp_file_t *f,  /* I - File to read from */
       */
 
       if (ch == '\n')
+      {
         f->linenum ++;
+        DEBUG_printf(("1_ippFileReadToken: LF in leading whitespace, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
+      }
     }
     else if (ch == '#')
     {
@@ -231,6 +239,8 @@ _ippFileReadToken(_ipp_file_t *f,   /* I - File to read from */
       * Comment...
       */
 
+      DEBUG_puts("1_ippFileReadToken: Skipping comment in leading whitespace...");
+
       while ((ch = cupsFileGetChar(f->fp)) != EOF)
       {
         if (ch == '\n')
@@ -238,7 +248,10 @@ _ippFileReadToken(_ipp_file_t *f,  /* I - File to read from */
       }
 
       if (ch == '\n')
+      {
         f->linenum ++;
+        DEBUG_printf(("1_ippFileReadToken: LF at end of comment, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
+      }
       else
         break;
     }
@@ -259,7 +272,10 @@ _ippFileReadToken(_ipp_file_t *f,  /* I - File to read from */
   while (ch != EOF)
   {
     if (ch == '\n')
+    {
       f->linenum ++;
+      DEBUG_printf(("1_ippFileReadToken: LF in token, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
+    }
 
     if (ch == quote)
     {
@@ -268,7 +284,7 @@ _ippFileReadToken(_ipp_file_t *f,   /* I - File to read from */
       */
 
       *tokptr = '\0';
-      DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token));
+      DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" at closing quote.", token));
       return (1);
     }
     else if (!quote && _cups_isspace(ch))
@@ -278,7 +294,7 @@ _ippFileReadToken(_ipp_file_t *f,   /* I - File to read from */
       */
 
       *tokptr = '\0';
-      DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token));
+      DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" before whitespace.", token));
       return (1);
     }
     else if (!quote && (ch == '\'' || ch == '\"'))
@@ -288,6 +304,8 @@ _ippFileReadToken(_ipp_file_t *f,   /* I - File to read from */
       */
 
       quote = ch;
+
+      DEBUG_printf(("1_ippFileReadToken: Start of quoted string, quote=%c, pos=%ld", quote, (long)cupsFileTell(f->fp)));
     }
     else if (!quote && ch == '#')
     {
@@ -297,7 +315,7 @@ _ippFileReadToken(_ipp_file_t *f,   /* I - File to read from */
 
       cupsFileSeek(f->fp, cupsFileTell(f->fp) - 1);
       *tokptr = '\0';
-      DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token));
+      DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" before comment.", token));
       return (1);
     }
     else if (!quote && (ch == '{' || ch == '}' || ch == ','))
@@ -335,6 +353,8 @@ _ippFileReadToken(_ipp_file_t *f,   /* I - File to read from */
         * Quoted character...
         */
 
+        DEBUG_printf(("1_ippFileReadToken: Quoted character at pos=%ld", (long)cupsFileTell(f->fp)));
+
         if ((ch = cupsFileGetChar(f->fp)) == EOF)
         {
          *token = '\0';
@@ -342,7 +362,24 @@ _ippFileReadToken(_ipp_file_t *f,  /* I - File to read from */
          return (0);
        }
        else if (ch == '\n')
+       {
          f->linenum ++;
+         DEBUG_printf(("1_ippFileReadToken: quoted LF, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
+       }
+       else if (ch == 'a')
+         ch = '\a';
+       else if (ch == 'b')
+         ch = '\b';
+       else if (ch == 'f')
+         ch = '\f';
+       else if (ch == 'n')
+         ch = '\n';
+       else if (ch == 'r')
+         ch = '\r';
+       else if (ch == 't')
+         ch = '\t';
+       else if (ch == 'v')
+         ch = '\v';
       }
 
       if (tokptr < tokend)
@@ -373,7 +410,7 @@ _ippFileReadToken(_ipp_file_t *f,   /* I - File to read from */
   }
 
   *tokptr = '\0';
-  DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token));
+  DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" at EOF.", token));
 
   return (tokptr > token);
 }
@@ -422,14 +459,14 @@ parse_collection(
 
       if (!_ippFileReadToken(f, syntax, sizeof(syntax)))
       {
-        report_error(f, v, user_data, "Missing ATTR syntax on line %d of \"%s\".", f->linenum, f->filename);
+        report_error(f, v, user_data, "Missing MEMBER syntax on line %d of \"%s\".", f->linenum, f->filename);
        ippDelete(col);
        col = NULL;
        break;
       }
       else if ((value_tag = ippTagValue(syntax)) < IPP_TAG_UNSUPPORTED_VALUE)
       {
-        report_error(f, v, user_data, "Bad ATTR syntax \"%s\" on line %d of \"%s\".", syntax, f->linenum, f->filename);
+        report_error(f, v, user_data, "Bad MEMBER syntax \"%s\" on line %d of \"%s\".", syntax, f->linenum, f->filename);
        ippDelete(col);
        col = NULL;
        break;
@@ -437,7 +474,7 @@ parse_collection(
 
       if (!_ippFileReadToken(f, name, sizeof(name)) || !name[0])
       {
-        report_error(f, v, user_data, "Missing ATTR name on line %d of \"%s\".", f->linenum, f->filename);
+        report_error(f, v, user_data, "Missing MEMBER name on line %d of \"%s\".", f->linenum, f->filename);
        ippDelete(col);
        col = NULL;
        break;
@@ -512,8 +549,11 @@ parse_value(_ipp_file_t      *f,   /* I  - IPP data file */
             ipp_attribute_t  **attr,   /* IO - IPP attribute */
             int              element)  /* I  - Element number */
 {
-  char value[1024],                    /* Value string */
-       temp[1024];                     /* Temporary string */
+  char         value[2049],            /* Value string */
+               *valueptr,              /* Pointer into value string */
+               temp[2049],             /* Temporary string */
+               *tempptr;               /* Pointer into temporary string */
+  size_t       valuelen;               /* Length of value */
 
 
   if (!_ippFileReadToken(f, temp, sizeof(temp)))
@@ -528,12 +568,10 @@ parse_value(_ipp_file_t      *f,  /* I  - IPP data file */
   {
     case IPP_TAG_BOOLEAN :
         return (ippSetBoolean(ipp, attr, element, !_cups_strcasecmp(value, "true")));
-        break;
 
     case IPP_TAG_ENUM :
     case IPP_TAG_INTEGER :
         return (ippSetInteger(ipp, attr, element, (int)strtol(value, NULL, 0)));
-        break;
 
     case IPP_TAG_DATE :
         {
@@ -546,8 +584,80 @@ parse_value(_ipp_file_t      *f,   /* I  - IPP data file */
                utc_offset = 0;         /* Timezone offset from UTC */
           ipp_uchar_t date[11];                /* dateTime value */
 
-          if (sscanf(value, "%d-%d-%dT%d:%d:%d-%d", &year, &month, &day, &hour, &minute, &second, &utc_offset) < 6)
+          if (*value == 'P')
+          {
+           /*
+            * Time period...
+            */
+
+            time_t     curtime;        /* Current time in seconds */
+            int                period = 0,     /* Current period value */
+                       saw_T = 0;      /* Saw time separator */
+
+            curtime = time(NULL);
+
+            for (valueptr = value + 1; *valueptr; valueptr ++)
+            {
+              if (isdigit(*valueptr & 255))
+              {
+                period = (int)strtol(valueptr, &valueptr, 10);
+
+                if (!valueptr || period < 0)
+                {
+                 report_error(f, v, user_data, "Bad dateTime value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
+                 return (0);
+               }
+              }
+
+              if (*valueptr == 'Y')
+              {
+                curtime += 365 * 86400 * period;
+                period  = 0;
+              }
+              else if (*valueptr == 'M')
+              {
+                if (saw_T)
+                  curtime += 60 * period;
+                else
+                  curtime += 30 * 86400 * period;
+
+                period = 0;
+              }
+              else if (*valueptr == 'D')
+              {
+                curtime += 86400 * period;
+                period  = 0;
+              }
+              else if (*valueptr == 'H')
+              {
+                curtime += 3600 * period;
+                period  = 0;
+              }
+              else if (*valueptr == 'S')
+              {
+                curtime += period;
+                period = 0;
+              }
+              else if (*valueptr == 'T')
+              {
+                saw_T  = 1;
+                period = 0;
+              }
+              else
+             {
+               report_error(f, v, user_data, "Bad dateTime value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
+               return (0);
+             }
+           }
+
+           return (ippSetDate(ipp, attr, element, ippTimeToDate(curtime)));
+          }
+          else if (sscanf(value, "%d-%d-%dT%d:%d:%d%d", &year, &month, &day, &hour, &minute, &second, &utc_offset) < 6)
           {
+           /*
+            * Date/time value did not parse...
+            */
+
            report_error(f, v, user_data, "Bad dateTime value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
            return (0);
           }
@@ -575,7 +685,6 @@ parse_value(_ipp_file_t      *f,    /* I  - IPP data file */
 
           return (ippSetDate(ipp, attr, element, date));
         }
-        break;
 
     case IPP_TAG_RESOLUTION :
        {
@@ -603,7 +712,6 @@ parse_value(_ipp_file_t      *f,    /* I  - IPP data file */
          else
            return (ippSetResolution(ipp, attr, element, (ipp_res_t)0, xres, yres));
        }
-       break;
 
     case IPP_TAG_RANGE :
        {
@@ -618,11 +726,46 @@ parse_value(_ipp_file_t      *f,  /* I  - IPP data file */
 
          return (ippSetRange(ipp, attr, element, lower, upper));
        }
-       break;
 
     case IPP_TAG_STRING :
-        return (ippSetOctetString(ipp, attr, element, value, (int)strlen(value)));
-        break;
+        valuelen = strlen(value);
+
+        if (value[0] == '<' && value[strlen(value) - 1] == '>')
+        {
+          if (valuelen & 1)
+          {
+           report_error(f, v, user_data, "Bad octetString value on line %d of \"%s\".", f->linenum, f->filename);
+           return (0);
+          }
+
+          valueptr = value + 1;
+          tempptr  = temp;
+
+          while (*valueptr && *valueptr != '>')
+          {
+           if (!isxdigit(valueptr[0] & 255) || !isxdigit(valueptr[1] & 255))
+           {
+             report_error(f, v, user_data, "Bad octetString value on line %d of \"%s\".", f->linenum, f->filename);
+             return (0);
+           }
+
+            if (valueptr[0] >= '0' && valueptr[0] <= '9')
+              *tempptr = (char)((valueptr[0] - '0') << 4);
+           else
+              *tempptr = (char)((tolower(valueptr[0]) - 'a' + 10) << 4);
+
+            if (valueptr[1] >= '0' && valueptr[1] <= '9')
+              *tempptr |= (valueptr[1] - '0');
+           else
+              *tempptr |= (tolower(valueptr[1]) - 'a' + 10);
+
+            tempptr ++;
+          }
+
+          return (ippSetOctetString(ipp, attr, element, temp, (int)(tempptr - temp)));
+        }
+        else
+          return (ippSetOctetString(ipp, attr, element, value, (int)valuelen));
 
     case IPP_TAG_TEXTLANG :
     case IPP_TAG_NAMELANG :
@@ -635,7 +778,6 @@ parse_value(_ipp_file_t      *f,    /* I  - IPP data file */
     case IPP_TAG_LANGUAGE :
     case IPP_TAG_MIMETYPE :
         return (ippSetString(ipp, attr, element, value));
-        break;
 
     case IPP_TAG_BEGIN_COLLECTION :
         {
@@ -644,7 +786,7 @@ parse_value(_ipp_file_t      *f,    /* I  - IPP data file */
 
           if (strcmp(value, "{"))
           {
-           report_error(f, v, user_data, "Bad ATTR collection value on line %d of \"%s\".", f->linenum, f->filename);
+           report_error(f, v, user_data, "Bad collection value on line %d of \"%s\".", f->linenum, f->filename);
            return (0);
           }
 
@@ -656,14 +798,11 @@ parse_value(_ipp_file_t      *f,  /* I  - IPP data file */
 
          return (status);
        }
-       break;
 
     default :
-        report_error(f, v, user_data, "Unsupported ATTR value on line %d of \"%s\".", f->linenum, f->filename);
+        report_error(f, v, user_data, "Unsupported value on line %d of \"%s\".", f->linenum, f->filename);
         return (0);
   }
-
-  return (1);
 }