diff options
-rw-r--r-- | cups/Makefile | 2 | ||||
-rw-r--r-- | cups/ipp-file.c | 637 | ||||
-rw-r--r-- | cups/ipp-private.h | 58 | ||||
-rw-r--r-- | cups/ipp-vars.c | 242 | ||||
-rw-r--r-- | cups/testipp.c | 86 | ||||
-rw-r--r-- | xcode/CUPS.xcodeproj/project.pbxproj | 24 |
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 */, |