summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael R Sweet <michaelrsweet@gmail.com>2018-01-22 21:23:24 -0500
committerMichael R Sweet <michaelrsweet@gmail.com>2018-01-22 21:23:24 -0500
commitfd96ad89ffb189935d8ab1193590070e80bf64de (patch)
tree630683cfb0c858b29fe076fc3d0ad2bf4675caaf
parentefb40dcacf6a5ee8844b5905e15ec7b309ab7be2 (diff)
Add (ASCII) IPP data file parser to libcups, to be used by ippserver and
ipptool.
-rw-r--r--cups/Makefile2
-rw-r--r--cups/ipp-file.c637
-rw-r--r--cups/ipp-private.h58
-rw-r--r--cups/ipp-vars.c242
-rw-r--r--cups/testipp.c86
-rw-r--r--xcode/CUPS.xcodeproj/project.pbxproj24
6 files changed, 1022 insertions, 27 deletions
diff --git a/cups/Makefile b/cups/Makefile
index 0715dba21..866b413ec 100644
--- a/cups/Makefile
+++ b/cups/Makefile
@@ -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
index 000000000..d5d6295c9
--- /dev/null
+++ b/cups/ipp-file.c
@@ -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);
+}
diff --git a/cups/ipp-private.h b/cups/ipp-private.h
index 5475652ea..be89fcf0b 100644
--- a/cups/ipp-private.h
+++ b/cups/ipp-private.h
@@ -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
index 000000000..d9f4cf0cb
--- /dev/null
+++ b/cups/ipp-vars.c
@@ -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);
+ }
+}
diff --git a/cups/testipp.c b/cups/testipp.c
index 39585f1d8..1d198649d 100644
--- a/cups/testipp.c
+++ b/cups/testipp.c
@@ -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);
}
}
@@ -863,6 +887,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.
*/
diff --git a/xcode/CUPS.xcodeproj/project.pbxproj b/xcode/CUPS.xcodeproj/project.pbxproj
index 548be4a37..75302c5d3 100644
--- a/xcode/CUPS.xcodeproj/project.pbxproj
+++ b/xcode/CUPS.xcodeproj/project.pbxproj
@@ -493,6 +493,10 @@
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 */; };
@@ -3328,6 +3332,8 @@
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>"; };
@@ -4929,17 +4935,16 @@
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 */,
@@ -4949,19 +4954,21 @@
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 */,
@@ -4971,6 +4978,7 @@
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 */,
@@ -4979,10 +4987,10 @@
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 */,
@@ -7830,6 +7838,7 @@
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 */,
@@ -7840,6 +7849,7 @@
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 */,
@@ -7986,6 +7996,7 @@
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 */,
@@ -7996,6 +8007,7 @@
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 */,