]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Add (ASCII) IPP data file parser to libcups, to be used by ippserver and
authorMichael R Sweet <michaelrsweet@gmail.com>
Tue, 23 Jan 2018 02:23:24 +0000 (21:23 -0500)
committerMichael R Sweet <michaelrsweet@gmail.com>
Tue, 23 Jan 2018 02:23:24 +0000 (21:23 -0500)
ipptool.

cups/Makefile
cups/ipp-file.c [new file with mode: 0644]
cups/ipp-private.h
cups/ipp-vars.c [new file with mode: 0644]
cups/testipp.c
xcode/CUPS.xcodeproj/project.pbxproj

index 0715dba2112d988d63fc08490313e8d415f2c0ef..866b413ec54fabc8b97918f687a0798e362e0ddb 100644 (file)
@@ -46,6 +46,8 @@ LIBOBJS       =       \
                http-addrlist.o \
                http-support.o \
                ipp.o \
+               ipp-file.o \
+               ipp-vars.o \
                ipp-support.o \
                langprintf.o \
                language.o \
diff --git a/cups/ipp-file.c b/cups/ipp-file.c
new file mode 100644 (file)
index 0000000..d5d6295
--- /dev/null
@@ -0,0 +1,637 @@
+/*
+ * IPP data file parsing functions.
+ *
+ * Copyright © 2007-2018 by Apple Inc.
+ * Copyright © 1997-2007 by Easy Software Products.
+ *
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more
+ * information.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "ipp-private.h"
+#include "string-private.h"
+#include "debug-private.h"
+
+
+/*
+ * Local functions...
+ */
+
+static ipp_t   *parse_collection(_ipp_file_t *f, _ipp_vars_t *v, _ipp_ferror_cb_t errorcb, void *user_data);
+static int     parse_value(_ipp_file_t *f, _ipp_vars_t *v, _ipp_ferror_cb_t errorcb, void *user_data, ipp_t *ipp, ipp_attribute_t **attr, int element);
+static void    report_error(_ipp_file_t *f, _ipp_ferror_cb_t errorcb, void *user_data, const char *message, ...) __attribute((__format__ (__printf__, 4, 5)));
+
+
+/*
+ * '_ippFileParse()' - Parse an IPP data file.
+ */
+
+ipp_t *                                        /* O - IPP attributes or @code NULL@ on failure */
+_ippFileParse(
+    _ipp_vars_t      *v,               /* I - Variables */
+    const char       *filename,                /* I - Name of file to parse */
+    _ipp_ftoken_cb_t tokencb,          /* I - Callback for unknown tokens */
+    _ipp_ferror_cb_t errorcb,          /* I - Callback for errors */
+    void             *user_data)       /* I - User data pointer */
+{
+  _ipp_file_t  f;                      /* IPP data file information */
+  ipp_attribute_t *attr = NULL;                /* Current attribute */
+  char         token[1024];            /* Token string */
+  int          status = 1;             /* Return status */
+
+
+  DEBUG_printf(("_ippFileParse(v=%p, filename=\"%s\", tokencb=%p, errorcb=%p, user_data=%p)", (void *)v, filename, (void *)tokencb, (void *)errorcb, user_data));
+
+ /*
+  * Initialize file info...
+  */
+
+  memset(&f, 0, sizeof(f));
+  f.filename = filename;
+  f.linenum  = 1;
+
+  if ((f.fp = cupsFileOpen(filename, "r")) == NULL)
+  {
+    DEBUG_printf(("1_ippFileParse: Unable to open \"%s\": %s", filename, strerror(errno)));
+    return (0);
+  }
+
+ /*
+  * Do the callback with a NULL token to setup any initial state...
+  */
+
+  (*tokencb)(&f, v, user_data, NULL);
+
+ /*
+  * Read data file, using the callback function as needed...
+  */
+
+  while (_ippFileReadToken(&f, token, sizeof(token)))
+  {
+    if (!_cups_strcasecmp(token, "DEFINE") || !_cups_strcasecmp(token, "DEFINE-DEFAULT"))
+    {
+      char     name[128],              /* Variable name */
+               value[1024],            /* Variable value */
+               temp[1024];             /* Temporary string */
+
+      attr = NULL;
+
+      if (_ippFileReadToken(&f, name, sizeof(name)) && _ippFileReadToken(&f, temp, sizeof(temp)))
+      {
+        _ippVarsExpand(v, value, temp, sizeof(value));
+        _ippVarsSet(v, name, value);
+      }
+      else
+      {
+        report_error(&f, errorcb, user_data, "Missing %s name and/or value on line %d of \"%s\".", token, f.linenum, f.filename);
+        status = 0;
+        break;
+      }
+    }
+    else if (f.attrs && !_cups_strcasecmp(token, "ATTR"))
+    {
+     /*
+      * Attribute definition...
+      */
+
+      char     syntax[128],            /* Attribute syntax (value tag) */
+               name[128];              /* Attribute name */
+      ipp_tag_t        value_tag;              /* Value tag */
+
+      attr = NULL;
+
+      if (!_ippFileReadToken(&f, syntax, sizeof(syntax)))
+      {
+        report_error(&f, errorcb, user_data, "Missing ATTR syntax on line %d of \"%s\".", f.linenum, f.filename);
+       status = 0;
+       break;
+      }
+      else if ((value_tag = ippTagValue(syntax)) < IPP_TAG_UNSUPPORTED_VALUE)
+      {
+        report_error(&f, errorcb, user_data, "Bad ATTR syntax \"%s\" on line %d of \"%s\".", syntax, f.linenum, f.filename);
+       status = 0;
+       break;
+      }
+
+      if (!_ippFileReadToken(&f, name, sizeof(name)) || !name[0])
+      {
+        report_error(&f, errorcb, user_data, "Missing ATTR name on line %d of \"%s\".", f.linenum, f.filename);
+       status = 0;
+       break;
+      }
+
+      if (value_tag < IPP_TAG_INTEGER)
+      {
+       /*
+       * Add out-of-band attribute - no value string needed...
+       */
+
+        ippAddOutOfBand(f.attrs, f.group_tag, value_tag, name);
+      }
+      else
+      {
+       /*
+        * Add attribute with one or more values...
+        */
+
+        attr = ippAddString(f.attrs, f.group_tag, value_tag, name, NULL, NULL);
+
+        if (!parse_value(&f, v, errorcb, user_data, f.attrs, &attr, 0))
+        {
+          status = 0;
+          break;
+       }
+      }
+
+    }
+    else if (attr && !_cups_strcasecmp(token, ","))
+    {
+     /*
+      * Additional value...
+      */
+
+      if (!parse_value(&f, v, errorcb, user_data, f.attrs, &attr, ippGetCount(attr)))
+      {
+       status = 0;
+       break;
+      }
+    }
+    else
+    {
+     /*
+      * Something else...
+      */
+
+      attr = NULL;
+
+      if (!(*tokencb)(&f, v, user_data, token))
+        break;
+    }
+  }
+
+ /*
+  * Close the file and free attributes, then return...
+  */
+
+  cupsFileClose(f.fp);
+
+  return (f.attrs);
+}
+
+
+/*
+ * '_ippFileReadToken()' - Read a token from an IPP data file.
+ */
+
+int                                    /* O - 1 on success, 0 on failure */
+_ippFileReadToken(_ipp_file_t *f,      /* I - File to read from */
+                  char        *token,  /* I - Token string buffer */
+                  size_t      tokensize)/* I - Size of token string buffer */
+{
+  int  ch,                             /* Character from file */
+       quote = 0;                      /* Quoting character */
+  char *tokptr = token,                /* Pointer into token buffer */
+       *tokend = token + tokensize - 1;/* End of token buffer */
+
+
+ /*
+  * Skip whitespace and comments...
+  */
+
+  while ((ch = cupsFileGetChar(f->fp)) != EOF)
+  {
+    if (_cups_isspace(ch))
+    {
+     /*
+      * Whitespace...
+      */
+
+      if (ch == '\n')
+        f->linenum ++;
+    }
+    else if (ch == '#')
+    {
+     /*
+      * Comment...
+      */
+
+      while ((ch = cupsFileGetChar(f->fp)) != EOF)
+      {
+        if (ch == '\n')
+          break;
+      }
+
+      if (ch == '\n')
+        f->linenum ++;
+      else
+        break;
+    }
+    else
+      break;
+  }
+
+  if (ch == EOF)
+  {
+    DEBUG_puts("1_ippFileReadToken: EOF");
+    return (0);
+  }
+
+ /*
+  * Read a token...
+  */
+
+  while (ch != EOF)
+  {
+    if (ch == quote)
+    {
+     /*
+      * End of quoted text...
+      */
+
+      *tokptr = '\0';
+      DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token));
+      return (1);
+    }
+    else if (!quote && _cups_isspace(ch))
+    {
+     /*
+      * End of unquoted text...
+      */
+
+      *tokptr = '\0';
+      DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token));
+      return (1);
+    }
+    else if (!quote && (ch == '\'' || ch == '\"'))
+    {
+     /*
+      * Start of quoted text or regular expression...
+      */
+
+      quote = ch;
+    }
+    else if (!quote && ch == '#')
+    {
+     /*
+      * Start of comment...
+      */
+
+      cupsFileSeek(f->fp, cupsFileTell(f->fp) - 1);
+      *tokptr = '\0';
+      DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token));
+      return (1);
+    }
+    else if (!quote && (ch == '{' || ch == '}' || ch == ','))
+    {
+     /*
+      * Delimiter...
+      */
+
+      if (tokptr > token)
+      {
+       /*
+        * Return the preceding token first...
+        */
+
+       cupsFileSeek(f->fp, cupsFileTell(f->fp) - 1);
+      }
+      else
+      {
+       /*
+        * Return this delimiter by itself...
+        */
+
+        *tokptr++ = (char)ch;
+      }
+
+      *tokptr = '\0';
+      DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token));
+      return (1);
+    }
+    else
+    {
+      if (ch == '\\')
+      {
+       /*
+        * Quoted character...
+        */
+
+        if ((ch = cupsFileGetChar(f->fp)) == EOF)
+        {
+         *token = '\0';
+         DEBUG_puts("1_ippFileReadToken: EOF");
+         return (0);
+       }
+      }
+
+      if (tokptr < tokend)
+      {
+       /*
+       * Add to current token...
+       */
+
+       *tokptr++ = (char)ch;
+      }
+      else
+      {
+       /*
+       * Token too long...
+       */
+
+       *tokptr = '\0';
+       DEBUG_printf(("1_ippFileReadToken: Too long: \"%s\".", token));
+       return (0);
+      }
+    }
+
+   /*
+    * Get the next character...
+    */
+
+    ch = cupsFileGetChar(f->fp);
+  }
+
+  *tokptr = '\0';
+  DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token));
+
+  return (tokptr > token);
+}
+
+
+/*
+ * 'parse_collection()' - Parse an IPP collection value.
+ */
+
+static ipp_t *                         /* O - Collection value or @code NULL@ on error */
+parse_collection(
+    _ipp_file_t      *f,               /* I - IPP data file */
+    _ipp_vars_t      *v,               /* I - IPP variables */
+    _ipp_ferror_cb_t errorcb,          /* I - Error callback */
+    void             *user_data)       /* I - User data pointer */
+{
+  ipp_t                *col = ippNew();        /* Collection value */
+  ipp_attribute_t *attr = NULL;                /* Current member attribute */
+  char         token[1024];            /* Token string */
+
+
+ /*
+  * Parse the collection value...
+  */
+
+  while (_ippFileReadToken(f, token, sizeof(token)))
+  {
+    if (!_cups_strcasecmp(token, "}"))
+    {
+     /*
+      * End of collection value...
+      */
+
+      break;
+    }
+    else if (!_cups_strcasecmp(token, "MEMBER"))
+    {
+     /*
+      * Member attribute definition...
+      */
+
+      char     syntax[128],            /* Attribute syntax (value tag) */
+               name[128];              /* Attribute name */
+      ipp_tag_t        value_tag;              /* Value tag */
+
+      attr = NULL;
+
+      if (!_ippFileReadToken(f, syntax, sizeof(syntax)))
+      {
+        report_error(f, errorcb, user_data, "Missing ATTR 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, errorcb, user_data, "Bad ATTR syntax \"%s\" on line %d of \"%s\".", syntax, f->linenum, f->filename);
+       ippDelete(col);
+       col = NULL;
+       break;
+      }
+
+      if (!_ippFileReadToken(f, name, sizeof(name)) || !name[0])
+      {
+        report_error(f, errorcb, user_data, "Missing ATTR name on line %d of \"%s\".", f->linenum, f->filename);
+       ippDelete(col);
+       col = NULL;
+       break;
+      }
+
+      if (value_tag < IPP_TAG_INTEGER)
+      {
+       /*
+       * Add out-of-band attribute - no value string needed...
+       */
+
+        ippAddOutOfBand(col, IPP_TAG_ZERO, value_tag, name);
+      }
+      else
+      {
+       /*
+        * Add attribute with one or more values...
+        */
+
+        attr = ippAddString(col, IPP_TAG_ZERO, value_tag, name, NULL, NULL);
+
+        if (!parse_value(f, v, errorcb, user_data, col, &attr, 0))
+        {
+         ippDelete(col);
+         col = NULL;
+          break;
+       }
+      }
+
+    }
+    else if (attr && !_cups_strcasecmp(token, ","))
+    {
+     /*
+      * Additional value...
+      */
+
+      if (!parse_value(f, v, errorcb, user_data, col, &attr, ippGetCount(attr)))
+      {
+       ippDelete(col);
+       col = NULL;
+       break;
+      }
+    }
+    else
+    {
+     /*
+      * Something else...
+      */
+
+      report_error(f, errorcb, user_data, "Unknown directive \"%s\" on line %d of \"%s\".", token, f->linenum, f->filename);
+      ippDelete(col);
+      col  = NULL;
+      attr = NULL;
+      break;
+
+    }
+  }
+
+  return (col);
+}
+
+
+/*
+ * 'parse_value()' - Parse an IPP value.
+ */
+
+static int                             /* O  - 1 on success or 0 on error */
+parse_value(_ipp_file_t      *f,       /* I  - IPP data file */
+            _ipp_vars_t      *v,       /* I  - IPP variables */
+            _ipp_ferror_cb_t errorcb,  /* I  - Error callback */
+            void             *user_data,/* I  - User data pointer */
+            ipp_t            *ipp,     /* I  - IPP message */
+            ipp_attribute_t  **attr,   /* IO - IPP attribute */
+            int              element)  /* I  - Element number */
+{
+  char value[1024],                    /* Value string */
+       temp[1024];                     /* Temporary string */
+
+
+  if (!_ippFileReadToken(f, temp, sizeof(temp)))
+  {
+    report_error(f, errorcb, user_data, "Missing value on line %d of \"%s\".", f->linenum, f->filename);
+    return (0);
+  }
+
+  _ippVarsExpand(v, value, temp, sizeof(value));
+
+  switch (ippGetValueTag(*attr))
+  {
+    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, strtol(value, NULL, 0)));
+        break;
+
+    case IPP_TAG_RESOLUTION :
+       {
+         int   xres,           /* X resolution */
+               yres;           /* Y resolution */
+         char  *ptr;           /* Pointer into value */
+
+         xres = yres = (int)strtol(value, (char **)&ptr, 10);
+         if (ptr > value && xres > 0)
+         {
+           if (*ptr == 'x')
+             yres = (int)strtol(ptr + 1, (char **)&ptr, 10);
+         }
+
+         if (ptr <= value || xres <= 0 || yres <= 0 || !ptr || (_cups_strcasecmp(ptr, "dpi") && _cups_strcasecmp(ptr, "dpc") && _cups_strcasecmp(ptr, "dpcm") && _cups_strcasecmp(ptr, "other")))
+         {
+           report_error(f, errorcb, user_data, "Bad resolution value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
+           return (0);
+         }
+
+         if (!_cups_strcasecmp(ptr, "dpi"))
+           return (ippSetResolution(ipp, attr, element, IPP_RES_PER_INCH, xres, yres));
+         else if (!_cups_strcasecmp(ptr, "dpc") || !_cups_strcasecmp(ptr, "dpcm"))
+           return (ippSetResolution(ipp, attr, element, IPP_RES_PER_CM, xres, yres));
+         else
+           return (ippSetResolution(ipp, attr, element, (ipp_res_t)0, xres, yres));
+       }
+       break;
+
+    case IPP_TAG_RANGE :
+       {
+         int   lower,                  /* Lower value */
+               upper;                  /* Upper value */
+
+          if (sscanf(value, "%d-%d", &lower, &upper) != 2)
+          {
+           report_error(f, errorcb, user_data, "Bad rangeOfInteger value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
+           return (0);
+         }
+
+         return (ippSetRange(ipp, attr, element, lower, upper));
+       }
+       break;
+
+    case IPP_TAG_STRING :
+        return (ippSetOctetString(ipp, attr, element, value, (int)strlen(value)));
+        break;
+
+    case IPP_TAG_TEXTLANG :
+    case IPP_TAG_NAMELANG :
+    case IPP_TAG_TEXT :
+    case IPP_TAG_NAME :
+    case IPP_TAG_KEYWORD :
+    case IPP_TAG_URI :
+    case IPP_TAG_URISCHEME :
+    case IPP_TAG_CHARSET :
+    case IPP_TAG_LANGUAGE :
+    case IPP_TAG_MIMETYPE :
+        return (ippSetString(ipp, attr, element, value));
+        break;
+
+    case IPP_TAG_BEGIN_COLLECTION :
+        {
+          int  status;                 /* Add status */
+          ipp_t *col;                  /* Collection value */
+
+          if (strcmp(value, "{"))
+          {
+           report_error(f, errorcb, user_data, "Bad ATTR collection value on line %d of \"%s\".", f->linenum, f->filename);
+           return (0);
+          }
+
+          if ((col = parse_collection(f, v, errorcb, user_data)) == NULL)
+            return (0);
+
+         status = ippSetCollection(ipp, attr, element, col);
+         ippDelete(col);
+
+         return (status);
+       }
+       break;
+
+    default :
+        report_error(f, errorcb, user_data, "Unsupported ATTR value on line %d of \"%s\".", f->linenum, f->filename);
+        return (0);
+  }
+
+  return (1);
+}
+
+
+/*
+ * 'report_error()' - Report an error.
+ */
+
+static void
+report_error(
+    _ipp_file_t      *f,               /* I - IPP data file */
+    _ipp_ferror_cb_t errorcb,          /* I - Error callback function, if any */
+    void             *user_data,       /* I - User data pointer */
+    const char       *message,         /* I - Printf-style message */
+    ...)                               /* I - Additional arguments as needed */
+{
+  char         buffer[8192];           /* Formatted string */
+  va_list      ap;                     /* Argument pointer */
+
+
+  va_start(ap, message);
+  vsnprintf(buffer, sizeof(buffer), message, ap);
+  va_end(ap);
+
+  if (errorcb)
+    (*errorcb)(f, user_data, buffer);
+  else
+    fprintf(stderr, "%s\n", buffer);
+}
index 5475652eafb3331cdf1ca1d1d68105e3b13a5fd9..be89fcf0bddbdf5013e1f1be754f8e9f5bd0e354 100644 (file)
@@ -1,10 +1,11 @@
 /*
  * Private IPP definitions for CUPS.
  *
- * Copyright 2007-2014 by Apple Inc.
- * Copyright 1997-2006 by Easy Software Products.
+ * Copyright © 2007-2018 by Apple Inc.
+ * Copyright © 1997-2006 by Easy Software Products.
  *
- * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more
+ * information.
  */
 
 #ifndef _CUPS_IPP_PRIVATE_H_
@@ -14,7 +15,7 @@
  * Include necessary headers...
  */
 
-#  include <cups/ipp.h>
+#  include <cups/cups.h>
 
 
 /*
@@ -49,16 +50,65 @@ typedef struct                              /**** Attribute mapping data ****/
   const ipp_op_t *operations;          /* Allowed operations for this attr */
 } _ipp_option_t;
 
+typedef struct _ipp_file_s _ipp_file_t;/**** File Parser ****/
+typedef struct _ipp_vars_s _ipp_vars_t;/**** Variables ****/
+
+typedef int (*_ipp_ferror_cb_t)(_ipp_file_t *f, void *user_data, const char *error);
+                                       /**** File Parser Error Callback ****/
+typedef int (*_ipp_ftoken_cb_t)(_ipp_file_t *f, _ipp_vars_t *v, void *user_data, const char *token);
+                                       /**** File Parser Token Callback ****/
+
+struct _ipp_vars_s                     /**** Variables ****/
+{
+  char         *uri,                   /* URI for printer */
+               scheme[64],             /* Scheme from URI */
+               username[256],          /* Username from URI */
+               *password,              /* Password from URI (if any) */
+               host[256],              /* Hostname from URI */
+               portstr[32],            /* Port number string */
+               resource[1024];         /* Resource path from URI */
+  int          port;                   /* Port number from URI */
+  http_encryption_t encryption;                /* Encryption for connection? */
+  double       timeout;                /* Timeout for connection */
+  int          family;                 /* Address family */
+  int          num_vars;               /* Number of variables */
+  cups_option_t        *vars;                  /* Array of variables */
+  int          password_tries;         /* Number of retries for password */
+};
+
+struct _ipp_file_s                     /**** File Parser */
+{
+  const char           *filename;      /* Filename */
+  cups_file_t          *fp;            /* File pointer */
+  int                  linenum;        /* Current line number */
+  ipp_t                        *attrs;         /* Attributes */
+  ipp_tag_t            group_tag;      /* Current group for new attributes */
+};
+
 
 /*
  * Prototypes for private functions...
  */
 
+/* encode.c */
 #ifdef DEBUG
 extern const char      *_ippCheckOptions(void);
 #endif /* DEBUG */
 extern _ipp_option_t   *_ippFindOption(const char *name);
 
+/* ipp-file.c */
+extern ipp_t           *_ippFileParse(_ipp_vars_t *v, const char *filename, _ipp_ftoken_cb_t tokencb, _ipp_ferror_cb_t errorcb, void *user_data);
+extern int             _ippFileReadToken(_ipp_file_t *f, char *token, size_t tokensize);
+
+/* ipp-vars.c */
+extern void            _ippVarsDeinit(_ipp_vars_t *v);
+extern void            _ippVarsExpand(_ipp_vars_t *v, char *dst, const char *src, size_t dstsize) __attribute__((nonnull(1,2,3)));
+extern const char      *_ippVarsGet(_ipp_vars_t *v, const char *name);
+extern void            _ippVarsInit(_ipp_vars_t *v);
+extern const char      *_ippVarsPasswordCB(const char *prompt, http_t *http, const char *method, const char *resource, void *user_data);
+extern int             _ippVarsSet(_ipp_vars_t *v, const char *name, const char *value);
+
+
 /*
  * C++ magic...
  */
diff --git a/cups/ipp-vars.c b/cups/ipp-vars.c
new file mode 100644 (file)
index 0000000..d9f4cf0
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * IPP data file parsing functions.
+ *
+ * Copyright © 2007-2018 by Apple Inc.
+ * Copyright © 1997-2007 by Easy Software Products.
+ *
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more
+ * information.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups.h>
+#include "ipp-private.h"
+#include "string-private.h"
+
+
+/*
+ * '_ippVarsDeinit()' - Free all memory associated with the IPP variables.
+ */
+
+void
+_ippVarsDeinit(_ipp_vars_t *v)         /* I - IPP variables */
+{
+  if (v->uri)
+  {
+    free(v->uri);
+    v->uri = NULL;
+  }
+
+  cupsFreeOptions(v->num_vars, v->vars);
+  v->num_vars = 0;
+  v->vars     = NULL;
+}
+
+
+/*
+ * '_ippVarsExpand()' - Expand variables in the source string.
+ */
+
+void
+_ippVarsExpand(_ipp_vars_t *v,         /* I - IPP variables */
+               char        *dst,       /* I - Destination buffer */
+               const char  *src,       /* I - Source string */
+               size_t      dstsize)    /* I - Destination buffer size */
+{
+  char         *dstptr,                /* Pointer into destination */
+               *dstend,                /* End of destination */
+               temp[256],              /* Temporary string */
+               *tempptr;               /* Pointer into temporary string */
+  const char   *value;                 /* Value to substitute */
+
+
+  dstptr = dst;
+  dstend = dst + dstsize - 1;
+
+  while (*src && dstptr < dstend)
+  {
+    if (*src == '$')
+    {
+     /*
+      * Substitute a string/number...
+      */
+
+      if (!strncmp(src, "$$", 2))
+      {
+        value = "$";
+       src   += 2;
+      }
+      else if (!strncmp(src, "$ENV[", 5))
+      {
+       strlcpy(temp, src + 5, sizeof(temp));
+
+       for (tempptr = temp; *tempptr; tempptr ++)
+         if (*tempptr == ']')
+           break;
+
+        if (*tempptr)
+         *tempptr++ = '\0';
+
+       value = getenv(temp);
+        src   += tempptr - temp + 5;
+      }
+      else
+      {
+        if (src[1] == '{')
+       {
+         src += 2;
+         strlcpy(temp, src, sizeof(temp));
+         if ((tempptr = strchr(temp, '}')) != NULL)
+           *tempptr = '\0';
+         else
+           tempptr = temp + strlen(temp);
+       }
+       else
+       {
+         strlcpy(temp, src + 1, sizeof(temp));
+
+         for (tempptr = temp; *tempptr; tempptr ++)
+           if (!isalnum(*tempptr & 255) && *tempptr != '-' && *tempptr != '_')
+             break;
+
+         if (*tempptr)
+           *tempptr = '\0';
+        }
+
+        value = _ippVarsGet(v, temp);
+
+        src += tempptr - temp + 1;
+      }
+
+      if (value)
+      {
+        strlcpy(dstptr, value, (size_t)(dstend - dstptr + 1));
+       dstptr += strlen(dstptr);
+      }
+    }
+    else
+      *dstptr++ = *src++;
+  }
+
+  *dstptr = '\0';
+}
+
+
+/*
+ * '_ippVarsGet()' - Get a variable string.
+ */
+
+const char *                           /* O - Value or @code NULL@ if not set */
+_ippVarsGet(_ipp_vars_t *v,            /* I - IPP variables */
+            const char  *name)         /* I - Variable name */
+{
+  if (!strcmp(name, "uri"))
+    return (v->uri);
+  else if (!strcmp(name, "uriuser") || !strcmp(name, "username"))
+    return (v->username[0] ? v->username : NULL);
+  else if (!strcmp(name, "scheme") || !strcmp(name, "method"))
+    return (v->scheme);
+  else if (!strcmp(name, "hostname"))
+    return (v->host);
+  else if (!strcmp(name, "port"))
+    return (v->portstr);
+  else if (!strcmp(name, "resource"))
+    return (v->resource);
+  else if (!strcmp(name, "user"))
+    return (cupsUser());
+  else
+    return (cupsGetOption(name, v->num_vars, v->vars));
+}
+
+
+/*
+ * '_ippVarsInit()' - Initialize .
+ */
+
+void
+_ippVarsInit(_ipp_vars_t *v)           /* I - IPP variables */
+{
+  memset(v, 0, sizeof(_ipp_vars_t));
+
+  v->family = AF_UNSPEC;
+}
+
+
+/*
+ * '_ippVarsPasswordCB()' - Password callback using the IPP variables.
+ */
+
+const char *                           /* O - Password string or @code NULL@ */
+_ippVarsPasswordCB(
+    const char *prompt,                        /* I - Prompt string (not used) */
+    http_t     *http,                  /* I - HTTP connection (not used) */
+    const char *method,                        /* I - HTTP method (not used) */
+    const char *resource,              /* I - Resource path (not used) */
+    void       *user_data)             /* I - IPP variables */
+{
+  _ipp_vars_t  *v = (_ipp_vars_t *)user_data;
+                                       /* I - IPP variables */
+
+
+  (void)prompt;
+  (void)http;
+  (void)method;
+  (void)resource;
+
+  if (v->username[0] && v->password && v->password_tries < 3)
+  {
+    v->password_tries ++;
+
+    cupsSetUser(v->username);
+
+    return (v->password);
+  }
+  else
+  {
+    return (NULL);
+  }
+}
+
+
+/*
+ * '_ippVarsSet()' - Set an IPP variable.
+ */
+
+int                                    /* O - 1 on success, 0 on failure */
+_ippVarsSet(_ipp_vars_t *v,            /* I - IPP variables */
+            const char  *name,         /* I - Variable name */
+            const char  *value)                /* I - Variable value */
+{
+  if (!strcmp(name, "uri"))
+  {
+    char               uri[1024];      /* New printer URI */
+    http_uri_status_t  uri_status;     /* URI status */
+
+    if ((uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, value, v->scheme, sizeof(v->scheme), v->username, sizeof(v->username), v->host, sizeof(v->host), &(v->port), v->resource, sizeof(v->resource))) < HTTP_URI_STATUS_OK)
+      return (0);
+
+    if (v->username[0])
+    {
+      if ((v->password = strchr(v->username, ':')) != NULL)
+       *(v->password)++ = '\0';
+    }
+
+    snprintf(v->portstr, sizeof(v->portstr), "%d", v->port);
+
+    if (v->uri)
+      free(v->uri);
+
+    httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), v->scheme, NULL, v->host, v->port, v->resource);
+    v->uri = strdup(uri);
+
+    return (v->uri != NULL);
+  }
+  else
+  {
+    v->num_vars = cupsAddOption(name, value, v->num_vars, &v->vars);
+    return (1);
+  }
+}
index 39585f1d83898023fb2f584e1970c9c9336ca7d9..1d198649dae201ab32c775ce3d51d24ca3a9e148 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * IPP test program for CUPS.
  *
- * Copyright 2007-2017 by Apple Inc.
- * Copyright 1997-2005 by Easy Software Products.
+ * Copyright © 2007-2018 by Apple Inc.
+ * Copyright © 1997-2005 by Easy Software Products.
  *
  * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
  */
@@ -223,6 +223,7 @@ static ipp_uchar_t mixed[] =                /* Mixed value buffer */
 void   hex_dump(const char *title, ipp_uchar_t *buffer, size_t bytes);
 void   print_attributes(ipp_t *ipp, int indent);
 ssize_t        read_cb(_ippdata_t *data, ipp_uchar_t *buffer, size_t bytes);
+int    token_cb(_ipp_file_t *f, _ipp_vars_t *v, void *user_data, const char *token);
 ssize_t        write_cb(_ippdata_t *data, ipp_uchar_t *buffer, size_t bytes);
 
 
@@ -706,30 +707,53 @@ main(int  argc,                   /* I - Number of command-line arguments */
 
     for (i = 1; i < (size_t)argc; i ++)
     {
-      if ((fp = cupsFileOpen(argv[i], "r")) == NULL)
+      if (strlen(argv[i]) > 5 && !strcmp(argv[i] + strlen(argv[i]) - 5, ".test"))
       {
-       printf("Unable to open \"%s\" - %s\n", argv[i], strerror(errno));
-       status = 1;
-       continue;
-      }
+       /*
+        * Read an ASCII IPP message...
+        */
 
-      request = ippNew();
-      while ((state = ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL,
-                                request)) == IPP_STATE_ATTRIBUTE);
+        _ipp_vars_t v;                 /* IPP variables */
 
-      if (state != IPP_STATE_DATA)
-      {
-       printf("Error reading IPP message from \"%s\"!\n", argv[i]);
-       status = 1;
+        _ippVarsInit(&v);
+        request = _ippFileParse(&v, argv[i], token_cb, NULL, NULL);
+        _ippVarsDeinit(&v);
       }
       else
+      {
+       /*
+        * Read a raw (binary) IPP message...
+        */
+
+       if ((fp = cupsFileOpen(argv[i], "r")) == NULL)
+       {
+         printf("Unable to open \"%s\" - %s\n", argv[i], strerror(errno));
+         status = 1;
+         continue;
+       }
+
+       request = ippNew();
+       while ((state = ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL,
+                                 request)) == IPP_STATE_ATTRIBUTE);
+
+       if (state != IPP_STATE_DATA)
+       {
+         printf("Error reading IPP message from \"%s\".\n", argv[i]);
+         status = 1;
+
+         ippDelete(request);
+         request = NULL;
+       }
+
+        cupsFileClose(fp);
+      }
+
+      if (request)
       {
        printf("\n%s:\n", argv[i]);
        print_attributes(request, 4);
+       ippDelete(request);
       }
-
-      ippDelete(request);
-      cupsFileClose(fp);
     }
   }
 
@@ -862,6 +886,34 @@ read_cb(_ippdata_t   *data,                /* I - Data */
 }
 
 
+/*
+ * 'token_cb()' - Token callback for ASCII IPP data file parser.
+ */
+
+int                                    /* O - 1 on success, 0 on failure */
+token_cb(_ipp_file_t *f,               /* I - IPP file data */
+         _ipp_vars_t *v,               /* I - IPP variables */
+         void        *user_data,       /* I - User data pointer */
+         const char  *token)           /* I - Token string */
+{
+  (void)v;
+  (void)user_data;
+
+  if (!token)
+  {
+    f->attrs     = ippNew();
+    f->group_tag = IPP_TAG_PRINTER;
+  }
+  else
+  {
+    fprintf(stderr, "Unknown directive \"%s\" on line %d of \"%s\".\n", token, f->linenum, f->filename);
+    return (0);
+  }
+
+  return (1);
+}
+
+
 /*
  * 'write_cb()' - Write data into a buffer.
  */
index 548be4a37a76429dbcf3a00d8b09127f3b4aeced..75302c5d328c750488d9427e04a2bce13c6dc4eb 100644 (file)
                720DD6CD1358FD720064AA82 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
                720DD6D31358FDDE0064AA82 /* snmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 720DD6D21358FDDE0064AA82 /* snmp.c */; };
                720DD6D413590AB90064AA82 /* ieee1284.c in Sources */ = {isa = PBXBuildFile; fileRef = 724379CA1334000E009631B9 /* ieee1284.c */; };
+               720E854320164E7B00C6C411 /* ipp-file.c in Sources */ = {isa = PBXBuildFile; fileRef = 720E854120164E7A00C6C411 /* ipp-file.c */; };
+               720E854420164E7B00C6C411 /* ipp-file.c in Sources */ = {isa = PBXBuildFile; fileRef = 720E854120164E7A00C6C411 /* ipp-file.c */; };
+               720E854520164E7B00C6C411 /* ipp-vars.c in Sources */ = {isa = PBXBuildFile; fileRef = 720E854220164E7A00C6C411 /* ipp-vars.c */; };
+               720E854620164E7B00C6C411 /* ipp-vars.c in Sources */ = {isa = PBXBuildFile; fileRef = 720E854220164E7A00C6C411 /* ipp-vars.c */; };
                72220EB61333052D00FCA411 /* adminutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EB51333052D00FCA411 /* adminutil.c */; };
                72220EC41333056300FCA411 /* adminutil.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EB71333056300FCA411 /* adminutil.h */; settings = {ATTRIBUTES = (Public, ); }; };
                72220EC51333056300FCA411 /* array.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EB81333056300FCA411 /* array.c */; };
                27F89DA21B3AC43B00E5A4B7 /* testraster.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = testraster.c; path = ../cups/testraster.c; sourceTree = "<group>"; };
                720DD6C21358FD5F0064AA82 /* snmp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = snmp; sourceTree = BUILT_PRODUCTS_DIR; };
                720DD6D21358FDDE0064AA82 /* snmp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = snmp.c; path = ../backend/snmp.c; sourceTree = "<group>"; };
+               720E854120164E7A00C6C411 /* ipp-file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "ipp-file.c"; path = "../cups/ipp-file.c"; sourceTree = "<group>"; };
+               720E854220164E7A00C6C411 /* ipp-vars.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "ipp-vars.c"; path = "../cups/ipp-vars.c"; sourceTree = "<group>"; };
                72220EAE1333047D00FCA411 /* libcups.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libcups.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
                72220EB51333052D00FCA411 /* adminutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = adminutil.c; path = ../cups/adminutil.c; sourceTree = "<group>"; };
                72220EB71333056300FCA411 /* adminutil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = adminutil.h; path = ../cups/adminutil.h; sourceTree = "<group>"; };
                        isa = PBXGroup;
                        children = (
                                276683561337A8C5000D33D0 /* cups.strings */,
-                               27D3037D134148CB00F022B1 /* libcups2.def */,
                                72220EB51333052D00FCA411 /* adminutil.c */,
                                72220EB81333056300FCA411 /* array.c */,
                                72220EBB1333056300FCA411 /* auth.c */,
                                72220EBC1333056300FCA411 /* backchannel.c */,
                                72220EBD1333056300FCA411 /* backend.c */,
                                72220ED1133305BB00FCA411 /* debug.c */,
-                               72220ED2133305BB00FCA411 /* dest.c */,
                                72CF95E018A13543000FCAE4 /* dest-job.c */,
                                72CF95E118A13543000FCAE4 /* dest-localization.c */,
                                72CF95E218A13543000FCAE4 /* dest-options.c */,
+                               72220ED2133305BB00FCA411 /* dest.c */,
                                72220ED3133305BB00FCA411 /* dir.c */,
                                72220ED4133305BB00FCA411 /* dir.h */,
                                72220ED6133305BB00FCA411 /* encode.c */,
                                72220EDC133305BB00FCA411 /* getputfile.c */,
                                72220EDD133305BB00FCA411 /* globals.c */,
                                7284F9EF1BFCCD940026F886 /* hash.c */,
-                               72220EE2133305BB00FCA411 /* http.c */,
                                72220EDE133305BB00FCA411 /* http-addr.c */,
                                72220EDF133305BB00FCA411 /* http-addrlist.c */,
                                72220EE1133305BB00FCA411 /* http-support.c */,
-                               72220EE6133305BB00FCA411 /* ipp.c */,
+                               72220EE2133305BB00FCA411 /* http.c */,
+                               720E854120164E7A00C6C411 /* ipp-file.c */,
                                72220EE5133305BB00FCA411 /* ipp-support.c */,
+                               720E854220164E7A00C6C411 /* ipp-vars.c */,
+                               72220EE6133305BB00FCA411 /* ipp.c */,
                                72220EE8133305BB00FCA411 /* langprintf.c */,
                                72220EEA133305BB00FCA411 /* language.c */,
+                               27D3037D134148CB00F022B1 /* libcups2.def */,
                                72220EEF133305BB00FCA411 /* md5.c */,
                                72220EF0133305BB00FCA411 /* md5passwd.c */,
                                72220EF1133305BB00FCA411 /* notify.c */,
                                72220EF2133305BB00FCA411 /* options.c */,
-                               72220EF6133305BB00FCA411 /* ppd.c */,
                                72220EBA1333056300FCA411 /* ppd-attr.c */,
                                72220EF4133305BB00FCA411 /* ppd-cache.c */,
                                72220EBF1333056300FCA411 /* ppd-conflicts.c */,
                                72220EED133305BB00FCA411 /* ppd-mark.c */,
                                72220EF3133305BB00FCA411 /* ppd-page.c */,
                                72A8B3D61C188BDE00A1A547 /* ppd-util.c */,
+                               72220EF6133305BB00FCA411 /* ppd.c */,
                                72220EF8133305BB00FCA411 /* pwg-media.c */,
                                72220EFB133305BB00FCA411 /* request.c */,
                                72220EFC133305BB00FCA411 /* sidechannel.c */,
                                72220F02133305BB00FCA411 /* string.c */,
                                72220F03133305BB00FCA411 /* tempfile.c */,
                                72220F05133305BB00FCA411 /* thread.c */,
-                               727AD5B619100A58009F6862 /* tls.c */,
                                270B267D17F5C06700C8A3A9 /* tls-darwin.c */,
                                270B267E17F5C06700C8A3A9 /* tls-gnutls.c */,
                                270B268117F5C5D600C8A3A9 /* tls-sspi.c */,
+                               727AD5B619100A58009F6862 /* tls.c */,
                                72220F06133305BB00FCA411 /* transcode.c */,
                                72220F08133305BB00FCA411 /* usersys.c */,
                                72220F09133305BB00FCA411 /* util.c */,
                                274FF68D1333B1C400317ECB /* ppd-attr.c in Sources */,
                                274FF68E1333B1C400317ECB /* auth.c in Sources */,
                                274FF68F1333B1C400317ECB /* backchannel.c in Sources */,
+                               720E854620164E7B00C6C411 /* ipp-vars.c in Sources */,
                                274FF6901333B1C400317ECB /* backend.c in Sources */,
                                274FF6911333B1C400317ECB /* ppd-conflicts.c in Sources */,
                                274FF6921333B1C400317ECB /* ppd-custom.c in Sources */,
                                274FF6971333B1C400317ECB /* encode.c in Sources */,
                                274FF6981333B1C400317ECB /* file.c in Sources */,
                                274FF6991333B1C400317ECB /* getdevices.c in Sources */,
+                               720E854420164E7B00C6C411 /* ipp-file.c in Sources */,
                                274FF69A1333B1C400317ECB /* getifaddrs.c in Sources */,
                                274FF69B1333B1C400317ECB /* getputfile.c in Sources */,
                                274FF69C1333B1C400317ECB /* globals.c in Sources */,
                                72220EC71333056300FCA411 /* ppd-attr.c in Sources */,
                                727AD5B719100A58009F6862 /* tls.c in Sources */,
                                72220EC81333056300FCA411 /* auth.c in Sources */,
+                               720E854520164E7B00C6C411 /* ipp-vars.c in Sources */,
                                72220EC91333056300FCA411 /* backchannel.c in Sources */,
                                72220ECA1333056300FCA411 /* backend.c in Sources */,
                                72220ECC1333056300FCA411 /* ppd-conflicts.c in Sources */,
                                72220F0F133305BB00FCA411 /* ppd-emit.c in Sources */,
                                72220F10133305BB00FCA411 /* encode.c in Sources */,
                                72220F12133305BB00FCA411 /* file.c in Sources */,
+                               720E854320164E7B00C6C411 /* ipp-file.c in Sources */,
                                72220F14133305BB00FCA411 /* getdevices.c in Sources */,
                                72220F15133305BB00FCA411 /* getifaddrs.c in Sources */,
                                72220F16133305BB00FCA411 /* getputfile.c in Sources */,