From 81e6635db6281ad3e30ccd9f9c6c511ae03cf800 Mon Sep 17 00:00:00 2001 From: Aakash Lahoti Date: Tue, 12 Jun 2018 18:36:09 +0530 Subject: [PATCH 01/10] Added hexadecimal value reading functionality in parse_value() function --- cups/ipp-file.c | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/cups/ipp-file.c b/cups/ipp-file.c index c1eda08b..91c6939e 100644 --- a/cups/ipp-file.c +++ b/cups/ipp-file.c @@ -85,7 +85,7 @@ _ippFileParse( { _ippVarsExpand(v, value, temp, sizeof(value)); _ippVarsSet(v, name, value); - } + } } else { @@ -623,7 +623,40 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ break; case IPP_TAG_STRING : - return (ippSetOctetString(ipp, attr, element, value, (int)strlen(value))); + { + if(value[0]=='<') /* Input is binary(in form of hex) values*/ + { + memmove(value, value+1, strlen(value)); /* Eliminate the '<' sign */ + char value_concat[50000]; /* Concatenated string with hexadecimal values without whitespace */ + int starting_line_number = f->linenum; + while(value[strlen(value)-1] != '>') + { + strcat(value_concat,value); + if (!_ippFileReadToken(f, value, sizeof(value))) + { + report_error(f, v, user_data, "hexadecimal value not terminated starting line %d of \"%s\".", starting_line_number, f->filename); + return (0); + } + } + value[(strlen(value)-1)]='\0'; /* Eliminate the last '>' sign */ + strcat(value_concat,value); /* Final concatenation for hexadecimal value to be complete*/ + for(int i=0;i= '0' && value_concat[i]<= '9') || (value_concat[i]>='a' && value_concat[i]<='f')) + { + report_error(f, v, user_data, "Bad hexadecimal value \"%s\" on line %d of \"%s\".", value_concat, starting_line_number, f->filename); + return (0); + } + } + return (ippSetOctetString(ipp, attr, element, value_concat, (int)strlen(value_concat))); + } + else + { + return (ippSetOctetString(ipp, attr, element, value, (int)strlen(value))); // If a quoted string like "..", pass it on + } + + } + break; case IPP_TAG_TEXTLANG : From 1321fe333ff42b42122288036328f4b430576fe9 Mon Sep 17 00:00:00 2001 From: Aakash Lahoti Date: Tue, 12 Jun 2018 23:47:11 +0530 Subject: [PATCH 02/10] Functionality for language over ride in textWithLanguage and nameWithLanguage --- cups/ipp-file.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/cups/ipp-file.c b/cups/ipp-file.c index 91c6939e..ca1d1859 100644 --- a/cups/ipp-file.c +++ b/cups/ipp-file.c @@ -652,7 +652,7 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ } else { - return (ippSetOctetString(ipp, attr, element, value, (int)strlen(value))); // If a quoted string like "..", pass it on + return (ippSetOctetString(ipp, attr, element, value, (int)strlen(value))); /* If a quoted string like "..", pass it on */ } } @@ -660,7 +660,33 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ break; case IPP_TAG_TEXTLANG : + { + (*attr)->values[element].string.text = _cupsStrAlloc(value); + if (!_ippFileReadToken(f, value, sizeof(value))) + { + report_error(f, v, user_data, "No Language Data in line %d of \"%s\".", f->linenum, f->filename); + return (0); + } + memmove(value, value+1, strlen(value)); + value[strlen(value)-1]='\0'; /* Purge parenthesis */ + (*attr)->values[element].string.language = _cupsStrAlloc(value); + + } + break; case IPP_TAG_NAMELANG : + { + (*attr)->values[element].string.text = _cupsStrAlloc(value); + if (!_ippFileReadToken(f, value, sizeof(value))) + { + report_error(f, v, user_data, "No Language Data in line %d of \"%s\".", f->linenum, f->filename); + return (0); + } + memmove(value, value+1, strlen(value)); + value[strlen(value)-1]='\0'; /* Purge parenthesis */ + (*attr)->values[element].string.language = _cupsStrAlloc(value); + + } + break; case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_KEYWORD : From 8aaba397c81755f6f3628c261546be4816fcea6d Mon Sep 17 00:00:00 2001 From: Aakash Lahoti Date: Tue, 26 Jun 2018 22:20:37 +0530 Subject: [PATCH 03/10] Changed for(int i=0; ;), to int i; for(i=0; ;) --- cups/ipp-file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cups/ipp-file.c b/cups/ipp-file.c index 9d2df86c..a1b11642 100644 --- a/cups/ipp-file.c +++ b/cups/ipp-file.c @@ -641,7 +641,8 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ } value[(strlen(value)-1)]='\0'; /* Eliminate the last '>' sign */ strcat(value_concat,value); /* Final concatenation for hexadecimal value to be complete*/ - for(int i=0;i= '0' && value_concat[i]<= '9') || (value_concat[i]>='a' && value_concat[i]<='f')) { From 69cec5c38ea68db1672004bfb9f46b32897a3b71 Mon Sep 17 00:00:00 2001 From: Aakash Lahoti Date: Thu, 19 Jul 2018 20:44:23 +0530 Subject: [PATCH 04/10] Merge remote-tracking branch 'upstream/master' --- .cups-upstream | 2 +- .dockerignore | 9 + .gitignore | 1 + .travis.yml | 6 +- DOCKER-COMPOSE.md | 20 + DOCKER.md | 30 +- Dockerfile | 26 + cups/auth.c | 9 +- cups/debug-private.h | 31 +- cups/debug.c | 6 +- cups/encode.c | 34 +- cups/file.h | 40 +- cups/http.h | 184 +- cups/ipp-file.c | 28 +- cups/ipp-private.h | 2 +- cups/language-private.h | 20 +- cups/raster-private.h | 16 +- cups/string-private.h | 10 +- cups/tls-darwin.c | 12 +- cups/versioning.h | 296 +- docker-compose.yml | 39 + ippsample.docker | 18 - scripts/update-cups.sh | 4 +- server/conf.c | 1 + server/ipp.c | 194 +- server/ippserver.h | 14 +- server/job.c | 6 +- server/printer.c | 48 +- server/resource.c | 4 +- snap/snapcraft.yaml | 14 +- tools/ippserver.c | 7370 --------------------------------------- tools/ipptool.c | 14 +- 32 files changed, 733 insertions(+), 7775 deletions(-) create mode 100644 .dockerignore create mode 100644 DOCKER-COMPOSE.md create mode 100644 Dockerfile create mode 100644 docker-compose.yml delete mode 100644 ippsample.docker delete mode 100644 tools/ippserver.c diff --git a/.cups-upstream b/.cups-upstream index 46dcbeb2..0ab72bb9 100644 --- a/.cups-upstream +++ b/.cups-upstream @@ -1 +1 @@ -6b2fb4354a803620ac5d165fbc1511a79ba25406 +a32af27c4c7ef29221d0764a251ff85244c20c64 diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..7c83a597 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +data +.git +config.status +config.log +Makedefs +*.o +config.h +Dockerfile +docker-compose.yml diff --git a/.gitignore b/.gitignore index 0f267d00..f1ec587f 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ cups/testi18n cups/testipp cups/testoptions cups/testraster +data doc/mantohtml examples/pwg-raster-samples* parts diff --git a/.travis.yml b/.travis.yml index 09d25924..5db4ada5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,8 +15,12 @@ matrix: - os: linux before_install: - sudo apt-get -qq update + # Note: Because Travis CI does not yet support Ubuntu Xenial 18.04, we + # cannot do build tests with MuPDF or other dependencies since the + # projects just aren't there... :/ + # - sudo apt-get install -y avahi-daemon avahi-utils cura-engine libavahi-client-dev libfreetype6-dev libgnutls28-dev libharfbuzz-dev libjbig2dec0-dev libjpeg-dev libmupdf-dev libnss-mdns libopenjp2-7-dev libpng-dev zlib1g-dev - sudo apt-get install -y avahi-daemon avahi-utils libavahi-client-dev libgnutls28-dev libjpeg-dev libnss-mdns libpng-dev zlib1g-dev # macOS-specific build stuff - os: osx - osx_image: xcode9.2 + osx_image: xcode9.4 diff --git a/DOCKER-COMPOSE.md b/DOCKER-COMPOSE.md new file mode 100644 index 00000000..1ea2083f --- /dev/null +++ b/DOCKER-COMPOSE.md @@ -0,0 +1,20 @@ +# Docker Compose Support for IPP Sample Code + +This repository includes a sample docker-compose.yml file +to run a IPP server with IPP clients in multiple containers. + +To start the IPP server: + + docker-compose up ippserver + +Run the IPP Everywhere test: + + docker-compose up ipptest + +To list all IPP printers: + + docker-compose up ippfind + +To run the IPP proxy: + + docker-compose up ippproxy diff --git a/DOCKER.md b/DOCKER.md index 3607dbc8..b1c56003 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -1,43 +1,45 @@ # Docker Support for IPP Sample Code -This repository includes a sample Docker configuration file ("ippsample.docker") -for running ippserver in a Docker container. +This repository includes a sample Dockerfile for compiling and running ippserver +in a Docker container. To run IPP sample code on Docker: 1. From a shell prompt in the directory (on Windows 10|2016, OS/X, or Linux) containing this docker file run: - docker build -t --security-opt seccomp=unconfined ubuntu[-ippserver | -ippclient] . - docker run -it -v d:\DockerShare:/data --security-opt seccomp=unconfined ubuntu-[ippclient | ippserver] bash + docker build -t ippsample . -2. From the bash prompt on the newly created container as root, start the services needed for Bonjour +You now can run the container with a bash terminal and go to the /root/ippsample folder manually. - service dbus start - service avahi-daemon start + docker run -it ippsample bash + +You can also run one of the IPP binaries instead of the bash terminal. To start the IPP server: -1. In the ippserver container run: +1. Run the IPP server with all its arguments: - ippserver -M byMyself -l rightHere -m coolPrinter -n myHost -p 631 -s 72 -vvvv myPrintService + docker run -it ippsample ippserver -M byMyself -l rightHere -m coolPrinter -n myHost -p 631 -s 72 -vvvv myPrintService 2. OR to run the server in debug mode using gdb: - gdb ippserver + docker run -it ippsample gdb ippserver run -M byMyself -l rightHere -m coolPrinter -n myHost -p 631 -s 72 -vvvv myPrintService Run the IPP Client: -1. From the bash command prompt on the IPP client container and in the /root/ippsample/examples directory with the IPP Server running, run: +1. First find all IPP printers from other Docker containers: - ippfind + docker run --rm ippsample ippfind (Note the URL returned, e.g., ipp://f8a365cfc7ec.local:631/ipp/print) - ipptool [URL returned] identify-printer-display.test +2. Now run the IPP tool in a new container in the /root/ippsample/examples directory with the IPP Server running, run: + + docker run --rm -it -w /root/ippsample/examples ippsample ipptool [URL returned] identify-printer-display.test (Note the "IDENTIFY from 172.17.0.4: Hello, World!" message in stdout on the ippserver container) 2. To run the IPP everywhere tests on the IPP Client using setup from step #1, run: - ipptool -V 2.0 -tf document-letter.pdf [URL returned] ipp-everywhere.test + docker run --rm -it -w /root/ippsample/examples ippsample ipptool -V 2.0 -tf document-letter.pdf [URL returned] ipp-everywhere.test diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..4ff05f46 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +FROM ubuntu:latest + +RUN apt-get update && apt-get install -y build-essential autoconf avahi-daemon avahi-utils cura-engine libavahi-client-dev libfreetype6-dev libgnutls28-dev libharfbuzz-dev libjbig2dec0-dev libjpeg-dev libmupdf-dev libnss-mdns libopenjp2-7-dev libpng-dev zlib1g-dev net-tools iputils-ping vim avahi-daemon tcpdump man curl +RUN /bin/echo 'colorscheme blue' > ~/.vimrc +RUN /bin/echo "LS_COLORS=\$LS_COLORS:'di=0;31:' ; export LS_COLORS" >> /root/.bashrc +# Make changes necessary to run bonjour +RUN sed -ie 's/rlimit-nproc=3/rlimit-nproc=8/' /etc/avahi/avahi-daemon.conf +RUN update-rc.d dbus defaults +RUN update-rc.d avahi-daemon defaults + +# Create entrypoint.sh script to start dbus and avahi-daemon +RUN echo '#!/bin/bash\n\ +service dbus start\n\ +service avahi-daemon start\n\ +$*\n\ +' > /usr/bin/entrypoint.sh && chmod +x /usr/bin/entrypoint.sh +ENTRYPOINT ["/usr/bin/entrypoint.sh"] + +# Copy source configs to +COPY config* /root/ippsample/ +COPY Make* /root/ippsample/ +RUN cd /root/ippsample; ./configure + +# Copy rest of the sources to use build cache as far as possible +COPY . /root/ippsample/ +RUN cd /root/ippsample; make; make install diff --git a/cups/auth.c b/cups/auth.c index 172f55cf..291a1a55 100644 --- a/cups/auth.c +++ b/cups/auth.c @@ -1115,10 +1115,6 @@ cups_local_auth(http_t *http) /* I - HTTP connection to server */ if (cups_auth_find(www_auth, "Negotiate")) return (1); # endif /* HAVE_GSSAPI */ -# ifdef HAVE_AUTHORIZATION_H - if (cups_auth_find(www_auth, "AuthRef")) - return (1); -# endif /* HAVE_AUTHORIZATION_H */ # if defined(SO_PEERCRED) && defined(AF_LOCAL) /* @@ -1168,7 +1164,7 @@ cups_local_auth(http_t *http) /* I - HTTP connection to server */ * No certificate for this PID; see if we can get the root certificate... */ - DEBUG_printf(("9cups_local_auth: Unable to open file %s: %s", filename, strerror(errno))); + DEBUG_printf(("9cups_local_auth: Unable to open file \"%s\": %s", filename, strerror(errno))); if (!cups_auth_param(schemedata, "trc", trc, sizeof(trc))) { @@ -1180,7 +1176,8 @@ cups_local_auth(http_t *http) /* I - HTTP connection to server */ } snprintf(filename, sizeof(filename), "%s/certs/0", cg->cups_statedir); - fp = fopen(filename, "r"); + if ((fp = fopen(filename, "r")) == NULL) + DEBUG_printf(("9cups_local_auth: Unable to open file \"%s\": %s", filename, strerror(errno))); } if (fp) diff --git a/cups/debug-private.h b/cups/debug-private.h index 461bdadc..eccebcd2 100644 --- a/cups/debug-private.h +++ b/cups/debug-private.h @@ -1,10 +1,11 @@ /* * Private debugging macros for CUPS. * - * Copyright 2007-2012 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. + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ #ifndef _CUPS_DEBUG_PRIVATE_H_ @@ -61,15 +62,6 @@ extern "C" { */ # ifdef DEBUG -# ifdef WIN32 -# ifdef LIBCUPS2_EXPORTS -# define DLLExport __declspec(dllexport) -# else -# define DLLExport -# endif /* LIBCUPS2_EXPORTS */ -# else -# define DLLExport -# endif /* WIN32 */ # define DEBUG_puts(x) _cups_debug_puts(x) # define DEBUG_printf(x) _cups_debug_printf x # define DEBUG_set(logfile,level,filter) _cups_debug_set(logfile,level,filter,1) @@ -85,16 +77,13 @@ extern "C" { * Prototypes... */ -extern int _cups_debug_fd; -extern int _cups_debug_level; -extern void DLLExport _cups_debug_printf(const char *format, ...) - __attribute__ ((__format__ (__printf__, 1, 2))); -extern void DLLExport _cups_debug_puts(const char *s); -extern void DLLExport _cups_debug_set(const char *logfile, - const char *level, const char *filter, - int force); +extern int _cups_debug_fd _CUPS_PRIVATE; +extern int _cups_debug_level _CUPS_PRIVATE; +extern void _cups_debug_printf(const char *format, ...) _CUPS_FORMAT(1,2) _CUPS_PUBLIC; +extern void _cups_debug_puts(const char *s) _CUPS_PUBLIC; +extern void _cups_debug_set(const char *logfile, const char *level, const char *filter, int force) _CUPS_PUBLIC; # ifdef WIN32 -extern int _cups_gettimeofday(struct timeval *tv, void *tz); +extern int _cups_gettimeofday(struct timeval *tv, void *tz) _CUPS_PRIVATE; # define gettimeofday(a,b) _cups_gettimeofday(a, b) # endif /* WIN32 */ diff --git a/cups/debug.c b/cups/debug.c index d2069271..a52fbd10 100644 --- a/cups/debug.c +++ b/cups/debug.c @@ -77,7 +77,7 @@ debug_thread_id(void) * '_cups_debug_printf()' - Write a formatted line to the log. */ -void DLLExport +void _cups_debug_printf(const char *format, /* I - Printf-style format string */ ...) /* I - Additional arguments as needed */ { @@ -162,7 +162,7 @@ _cups_debug_printf(const char *format, /* I - Printf-style format string */ * '_cups_debug_puts()' - Write a single line to the log. */ -void DLLExport +void _cups_debug_puts(const char *s) /* I - String to output */ { struct timeval curtime; /* Current time */ @@ -242,7 +242,7 @@ _cups_debug_puts(const char *s) /* I - String to output */ * '_cups_debug_set()' - Enable or disable debug logging. */ -void DLLExport +void _cups_debug_set(const char *logfile, /* I - Log file or NULL */ const char *level, /* I - Log level or NULL */ const char *filter, /* I - Filter string or NULL */ diff --git a/cups/encode.c b/cups/encode.c index e08bc9a6..04058b56 100644 --- a/cups/encode.c +++ b/cups/encode.c @@ -129,6 +129,9 @@ static const _ipp_option_t ipp_options[] = cups_schemes }, { 1, "finishings", IPP_TAG_ENUM, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, + { 1, "finishings-col", IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB, + IPP_TAG_DOCUMENT }, + { 1, "finishings-col-default", IPP_TAG_BEGIN_COLLECTION, IPP_TAG_PRINTER }, { 1, "finishings-default", IPP_TAG_ENUM, IPP_TAG_PRINTER }, { 0, "fit-to-page", IPP_TAG_BOOLEAN, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, @@ -142,6 +145,7 @@ static const _ipp_option_t ipp_options[] = { 1, "include-schemes", IPP_TAG_NAME, IPP_TAG_OPERATION, IPP_TAG_ZERO, cups_schemes }, + { 0, "ipp-attribute-fidelity", IPP_TAG_BOOLEAN, IPP_TAG_OPERATION }, { 0, "job-account-id", IPP_TAG_NAME, IPP_TAG_JOB }, { 0, "job-account-id-default",IPP_TAG_NAME, IPP_TAG_PRINTER }, { 0, "job-accounting-user-id", IPP_TAG_NAME, IPP_TAG_JOB }, @@ -150,6 +154,7 @@ static const _ipp_option_t ipp_options[] = { 0, "job-cancel-after", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "job-cancel-after-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "job-hold-until", IPP_TAG_KEYWORD, IPP_TAG_JOB }, + { 0, "job-hold-until-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, { 0, "job-id", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ { 0, "job-impressions", IPP_TAG_INTEGER, IPP_TAG_OPERATION }, { 0, "job-impressions-completed", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ @@ -158,6 +163,8 @@ static const _ipp_option_t ipp_options[] = { 0, "job-k-octets-completed",IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ { 0, "job-media-sheets", IPP_TAG_INTEGER, IPP_TAG_OPERATION }, { 0, "job-media-sheets-completed", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ + { 0, "job-name", IPP_TAG_NAME, IPP_TAG_OPERATION, + IPP_TAG_JOB }, { 0, "job-page-limit", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "job-pages", IPP_TAG_INTEGER, IPP_TAG_OPERATION }, { 0, "job-pages-completed", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ @@ -168,6 +175,7 @@ static const _ipp_option_t ipp_options[] = IPP_TAG_ZERO, ipp_job_creation }, { 0, "job-priority", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { 0, "job-priority-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "job-quota-period", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 1, "job-sheets", IPP_TAG_NAME, IPP_TAG_JOB }, { 1, "job-sheets-default", IPP_TAG_NAME, IPP_TAG_PRINTER }, @@ -212,6 +220,9 @@ static const _ipp_option_t ipp_options[] = IPP_TAG_DOCUMENT }, { 0, "mirror", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, { 0, "mirror-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, + { 0, "multiple-document-handling", IPP_TAG_KEYWORD, IPP_TAG_JOB, + IPP_TAG_DOCUMENT }, + { 0, "multiple-document-handling-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, { 0, "natural-scaling", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "natural-scaling-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "notify-charset", IPP_TAG_CHARSET, IPP_TAG_SUBSCRIPTION }, @@ -227,18 +238,26 @@ static const _ipp_option_t ipp_options[] = { 0, "number-up", IPP_TAG_INTEGER, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "number-up-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, + { 0, "number-up-layout", IPP_TAG_KEYWORD, IPP_TAG_JOB, + IPP_TAG_DOCUMENT }, + { 0, "number-up-layout-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, { 0, "orientation-requested", IPP_TAG_ENUM, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "orientation-requested-default", IPP_TAG_ENUM, IPP_TAG_PRINTER }, + { 0, "output-bin", IPP_TAG_KEYWORD, IPP_TAG_JOB, + IPP_TAG_DOCUMENT }, + { 0, "output-bin-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, { 1, "overrides", IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "page-bottom", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "page-bottom-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, + { 0, "page-delivery", IPP_TAG_KEYWORD, IPP_TAG_JOB, + IPP_TAG_DOCUMENT }, + { 0, "page-delivery-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, { 0, "page-left", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "page-left-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 1, "page-ranges", IPP_TAG_RANGE, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, - { 1, "page-ranges-default", IPP_TAG_RANGE, IPP_TAG_PRINTER }, { 0, "page-right", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "page-right-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "page-top", IPP_TAG_INTEGER, IPP_TAG_JOB }, @@ -279,9 +298,21 @@ static const _ipp_option_t ipp_options[] = { 0, "ppi-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "prettyprint", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, { 0, "prettyprint-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, + { 0, "print-color-mode", IPP_TAG_KEYWORD, IPP_TAG_JOB, + IPP_TAG_DOCUMENT }, + { 0, "print-color-mode-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, + { 0, "print-content-optimize", IPP_TAG_KEYWORD, IPP_TAG_JOB, + IPP_TAG_DOCUMENT }, + { 0, "print-content-optimize-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, { 0, "print-quality", IPP_TAG_ENUM, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "print-quality-default", IPP_TAG_ENUM, IPP_TAG_PRINTER }, + { 0, "print-rendering-intent", IPP_TAG_KEYWORD, IPP_TAG_JOB, + IPP_TAG_DOCUMENT }, + { 0, "print-rendering-intent-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, + { 0, "print-scaling", IPP_TAG_KEYWORD, IPP_TAG_JOB, + IPP_TAG_DOCUMENT }, + { 0, "print-scaling-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, { 1, "printer-alert", IPP_TAG_STRING, IPP_TAG_PRINTER }, { 1, "printer-alert-description", IPP_TAG_TEXT, IPP_TAG_PRINTER }, { 1, "printer-commands", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, @@ -303,6 +334,7 @@ static const _ipp_option_t ipp_options[] = { 1, "printer-output-tray", IPP_TAG_STRING, IPP_TAG_PRINTER }, { 0, "printer-resolution", IPP_TAG_RESOLUTION, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, + { 0, "printer-resolution-default", IPP_TAG_RESOLUTION, IPP_TAG_PRINTER }, { 0, "printer-state", IPP_TAG_ENUM, IPP_TAG_PRINTER }, { 0, "printer-state-change-time", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 1, "printer-state-reasons", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, diff --git a/cups/file.h b/cups/file.h index ed4bed70..43137b1f 100644 --- a/cups/file.h +++ b/cups/file.h @@ -6,10 +6,11 @@ * our own file functions allows us to provide transparent support of * different line endings, gzip'd print files, PPD files, etc. * - * Copyright 2007-2017 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * Copyright © 2007-2018 by Apple Inc. + * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * - * 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_FILE_H_ @@ -61,34 +62,22 @@ typedef struct _cups_file_s cups_file_t;/**** CUPS file type ****/ extern int cupsFileClose(cups_file_t *fp) _CUPS_API_1_2; extern int cupsFileCompression(cups_file_t *fp) _CUPS_API_1_2; extern int cupsFileEOF(cups_file_t *fp) _CUPS_API_1_2; -extern const char *cupsFileFind(const char *filename, const char *path, - int executable, char *buffer, - int bufsize) _CUPS_API_1_2; +extern const char *cupsFileFind(const char *filename, const char *path, int executable, char *buffer, int bufsize) _CUPS_API_1_2; extern int cupsFileFlush(cups_file_t *fp) _CUPS_API_1_2; extern int cupsFileGetChar(cups_file_t *fp) _CUPS_API_1_2; -extern char *cupsFileGetConf(cups_file_t *fp, char *buf, - size_t buflen, char **value, - int *linenum) _CUPS_API_1_2; -extern size_t cupsFileGetLine(cups_file_t *fp, char *buf, - size_t buflen) _CUPS_API_1_2; -extern char *cupsFileGets(cups_file_t *fp, char *buf, size_t buflen) - _CUPS_API_1_2; +extern char *cupsFileGetConf(cups_file_t *fp, char *buf, size_t buflen, char **value, int *linenum) _CUPS_API_1_2; +extern size_t cupsFileGetLine(cups_file_t *fp, char *buf, size_t buflen) _CUPS_API_1_2; +extern char *cupsFileGets(cups_file_t *fp, char *buf, size_t buflen) _CUPS_API_1_2; extern int cupsFileLock(cups_file_t *fp, int block) _CUPS_API_1_2; extern int cupsFileNumber(cups_file_t *fp) _CUPS_API_1_2; -extern cups_file_t *cupsFileOpen(const char *filename, const char *mode) - _CUPS_API_1_2; +extern cups_file_t *cupsFileOpen(const char *filename, const char *mode) _CUPS_API_1_2; extern cups_file_t *cupsFileOpenFd(int fd, const char *mode) _CUPS_API_1_2; extern int cupsFilePeekChar(cups_file_t *fp) _CUPS_API_1_2; -extern int cupsFilePrintf(cups_file_t *fp, const char *format, ...) - __attribute__((__format__ (__printf__, 2, 3))) - _CUPS_API_1_2; +extern int cupsFilePrintf(cups_file_t *fp, const char *format, ...) _CUPS_FORMAT(2, 3) _CUPS_API_1_2; extern int cupsFilePutChar(cups_file_t *fp, int c) _CUPS_API_1_2; -extern ssize_t cupsFilePutConf(cups_file_t *fp, const char *directive, - const char *value) _CUPS_API_1_4; -extern int cupsFilePuts(cups_file_t *fp, const char *s) - _CUPS_API_1_2; -extern ssize_t cupsFileRead(cups_file_t *fp, char *buf, size_t bytes) - _CUPS_API_1_2; +extern ssize_t cupsFilePutConf(cups_file_t *fp, const char *directive, const char *value) _CUPS_API_1_4; +extern int cupsFilePuts(cups_file_t *fp, const char *s) _CUPS_API_1_2; +extern ssize_t cupsFileRead(cups_file_t *fp, char *buf, size_t bytes) _CUPS_API_1_2; extern off_t cupsFileRewind(cups_file_t *fp) _CUPS_API_1_2; extern off_t cupsFileSeek(cups_file_t *fp, off_t pos) _CUPS_API_1_2; extern cups_file_t *cupsFileStderr(void) _CUPS_API_1_2; @@ -96,8 +85,7 @@ extern cups_file_t *cupsFileStdin(void) _CUPS_API_1_2; extern cups_file_t *cupsFileStdout(void) _CUPS_API_1_2; extern off_t cupsFileTell(cups_file_t *fp) _CUPS_API_1_2; extern int cupsFileUnlock(cups_file_t *fp) _CUPS_API_1_2; -extern ssize_t cupsFileWrite(cups_file_t *fp, const char *buf, - size_t bytes) _CUPS_API_1_2; +extern ssize_t cupsFileWrite(cups_file_t *fp, const char *buf, size_t bytes) _CUPS_API_1_2; # ifdef __cplusplus diff --git a/cups/http.h b/cups/http.h index 0cb26eb3..50083cb0 100644 --- a/cups/http.h +++ b/cups/http.h @@ -1,10 +1,11 @@ /* * Hyper-Text Transport Protocol definitions for CUPS. * - * Copyright 2007-2017 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * Copyright © 2007-2018 by Apple Inc. + * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * - * 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_HTTP_H_ @@ -448,53 +449,43 @@ typedef int (*http_timeout_cb_t)(http_t *http, void *user_data); * Prototypes... */ -extern void httpBlocking(http_t *http, int b); -extern int httpCheck(http_t *http); -extern void httpClearFields(http_t *http); -extern void httpClose(http_t *http); -extern http_t *httpConnect(const char *host, int port) - _CUPS_DEPRECATED_1_7_MSG("Use httpConnect2 instead."); -extern http_t *httpConnectEncrypt(const char *host, int port, - http_encryption_t encryption) - _CUPS_DEPRECATED_1_7_MSG("Use httpConnect2 instead."); -extern int httpDelete(http_t *http, const char *uri); -extern int httpEncryption(http_t *http, http_encryption_t e); -extern int httpError(http_t *http); -extern void httpFlush(http_t *http); -extern int httpGet(http_t *http, const char *uri); -extern char *httpGets(char *line, int length, http_t *http); -extern const char *httpGetDateString(time_t t); -extern time_t httpGetDateTime(const char *s); -extern const char *httpGetField(http_t *http, http_field_t field); -extern struct hostent *httpGetHostByName(const char *name); -extern char *httpGetSubField(http_t *http, http_field_t field, - const char *name, char *value); -extern int httpHead(http_t *http, const char *uri); -extern void httpInitialize(void); -extern int httpOptions(http_t *http, const char *uri); -extern int httpPost(http_t *http, const char *uri); -extern int httpPrintf(http_t *http, const char *format, ...) - __attribute__ ((__format__ (__printf__, 2, 3))); -extern int httpPut(http_t *http, const char *uri); +extern void httpBlocking(http_t *http, int b) _CUPS_PUBLIC; +extern int httpCheck(http_t *http) _CUPS_PUBLIC; +extern void httpClearFields(http_t *http) _CUPS_PUBLIC; +extern void httpClose(http_t *http) _CUPS_PUBLIC; +extern http_t *httpConnect(const char *host, int port) _CUPS_DEPRECATED_1_7_MSG("Use httpConnect2 instead."); +extern http_t *httpConnectEncrypt(const char *host, int port, http_encryption_t encryption) _CUPS_DEPRECATED_1_7_MSG("Use httpConnect2 instead."); +extern int httpDelete(http_t *http, const char *uri) _CUPS_PUBLIC; +extern int httpEncryption(http_t *http, http_encryption_t e) _CUPS_PUBLIC; +extern int httpError(http_t *http) _CUPS_PUBLIC; +extern void httpFlush(http_t *http) _CUPS_PUBLIC; +extern int httpGet(http_t *http, const char *uri) _CUPS_PUBLIC; +extern char *httpGets(char *line, int length, http_t *http) _CUPS_PUBLIC; +extern const char *httpGetDateString(time_t t) _CUPS_PUBLIC; +extern time_t httpGetDateTime(const char *s) _CUPS_PUBLIC; +extern const char *httpGetField(http_t *http, http_field_t field) _CUPS_PUBLIC; +extern struct hostent *httpGetHostByName(const char *name) _CUPS_PUBLIC; +extern char *httpGetSubField(http_t *http, http_field_t field, const char *name, char *value) _CUPS_PUBLIC; +extern int httpHead(http_t *http, const char *uri) _CUPS_PUBLIC; +extern void httpInitialize(void) _CUPS_PUBLIC; +extern int httpOptions(http_t *http, const char *uri) _CUPS_PUBLIC; +extern int httpPost(http_t *http, const char *uri) _CUPS_PUBLIC; +extern int httpPrintf(http_t *http, const char *format, ...) _CUPS_FORMAT(2, 3) _CUPS_PUBLIC; +extern int httpPut(http_t *http, const char *uri) _CUPS_PUBLIC; extern int httpRead(http_t *http, char *buffer, int length) _CUPS_DEPRECATED_MSG("Use httpRead2 instead."); extern int httpReconnect(http_t *http) _CUPS_DEPRECATED_1_6_MSG("Use httpReconnect2 instead."); -extern void httpSeparate(const char *uri, char *method, - char *username, char *host, int *port, - char *resource) _CUPS_DEPRECATED_MSG("Use httpSeparateURI instead."); -extern void httpSetField(http_t *http, http_field_t field, - const char *value); -extern const char *httpStatus(http_status_t status); -extern int httpTrace(http_t *http, const char *uri); -extern http_status_t httpUpdate(http_t *http); +extern void httpSeparate(const char *uri, char *method, char *username, char *host, int *port, char *resource) _CUPS_DEPRECATED_1_2_MSG("Use httpSeparateURI instead."); +extern void httpSetField(http_t *http, http_field_t field, const char *value) _CUPS_PUBLIC; +extern const char *httpStatus(http_status_t status) _CUPS_PUBLIC; +extern int httpTrace(http_t *http, const char *uri) _CUPS_PUBLIC; +extern http_status_t httpUpdate(http_t *http) _CUPS_PUBLIC; extern int httpWrite(http_t *http, const char *buffer, int length) _CUPS_DEPRECATED_MSG("Use httpWrite2 instead."); extern char *httpEncode64(char *out, const char *in) _CUPS_DEPRECATED_MSG("Use httpEncode64_2 instead."); extern char *httpDecode64(char *out, const char *in) _CUPS_DEPRECATED_MSG("Use httpDecode64_2 instead."); -extern int httpGetLength(http_t *http) _CUPS_DEPRECATED_MSG("Use httpGetLength2 instead."); -extern char *httpMD5(const char *, const char *, const char *, - char [33]) _CUPS_DEPRECATED_MSG("Use cupsDoAuth or cupsHashData instead."); -extern char *httpMD5Final(const char *, const char *, const char *, - char [33]) _CUPS_DEPRECATED_MSG("Use cupsDoAuth or cupsHashData instead."); -extern char *httpMD5String(const unsigned char *, char [33]) _CUPS_DEPRECATED_MSG("Use cupsHashString instead."); +extern int httpGetLength(http_t *http) _CUPS_DEPRECATED_1_2_MSG("Use httpGetLength2 instead."); +extern char *httpMD5(const char *, const char *, const char *, char [33]) _CUPS_DEPRECATED_MSG("Use cupsDoAuth or cupsHashData instead."); +extern char *httpMD5Final(const char *, const char *, const char *, char [33]) _CUPS_DEPRECATED_2_2_MSG("Use cupsDoAuth or cupsHashData instead."); +extern char *httpMD5String(const unsigned char *, char [33]) _CUPS_DEPRECATED_2_2_MSG("Use cupsHashString instead."); /**** New in CUPS 1.1.19 ****/ extern void httpClearCookie(http_t *http) _CUPS_API_1_1_19; @@ -504,40 +495,21 @@ extern int httpWait(http_t *http, int msec) _CUPS_API_1_1_19; /**** New in CUPS 1.1.21 ****/ extern char *httpDecode64_2(char *out, int *outlen, const char *in) _CUPS_API_1_1_21; -extern char *httpEncode64_2(char *out, int outlen, const char *in, - int inlen) _CUPS_API_1_1_21; -extern void httpSeparate2(const char *uri, - char *method, int methodlen, - char *username, int usernamelen, - char *host, int hostlen, int *port, - char *resource, int resourcelen) _CUPS_DEPRECATED_MSG("Use httpSeparateURI instead."); +extern char *httpEncode64_2(char *out, int outlen, const char *in, int inlen) _CUPS_API_1_1_21; +extern void httpSeparate2(const char *uri, char *method, int methodlen, char *username, int usernamelen, char *host, int hostlen, int *port, char *resource, int resourcelen) _CUPS_DEPRECATED_1_2_MSG("Use httpSeparateURI instead."); /**** New in CUPS 1.2/macOS 10.5 ****/ extern int httpAddrAny(const http_addr_t *addr) _CUPS_API_1_2; extern http_addrlist_t *httpAddrConnect(http_addrlist_t *addrlist, int *sock) _CUPS_API_1_2; -extern int httpAddrEqual(const http_addr_t *addr1, - const http_addr_t *addr2) _CUPS_API_1_2; +extern int httpAddrEqual(const http_addr_t *addr1, const http_addr_t *addr2) _CUPS_API_1_2; extern void httpAddrFreeList(http_addrlist_t *addrlist) _CUPS_API_1_2; -extern http_addrlist_t *httpAddrGetList(const char *hostname, int family, - const char *service) _CUPS_API_1_2; +extern http_addrlist_t *httpAddrGetList(const char *hostname, int family, const char *service) _CUPS_API_1_2; extern int httpAddrLength(const http_addr_t *addr) _CUPS_API_1_2; extern int httpAddrLocalhost(const http_addr_t *addr) _CUPS_API_1_2; -extern char *httpAddrLookup(const http_addr_t *addr, - char *name, int namelen) _CUPS_API_1_2; -extern char *httpAddrString(const http_addr_t *addr, - char *s, int slen) _CUPS_API_1_2; -extern http_uri_status_t httpAssembleURI(http_uri_coding_t encoding, - char *uri, int urilen, - const char *scheme, - const char *username, - const char *host, int port, - const char *resource) _CUPS_API_1_2; -extern http_uri_status_t httpAssembleURIf(http_uri_coding_t encoding, - char *uri, int urilen, - const char *scheme, - const char *username, - const char *host, int port, - const char *resourcef, ...) _CUPS_API_1_2; +extern char *httpAddrLookup(const http_addr_t *addr, char *name, int namelen) _CUPS_API_1_2; +extern char *httpAddrString(const http_addr_t *addr, char *s, int slen) _CUPS_API_1_2; +extern http_uri_status_t httpAssembleURI(http_uri_coding_t encoding, char *uri, int urilen, const char *scheme, const char *username, const char *host, int port, const char *resource) _CUPS_API_1_2; +extern http_uri_status_t httpAssembleURIf(http_uri_coding_t encoding, char *uri, int urilen, const char *scheme, const char *username, const char *host, int port, const char *resourcef, ...) _CUPS_FORMAT(8, 9) _CUPS_API_1_2; extern int httpFlushWrite(http_t *http) _CUPS_API_1_2; extern int httpGetBlocking(http_t *http) _CUPS_API_1_2; extern const char *httpGetDateString2(time_t t, char *s, int slen) _CUPS_API_1_2; @@ -545,76 +517,44 @@ extern int httpGetFd(http_t *http) _CUPS_API_1_2; extern const char *httpGetHostname(http_t *http, char *s, int slen) _CUPS_API_1_2; extern off_t httpGetLength2(http_t *http) _CUPS_API_1_2; extern http_status_t httpGetStatus(http_t *http) _CUPS_API_1_2; -extern char *httpGetSubField2(http_t *http, http_field_t field, - const char *name, char *value, - int valuelen) _CUPS_API_1_2; +extern char *httpGetSubField2(http_t *http, http_field_t field, const char *name, char *value, int valuelen) _CUPS_API_1_2; extern ssize_t httpRead2(http_t *http, char *buffer, size_t length) _CUPS_API_1_2; -extern http_uri_status_t httpSeparateURI(http_uri_coding_t decoding, - const char *uri, - char *scheme, int schemelen, - char *username, int usernamelen, - char *host, int hostlen, int *port, - char *resource, int resourcelen) _CUPS_API_1_2; +extern http_uri_status_t httpSeparateURI(http_uri_coding_t decoding, const char *uri, char *scheme, int schemelen, char *username, int usernamelen, char *host, int hostlen, int *port, char *resource, int resourcelen) _CUPS_API_1_2; extern void httpSetExpect(http_t *http, http_status_t expect) _CUPS_API_1_2; extern void httpSetLength(http_t *http, size_t length) _CUPS_API_1_2; -extern ssize_t httpWrite2(http_t *http, const char *buffer, - size_t length) _CUPS_API_1_2; +extern ssize_t httpWrite2(http_t *http, const char *buffer, size_t length) _CUPS_API_1_2; /**** New in CUPS 1.3/macOS 10.5 ****/ extern char *httpGetAuthString(http_t *http) _CUPS_API_1_3; -extern void httpSetAuthString(http_t *http, const char *scheme, - const char *data) _CUPS_API_1_3; +extern void httpSetAuthString(http_t *http, const char *scheme, const char *data) _CUPS_API_1_3; /**** New in CUPS 1.5/macOS 10.7 ****/ -extern int httpAddCredential(cups_array_t *credentials, - const void *data, size_t datalen) - _CUPS_API_1_5; -extern int httpCopyCredentials(http_t *http, - cups_array_t **credentials) - _CUPS_API_1_5; +extern int httpAddCredential(cups_array_t *credentials, const void *data, size_t datalen) _CUPS_API_1_5; +extern int httpCopyCredentials(http_t *http, cups_array_t **credentials) _CUPS_API_1_5; extern void httpFreeCredentials(cups_array_t *certs) _CUPS_API_1_5; -extern int httpSetCredentials(http_t *http, cups_array_t *certs) - _CUPS_API_1_5; -extern void httpSetTimeout(http_t *http, double timeout, - http_timeout_cb_t cb, void *user_data) - _CUPS_API_1_5; +extern int httpSetCredentials(http_t *http, cups_array_t *certs) _CUPS_API_1_5; +extern void httpSetTimeout(http_t *http, double timeout, http_timeout_cb_t cb, void *user_data) _CUPS_API_1_5; /**** New in CUPS 1.6/macOS 10.8 ****/ -extern http_addrlist_t *httpAddrConnect2(http_addrlist_t *addrlist, int *sock, - int msec, int *cancel) - _CUPS_API_1_6; +extern http_addrlist_t *httpAddrConnect2(http_addrlist_t *addrlist, int *sock, int msec, int *cancel) _CUPS_API_1_6; extern http_state_t httpGetState(http_t *http) _CUPS_API_1_6; extern http_version_t httpGetVersion(http_t *http) _CUPS_API_1_6; -extern int httpReconnect2(http_t *http, int msec, int *cancel) - _CUPS_API_1_6; +extern int httpReconnect2(http_t *http, int msec, int *cancel) _CUPS_API_1_6; /**** New in CUPS 1.7/macOS 10.9 ****/ -extern http_t *httpAcceptConnection(int fd, int blocking) - _CUPS_API_1_7; +extern http_t *httpAcceptConnection(int fd, int blocking) _CUPS_API_1_7; extern http_addrlist_t *httpAddrCopyList(http_addrlist_t *src) _CUPS_API_1_7; -extern int httpAddrListen(http_addr_t *addr, int port) - _CUPS_API_1_7; +extern int httpAddrListen(http_addr_t *addr, int port) _CUPS_API_1_7; extern int httpAddrPort(http_addr_t *addr) _CUPS_API_1_7; -extern char *httpAssembleUUID(const char *server, int port, - const char *name, int number, - char *buffer, size_t bufsize) - _CUPS_API_1_7; -extern http_t *httpConnect2(const char *host, int port, - http_addrlist_t *addrlist, - int family, http_encryption_t encryption, - int blocking, int msec, int *cancel) - _CUPS_API_1_7; +extern char *httpAssembleUUID(const char *server, int port, const char *name, int number, char *buffer, size_t bufsize) _CUPS_API_1_7; +extern http_t *httpConnect2(const char *host, int port, http_addrlist_t *addrlist, int family, http_encryption_t encryption, int blocking, int msec, int *cancel) _CUPS_API_1_7; extern const char *httpGetContentEncoding(http_t *http) _CUPS_API_1_7; extern http_status_t httpGetExpect(http_t *http) _CUPS_API_1_7; -extern ssize_t httpPeek(http_t *http, char *buffer, size_t length) - _CUPS_API_1_7; -extern http_state_t httpReadRequest(http_t *http, char *resource, - size_t resourcelen) _CUPS_API_1_7; -extern void httpSetDefaultField(http_t *http, http_field_t field, - const char *value) _CUPS_API_1_7; -extern http_state_t httpWriteResponse(http_t *http, - http_status_t status) _CUPS_API_1_7; +extern ssize_t httpPeek(http_t *http, char *buffer, size_t length) _CUPS_API_1_7; +extern http_state_t httpReadRequest(http_t *http, char *resource, size_t resourcelen) _CUPS_API_1_7; +extern void httpSetDefaultField(http_t *http, http_field_t field, const char *value) _CUPS_API_1_7; +extern http_state_t httpWriteResponse(http_t *http, http_status_t status) _CUPS_API_1_7; /* New in CUPS 2.0/macOS 10.10 */ extern int httpAddrClose(http_addr_t *addr, int fd) _CUPS_API_2_0; diff --git a/cups/ipp-file.c b/cups/ipp-file.c index a1b11642..bf763260 100644 --- a/cups/ipp-file.c +++ b/cups/ipp-file.c @@ -217,6 +217,8 @@ _ippFileReadToken(_ipp_file_t *f, /* I - File to read from */ * Skip whitespace and comments... */ + DEBUG_printf(("1_ippFileReadToken: linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp))); + while ((ch = cupsFileGetChar(f->fp)) != EOF) { if (_cups_isspace(ch)) @@ -226,7 +228,10 @@ _ippFileReadToken(_ipp_file_t *f, /* I - File to read from */ */ if (ch == '\n') + { f->linenum ++; + DEBUG_printf(("1_ippFileReadToken: LF in leading whitespace, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp))); + } } else if (ch == '#') { @@ -234,6 +239,8 @@ _ippFileReadToken(_ipp_file_t *f, /* I - File to read from */ * Comment... */ + DEBUG_puts("1_ippFileReadToken: Skipping comment in leading whitespace..."); + while ((ch = cupsFileGetChar(f->fp)) != EOF) { if (ch == '\n') @@ -241,7 +248,10 @@ _ippFileReadToken(_ipp_file_t *f, /* I - File to read from */ } if (ch == '\n') + { f->linenum ++; + DEBUG_printf(("1_ippFileReadToken: LF at end of comment, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp))); + } else break; } @@ -262,7 +272,10 @@ _ippFileReadToken(_ipp_file_t *f, /* I - File to read from */ while (ch != EOF) { if (ch == '\n') + { f->linenum ++; + DEBUG_printf(("1_ippFileReadToken: LF in token, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp))); + } if (ch == quote) { @@ -271,7 +284,7 @@ _ippFileReadToken(_ipp_file_t *f, /* I - File to read from */ */ *tokptr = '\0'; - DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token)); + DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" at closing quote.", token)); return (1); } else if (!quote && _cups_isspace(ch)) @@ -281,7 +294,7 @@ _ippFileReadToken(_ipp_file_t *f, /* I - File to read from */ */ *tokptr = '\0'; - DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token)); + DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" before whitespace.", token)); return (1); } else if (!quote && (ch == '\'' || ch == '\"')) @@ -291,6 +304,8 @@ _ippFileReadToken(_ipp_file_t *f, /* I - File to read from */ */ quote = ch; + + DEBUG_printf(("1_ippFileReadToken: Start of quoted string, quote=%c, pos=%ld", quote, (long)cupsFileTell(f->fp))); } else if (!quote && ch == '#') { @@ -300,7 +315,7 @@ _ippFileReadToken(_ipp_file_t *f, /* I - File to read from */ cupsFileSeek(f->fp, cupsFileTell(f->fp) - 1); *tokptr = '\0'; - DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token)); + DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" before comment.", token)); return (1); } else if (!quote && (ch == '{' || ch == '}' || ch == ',')) @@ -338,6 +353,8 @@ _ippFileReadToken(_ipp_file_t *f, /* I - File to read from */ * Quoted character... */ + DEBUG_printf(("1_ippFileReadToken: Quoted character at pos=%ld", (long)cupsFileTell(f->fp))); + if ((ch = cupsFileGetChar(f->fp)) == EOF) { *token = '\0'; @@ -345,7 +362,10 @@ _ippFileReadToken(_ipp_file_t *f, /* I - File to read from */ return (0); } else if (ch == '\n') + { f->linenum ++; + DEBUG_printf(("1_ippFileReadToken: quoted LF, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp))); + } } if (tokptr < tokend) @@ -376,7 +396,7 @@ _ippFileReadToken(_ipp_file_t *f, /* I - File to read from */ } *tokptr = '\0'; - DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token)); + DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" at EOF.", token)); return (tokptr > token); } diff --git a/cups/ipp-private.h b/cups/ipp-private.h index 66ed11b6..280d4962 100644 --- a/cups/ipp-private.h +++ b/cups/ipp-private.h @@ -202,7 +202,7 @@ 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 void _ippVarsExpand(_ipp_vars_t *v, char *dst, const char *src, size_t dstsize) _CUPS_NONNULL(1,2,3); extern const char *_ippVarsGet(_ipp_vars_t *v, const char *name); extern void _ippVarsInit(_ipp_vars_t *v, _ipp_fattr_cb_t attrcb, _ipp_ferror_cb_t errorcb, _ipp_ftoken_cb_t tokencb); extern const char *_ippVarsPasswordCB(const char *prompt, http_t *http, const char *method, const char *resource, void *user_data); diff --git a/cups/language-private.h b/cups/language-private.h index fb42a6b9..5828ceb2 100644 --- a/cups/language-private.h +++ b/cups/language-private.h @@ -1,10 +1,11 @@ /* * Private localization support for CUPS. * - * Copyright 2007-2017 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_LANGUAGE_PRIVATE_H_ @@ -62,16 +63,11 @@ extern const char *_cupsAppleLocale(CFStringRef languageName, char *locale, size # endif /* __APPLE__ */ extern void _cupsCharmapFlush(void); extern const char *_cupsEncodingName(cups_encoding_t encoding); -extern void _cupsLangPrintError(const char *prefix, - const char *message); -extern int _cupsLangPrintFilter(FILE *fp, const char *prefix, - const char *message, ...) - __attribute__ ((__format__ (__printf__, 3, 4))); -extern int _cupsLangPrintf(FILE *fp, const char *message, ...) - __attribute__ ((__format__ (__printf__, 2, 3))); +extern void _cupsLangPrintError(const char *prefix, const char *message); +extern int _cupsLangPrintFilter(FILE *fp, const char *prefix, const char *message, ...) _CUPS_FORMAT(3, 4); +extern int _cupsLangPrintf(FILE *fp, const char *message, ...) _CUPS_FORMAT(2, 3); extern int _cupsLangPuts(FILE *fp, const char *message); -extern const char *_cupsLangString(cups_lang_t *lang, - const char *message); +extern const char *_cupsLangString(cups_lang_t *lang, const char *message); extern void _cupsMessageFree(cups_array_t *a); extern cups_array_t *_cupsMessageLoad(const char *filename, int flags); extern const char *_cupsMessageLookup(cups_array_t *a, const char *m); diff --git a/cups/raster-private.h b/cups/raster-private.h index 19cf295e..a776714e 100644 --- a/cups/raster-private.h +++ b/cups/raster-private.h @@ -1,10 +1,11 @@ /* * Private image library definitions for CUPS. * - * Copyright 2007-2015 by Apple Inc. - * Copyright 1993-2006 by Easy Software Products. + * Copyright © 2007-2018 by Apple Inc. + * Copyright © 1993-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_RASTER_PRIVATE_H_ @@ -43,12 +44,9 @@ * Prototypes... */ -extern int _cupsRasterExecPS(cups_page_header2_t *h, - int *preferred_bits, - const char *code) - __attribute__((nonnull(3))); -extern void _cupsRasterAddError(const char *f, ...) - __attribute__((__format__(__printf__, 1, 2))); +extern int _cupsRasterExecPS(cups_page_header2_t *h, int *preferred_bits, + const char *code) _CUPS_NONNULL(3); +extern void _cupsRasterAddError(const char *f, ...) _CUPS_FORMAT(1,2); extern void _cupsRasterClearError(void); #endif /* !_CUPS_RASTER_PRIVATE_H_ */ diff --git a/cups/string-private.h b/cups/string-private.h index 3e58cac5..0b0f5fce 100644 --- a/cups/string-private.h +++ b/cups/string-private.h @@ -1,10 +1,11 @@ /* * Private string definitions for CUPS. * - * Copyright 2007-2015 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_STRING_PRIVATE_H_ @@ -169,8 +170,7 @@ extern size_t _cups_strlcpy(char *, const char *, size_t); # endif /* !HAVE_STRLCPY */ # ifndef HAVE_SNPRINTF -extern int _cups_snprintf(char *, size_t, const char *, ...) - __attribute__ ((__format__ (__printf__, 3, 4))); +extern int _cups_snprintf(char *, size_t, const char *, ...) _CUPS_FORMAT(3, 4); # define snprintf _cups_snprintf # endif /* !HAVE_SNPRINTF */ diff --git a/cups/tls-darwin.c b/cups/tls-darwin.c index 3e3a95da..e8c44808 100644 --- a/cups/tls-darwin.c +++ b/cups/tls-darwin.c @@ -1283,14 +1283,16 @@ _httpTLSStart(http_t *http) /* I - HTTP connection */ kTLSProtocol1, kTLSProtocol11, kTLSProtocol12, - kTLSProtocol12, /* TODO: update to 1.3 when 1.3 is supported */ - kTLSProtocol12 /* TODO: update to 1.3 when 1.3 is supported */ + kTLSProtocol13 }; - error = SSLSetProtocolVersionMin(http->tls, protocols[tls_min_version]); - DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMin(%d), error=%d", protocols[tls_min_version], (int)error)); + if (tls_min_version < _HTTP_TLS_MAX) + { + error = SSLSetProtocolVersionMin(http->tls, protocols[tls_min_version]); + DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMin(%d), error=%d", protocols[tls_min_version], (int)error)); + } - if (!error) + if (!error && tls_max_version < _HTTP_TLS_MAX) { error = SSLSetProtocolVersionMax(http->tls, protocols[tls_max_version]); DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMax(%d), error=%d", protocols[tls_max_version], (int)error)); diff --git a/cups/versioning.h b/cups/versioning.h index 1b86813b..19cd186a 100644 --- a/cups/versioning.h +++ b/cups/versioning.h @@ -11,87 +11,39 @@ # define _CUPS_VERSIONING_H_ /* - * This header defines several constants - _CUPS_DEPRECATED, - * _CUPS_DEPRECATED_MSG, _CUPS_INTERNAL_MSG, _CUPS_API_major_minor, and - * _CUPS_API_major_minor_patch - which add compiler-specific attributes that - * flag functions that are deprecated, added in particular releases, or internal - * to CUPS. + * This header defines several macros that add compiler-specific attributes for + * functions: * - * On macOS, the _CUPS_API_* constants are defined based on the values of - * the MAC_OS_X_VERSION_MIN_ALLOWED and MAC_OS_X_VERSION_MAX_ALLOWED constants - * provided by the compiler. + * - _CUPS_API_major_minor[_patch]: Specifies when an API became available by + * CUPS version. + * - _CUPS_DEPRECATED: Function is deprecated with no replacement. + * - _CUPS_DEPRECATED_MSG("message"): Function is deprecated and has a + * replacement. + * - _CUPS_FORMAT(format-index, additional-args-index): Function has a + * printf-style format argument followed by zero or more additional + * arguments. Indices start at 1. + * - _CUPS_INTERNAL_MSG("msg"): Function is + * - _CUPS_NONNULL((arg list)): Specifies the comma-separated argument indices + * are assumed non-NULL. Indices start at 1. + * - _CUPS_NORETURN: Specifies the function does not return. + * - _CUPS_PRIVATE: Specifies the function is private to CUPS. + * - _CUPS_PUBLIC: Specifies the function is public API. */ -# if defined(__APPLE__) && !defined(_CUPS_SOURCE) && !TARGET_OS_IOS -# include -# ifndef AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER -# define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER __attribute__((unavailable)) -# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER */ -# ifndef AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER -# define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER __attribute__((unavailable)) -# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER */ -# ifndef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER -# define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER __attribute__((unavailable)) -# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER */ -# ifndef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER -# define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER __attribute__((unavailable)) -# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER */ -# ifndef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER -# define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER __attribute__((unavailable)) -# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER */ -# ifndef AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER -# define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER __attribute__((unavailable)) -# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER */ -# ifndef AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER -# define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER __attribute__((unavailable)) -# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER */ -# ifndef AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER -# define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER __attribute__((unavailable)) -# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER */ -# ifndef AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER -# define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER __attribute__((unavailable)) -# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER */ -# ifndef AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER -# define AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER __attribute__((unavailable)) -# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER */ -# define _CUPS_API_1_1_19 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER -# define _CUPS_API_1_1_20 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER -# define _CUPS_API_1_1_21 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER -# define _CUPS_API_1_2 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER -# define _CUPS_API_1_3 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER -# define _CUPS_API_1_4 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER -# define _CUPS_API_1_5 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER -# define _CUPS_API_1_6 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER -# define _CUPS_API_1_7 AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER -# define _CUPS_API_2_0 AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER -# define _CUPS_API_2_2 AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER -# define _CUPS_API_2_2_4 AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER -# define _CUPS_API_2_2_7 -# define _CUPS_API_2_3 -# else -# define _CUPS_API_1_1_19 -# define _CUPS_API_1_1_20 -# define _CUPS_API_1_1_21 -# define _CUPS_API_1_2 -# define _CUPS_API_1_3 -# define _CUPS_API_1_4 -# define _CUPS_API_1_5 -# define _CUPS_API_1_6 -# define _CUPS_API_1_7 -# define _CUPS_API_2_0 -# define _CUPS_API_2_2 -# define _CUPS_API_2_2_4 -# define _CUPS_API_2_2_7 -# define _CUPS_API_2_3 -# endif /* __APPLE__ && !_CUPS_SOURCE */ - /* - * With GCC and Clang we can mark old APIs as "deprecated" or "unavailable" with - * messages so you get warnings/errors are compile-time... + * Determine which compiler is being used and what annotation features are + * available... */ +# ifdef __APPLE__ +# include +# endif /* __APPLE__ */ + # ifdef __has_extension /* Clang */ # define _CUPS_HAS_DEPRECATED +# define _CUPS_HAS_FORMAT +# define _CUPS_HAS_NORETURN +# define _CUPS_HAS_VISIBILITY # if __has_extension(attribute_deprecated_with_message) # define _CUPS_HAS_DEPRECATED_WITH_MESSAGE # endif @@ -101,6 +53,9 @@ # elif defined(__GNUC__) /* GCC and compatible */ # if __GNUC__ >= 3 /* GCC 3.0 or higher */ # define _CUPS_HAS_DEPRECATED +# define _CUPS_HAS_FORMAT +# define _CUPS_HAS_NORETURN +# define _CUPS_HAS_VISIBILITY # endif /* __GNUC__ >= 3 */ # if __GNUC__ >= 5 /* GCC 5.x */ # define _CUPS_HAS_DEPRECATED_WITH_MESSAGE @@ -110,59 +65,184 @@ # endif /* __GNUC__ >= 5 */ # endif /* __has_extension */ + +/* + * Define _CUPS_PRIVATE and _CUPS_PUBLIC visibilty macros for private/public + * functions... + */ + +# ifdef _CUPS_HAS_VISIBILITY +# define _CUPS_PRIVATE __attribute__ ((visibility("hidden"))) +# define _CUPS_PUBLIC __attribute__ ((visibility("default"))) +# elif defined(WIN32) && defined(LIBCUPS2_EXPORTS) +# define _CUPS_PRIVATE +# define _CUPS_PUBLIC __declspec(dllexport) +# else +# define _CUPS_PRIVATE +# define _CUPS_PUBLIC +# endif /* _CUPS_HAS_VISIBILITY */ + + +/* + * Define _CUPS_API_major_minor[_patch] availability macros for CUPS. + * + * Note: Using any of the _CUPS_API macros automatically adds _CUPS_PUBLIC. + */ + +# if defined(__APPLE__) && !defined(_CUPS_SOURCE) && !TARGET_OS_IOS +/* + * On Apple operating systems, the _CUPS_API_* constants are defined using the + * API_ macros in . + * + * On iOS, we don't actually have libcups available directly, but the supplied + * libcups_static target in the Xcode project supports building on iOS 11.0 and + * later. + */ +# define _CUPS_API_1_1_19 API_AVAILABLE(macos(10.3), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_1_1_20 API_AVAILABLE(macos(10.4), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_1_1_21 API_AVAILABLE(macos(10.4), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_1_2 API_AVAILABLE(macos(10.5), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_1_3 API_AVAILABLE(macos(10.5), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_1_4 API_AVAILABLE(macos(10.6), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_1_5 API_AVAILABLE(macos(10.7), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_1_6 API_AVAILABLE(macos(10.8), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_1_7 API_AVAILABLE(macos(10.9), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_2_0 API_AVAILABLE(macos(10.10), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_2_2 API_AVAILABLE(macos(10.12), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_2_2_4 API_AVAILABLE(macos(10.13), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_2_2_7 API_AVAILABLE(macos(10.14), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_2_3 _CUPS_PUBLIC +# else +# define _CUPS_API_1_1_19 _CUPS_PUBLIC +# define _CUPS_API_1_1_20 _CUPS_PUBLIC +# define _CUPS_API_1_1_21 _CUPS_PUBLIC +# define _CUPS_API_1_2 _CUPS_PUBLIC +# define _CUPS_API_1_3 _CUPS_PUBLIC +# define _CUPS_API_1_4 _CUPS_PUBLIC +# define _CUPS_API_1_5 _CUPS_PUBLIC +# define _CUPS_API_1_6 _CUPS_PUBLIC +# define _CUPS_API_1_7 _CUPS_PUBLIC +# define _CUPS_API_2_0 _CUPS_PUBLIC +# define _CUPS_API_2_2 _CUPS_PUBLIC +# define _CUPS_API_2_2_4 _CUPS_PUBLIC +# define _CUPS_API_2_2_7 _CUPS_PUBLIC +# define _CUPS_API_2_3 _CUPS_PUBLIC +# endif /* __APPLE__ && !_CUPS_SOURCE */ + + +/* + * Define _CUPS_DEPRECATED and _CUPS_INTERNAL macros to mark old APIs as + * "deprecated" or "unavailable" with messages so you get warnings/errors are + * compile-time... + * + * Note: Using any of the _CUPS_DEPRECATED macros automatically adds + * _CUPS_PUBLIC. + */ + # if !defined(_CUPS_HAS_DEPRECATED) || (defined(_CUPS_SOURCE) && !defined(_CUPS_NO_DEPRECATED)) /* * Don't mark functions deprecated if the compiler doesn't support it * or we are building CUPS source that doesn't care. */ -# define _CUPS_DEPRECATED -# define _CUPS_DEPRECATED_MSG(m) -# define _CUPS_DEPRECATED_1_6_MSG(m) -# define _CUPS_DEPRECATED_1_7_MSG(m) -# define _CUPS_INTERNAL_MSG(m) +# define _CUPS_DEPRECATED _CUPS_PUBLIC +# define _CUPS_DEPRECATED_MSG(m) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_2_MSG(m) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_6_MSG(m) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_7_MSG(m) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_2_2_MSG(m) _CUPS_PUBLIC +# elif defined(__APPLE__) + /* + * Compiler supports the unavailable attribute, so use it when the code + * wants to exclude the use of deprecated API. + */ +# define _CUPS_DEPRECATED __attribute__ ((unavailable)) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((unavailable(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_2_MSG(m) API_DEPRECATED(m, macos(10.2,10.5)) API_UNAVAILABLE(ios) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_6_MSG(m) API_DEPRECATED(m, macos(10.2,10.8)) API_UNAVAILABLE(ios) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_7_MSG(m) API_DEPRECATED(m, macos(10.2,10.9)) API_UNAVAILABLE(ios) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_2_2_MSG(m) API_DEPRECATED(m, macos(10.2,10.12)) API_UNAVAILABLE(ios) _CUPS_PUBLIC # elif defined(_CUPS_HAS_UNAVAILABLE_WITH_MESSAGE) && defined(_CUPS_NO_DEPRECATED) /* * Compiler supports the unavailable attribute, so use it when the code * wants to exclude the use of deprecated API. */ -# define _CUPS_DEPRECATED __attribute__ ((unavailable)) -# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((unavailable(m))) -# define _CUPS_DEPRECATED_1_6_MSG(m) __attribute__ ((unavailable(m))) -# define _CUPS_DEPRECATED_1_7_MSG(m) __attribute__ ((unavailable(m))) -# define _CUPS_INTERNAL_MSG(m) __attribute__ ((unavailable(m))) +# define _CUPS_DEPRECATED __attribute__ ((unavailable)) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((unavailable(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_2_MSG(m) __attribute__ ((unavailable(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_6_MSG(m) __attribute__ ((unavailable(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_7_MSG(m) __attribute__ ((unavailable(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_2_2_MSG(m) __attribute__ ((unavailable(m))) _CUPS_PUBLIC # else /* * Compiler supports the deprecated attribute, so use it. */ -# define _CUPS_DEPRECATED __attribute__ ((deprecated)) +# define _CUPS_DEPRECATED __attribute__ ((deprecated)) _CUPS_PUBLIC # ifdef _CUPS_HAS_DEPRECATED_WITH_MESSAGE -# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((deprecated(m))) +# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((deprecated(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_2_MSG(m) __attribute__ ((deprecated(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_6_MSG(m) __attribute__ ((deprecated(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_7_MSG(m) __attribute__ ((deprecated(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_2_2_MSG(m) __attribute__ ((deprecated(m))) _CUPS_PUBLIC # else -# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((deprecated)) +# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((deprecated)) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_2_MSG(m) __attribute__ ((deprecated)) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_6_MSG(m) __attribute__ ((deprecated)) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_7_MSG(m) __attribute__ ((deprecated)) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_2_2_MSG(m) __attribute__ ((deprecated)) _CUPS_PUBLIC # endif /* _CUPS_HAS_DEPRECATED_WITH_MESSAGE */ -# if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8 -# define _CUPS_DEPRECATED_1_6_MSG(m) _CUPS_DEPRECATED_MSG(m) -# else -# define _CUPS_DEPRECATED_1_6_MSG(m) -# endif /* MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_8 */ -# if defined(MAC_OS_X_VERSION_10_9) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9 -# define _CUPS_DEPRECATED_1_7_MSG(m) _CUPS_DEPRECATED_MSG(m) -# else -# define _CUPS_DEPRECATED_1_7_MSG(m) -# endif /* MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_9 */ -# ifdef _CUPS_SOURCE -# define _CUPS_INTERNAL_MSG(m) -# elif defined(_CUPS_HAS_UNAVAILABLE_WITH_MESSAGE) -# define _CUPS_INTERNAL_MSG(m) __attribute__ ((unavailable(m))) -# elif defined(_CUPS_HAS_DEPRECATED_WITH_MESSAGE) -# define _CUPS_INTERNAL_MSG(m) __attribute__ ((deprecated(m))) -# else -# define _CUPS_INTERNAL_MSG(m) __attribute__ ((deprecated)) -# endif /* _CUPS_SOURCE */ # endif /* !_CUPS_HAS_DEPRECATED || (_CUPS_SOURCE && !_CUPS_NO_DEPRECATED) */ -# ifndef __GNUC__ -# define __attribute__(x) -# endif /* !__GNUC__ */ + +/* + * Define _CUPS_FORMAT macro for printf-style functions... + */ + +# ifdef _CUPS_HAS_FORMAT +# define _CUPS_FORMAT(a,b) __attribute__ ((__format__(__printf__, a,b))) +# else +# define _CUPS_FORMAT(a,b) +# endif /* _CUPS_HAS_FORMAT */ + + +/* + * Define _CUPS_INTERNAL_MSG macro for private APIs that have (historical) + * public visibility. + * + * Note: Using the _CUPS_INTERNAL_MSG macro automatically adds _CUPS_PUBLIC. + */ + +# ifdef _CUPS_SOURCE +# define _CUPS_INTERNAL_MSG(m) _CUPS_PUBLIC +# elif defined(_CUPS_HAS_UNAVAILABLE_WITH_MESSAGE) +# define _CUPS_INTERNAL_MSG(m) __attribute__ ((unavailable(m))) _CUPS_PUBLIC +# elif defined(_CUPS_HAS_DEPRECATED_WITH_MESSAGE) +# define _CUPS_INTERNAL_MSG(m) __attribute__ ((deprecated(m))) _CUPS_PUBLIC +# else +# define _CUPS_INTERNAL_MSG(m) __attribute__ ((deprecated)) _CUPS_PUBLIC +# endif /* _CUPS_SOURCE */ + + +/* + * Define _CUPS_NONNULL macro for functions that don't expect non-null + * arguments... + */ + +# ifdef _CUPS_HAS_NONNULL +# define _CUPS_NONNULL(...) __attribute__ ((nonnull(__VA_ARGS__))) +# else +# define _CUPS_NONNULL(...) +# endif /* _CUPS_HAS_FORMAT */ + + +/* + * Define _CUPS_NORETURN macro for functions that don't return. + */ + +# ifdef _CUPS_HAS_NORETURN +# define _CUPS_NORETURN __attribute__ ((noreturn)) +# else +# define _CUPS_NORETURN +# endif /* _CUPS_HAS_NORETURN */ + #endif /* !_CUPS_VERSIONING_H_ */ diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..9de6feb3 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,39 @@ +version: '2.1' +services: + ippserver: + hostname: ippserver + build: + context: . + dockerfile: Dockerfile + volumes: + - './test:/config' + - './data/print:/print' + - './data/spool:/spool' + command: ippserver -C /config -r _print + + ippfind: + build: + context: . + dockerfile: Dockerfile + command: ippfind + depends_on: + - "ippserver" + + ipptest: + build: + context: . + dockerfile: Dockerfile + volumes: + - './examples:/examples' + working_dir: /examples + command: ipptool -V 2.0 -tf document-letter.pdf ipp://ippserver.local:8991/ipp/print/foo ipp-everywhere.test + depends_on: + - "ippserver" + + ippproxy: + build: + context: . + dockerfile: Dockerfile + command: ippproxy -d ipp://ippserver.local:8991/ipp/print/foo ipp://ippserver.local:8991/ipp/print/bar + depends_on: + - "ippserver" diff --git a/ippsample.docker b/ippsample.docker deleted file mode 100644 index 7692fec9..00000000 --- a/ippsample.docker +++ /dev/null @@ -1,18 +0,0 @@ - # Dockerfile used to build docker image for the ipp sample code from github - # From the directory cotaining this docker file run: docker build -t --security-opt seccomp=unconfined ubuntu[-ippserver | -ippclient] . - FROM ubuntu:latest - MAINTAINER Craig Whittle - RUN apt-get -y update && apt-get install -y net-tools iputils-ping vim gcc git make libavahi-client-dev avahi-daemon gdb tcpdump - RUN /bin/echo 'colorscheme blue' > ~/.vimrc - RUN /bin/echo "LS_COLORS=\$LS_COLORS:'di=0;31:' ; export LS_COLORS" >> /root/.bashrc - RUN /usr/bin/git clone https://github.com/istopwg/ippsample /root/ippsample - RUN cd /root/ippsample; ./configure; make; make install - - # Make changes necessary to run bonjour - RUN sed -ie 's/rlimit-nproc=3/rlimit-nproc=8/' /etc/avahi/avahi-daemon.conf - RUN update-rc.d dbus defaults - RUN update-rc.d avahi-daemon defaults - # RUN service dbus start; service avahi-daemon start - # Once running start the services needed for Bonjour - # a. service dbus start - # b. service avahi-daemon start diff --git a/scripts/update-cups.sh b/scripts/update-cups.sh index dddfdf62..ecae0597 100755 --- a/scripts/update-cups.sh +++ b/scripts/update-cups.sh @@ -16,5 +16,5 @@ fi oldrev=`cat .cups-upstream` newrev=`cd ../cups; git show | head -1 | awk '{print $2}'` -(cd ../cups; git diff $oldrev cups ':!cups/Dependencies' ':!cups/Makefile' ':!cups/libcups2.def' ':!cups/ppd*' ':!cups/test*') >$newrev.patch -git apply $newrev.patch && (echo $newrev >.cups-upstream; git commit -a -m "Sync up libcups changes from CUPS master@$newrev"; rm -f $newrev.patch) +(cd ../cups; git diff $oldrev cups ':!cups/Dependencies' ':!cups/Makefile' ':!cups/libcups2.def' ':!cups/ppd*' ':!cups/test*' ':!cups/tlscheck.c') >$newrev.patch +git apply $newrev.patch && (echo $newrev >.cups-upstream; git commit -a -m "Sync up libcups changes from CUPS master@$newrev"; rm -f $newrev.patch) || echo "$newrev.patch did not apply." diff --git a/server/conf.c b/server/conf.c index 2580f379..40780c75 100644 --- a/server/conf.c +++ b/server/conf.c @@ -934,6 +934,7 @@ attr_cb(_ipp_file_t *f, /* I - IPP file */ "device-uuid", "document-format-varying-attributes", "job-settable-attributes-supported", + "operations-supported", "printer-alert", "printer-alert-description", "printer-camera-image-uri", diff --git a/server/ipp.c b/server/ipp.c index 52614702..012d6129 100644 --- a/server/ipp.c +++ b/server/ipp.c @@ -47,6 +47,7 @@ static const char *get_document_uri(server_client_t *client); static void ipp_acknowledge_document(server_client_t *client); static void ipp_acknowledge_identify_printer(server_client_t *client); static void ipp_acknowledge_job(server_client_t *client); +static void ipp_cancel_current_job(server_client_t *client); static void ipp_cancel_job(server_client_t *client); static void ipp_cancel_jobs(server_client_t *client); static void ipp_cancel_subscription(server_client_t *client); @@ -76,11 +77,13 @@ static void ipp_get_subscriptions(server_client_t *client); static void ipp_get_system_attributes(server_client_t *client); static void ipp_get_system_supported_values(server_client_t *client); static void ipp_hold_job(server_client_t *client); +static void ipp_hold_new_jobs(server_client_t *client); static void ipp_identify_printer(server_client_t *client); static void ipp_pause_all_printers(server_client_t *client); static void ipp_pause_printer(server_client_t *client); static void ipp_print_job(server_client_t *client); static void ipp_print_uri(server_client_t *client); +static void ipp_release_held_new_jobs(server_client_t *client); static void ipp_release_job(server_client_t *client); static void ipp_renew_subscription(server_client_t *client); static void ipp_restart_printer(server_client_t *client); @@ -1195,6 +1198,70 @@ ipp_acknowledge_job( } +/* + * 'ipp_cancel_current_job()' - Cancel the current job. + */ + +static void +ipp_cancel_current_job( + server_client_t *client) /* I - Client */ +{ + server_job_t *job; /* Job information */ + + + if (Authentication && !client->username[0]) + { + /* + * Require authenticated username... + */ + + serverRespondHTTP(client, HTTP_STATUS_UNAUTHORIZED, NULL, NULL, 0); + return; + } + + /* + * Get the current job, if any... + */ + + _cupsRWLockWrite(&(client->printer->rwlock)); + + if ((job = client->printer->processing_job) == NULL) + { + _cupsRWUnlock(&client->printer->rwlock); + serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "No job being processed."); + return; + } + + if (Authentication && !serverAuthorizeUser(client, job->username, SERVER_GROUP_NONE, JobPrivacyScope)) + { + _cupsRWUnlock(&client->printer->rwlock); + serverRespondIPP(client, IPP_STATUS_ERROR_NOT_AUTHORIZED, "Not authorized to access this job."); + return; + } + + if (job->state == IPP_JSTATE_PROCESSING || (job->state == IPP_JSTATE_HELD && job->fd >= 0)) + { + job->cancel = 1; + + if (job->state == IPP_JSTATE_PROCESSING) + serverStopJob(job); + } + else + { + job->state = IPP_JSTATE_CANCELED; + job->completed = time(NULL); + } + + _cupsRWUnlock(&(client->printer->rwlock)); + + serverAddEventNoLock(client->printer, job, NULL, SERVER_EVENT_JOB_COMPLETED, NULL); + + serverRespondIPP(client, IPP_STATUS_OK, NULL); +} + + + + /* * 'ipp_cancel_job()' - Cancel a job. */ @@ -1643,7 +1710,7 @@ ipp_create_job(server_client_t *client) /* I - Client */ if ((hold_until = ippFindAttribute(client->request, "job-hold-until", IPP_TAG_KEYWORD)) == NULL) hold_until = ippFindAttribute(client->request, "job-hold-until-time", IPP_TAG_DATE); - if (hold_until) + if (hold_until || (job->printer->state_reasons & SERVER_PREASON_HOLD_NEW_JOBS)) serverHoldJob(job, hold_until); /* @@ -3826,6 +3893,47 @@ ipp_hold_job(server_client_t *client) /* I - Client */ } +/* + * 'ipp_hold_new_jobs()' - Hold new jobs for printing. + */ + +static void +ipp_hold_new_jobs( + server_client_t *client) /* I - Client */ +{ + if (Authentication) + { + /* + * Require authenticated username belonging to the admin group... + */ + + if (!client->username[0]) + { + serverRespondHTTP(client, HTTP_STATUS_UNAUTHORIZED, NULL, NULL, 0); + return; + } + + if (!serverAuthorizeUser(client, NULL, AuthAdminGroup, SERVER_SCOPE_DEFAULT)) + { + serverRespondHTTP(client, HTTP_STATUS_FORBIDDEN, NULL, NULL, 0); + return; + } + } + + /* + * Set the 'hold-new-jobs' reason... + */ + + _cupsRWLockWrite(&client->printer->rwlock); + + client->printer->state_reasons |= SERVER_PREASON_HOLD_NEW_JOBS; + + _cupsRWUnlock(&client->printer->rwlock); + + serverRespondIPP(client, IPP_STATUS_OK, NULL); +} + + /* * 'ipp_identify_printer()' - Beep or display a message. */ @@ -4038,7 +4146,7 @@ ipp_print_job(server_client_t *client) /* I - Client */ if ((hold_until = ippFindAttribute(client->request, "job-hold-until", IPP_TAG_KEYWORD)) == NULL) hold_until = ippFindAttribute(client->request, "job-hold-until-time", IPP_TAG_DATE); - if (hold_until) + if (hold_until || (job->printer->state_reasons & SERVER_PREASON_HOLD_NEW_JOBS)) serverHoldJob(job, hold_until); /* @@ -4217,10 +4325,10 @@ ipp_print_uri(server_client_t *client) /* I - Client */ if ((hold_until = ippFindAttribute(client->request, "job-hold-until", IPP_TAG_KEYWORD)) == NULL) hold_until = ippFindAttribute(client->request, "job-hold-until-time", IPP_TAG_DATE); - if (hold_until) + if (hold_until || (job->printer->state_reasons & SERVER_PREASON_HOLD_NEW_JOBS)) serverHoldJob(job, hold_until); - if (copy_document_uri(client, job, uri) && !job->hold_until) + if (copy_document_uri(client, job, uri) && job->hold_until == 0) job->state = IPP_JSTATE_PENDING; /* @@ -4254,6 +4362,66 @@ ipp_print_uri(server_client_t *client) /* I - Client */ } +/* + * 'ipp_release_held_new_jobs()' - Release any new jobs that were held. + */ + +static void +ipp_release_held_new_jobs( + server_client_t *client) /* I - Client */ +{ + server_job_t *job; /* Current job */ + + + if (Authentication) + { + /* + * Require authenticated username belonging to the admin group... + */ + + if (!client->username[0]) + { + serverRespondHTTP(client, HTTP_STATUS_UNAUTHORIZED, NULL, NULL, 0); + return; + } + + if (!serverAuthorizeUser(client, NULL, AuthAdminGroup, SERVER_SCOPE_DEFAULT)) + { + serverRespondHTTP(client, HTTP_STATUS_FORBIDDEN, NULL, NULL, 0); + return; + } + } + + /* + * Clear the 'hold-new-jobs' reason and release any held jobs... + */ + + _cupsRWLockWrite(&client->printer->rwlock); + + client->printer->state_reasons &= (server_preason_t)~SERVER_PREASON_HOLD_NEW_JOBS; + + for (job = (server_job_t *)cupsArrayFirst(client->printer->active_jobs); job; job = (server_job_t *)cupsArrayNext(client->printer->active_jobs)) + { + if (job->state == IPP_JSTATE_HELD) + { + const char *hold_until; /* job-hold-until attribute, if any */ + int resume; /* Do we need to resume the job? */ + + _cupsRWLockRead(&job->rwlock); + resume = (hold_until = ippGetString(ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_ZERO), 0, NULL)) != NULL && !strcmp(hold_until, "none"); + _cupsRWUnlock(&job->rwlock); + + if (resume) + serverReleaseJob(job); + } + } + + _cupsRWUnlock(&client->printer->rwlock); + + serverRespondIPP(client, IPP_STATUS_OK, NULL); +} + + /* * 'ipp_release_job()' - Release a held job. */ @@ -4694,7 +4862,9 @@ ipp_send_document(server_client_t *client)/* I - Client */ job->fd = -1; job->filename = strdup(filename); - job->state = IPP_JSTATE_PENDING; + + if (job->hold_until == 0) + job->state = IPP_JSTATE_PENDING; _cupsRWUnlock(&(client->printer->rwlock)); @@ -4843,7 +5013,7 @@ ipp_send_uri(server_client_t *client) /* I - Client */ else job->format = "application/octet-stream"; - if (copy_document_uri(client, job, uri) && !job->hold_until) + if (copy_document_uri(client, job, uri) && job->hold_until == 0) job->state = IPP_JSTATE_PENDING; /* @@ -6124,6 +6294,10 @@ serverProcessIPP( ipp_cancel_job(client); break; + case IPP_OP_CANCEL_CURRENT_JOB : + ipp_cancel_current_job(client); + break; + case IPP_OP_CANCEL_JOBS : ipp_cancel_jobs(client); break; @@ -6156,10 +6330,18 @@ serverProcessIPP( ipp_hold_job(client); break; + case IPP_OP_HOLD_NEW_JOBS : + ipp_hold_new_jobs(client); + break; + case IPP_OP_RELEASE_JOB : ipp_release_job(client); break; + case IPP_OP_RELEASE_HELD_NEW_JOBS : + ipp_release_held_new_jobs(client); + break; + case IPP_OP_IDENTIFY_PRINTER : ipp_identify_printer(client); break; diff --git a/server/ippserver.h b/server/ippserver.h index 1f6eba8b..67606850 100644 --- a/server/ippserver.h +++ b/server/ippserver.h @@ -9,11 +9,10 @@ */ /* - * Disable private and deprecated stuff so we can verify that the public API - * is sufficient to implement a server. + * Disable deprecated stuff so we can verify that the public API is sufficient + * to implement a server. */ -#define _IPP_PRIVATE_STRUCTURES 0 /* Disable private IPP stuff */ #define _CUPS_NO_DEPRECATED 1 /* Disable deprecated stuff */ @@ -346,10 +345,12 @@ enum server_preason_e /* printer-state-reasons bit values */ SERVER_PREASON_TONER_LOW = 0x20000, /* toner-low */ SERVER_PREASON_IDENTIFY_PRINTER_REQUESTED = 0x40000, /* identify-printer-requested */ - SERVER_PREASON_DELETING = 0x80000 /* deleting */ + SERVER_PREASON_DELETING = 0x80000, /* deleting */ + SERVER_PREASON_HOLD_NEW_JOBS = 0x100000 + /* hold-new-jobs */ }; typedef unsigned int server_preason_t; /* Bitfield for printer-state-reasons */ -VAR const char * const server_preasons[20] +VAR const char * const server_preasons[21] VALUE({ /* Strings for bits */ /* "none" is implied for no bits set */ "other", @@ -371,7 +372,8 @@ VALUE({ /* Strings for bits */ "toner-empty", "toner-low", "identify-printer-requested", - "deleting" + "deleting", + "hold-new-jobs" }); typedef enum server_transform_e /* Transform modes for server */ diff --git a/server/job.c b/server/job.c index 840ae3fd..d7b81d10 100644 --- a/server/job.c +++ b/server/job.c @@ -66,7 +66,7 @@ serverCheckJobs(server_printer_t *printer) /* I - Printer */ job; job = (server_job_t *)cupsArrayNext(printer->active_jobs)) { - if (job->state == IPP_JSTATE_HELD && job->hold_until && job->hold_until <= time(NULL)) + if (job->state == IPP_JSTATE_HELD && job->hold_until > 0 && job->hold_until <= time(NULL)) serverReleaseJob(job); if (job->state == IPP_JSTATE_PENDING || (job->state == IPP_JSTATE_STOPPED && !(job->state_reasons & SERVER_JREASON_JOB_FETCHABLE))) @@ -585,14 +585,14 @@ serverHoldJob( * Any other value maps to "indefinite" - hold until released. */ - job->hold_until = 0; + job->hold_until = -1; } } if ((attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_ZERO)) != NULL) { if (!hold_until) - ippSetString(job->attrs, &attr, 0, "indefinite"); + ippSetString(job->attrs, &attr, 0, "none"); else if (ippGetValueTag(hold_until) == IPP_TAG_DATE) ippDeleteAttribute(job->attrs, attr); else diff --git a/server/printer.c b/server/printer.c index 0ff216fa..6a485d4f 100644 --- a/server/printer.c +++ b/server/printer.c @@ -316,9 +316,35 @@ serverCreatePrinter( "display", "sound" }; + static const char * const doc_creation[] = + { /* document-creation-attributes-supported values */ + "copies", + "document-name", + "media", + "media-col", + "orientation-requested", + "output-bin", + "page-ranges", + "print-color-mode", + "print-quality", + "sides" + }; + static const char * const doc_creation3d[] = + { /* document-creation-attributes-supported values for 3D printers */ + "copies", + "document-name", + "materials-col", + "platform-temperature", + "print-accuracy", + "print-base", + "print-quality", + "print-supports" + }; static const char * const job_creation[] = { /* job-creation-attributes-supported values */ "copies", + "finishings", + "finishings-col", "ipp-attribute-fidelity", "job-account-id", "job-accounting-user-id", @@ -330,17 +356,18 @@ serverCreatePrinter( "multiple-document-handling", "orientation-requested", "output-bin", + "page-ranges", "print-color-mode", "print-quality", "sides" }; static const char * const job_creation3d[] = - { /* job-creation-attributes-supported values */ + { /* job-creation-attributes-supported values for 3D printers */ "ipp-attribute-fidelity", "job-name", "job-priority", "materials-col", - "platform-temperatures", + "platform-temperature", "print-accuracy", "print-base", "print-quality", @@ -698,6 +725,15 @@ serverCreatePrinter( if (!cupsArrayFind(existing, (void *)"copies-supported")) ippAddRange(printer->pinfo.attrs, IPP_TAG_PRINTER, "copies-supported", 1, is_print3d ? 1 : 999); + /* document-creation-attributes-supported */ + if (!cupsArrayFind(existing, (void *)"document-creation-attributes-supported")) + { + if (is_print3d) + ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "document-creation-attributes-supported", sizeof(doc_creation3d) / sizeof(doc_creation3d[0]), NULL, doc_creation3d); + else + ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "document-creation-attributes-supported", sizeof(doc_creation) / sizeof(doc_creation[0]), NULL, doc_creation); + } + /* document-format-default */ if (defformat && !cupsArrayFind(existing, (void *)"document-format-default")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, "document-format-default", NULL, defformat); @@ -799,14 +835,6 @@ serverCreatePrinter( if (!cupsArrayFind(existing, (void *)"job-priority-supported")) ippAddInteger(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-priority-supported", 100); - /* job-sheets-default */ - if (!is_print3d && !cupsArrayFind(existing, (void *)"job-sheets-default")) - ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "job-sheets-default", NULL, "none"); - - /* job-sheets-supported */ - if (!is_print3d && !cupsArrayFind(existing, (void *)"job-sheets-supported")) - ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "job-sheets-supported", NULL, "none"); - if (!is_print3d) { /* media-bottom-margin-supported */ diff --git a/server/resource.c b/server/resource.c index cf4c7d2c..88047b2c 100644 --- a/server/resource.c +++ b/server/resource.c @@ -43,10 +43,10 @@ serverAddResourceFile( #ifdef HAVE_SSL if (Encryption != HTTP_ENCRYPTION_NEVER) - httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "https", NULL, lis->host, lis->port, res->resource); + httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "https", NULL, lis->host, lis->port, res->resource); else #endif /* HAVE_SSL */ - httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "http", NULL, lis->host, lis->port, res->resource); + httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "http", NULL, lis->host, lis->port, res->resource); ippAddString(res->attrs, IPP_TAG_RESOURCE, IPP_TAG_URI, "resource-data-uri", NULL, uri); ippAddString(res->attrs, IPP_TAG_RESOURCE, IPP_TAG_MIMETYPE, "resource-format", NULL, res->format); diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 9be5425f..5cfeeb27 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -32,22 +32,10 @@ apps: plugs: [avahi-observe, home, network] parts: - mupdf: - plugin: make - make-install-var: prefix - make-parameters: [HAVE_X11=no, HAVE_GLFW=no, HAVE_GLUT=no] - source: https://mupdf.com/downloads/mupdf-1.12.0-source.tar.gz - prime: - - -bin/mu* - - -include/mu* - - -lib/libmu* - - -share/doc/mupdf - - -share/man/man1/mu* main: - after: [mupdf] plugin: autotools configflags: [--with-name-prefix=] source: . -build-packages: [cura-engine, libavahi-client-dev, libgnutls28-dev, libjpeg-dev, libpng-dev, zlib1g-dev] +build-packages: [cura-engine, libavahi-client-dev, libgnutls28-dev, libharfbuzz-dev libjbig2dec0-dev, libjpeg-dev, libmupdf-dev, libopenjp2-7-dev, libpng-dev, zlib1g-dev] diff --git a/tools/ippserver.c b/tools/ippserver.c deleted file mode 100644 index 6180695d..00000000 --- a/tools/ippserver.c +++ /dev/null @@ -1,7370 +0,0 @@ -/* - * Sample IPP Everywhere server for CUPS. - * - * Copyright 2010-2017 by Apple Inc. - * - * Licensed under Apache License v2.0. See the file "LICENSE" for more information. - */ - -/* - * Disable private and deprecated stuff so we can verify that the public API - * is sufficient to implement a server. - */ - -#define _IPP_PRIVATE_STRUCTURES 0 /* Disable private IPP stuff */ -#define _CUPS_NO_DEPRECATED 1 /* Disable deprecated stuff */ - - -/* - * Include necessary headers... - */ - -#include /* CUPS configuration header */ -#include /* Public API */ -#include /* CUPS string functions */ -#include /* For multithreading functions */ -#include -#include -#include -#include -#include -#include -#include - -#ifdef WIN32 -# include -# include -# include -# define WEXITSTATUS(s) (s) -# include -typedef ULONG nfds_t; -# define poll WSAPoll -#else -extern char **environ; - -# include -# include -# include -#endif /* WIN32 */ - -#ifdef HAVE_DNSSD -# include -#elif defined(HAVE_AVAHI) -# include -# include -# include -# include -#endif /* HAVE_DNSSD */ -#ifdef HAVE_SYS_MOUNT_H -# include -#endif /* HAVE_SYS_MOUNT_H */ -#ifdef HAVE_SYS_STATFS_H -# include -#endif /* HAVE_SYS_STATFS_H */ -#ifdef HAVE_SYS_STATVFS_H -# include -#endif /* HAVE_SYS_STATVFS_H */ -#ifdef HAVE_SYS_VFS_H -# include -#endif /* HAVE_SYS_VFS_H */ - - -/* - * Constants... - */ - -enum _ipp_preason_e /* printer-state-reasons bit values */ -{ - _IPP_PREASON_NONE = 0x0000, /* none */ - _IPP_PREASON_OTHER = 0x0001, /* other */ - _IPP_PREASON_COVER_OPEN = 0x0002, /* cover-open */ - _IPP_PREASON_INPUT_TRAY_MISSING = 0x0004, - /* input-tray-missing */ - _IPP_PREASON_MARKER_SUPPLY_EMPTY = 0x0008, - /* marker-supply-empty */ - _IPP_PREASON_MARKER_SUPPLY_LOW = 0x0010, - /* marker-supply-low */ - _IPP_PREASON_MARKER_WASTE_ALMOST_FULL = 0x0020, - /* marker-waste-almost-full */ - _IPP_PREASON_MARKER_WASTE_FULL = 0x0040, - /* marker-waste-full */ - _IPP_PREASON_MEDIA_EMPTY = 0x0080, /* media-empty */ - _IPP_PREASON_MEDIA_JAM = 0x0100, /* media-jam */ - _IPP_PREASON_MEDIA_LOW = 0x0200, /* media-low */ - _IPP_PREASON_MEDIA_NEEDED = 0x0400, /* media-needed */ - _IPP_PREASON_MOVING_TO_PAUSED = 0x0800, - /* moving-to-paused */ - _IPP_PREASON_PAUSED = 0x1000, /* paused */ - _IPP_PREASON_SPOOL_AREA_FULL = 0x2000,/* spool-area-full */ - _IPP_PREASON_TONER_EMPTY = 0x4000, /* toner-empty */ - _IPP_PREASON_TONER_LOW = 0x8000 /* toner-low */ -}; -typedef unsigned int _ipp_preason_t; /* Bitfield for printer-state-reasons */ -static const char * const _ipp_preason_strings[] = -{ /* Strings for each bit */ - /* "none" is implied for no bits set */ - "other", - "cover-open", - "input-tray-missing", - "marker-supply-empty", - "marker-supply-low", - "marker-waste-almost-full", - "marker-waste-full", - "media-empty", - "media-jam", - "media-low", - "media-needed", - "moving-to-paused", - "paused", - "spool-area-full", - "toner-empty", - "toner-low" -}; - -typedef enum _ipp_media_class_e -{ - _IPP_GENERAL, /* General-purpose size */ - _IPP_PHOTO_ONLY, /* Photo-only size */ - _IPP_ENV_ONLY /* Envelope-only size */ -} _ipp_media_class_t; - -typedef enum _ipp_media_size_e -{ - _IPP_MEDIA_SIZE_NONE = -1, - _IPP_MEDIA_SIZE_A4, - _IPP_MEDIA_SIZE_A5, - _IPP_MEDIA_SIZE_A6, - _IPP_MEDIA_SIZE_DL, - _IPP_MEDIA_SIZE_LEGAL, - _IPP_MEDIA_SIZE_LETTER, - _IPP_MEDIA_SIZE_COM10, - _IPP_MEDIA_SIZE_3x5, - _IPP_MEDIA_SIZE_L, - _IPP_MEDIA_SIZE_4x6, - _IPP_MEDIA_SIZE_5x7 -} _ipp_media_size_t; -static const char * const media_supported[] = -{ /* media-supported values */ - "iso_a4_210x297mm", /* A4 */ - "iso_a5_148x210mm", /* A5 */ - "iso_a6_105x148mm", /* A6 */ - "iso_dl_110x220mm", /* DL */ - "na_legal_8.5x14in", /* Legal */ - "na_letter_8.5x11in", /* Letter */ - "na_number-10_4.125x9.5in", /* #10 */ - "na_index-3x5_3x5in", /* 3x5 */ - "oe_photo-l_3.5x5in", /* L */ - "na_index-4x6_4x6in", /* 4x6 */ - "na_5x7_5x7in" /* 5x7 aka 2L */ -}; -static const int media_col_sizes[][3] = -{ /* media-col-database sizes */ - { 21000, 29700, _IPP_GENERAL }, /* A4 */ - { 14800, 21000, _IPP_PHOTO_ONLY }, /* A5 */ - { 10500, 14800, _IPP_PHOTO_ONLY }, /* A6 */ - { 11000, 22000, _IPP_ENV_ONLY }, /* DL */ - { 21590, 35560, _IPP_GENERAL }, /* Legal */ - { 21590, 27940, _IPP_GENERAL }, /* Letter */ - { 10477, 24130, _IPP_ENV_ONLY }, /* #10 */ - { 7630, 12700, _IPP_PHOTO_ONLY }, /* 3x5 */ - { 8890, 12700, _IPP_PHOTO_ONLY }, /* L */ - { 10160, 15240, _IPP_PHOTO_ONLY }, /* 4x6 */ - { 12700, 17780, _IPP_PHOTO_ONLY } /* 5x7 aka 2L */ -}; - -typedef enum _ipp_media_source_e -{ - _IPP_MEDIA_SOURCE_NONE = -1, - _IPP_MEDIA_SOURCE_AUTO, - _IPP_MEDIA_SOURCE_MAIN, - _IPP_MEDIA_SOURCE_MANUAL, - _IPP_MEDIA_SOURCE_ENVELOPE, - _IPP_MEDIA_SOURCE_PHOTO -} _ipp_media_source_t; -static const char * const media_source_supported[] = - /* media-source-supported values */ -{ - "auto", - "main", - "manual", - "envelope", - "photo" -}; - -typedef enum _ipp_media_type_e -{ - _IPP_MEDIA_TYPE_NONE = -1, - _IPP_MEDIA_TYPE_AUTO, - _IPP_MEDIA_TYPE_CARDSTOCK, - _IPP_MEDIA_TYPE_ENVELOPE, - _IPP_MEDIA_TYPE_LABELS, - _IPP_MEDIA_TYPE_OTHER, - _IPP_MEDIA_TYPE_GLOSSY, - _IPP_MEDIA_TYPE_HIGH_GLOSS, - _IPP_MEDIA_TYPE_MATTE, - _IPP_MEDIA_TYPE_SATIN, - _IPP_MEDIA_TYPE_SEMI_GLOSS, - _IPP_MEDIA_TYPE_STATIONERY, - _IPP_MEDIA_TYPE_LETTERHEAD, - _IPP_MEDIA_TYPE_TRANSPARENCY -} _ipp_media_type_t; -static const char * const media_type_supported[] = - /* media-type-supported values */ -{ - "auto", - "cardstock", - "envelope", - "labels", - "other", - "photographic-glossy", - "photographic-high-gloss", - "photographic-matte", - "photographic-satin", - "photographic-semi-gloss", - "stationery", - "stationery-letterhead", - "transparency" -}; - -typedef enum _ipp_supply_e -{ - _IPP_SUPPLY_CYAN, /* Cyan Toner */ - _IPP_SUPPLY_MAGENTA, /* Magenta Toner */ - _IPP_SUPPLY_YELLOW, /* Yellow Toner */ - _IPP_SUPPLY_BLACK, /* Black Toner */ - _IPP_SUPPLY_WASTE /* Waste Toner */ -} _ipp_supply_t; -static const char * const printer_supplies[] = -{ /* printer-supply-description values */ - "Cyan Toner", - "Magenta Toner", - "Yellow Toner", - "Black Toner", - "Toner Waste" -}; - -/* - * URL scheme for web resources... - */ - -#ifdef HAVE_SSL -# define WEB_SCHEME "https" -#else -# define WEB_SCHEME "http" -#endif /* HAVE_SSL */ - - -/* - * Structures... - */ - -#ifdef HAVE_DNSSD -typedef DNSServiceRef _ipp_srv_t; /* Service reference */ -typedef TXTRecordRef _ipp_txt_t; /* TXT record */ - -#elif defined(HAVE_AVAHI) -typedef AvahiEntryGroup *_ipp_srv_t; /* Service reference */ -typedef AvahiStringList *_ipp_txt_t; /* TXT record */ - -#else -typedef void *_ipp_srv_t; /* Service reference */ -typedef void *_ipp_txt_t; /* TXT record */ -#endif /* HAVE_DNSSD */ - -typedef struct _ipp_filter_s /**** Attribute filter ****/ -{ - cups_array_t *ra; /* Requested attributes */ - ipp_tag_t group_tag; /* Group to copy */ -} _ipp_filter_t; - -typedef struct _ipp_job_s _ipp_job_t; - -typedef struct _ipp_printer_s /**** Printer data ****/ -{ - int ipv4, /* IPv4 listener */ - ipv6; /* IPv6 listener */ - _ipp_srv_t ipp_ref, /* Bonjour IPP service */ - ipps_ref, /* Bonjour IPPS service */ - http_ref, /* Bonjour HTTP service */ - printer_ref; /* Bonjour LPD service */ - char *dnssd_name, /* printer-dnssd-name */ - *name, /* printer-name */ - *icon, /* Icon filename */ - *directory, /* Spool directory */ - *hostname, /* Hostname */ - *uri, /* printer-uri-supported */ - *command; /* Command to run with job file */ - int port; /* Port */ - size_t urilen; /* Length of printer URI */ - ipp_t *attrs; /* Static attributes */ - time_t start_time; /* Startup time */ - time_t config_time; /* printer-config-change-time */ - ipp_pstate_t state; /* printer-state value */ - _ipp_preason_t state_reasons; /* printer-state-reasons values */ - time_t state_time; /* printer-state-change-time */ - cups_array_t *jobs; /* Jobs */ - _ipp_job_t *active_job; /* Current active/pending job */ - int next_job_id; /* Next job-id value */ - _cups_rwlock_t rwlock; /* Printer lock */ - _ipp_media_size_t main_size; /* Ready media */ - _ipp_media_type_t main_type; - int main_level; - _ipp_media_size_t envelope_size; - int envelope_level; - _ipp_media_size_t photo_size; - _ipp_media_type_t photo_type; - int photo_level; - int supplies[5]; /* Supply levels (0-100) */ -} _ipp_printer_t; - -struct _ipp_job_s /**** Job data ****/ -{ - int id; /* Job ID */ - const char *name, /* job-name */ - *username, /* job-originating-user-name */ - *format; /* document-format */ - ipp_jstate_t state; /* job-state value */ - time_t created, /* time-at-creation value */ - processing, /* time-at-processing value */ - completed; /* time-at-completed value */ - int impressions, /* job-impressions value */ - impcompleted; /* job-impressions-completed value */ - ipp_t *attrs; /* Static attributes */ - int cancel; /* Non-zero when job canceled */ - char *filename; /* Print file name */ - int fd; /* Print file descriptor */ - _ipp_printer_t *printer; /* Printer */ -}; - -typedef struct _ipp_client_s /**** Client data ****/ -{ - http_t *http; /* HTTP connection */ - ipp_t *request, /* IPP request */ - *response; /* IPP response */ - time_t start; /* Request start time */ - http_state_t operation; /* Request operation */ - ipp_op_t operation_id; /* IPP operation-id */ - char uri[1024], /* Request URI */ - *options; /* URI options */ - http_addr_t addr; /* Client address */ - char hostname[256]; /* Client hostname */ - _ipp_printer_t *printer; /* Printer */ - _ipp_job_t *job; /* Current job, if any */ -} _ipp_client_t; - - -/* - * Local functions... - */ - -static void clean_jobs(_ipp_printer_t *printer); -static int compare_jobs(_ipp_job_t *a, _ipp_job_t *b); -static void copy_attributes(ipp_t *to, ipp_t *from, cups_array_t *ra, - ipp_tag_t group_tag, int quickcopy); -static void copy_job_attributes(_ipp_client_t *client, - _ipp_job_t *job, cups_array_t *ra); -static _ipp_client_t *create_client(_ipp_printer_t *printer, int sock); -static _ipp_job_t *create_job(_ipp_client_t *client); -static int create_listener(int family, int port); -static ipp_t *create_media_col(const char *media, const char *source, const char *type, int width, int length, int margins); -static ipp_t *create_media_size(int width, int length); -static _ipp_printer_t *create_printer(const char *servername, - const char *name, const char *location, - const char *make, const char *model, - const char *icon, - const char *docformats, int ppm, - int ppm_color, int duplex, int port, - int pin, const char *subtype, - const char *directory, - const char *command, - const char *attrfile); -static void debug_attributes(const char *title, ipp_t *ipp, - int response); -static void delete_client(_ipp_client_t *client); -static void delete_job(_ipp_job_t *job); -static void delete_printer(_ipp_printer_t *printer); -#ifdef HAVE_DNSSD -static void DNSSD_API dnssd_callback(DNSServiceRef sdRef, - DNSServiceFlags flags, - DNSServiceErrorType errorCode, - const char *name, - const char *regtype, - const char *domain, - _ipp_printer_t *printer); -#elif defined(HAVE_AVAHI) -static void dnssd_callback(AvahiEntryGroup *p, AvahiEntryGroupState state, void *context); -static void dnssd_client_cb(AvahiClient *c, AvahiClientState state, void *userdata); -#endif /* HAVE_DNSSD */ -static void dnssd_init(void); -static int filter_cb(_ipp_filter_t *filter, ipp_t *dst, ipp_attribute_t *attr); -static _ipp_job_t *find_job(_ipp_client_t *client); -static ipp_t *get_collection(FILE *fp, const char *filename, int *linenum); -static char *get_token(FILE *fp, char *buf, int buflen, int *linenum); -static void html_escape(_ipp_client_t *client, const char *s, - size_t slen); -static void html_footer(_ipp_client_t *client); -static void html_header(_ipp_client_t *client, const char *title); -static void html_printf(_ipp_client_t *client, const char *format, - ...) __attribute__((__format__(__printf__, - 2, 3))); -static void ipp_cancel_job(_ipp_client_t *client); -static void ipp_close_job(_ipp_client_t *client); -static void ipp_create_job(_ipp_client_t *client); -static void ipp_get_job_attributes(_ipp_client_t *client); -static void ipp_get_jobs(_ipp_client_t *client); -static void ipp_get_printer_attributes(_ipp_client_t *client); -static void ipp_identify_printer(_ipp_client_t *client); -static void ipp_print_job(_ipp_client_t *client); -static void ipp_print_uri(_ipp_client_t *client); -static void ipp_send_document(_ipp_client_t *client); -static void ipp_send_uri(_ipp_client_t *client); -static void ipp_validate_job(_ipp_client_t *client); -static void load_attributes(const char *filename, ipp_t *attrs); -static int parse_options(_ipp_client_t *client, cups_option_t **options); -static void process_attr_message(_ipp_job_t *job, char *message); -static void *process_client(_ipp_client_t *client); -static int process_http(_ipp_client_t *client); -static int process_ipp(_ipp_client_t *client); -static void *process_job(_ipp_job_t *job); -static void process_state_message(_ipp_job_t *job, char *message); -static int register_printer(_ipp_printer_t *printer, const char *location, const char *make, const char *model, const char *formats, const char *adminurl, const char *uuid, int color, int duplex, const char *regtype); -static int respond_http(_ipp_client_t *client, http_status_t code, - const char *content_coding, - const char *type, size_t length); -static void respond_ipp(_ipp_client_t *client, ipp_status_t status, - const char *message, ...) - __attribute__ ((__format__ (__printf__, 3, 4))); -static void respond_unsupported(_ipp_client_t *client, - ipp_attribute_t *attr); -static void run_printer(_ipp_printer_t *printer); -static char *time_string(time_t tv, char *buffer, size_t bufsize); -static void usage(int status) __attribute__((noreturn)); -static int valid_doc_attributes(_ipp_client_t *client); -static int valid_job_attributes(_ipp_client_t *client); - - -/* - * Globals... - */ - -#ifdef HAVE_DNSSD -static DNSServiceRef DNSSDMaster = NULL; -#elif defined(HAVE_AVAHI) -static AvahiThreadedPoll *DNSSDMaster = NULL; -static AvahiClient *DNSSDClient = NULL; -#endif /* HAVE_DNSSD */ - -static int KeepFiles = 0, - Verbosity = 0; - - -/* - * 'main()' - Main entry to the sample server. - */ - -int /* O - Exit status */ -main(int argc, /* I - Number of command-line args */ - char *argv[]) /* I - Command-line arguments */ -{ - int i; /* Looping var */ - const char *opt, /* Current option character */ - *attrfile = NULL, /* Attributes file */ - *command = NULL, /* Command to run with job files */ - *servername = NULL, /* Server host name */ - *name = NULL, /* Printer name */ - *location = "", /* Location of printer */ - *make = "Test", /* Manufacturer */ - *model = "Printer", /* Model */ - *icon = "printer.png", /* Icon file */ - *formats = "application/pdf,image/jpeg,image/pwg-raster"; - /* Supported formats */ -#ifdef HAVE_SSL - const char *keypath = NULL; /* Keychain path */ -#endif /* HAVE_SSL */ - const char *subtype = "_print"; /* Bonjour service subtype */ - int port = 0, /* Port number (0 = auto) */ - duplex = 0, /* Duplex mode */ - ppm = 10, /* Pages per minute for mono */ - ppm_color = 0, /* Pages per minute for color */ - pin = 0; /* PIN printing mode? */ - char directory[1024] = "", /* Spool directory */ - hostname[1024]; /* Auto-detected hostname */ - _ipp_printer_t *printer; /* Printer object */ - - - /* - * Parse command-line arguments... - */ - - for (i = 1; i < argc; i ++) - if (argv[i][0] == '-') - { - for (opt = argv[i] + 1; *opt; opt ++) - { - switch (*opt) - { - case '2' : /* -2 (enable 2-sided printing) */ - duplex = 1; - break; - -#ifdef HAVE_SSL - case 'K' : /* -K keypath */ - i ++; - if (i >= argc) - usage(1); - keypath = argv[i]; - break; -#endif /* HAVE_SSL */ - - case 'M' : /* -M manufacturer */ - i ++; - if (i >= argc) - usage(1); - make = argv[i]; - break; - - case 'P' : /* -P (PIN printing mode) */ - pin = 1; - break; - - case 'a' : /* -a attributes-file */ - i ++; - if (i >= argc) - usage(1); - - attrfile = argv[i]; - break; - - case 'c' : /* -c command */ - i ++; - if (i >= argc) - usage(1); - - command = argv[i]; - break; - - case 'd' : /* -d spool-directory */ - i ++; - if (i >= argc) - usage(1); - strlcpy(directory, argv[i], sizeof(directory)); - break; - - case 'f' : /* -f type/subtype[,...] */ - i ++; - if (i >= argc) - usage(1); - formats = argv[i]; - break; - - case 'h' : /* -h (show help) */ - usage(0); - - case 'i' : /* -i icon.png */ - i ++; - if (i >= argc) - usage(1); - icon = argv[i]; - break; - - case 'k' : /* -k (keep files) */ - KeepFiles = 1; - break; - - case 'l' : /* -l location */ - i ++; - if (i >= argc) - usage(1); - location = argv[i]; - break; - - case 'm' : /* -m model */ - i ++; - if (i >= argc) - usage(1); - model = argv[i]; - break; - - case 'n' : /* -n hostname */ - i ++; - if (i >= argc) - usage(1); - servername = argv[i]; - break; - - case 'p' : /* -p port */ - i ++; - if (i >= argc || !isdigit(argv[i][0] & 255)) - usage(1); - port = atoi(argv[i]); - break; - - case 'r' : /* -r subtype */ - i ++; - if (i >= argc) - usage(1); - subtype = argv[i]; - break; - - case 's' : /* -s speed[,color-speed] */ - i ++; - if (i >= argc) - usage(1); - if (sscanf(argv[i], "%d,%d", &ppm, &ppm_color) < 1) - usage(1); - break; - - case 'v' : /* -v (be verbose) */ - Verbosity ++; - break; - - default : /* Unknown */ - fprintf(stderr, "Unknown option \"-%c\".\n", *opt); - usage(1); - } - } - } - else if (!name) - { - name = argv[i]; - } - else - { - fprintf(stderr, "Unexpected command-line argument \"%s\"\n", argv[i]); - usage(1); - } - - if (!name) - usage(1); - - /* - * Apply defaults as needed... - */ - - if (!servername) - servername = httpGetHostname(NULL, hostname, sizeof(hostname)); - - if (!port) - { -#ifdef WIN32 - /* - * Windows is almost always used as a single user system, so use a default - * port number of 8631. - */ - - port = 8631; - -#else - /* - * Use 8000 + UID mod 1000 for the default port number... - */ - - port = 8000 + ((int)getuid() % 1000); -#endif /* WIN32 */ - - fprintf(stderr, "Listening on port %d.\n", port); - } - - if (!directory[0]) - { - const char *tmpdir; /* Temporary directory */ - -#ifdef WIN32 - if ((tmpdir = getenv("TEMP")) == NULL) - tmpdir = "C:/TEMP"; -#elif defined(__APPLE__) && !TARGET_OS_IOS - if ((tmpdir = getenv("TMPDIR")) == NULL) - tmpdir = "/private/tmp"; -#else - if ((tmpdir = getenv("TMPDIR")) == NULL) - tmpdir = "/tmp"; -#endif /* WIN32 */ - - snprintf(directory, sizeof(directory), "%s/ippserver.%d", tmpdir, (int)getpid()); - - if (mkdir(directory, 0755) && errno != EEXIST) - { - fprintf(stderr, "Unable to create spool directory \"%s\": %s\n", - directory, strerror(errno)); - usage(1); - } - - if (Verbosity) - fprintf(stderr, "Using spool directory \"%s\".\n", directory); - } - -#ifdef HAVE_SSL - cupsSetServerCredentials(keypath, servername, 1); -#endif /* HAVE_SSL */ - - /* - * Initialize Bonjour... - */ - - dnssd_init(); - - /* - * Create the printer... - */ - - if ((printer = create_printer(servername, name, location, make, model, icon, - formats, ppm, ppm_color, duplex, port, pin, - subtype, directory, command, attrfile)) == NULL) - return (1); - - /* - * Run the print service... - */ - - run_printer(printer); - - /* - * Destroy the printer and exit... - */ - - delete_printer(printer); - - return (0); -} - - -/* - * 'clean_jobs()' - Clean out old (completed) jobs. - */ - -static void -clean_jobs(_ipp_printer_t *printer) /* I - Printer */ -{ - _ipp_job_t *job; /* Current job */ - time_t cleantime; /* Clean time */ - - - if (cupsArrayCount(printer->jobs) == 0) - return; - - cleantime = time(NULL) - 60; - - _cupsRWLockWrite(&(printer->rwlock)); - for (job = (_ipp_job_t *)cupsArrayFirst(printer->jobs); - job; - job = (_ipp_job_t *)cupsArrayNext(printer->jobs)) - if (job->completed && job->completed < cleantime) - { - cupsArrayRemove(printer->jobs, job); - delete_job(job); - } - else - break; - _cupsRWUnlock(&(printer->rwlock)); -} - - -/* - * 'compare_jobs()' - Compare two jobs. - */ - -static int /* O - Result of comparison */ -compare_jobs(_ipp_job_t *a, /* I - First job */ - _ipp_job_t *b) /* I - Second job */ -{ - return (b->id - a->id); -} - - -/* - * 'copy_attributes()' - Copy attributes from one request to another. - */ - -static void -copy_attributes(ipp_t *to, /* I - Destination request */ - ipp_t *from, /* I - Source request */ - cups_array_t *ra, /* I - Requested attributes */ - ipp_tag_t group_tag, /* I - Group to copy */ - int quickcopy) /* I - Do a quick copy? */ -{ - _ipp_filter_t filter; /* Filter data */ - - - filter.ra = ra; - filter.group_tag = group_tag; - - ippCopyAttributes(to, from, quickcopy, (ipp_copycb_t)filter_cb, &filter); -} - - -/* - * 'copy_job_attrs()' - Copy job attributes to the response. - */ - -static void -copy_job_attributes( - _ipp_client_t *client, /* I - Client */ - _ipp_job_t *job, /* I - Job */ - cups_array_t *ra) /* I - requested-attributes */ -{ - copy_attributes(client->response, job->attrs, ra, IPP_TAG_JOB, 0); - - if (!ra || cupsArrayFind(ra, "date-time-at-completed")) - { - if (job->completed) - ippAddDate(client->response, IPP_TAG_JOB, "date-time-at-completed", ippTimeToDate(job->completed)); - else - ippAddOutOfBand(client->response, IPP_TAG_JOB, IPP_TAG_NOVALUE, "date-time-at-completed"); - } - - if (!ra || cupsArrayFind(ra, "date-time-at-processing")) - { - if (job->processing) - ippAddDate(client->response, IPP_TAG_JOB, "date-time-at-processing", ippTimeToDate(job->processing)); - else - ippAddOutOfBand(client->response, IPP_TAG_JOB, IPP_TAG_NOVALUE, "date-time-at-processing"); - } - - if (!ra || cupsArrayFind(ra, "job-impressions")) - ippAddInteger(client->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-impressions", job->impressions); - - if (!ra || cupsArrayFind(ra, "job-impressions-completed")) - ippAddInteger(client->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-impressions-completed", job->impcompleted); - - if (!ra || cupsArrayFind(ra, "job-printer-up-time")) - ippAddInteger(client->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-printer-up-time", (int)(time(NULL) - client->printer->start_time)); - - if (!ra || cupsArrayFind(ra, "job-state")) - ippAddInteger(client->response, IPP_TAG_JOB, IPP_TAG_ENUM, - "job-state", job->state); - - if (!ra || cupsArrayFind(ra, "job-state-message")) - { - switch (job->state) - { - case IPP_JSTATE_PENDING : - ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job pending."); - break; - - case IPP_JSTATE_HELD : - if (job->fd >= 0) - ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job incoming."); - else if (ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_ZERO)) - ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job held."); - else - ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job created."); - break; - - case IPP_JSTATE_PROCESSING : - if (job->cancel) - ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job canceling."); - else - ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job printing."); - break; - - case IPP_JSTATE_STOPPED : - ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job stopped."); - break; - - case IPP_JSTATE_CANCELED : - ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job canceled."); - break; - - case IPP_JSTATE_ABORTED : - ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job aborted."); - break; - - case IPP_JSTATE_COMPLETED : - ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job completed."); - break; - } - } - - if (!ra || cupsArrayFind(ra, "job-state-reasons")) - { - switch (job->state) - { - case IPP_JSTATE_PENDING : - ippAddString(client->response, IPP_TAG_JOB, - IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", - NULL, "none"); - break; - - case IPP_JSTATE_HELD : - if (job->fd >= 0) - ippAddString(client->response, IPP_TAG_JOB, - IPP_CONST_TAG(IPP_TAG_KEYWORD), - "job-state-reasons", NULL, "job-incoming"); - else if (ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_ZERO)) - ippAddString(client->response, IPP_TAG_JOB, - IPP_CONST_TAG(IPP_TAG_KEYWORD), - "job-state-reasons", NULL, "job-hold-until-specified"); - else - ippAddString(client->response, IPP_TAG_JOB, - IPP_CONST_TAG(IPP_TAG_KEYWORD), - "job-state-reasons", NULL, "job-data-insufficient"); - break; - - case IPP_JSTATE_PROCESSING : - if (job->cancel) - ippAddString(client->response, IPP_TAG_JOB, - IPP_CONST_TAG(IPP_TAG_KEYWORD), - "job-state-reasons", NULL, "processing-to-stop-point"); - else - ippAddString(client->response, IPP_TAG_JOB, - IPP_CONST_TAG(IPP_TAG_KEYWORD), - "job-state-reasons", NULL, "job-printing"); - break; - - case IPP_JSTATE_STOPPED : - ippAddString(client->response, IPP_TAG_JOB, - IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", - NULL, "job-stopped"); - break; - - case IPP_JSTATE_CANCELED : - ippAddString(client->response, IPP_TAG_JOB, - IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", - NULL, "job-canceled-by-user"); - break; - - case IPP_JSTATE_ABORTED : - ippAddString(client->response, IPP_TAG_JOB, - IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", - NULL, "aborted-by-system"); - break; - - case IPP_JSTATE_COMPLETED : - ippAddString(client->response, IPP_TAG_JOB, - IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", - NULL, "job-completed-successfully"); - break; - } - } - - if (!ra || cupsArrayFind(ra, "time-at-completed")) - ippAddInteger(client->response, IPP_TAG_JOB, - job->completed ? IPP_TAG_INTEGER : IPP_TAG_NOVALUE, - "time-at-completed", (int)(job->completed - client->printer->start_time)); - - if (!ra || cupsArrayFind(ra, "time-at-processing")) - ippAddInteger(client->response, IPP_TAG_JOB, - job->processing ? IPP_TAG_INTEGER : IPP_TAG_NOVALUE, - "time-at-processing", (int)(job->processing - client->printer->start_time)); -} - - -/* - * 'create_client()' - Accept a new network connection and create a client - * object. - */ - -static _ipp_client_t * /* O - Client */ -create_client(_ipp_printer_t *printer, /* I - Printer */ - int sock) /* I - Listen socket */ -{ - _ipp_client_t *client; /* Client */ - - - if ((client = calloc(1, sizeof(_ipp_client_t))) == NULL) - { - perror("Unable to allocate memory for client"); - return (NULL); - } - - client->printer = printer; - - /* - * Accept the client and get the remote address... - */ - - if ((client->http = httpAcceptConnection(sock, 1)) == NULL) - { - perror("Unable to accept client connection"); - - free(client); - - return (NULL); - } - - httpGetHostname(client->http, client->hostname, sizeof(client->hostname)); - - if (Verbosity) - fprintf(stderr, "Accepted connection from %s\n", client->hostname); - - return (client); -} - - -/* - * 'create_job()' - Create a new job object from a Print-Job or Create-Job - * request. - */ - -static _ipp_job_t * /* O - Job */ -create_job(_ipp_client_t *client) /* I - Client */ -{ - _ipp_job_t *job; /* Job */ - ipp_attribute_t *attr; /* Job attribute */ - char uri[1024], /* job-uri value */ - uuid[64]; /* job-uuid value */ - - - _cupsRWLockWrite(&(client->printer->rwlock)); - if (client->printer->active_job && - client->printer->active_job->state < IPP_JSTATE_CANCELED) - { - /* - * Only accept a single job at a time... - */ - - _cupsRWUnlock(&(client->printer->rwlock)); - return (NULL); - } - - /* - * Allocate and initialize the job object... - */ - - if ((job = calloc(1, sizeof(_ipp_job_t))) == NULL) - { - perror("Unable to allocate memory for job"); - return (NULL); - } - - job->printer = client->printer; - job->attrs = ippNew(); - job->state = IPP_JSTATE_HELD; - job->fd = -1; - - /* - * Copy all of the job attributes... - */ - - copy_attributes(job->attrs, client->request, NULL, IPP_TAG_JOB, 0); - - /* - * Get the requesting-user-name, document format, and priority... - */ - - if ((attr = ippFindAttribute(client->request, "requesting-user-name", IPP_TAG_NAME)) != NULL) - job->username = ippGetString(attr, 0, NULL); - else - job->username = "anonymous"; - - ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-user-name", NULL, job->username); - - if (ippGetOperation(client->request) != IPP_OP_CREATE_JOB) - { - if ((attr = ippFindAttribute(job->attrs, "document-format-detected", IPP_TAG_MIMETYPE)) != NULL) - job->format = ippGetString(attr, 0, NULL); - else if ((attr = ippFindAttribute(job->attrs, "document-format-supplied", IPP_TAG_MIMETYPE)) != NULL) - job->format = ippGetString(attr, 0, NULL); - else - job->format = "application/octet-stream"; - } - - if ((attr = ippFindAttribute(client->request, "job-impressions", IPP_TAG_INTEGER)) != NULL) - job->impressions = ippGetInteger(attr, 0); - - if ((attr = ippFindAttribute(client->request, "job-name", IPP_TAG_NAME)) != NULL) - job->name = ippGetString(attr, 0, NULL); - - /* - * Add job description attributes and add to the jobs array... - */ - - job->id = client->printer->next_job_id ++; - - snprintf(uri, sizeof(uri), "%s/%d", client->printer->uri, job->id); - httpAssembleUUID(client->printer->hostname, client->printer->port, client->printer->name, job->id, uuid, sizeof(uuid)); - - ippAddDate(job->attrs, IPP_TAG_JOB, "date-time-at-creation", ippTimeToDate(time(&job->created))); - ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id); - ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, uri); - ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-uuid", NULL, uuid); - if ((attr = ippFindAttribute(client->request, "printer-uri", IPP_TAG_URI)) != NULL) - ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL, ippGetString(attr, 0, NULL)); - else - ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL, client->printer->uri); - ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation", (int)(job->created - client->printer->start_time)); - - cupsArrayAdd(client->printer->jobs, job); - client->printer->active_job = job; - - _cupsRWUnlock(&(client->printer->rwlock)); - - return (job); -} - - -/* - * 'create_job_filename()' - Create the filename for a document in a job. - */ - -static void create_job_filename( - _ipp_printer_t *printer, /* I - Printer */ - _ipp_job_t *job, /* I - Job */ - char *fname, /* I - Filename buffer */ - size_t fnamesize) /* I - Size of filename buffer */ -{ - char name[256], /* "Safe" filename */ - *nameptr; /* Pointer into filename */ - const char *ext, /* Filename extension */ - *job_name; /* job-name value */ - ipp_attribute_t *job_name_attr; /* job-name attribute */ - - - /* - * Make a name from the job-name attribute... - */ - - if ((job_name_attr = ippFindAttribute(job->attrs, "job-name", IPP_TAG_NAME)) != NULL) - job_name = ippGetString(job_name_attr, 0, NULL); - else - job_name = "untitled"; - - for (nameptr = name; *job_name && nameptr < (name + sizeof(name) - 1); job_name ++) - if (isalnum(*job_name & 255) || *job_name == '-') - *nameptr++ = (char)tolower(*job_name & 255); - else - *nameptr++ = '_'; - - *nameptr = '\0'; - - /* - * Figure out the extension... - */ - - if (!strcasecmp(job->format, "image/jpeg")) - ext = "jpg"; - else if (!strcasecmp(job->format, "image/png")) - ext = "png"; - else if (!strcasecmp(job->format, "image/pwg-raster")) - ext = "ras"; - else if (!strcasecmp(job->format, "image/urf")) - ext = "urf"; - else if (!strcasecmp(job->format, "application/pdf")) - ext = "pdf"; - else if (!strcasecmp(job->format, "application/postscript")) - ext = "ps"; - else - ext = "prn"; - - /* - * Create a filename with the job-id, job-name, and document-format (extension)... - */ - - snprintf(fname, fnamesize, "%s/%d-%s.%s", printer->directory, job->id, name, ext); -} - - -/* - * 'create_listener()' - Create a listener socket. - */ - -static int /* O - Listener socket or -1 on error */ -create_listener(int family, /* I - Address family */ - int port) /* I - Port number */ -{ - int sock; /* Listener socket */ - http_addrlist_t *addrlist; /* Listen address */ - char service[255]; /* Service port */ - - - snprintf(service, sizeof(service), "%d", port); - if ((addrlist = httpAddrGetList(NULL, family, service)) == NULL) - return (-1); - - sock = httpAddrListen(&(addrlist->addr), port); - - httpAddrFreeList(addrlist); - - return (sock); -} - - -/* - * 'create_media_col()' - Create a media-col value. - */ - -static ipp_t * /* O - media-col collection */ -create_media_col(const char *media, /* I - Media name */ - const char *source, /* I - Media source */ - const char *type, /* I - Media type */ - int width, /* I - x-dimension in 2540ths */ - int length, /* I - y-dimension in 2540ths */ - int margins) /* I - Value for margins */ -{ - ipp_t *media_col = ippNew(), /* media-col value */ - *media_size = create_media_size(width, length); - /* media-size value */ - char media_key[256]; /* media-key value */ - - - if (type && source) - snprintf(media_key, sizeof(media_key), "%s_%s_%s%s", media, source, type, margins == 0 ? "_borderless" : ""); - else if (type) - snprintf(media_key, sizeof(media_key), "%s__%s%s", media, type, margins == 0 ? "_borderless" : ""); - else if (source) - snprintf(media_key, sizeof(media_key), "%s_%s%s", media, source, margins == 0 ? "_borderless" : ""); - else - snprintf(media_key, sizeof(media_key), "%s%s", media, margins == 0 ? "_borderless" : ""); - - ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-key", NULL, - media_key); - ippAddCollection(media_col, IPP_TAG_PRINTER, "media-size", media_size); - ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-size-name", NULL, media); - ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "media-bottom-margin", margins); - ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "media-left-margin", margins); - ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "media-right-margin", margins); - ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "media-top-margin", margins); - if (source) - ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-source", NULL, source); - if (type) - ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-type", NULL, type); - - ippDelete(media_size); - - return (media_col); -} - - -/* - * 'create_media_size()' - Create a media-size value. - */ - -static ipp_t * /* O - media-col collection */ -create_media_size(int width, /* I - x-dimension in 2540ths */ - int length) /* I - y-dimension in 2540ths */ -{ - ipp_t *media_size = ippNew(); /* media-size value */ - - - ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "x-dimension", - width); - ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "y-dimension", - length); - - return (media_size); -} - - -/* - * 'create_printer()' - Create, register, and listen for connections to a - * printer object. - */ - -static _ipp_printer_t * /* O - Printer */ -create_printer(const char *servername, /* I - Server hostname (NULL for default) */ - const char *name, /* I - printer-name */ - const char *location, /* I - printer-location */ - const char *make, /* I - printer-make-and-model */ - const char *model, /* I - printer-make-and-model */ - const char *icon, /* I - printer-icons */ - const char *docformats, /* I - document-format-supported */ - int ppm, /* I - Pages per minute in grayscale */ - int ppm_color, /* I - Pages per minute in color (0 for gray) */ - int duplex, /* I - 1 = duplex, 0 = simplex */ - int port, /* I - Port for listeners or 0 for auto */ - int pin, /* I - Require PIN printing */ - const char *subtype, /* I - Bonjour service subtype */ - const char *directory, /* I - Spool directory */ - const char *command, /* I - Command to run on job files */ - const char *attrfile) /* I - Attributes file */ -{ - int i, j; /* Looping vars */ - _ipp_printer_t *printer; /* Printer */ -#ifndef WIN32 - char path[1024]; /* Full path to command */ -#endif /* !WIN32 */ - char uri[1024], /* Printer URI */ -#ifdef HAVE_SSL - securi[1024], /* Secure printer URI */ - *uris[2], /* All URIs */ -#endif /* HAVE_SSL */ - icons[1024], /* printer-icons URI */ - adminurl[1024], /* printer-more-info URI */ - supplyurl[1024],/* printer-supply-info-uri URI */ - device_id[1024],/* printer-device-id */ - make_model[128],/* printer-make-and-model */ - uuid[128]; /* printer-uuid */ - int num_formats; /* Number of document-format-supported values */ - char *defformat, /* document-format-default value */ - *formats[100], /* document-format-supported values */ - *ptr; /* Pointer into string */ - const char *prefix; /* Prefix string */ - int num_database; /* Number of database values */ - ipp_attribute_t *media_col_database, - /* media-col-database value */ - *media_size_supported; - /* media-size-supported value */ - ipp_t *media_col_default; - /* media-col-default value */ - int media_col_index;/* Current media-col-database value */ - int k_supported; /* Maximum file size supported */ -#ifdef HAVE_STATVFS - struct statvfs spoolinfo; /* FS info for spool directory */ - double spoolsize; /* FS size */ -#elif defined(HAVE_STATFS) - struct statfs spoolinfo; /* FS info for spool directory */ - double spoolsize; /* FS size */ -#endif /* HAVE_STATVFS */ - static const int orients[4] = /* orientation-requested-supported values */ - { - IPP_ORIENT_PORTRAIT, - IPP_ORIENT_LANDSCAPE, - IPP_ORIENT_REVERSE_LANDSCAPE, - IPP_ORIENT_REVERSE_PORTRAIT - }; - static const char * const versions[] =/* ipp-versions-supported values */ - { - "1.0", - "1.1", - "2.0" - }; - static const char * const features[] =/* ipp-features-supported values */ - { - "ipp-everywhere" - }; - static const int ops[] = /* operations-supported values */ - { - IPP_OP_PRINT_JOB, - IPP_OP_PRINT_URI, - IPP_OP_VALIDATE_JOB, - IPP_OP_CREATE_JOB, - IPP_OP_SEND_DOCUMENT, - IPP_OP_SEND_URI, - IPP_OP_CANCEL_JOB, - IPP_OP_GET_JOB_ATTRIBUTES, - IPP_OP_GET_JOBS, - IPP_OP_GET_PRINTER_ATTRIBUTES, - IPP_OP_CANCEL_MY_JOBS, - IPP_OP_CLOSE_JOB, - IPP_OP_IDENTIFY_PRINTER - }; - static const char * const charsets[] =/* charset-supported values */ - { - "us-ascii", - "utf-8" - }; - static const char * const compressions[] =/* compression-supported values */ - { -#ifdef HAVE_LIBZ - "deflate", - "gzip", -#endif /* HAVE_LIBZ */ - "none" - }; - static const char * const identify_actions[] = - { - "display", - "sound" - }; - static const char * const job_creation[] = - { /* job-creation-attributes-supported values */ - "copies", - "ipp-attribute-fidelity", - "job-account-id", - "job-accounting-user-id", - "job-name", - "job-password", - "job-priority", - "media", - "media-col", - "multiple-document-handling", - "orientation-requested", - "print-quality", - "sides" - }; - static const char * const media_col_supported[] = - { /* media-col-supported values */ - "media-bottom-margin", - "media-left-margin", - "media-right-margin", - "media-size", - "media-source", - "media-top-margin", - "media-type" - }; - static const int media_xxx_margin_supported[] = - { /* media-xxx-margin-supported values */ - 0, - 635 - }; - static const char * const multiple_document_handling[] = - { /* multiple-document-handling-supported values */ - "separate-documents-uncollated-copies", - "separate-documents-collated-copies" - }; - static const char * const overrides[] = - { /* overrides-supported */ - "document-number", - "pages" - }; - static const char * const print_color_mode_supported[] = - { /* print-color-mode-supported values */ - "auto", - "color", - "monochrome" - }; - static const int print_quality_supported[] = - { /* print-quality-supported values */ - IPP_QUALITY_DRAFT, - IPP_QUALITY_NORMAL, - IPP_QUALITY_HIGH - }; - static const int pwg_raster_document_resolution_supported[] = - { - 150, - 300 - }; - static const char * const pwg_raster_document_type_supported[] = - { - "black_1", - "cmyk_8", - "sgray_8", - "srgb_8", - "srgb_16" - }; - static const char * const reference_uri_schemes_supported[] = - { /* reference-uri-schemes-supported */ - "file", - "ftp", - "http" -#ifdef HAVE_SSL - , "https" -#endif /* HAVE_SSL */ - }; - static const char * const sides_supported[] = - { /* sides-supported values */ - "one-sided", - "two-sided-long-edge", - "two-sided-short-edge" - }; - static const char * const urf_supported[] = - { /* urf-supported values */ - "CP1", - "IS1-5-7", - "MT1-2-3-4-5-6-8-9-10-11-12-13", - "RS300", - "SRGB24", - "V1.4", - "W8", - "DM1" - }; -#ifdef HAVE_SSL - static const char * const uri_authentication_supported[] = - { /* uri-authentication-supported values */ - "none", - "none" - }; - static const char * const uri_security_supported[] = - { /* uri-security-supported values */ - "none", - "tls" - }; -#endif /* HAVE_SSL */ - static const char * const which_jobs[] = - { /* which-jobs-supported values */ - "completed", - "not-completed", - "aborted", - "all", - "canceled", - "pending", - "pending-held", - "processing", - "processing-stopped" - }; - - -#ifndef WIN32 - /* - * If a command was specified, make sure it exists and is executable... - */ - - if (command) - { - if (*command == '/' || !strncmp(command, "./", 2)) - { - if (access(command, X_OK)) - { - fprintf(stderr, "ippserver: Unable to execute command \"%s\": %s\n", command, strerror(errno)); - return (NULL); - } - } - else - { - if (!cupsFileFind(command, getenv("PATH"), 1, path, sizeof(path))) - { - fprintf(stderr, "ippserver: Unable to find command \"%s\".\n", command); - return (NULL); - } - - command = path; - } - } -#endif /* !WIN32 */ - - /* - * Allocate memory for the printer... - */ - - if ((printer = calloc(1, sizeof(_ipp_printer_t))) == NULL) - { - perror("ippserver: Unable to allocate memory for printer"); - return (NULL); - } - - printer->ipv4 = -1; - printer->ipv6 = -1; - printer->name = strdup(name); - printer->dnssd_name = strdup(printer->name); - printer->command = command ? strdup(command) : NULL; - printer->directory = strdup(directory); - printer->hostname = strdup(servername); - printer->port = port; - printer->start_time = time(NULL); - printer->config_time = printer->start_time; - printer->state = IPP_PSTATE_IDLE; - printer->state_reasons = _IPP_PREASON_NONE; - printer->state_time = printer->start_time; - printer->jobs = cupsArrayNew((cups_array_func_t)compare_jobs, NULL); - printer->next_job_id = 1; - - httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, printer->hostname, printer->port, "/ipp/print"); - printer->uri = strdup(uri); - printer->urilen = strlen(uri); - -#ifdef HAVE_SSL - httpAssembleURI(HTTP_URI_CODING_ALL, securi, sizeof(securi), "ipps", NULL, printer->hostname, printer->port, "/ipp/print"); -#endif /* HAVE_SSL */ - - if (icon) - printer->icon = strdup(icon); - - printer->main_size = _IPP_MEDIA_SIZE_A4; - printer->main_type = _IPP_MEDIA_TYPE_STATIONERY; - printer->main_level = 500; - - printer->envelope_size = _IPP_MEDIA_SIZE_NONE; - printer->envelope_level = 0; - - printer->photo_size = _IPP_MEDIA_SIZE_NONE; - printer->photo_type = _IPP_MEDIA_TYPE_NONE; - printer->photo_level = 0; - - printer->supplies[_IPP_SUPPLY_CYAN] = 100; - printer->supplies[_IPP_SUPPLY_MAGENTA] = 100; - printer->supplies[_IPP_SUPPLY_YELLOW] = 100; - printer->supplies[_IPP_SUPPLY_BLACK] = 100; - printer->supplies[_IPP_SUPPLY_WASTE] = 0; - - _cupsRWInit(&(printer->rwlock)); - - /* - * Create the listener sockets... - */ - - if ((printer->ipv4 = create_listener(AF_INET, printer->port)) < 0) - { - perror("Unable to create IPv4 listener"); - goto bad_printer; - } - - if ((printer->ipv6 = create_listener(AF_INET6, printer->port)) < 0) - { - perror("Unable to create IPv6 listener"); - goto bad_printer; - } - - /* - * Prepare values for the printer attributes... - */ - - httpAssembleURI(HTTP_URI_CODING_ALL, icons, sizeof(icons), WEB_SCHEME, NULL, printer->hostname, printer->port, "/icon.png"); - httpAssembleURI(HTTP_URI_CODING_ALL, adminurl, sizeof(adminurl), WEB_SCHEME, NULL, printer->hostname, printer->port, "/"); - httpAssembleURI(HTTP_URI_CODING_ALL, supplyurl, sizeof(supplyurl), WEB_SCHEME, NULL, printer->hostname, printer->port, "/supplies"); - - if (Verbosity) - { - fprintf(stderr, "printer-more-info=\"%s\"\n", adminurl); - fprintf(stderr, "printer-supply-info-uri=\"%s\"\n", supplyurl); - fprintf(stderr, "printer-uri=\"%s\"\n", uri); - } - - snprintf(make_model, sizeof(make_model), "%s %s", make, model); - - num_formats = 1; - formats[0] = strdup(docformats); - defformat = formats[0]; - for (ptr = strchr(formats[0], ','); ptr; ptr = strchr(ptr, ',')) - { - *ptr++ = '\0'; - formats[num_formats++] = ptr; - - if (!strcasecmp(ptr, "application/octet-stream")) - defformat = ptr; - } - - snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;", make, model); - ptr = device_id + strlen(device_id); - prefix = "CMD:"; - for (i = 0; i < num_formats; i ++) - { - if (!strcasecmp(formats[i], "application/pdf")) - snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPDF", prefix); - else if (!strcasecmp(formats[i], "application/postscript")) - snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPS", prefix); - else if (!strcasecmp(formats[i], "application/vnd.hp-PCL")) - snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPCL", prefix); - else if (!strcasecmp(formats[i], "image/jpeg")) - snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sJPEG", prefix); - else if (!strcasecmp(formats[i], "image/png")) - snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPNG", prefix); - else if (strcasecmp(formats[i], "application/octet-stream")) - snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%s%s", prefix, formats[i]); - - ptr += strlen(ptr); - prefix = ","; - } - if (ptr < (device_id + sizeof(device_id) - 1)) - { - *ptr++ = ';'; - *ptr = '\0'; - } - - /* - * Get the maximum spool size based on the size of the filesystem used for - * the spool directory. If the host OS doesn't support the statfs call - * or the filesystem is larger than 2TiB, always report INT_MAX. - */ - -#ifdef HAVE_STATVFS - if (statvfs(printer->directory, &spoolinfo)) - k_supported = INT_MAX; - else if ((spoolsize = (double)spoolinfo.f_frsize * - spoolinfo.f_blocks / 1024) > INT_MAX) - k_supported = INT_MAX; - else - k_supported = (int)spoolsize; - -#elif defined(HAVE_STATFS) - if (statfs(printer->directory, &spoolinfo)) - k_supported = INT_MAX; - else if ((spoolsize = (double)spoolinfo.f_bsize * - spoolinfo.f_blocks / 1024) > INT_MAX) - k_supported = INT_MAX; - else - k_supported = (int)spoolsize; - -#else - k_supported = INT_MAX; -#endif /* HAVE_STATVFS */ - - /* - * Create the printer attributes. This list of attributes is sorted to improve - * performance when the client provides a requested-attributes attribute... - */ - - printer->attrs = ippNew(); - - if (attrfile) - load_attributes(attrfile, printer->attrs); - - /* charset-configured */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_CHARSET), "charset-configured", NULL, "utf-8"); - - /* charset-supported */ - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_CHARSET), "charset-supported", sizeof(charsets) / sizeof(charsets[0]), NULL, charsets); - - /* color-supported */ - if (!ippFindAttribute(printer->attrs, "color-supported", IPP_TAG_ZERO)) - ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "color-supported", ppm_color > 0); - - /* compression-supported */ - if (!ippFindAttribute(printer->attrs, "compression-supported", IPP_TAG_ZERO)) - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "compression-supported", (int)(sizeof(compressions) / sizeof(compressions[0])), NULL, compressions); - - /* copies-default */ - if (!ippFindAttribute(printer->attrs, "copies-default", IPP_TAG_ZERO)) - ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default", 1); - - /* copies-supported */ - if (!ippFindAttribute(printer->attrs, "copies-supported", IPP_TAG_ZERO)) - ippAddRange(printer->attrs, IPP_TAG_PRINTER, "copies-supported", 1, 999); - - /* document-format-default */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, - "document-format-default", NULL, defformat); - - /* document-format-supported */ - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, - "document-format-supported", num_formats, NULL, - (const char * const *)formats); - - /* document-password-supported */ - if (!ippFindAttribute(printer->attrs, "document-password-supported", IPP_TAG_ZERO)) - ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "document-password-supported", 127); - - /* finishings-default */ - if (!ippFindAttribute(printer->attrs, "finishings-default", IPP_TAG_ZERO)) - ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "finishings-default", IPP_FINISHINGS_NONE); - - /* finishings-supported */ - if (!ippFindAttribute(printer->attrs, "finishings-supported", IPP_TAG_ZERO)) - ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "finishings-supported", IPP_FINISHINGS_NONE); - - /* generated-natural-language-supported */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_LANGUAGE), "generated-natural-language-supported", NULL, "en"); - - /* identify-actions-default */ - if (!ippFindAttribute(printer->attrs, "identify-actions-default", IPP_TAG_ZERO)) - ippAddString (printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "identify-actions-default", NULL, "sound"); - - /* identify-actions-supported */ - if (!ippFindAttribute(printer->attrs, "identify-actions-supported", IPP_TAG_ZERO)) - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "identify-actions-supported", sizeof(identify_actions) / sizeof(identify_actions[0]), NULL, identify_actions); - - /* ipp-features-supported */ - if (!ippFindAttribute(printer->attrs, "ipp-features-supported", IPP_TAG_ZERO)) - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "ipp-features-supported", sizeof(features) / sizeof(features[0]), NULL, features); - - /* ipp-versions-supported */ - if (!ippFindAttribute(printer->attrs, "ipp-versions-supported", IPP_TAG_ZERO)) - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]), NULL, versions); - - /* job-account-id-default */ - if (!ippFindAttribute(printer->attrs, "job-account-id-default", IPP_TAG_ZERO)) - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "job-account-id-default", NULL, ""); - - /* job-account-id-supported */ - if (!ippFindAttribute(printer->attrs, "job-account-id-supported", IPP_TAG_ZERO)) - ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "job-account-id-supported", 1); - - /* job-accounting-user-id-default */ - if (!ippFindAttribute(printer->attrs, "job-accounting-user-id-default", IPP_TAG_ZERO)) - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "job-accounting-user-id-default", NULL, ""); - - /* job-accounting-user-id-supported */ - if (!ippFindAttribute(printer->attrs, "job-accounting-user-id-supported", IPP_TAG_ZERO)) - ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "job-accounting-user-id-supported", 1); - - /* job-creation-attributes-supported */ - if (!ippFindAttribute(printer->attrs, "job-creation-attributes-supported", IPP_TAG_ZERO)) - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-creation-attributes-supported", sizeof(job_creation) / sizeof(job_creation[0]), NULL, job_creation); - - /* job-ids-supported */ - ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "job-ids-supported", 1); - - /* job-k-octets-supported */ - ippAddRange(printer->attrs, IPP_TAG_PRINTER, "job-k-octets-supported", 0, - k_supported); - - /* job-password-supported */ - if (!ippFindAttribute(printer->attrs, "job-password-supported", IPP_TAG_ZERO)) - ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-password-supported", 4); - - /* job-priority-default */ - if (!ippFindAttribute(printer->attrs, "job-priority-default", IPP_TAG_ZERO)) - ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-priority-default", 50); - - /* job-priority-supported */ - if (!ippFindAttribute(printer->attrs, "job-priority-supported", IPP_TAG_ZERO)) - ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-priority-supported", 100); - - /* job-sheets-default */ - if (!ippFindAttribute(printer->attrs, "job-sheets-default", IPP_TAG_ZERO)) - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "job-sheets-default", NULL, "none"); - - /* job-sheets-supported */ - if (!ippFindAttribute(printer->attrs, "job-sheets-supported", IPP_TAG_ZERO)) - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "job-sheets-supported", NULL, "none"); - - /* media-bottom-margin-supported */ - if (!ippFindAttribute(printer->attrs, "media-bottom-margin-supported", IPP_TAG_ZERO)) - ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-bottom-margin-supported", (int)(sizeof(media_xxx_margin_supported) / sizeof(media_xxx_margin_supported[0])), media_xxx_margin_supported); - - /* media-col-database */ - if (!ippFindAttribute(printer->attrs, "media-col-database", IPP_TAG_ZERO)) - { - for (num_database = 0, i = 0; - i < (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0])); - i ++) - { - if (media_col_sizes[i][2] == _IPP_ENV_ONLY) - num_database += 3; /* auto + manual + envelope */ - else if (media_col_sizes[i][2] == _IPP_PHOTO_ONLY) - num_database += 6 * 3; /* auto + photographic-* from auto, manual, and photo */ - else - num_database += 2; /* Regular + borderless */ - } - - media_col_database = ippAddCollections(printer->attrs, IPP_TAG_PRINTER, "media-col-database", num_database, NULL); - for (media_col_index = 0, i = 0; - i < (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0])); - i ++) - { - switch (media_col_sizes[i][2]) - { - case _IPP_GENERAL : - /* - * Regular + borderless for the general class; no source/type - * selectors... - */ - - ippSetCollection(printer->attrs, &media_col_database, media_col_index ++, create_media_col(media_supported[i], NULL, NULL, media_col_sizes[i][0], media_col_sizes[i][1], media_xxx_margin_supported[1])); - ippSetCollection(printer->attrs, &media_col_database, media_col_index ++, create_media_col(media_supported[i], NULL, NULL, media_col_sizes[i][0], media_col_sizes[i][1], media_xxx_margin_supported[0])); - break; - - case _IPP_ENV_ONLY : - /* - * Regular margins for "auto", "manual", and "envelope" sources. - */ - - ippSetCollection(printer->attrs, &media_col_database, media_col_index ++, create_media_col(media_supported[i], "auto", "envelope", media_col_sizes[i][0], media_col_sizes[i][1], media_xxx_margin_supported[1])); - ippSetCollection(printer->attrs, &media_col_database, media_col_index ++, create_media_col(media_supported[i], "manual", "envelope", media_col_sizes[i][0], media_col_sizes[i][1], media_xxx_margin_supported[1])); - ippSetCollection(printer->attrs, &media_col_database, media_col_index ++, create_media_col(media_supported[i], "envelope", "envelope", media_col_sizes[i][0], media_col_sizes[i][1], media_xxx_margin_supported[1])); - break; - case _IPP_PHOTO_ONLY : - /* - * Photos have specific media types and can only be printed via - * the auto, manual, and photo sources... - */ - - for (j = 0; - j < (int)(sizeof(media_type_supported) / - sizeof(media_type_supported[0])); - j ++) - { - if (strcmp(media_type_supported[j], "auto") && strncmp(media_type_supported[j], "photographic-", 13)) - continue; - - ippSetCollection(printer->attrs, &media_col_database, media_col_index ++, create_media_col(media_supported[i], "auto", media_type_supported[j], media_col_sizes[i][0], media_col_sizes[i][1], media_xxx_margin_supported[0])); - ippSetCollection(printer->attrs, &media_col_database, media_col_index ++, create_media_col(media_supported[i], "manual", media_type_supported[j], media_col_sizes[i][0], media_col_sizes[i][1], media_xxx_margin_supported[0])); - ippSetCollection(printer->attrs, &media_col_database, media_col_index ++, create_media_col(media_supported[i], "photo", media_type_supported[j], media_col_sizes[i][0], media_col_sizes[i][1], media_xxx_margin_supported[0])); - } - break; - } - } - } - - /* media-col-default */ - if (!ippFindAttribute(printer->attrs, "media-col-default", IPP_TAG_ZERO)) - { - media_col_default = create_media_col(media_supported[0], media_source_supported[0], media_type_supported[0], media_col_sizes[0][0], media_col_sizes[0][1],media_xxx_margin_supported[1]); - - ippAddCollection(printer->attrs, IPP_TAG_PRINTER, "media-col-default", - media_col_default); - ippDelete(media_col_default); - } - - /* media-col-supported */ - if (!ippFindAttribute(printer->attrs, "media-col-supported", IPP_TAG_ZERO)) - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-col-supported", (int)(sizeof(media_col_supported) / sizeof(media_col_supported[0])), NULL, media_col_supported); - - /* media-default */ - if (!ippFindAttribute(printer->attrs, "media-default", IPP_TAG_ZERO)) - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-default", NULL, media_supported[0]); - - /* media-left-margin-supported */ - if (!ippFindAttribute(printer->attrs, "media-left-margin-supported", IPP_TAG_ZERO)) - ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-left-margin-supported", (int)(sizeof(media_xxx_margin_supported) / sizeof(media_xxx_margin_supported[0])), media_xxx_margin_supported); - - /* media-right-margin-supported */ - if (!ippFindAttribute(printer->attrs, "media-right-margin-supported", IPP_TAG_ZERO)) - ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-right-margin-supported", (int)(sizeof(media_xxx_margin_supported) / sizeof(media_xxx_margin_supported[0])), media_xxx_margin_supported); - - /* media-supported */ - if (!ippFindAttribute(printer->attrs, "media-supported", IPP_TAG_ZERO)) - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-supported", (int)(sizeof(media_supported) / sizeof(media_supported[0])), NULL, media_supported); - - /* media-size-supported */ - if (!ippFindAttribute(printer->attrs, "media-size-supported", IPP_TAG_ZERO)) - { - media_size_supported = ippAddCollections(printer->attrs, IPP_TAG_PRINTER, "media-size-supported", (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0])), NULL); - - for (i = 0; - i < (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0])); - i ++) - { - ipp_t *size = create_media_size(media_col_sizes[i][0], media_col_sizes[i][1]); - - ippSetCollection(printer->attrs, &media_size_supported, i, size); - ippDelete(size); - } - } - - /* media-source-supported */ - if (!ippFindAttribute(printer->attrs, "media-source-supported", IPP_TAG_ZERO)) - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-source-supported", (int)(sizeof(media_source_supported) / sizeof(media_source_supported[0])), NULL, media_source_supported); - - /* media-top-margin-supported */ - if (!ippFindAttribute(printer->attrs, "media-top-margin-supported", IPP_TAG_ZERO)) - ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-top-margin-supported", (int)(sizeof(media_xxx_margin_supported) / sizeof(media_xxx_margin_supported[0])), media_xxx_margin_supported); - - /* media-type-supported */ - if (!ippFindAttribute(printer->attrs, "media-type-supported", IPP_TAG_ZERO)) - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-type-supported", (int)(sizeof(media_type_supported) / sizeof(media_type_supported[0])), NULL, media_type_supported); - - /* multiple-document-handling-supported */ - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "multiple-document-handling-supported", sizeof(multiple_document_handling) / sizeof(multiple_document_handling[0]), NULL, multiple_document_handling); - - /* multiple-document-jobs-supported */ - ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "multiple-document-jobs-supported", 0); - - /* multiple-operation-time-out */ - ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "multiple-operation-time-out", 60); - - /* multiple-operation-time-out-action */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "multiple-operation-time-out-action", NULL, "abort-job"); - - /* natural-language-configured */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, - IPP_CONST_TAG(IPP_TAG_LANGUAGE), - "natural-language-configured", NULL, "en"); - - /* number-up-default */ - if (!ippFindAttribute(printer->attrs, "number-up-default", IPP_TAG_ZERO)) - ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "number-up-default", 1); - - /* number-up-supported */ - if (!ippFindAttribute(printer->attrs, "number-up-supported", IPP_TAG_ZERO)) - ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "number-up-supported", 1); - - /* operations-supported */ - ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "operations-supported", sizeof(ops) / sizeof(ops[0]), ops); - - /* orientation-requested-default */ - if (!ippFindAttribute(printer->attrs, "orientation-requested-default", IPP_TAG_ZERO)) - ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, "orientation-requested-default", 0); - - /* orientation-requested-supported */ - if (!ippFindAttribute(printer->attrs, "orientation-requested-supported", IPP_TAG_ZERO)) - ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "orientation-requested-supported", 4, orients); - - /* output-bin-default */ - if (!ippFindAttribute(printer->attrs, "output-bin-default", IPP_TAG_ZERO)) - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "output-bin-default", NULL, "face-down"); - - /* output-bin-supported */ - if (!ippFindAttribute(printer->attrs, "output-bin-supported", IPP_TAG_ZERO)) - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "output-bin-supported", NULL, "face-down"); - - /* overrides-supported */ - if (!ippFindAttribute(printer->attrs, "overrides-supported", IPP_TAG_ZERO)) - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "overrides-supported", (int)(sizeof(overrides) / sizeof(overrides[0])), NULL, overrides); - - /* page-ranges-supported */ - if (!ippFindAttribute(printer->attrs, "page-ranges-supported", IPP_TAG_ZERO)) - ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "page-ranges-supported", 1); - - /* pages-per-minute */ - ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "pages-per-minute", ppm); - - /* pages-per-minute-color */ - if (ppm_color > 0) - ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "pages-per-minute-color", ppm_color); - - /* pdl-override-supported */ - if (!ippFindAttribute(printer->attrs, "pdl-override-supported", IPP_TAG_ZERO)) - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pdl-override-supported", NULL, "attempted"); - - /* preferred-attributes-supported */ - ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "preferred-attributes-supported", 0); - - /* print-color-mode-default */ - if (!ippFindAttribute(printer->attrs, "print-color-mode-default", IPP_TAG_ZERO)) - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-color-mode-default", NULL, "auto"); - - /* print-color-mode-supported */ - if (!ippFindAttribute(printer->attrs, "print-color-mode-supported", IPP_TAG_ZERO)) - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-color-mode-supported", (int)(sizeof(print_color_mode_supported) / sizeof(print_color_mode_supported[0])), NULL, print_color_mode_supported); - - /* print-content-optimize-default */ - if (!ippFindAttribute(printer->attrs, "print-content-optimize-default", IPP_TAG_ZERO)) - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-content-optimize-default", NULL, "auto"); - - /* print-content-optimize-supported */ - if (!ippFindAttribute(printer->attrs, "print-content-optimize-supported", IPP_TAG_ZERO)) - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-content-optimize-supported", NULL, "auto"); - - /* print-rendering-intent-default */ - if (!ippFindAttribute(printer->attrs, "print-rendering-intent-default", IPP_TAG_ZERO)) - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-rendering-intent-default", NULL, "auto"); - - /* print-rendering-intent-supported */ - if (!ippFindAttribute(printer->attrs, "print-rendering-intent-supported", IPP_TAG_ZERO)) - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-rendering-intent-supported", NULL, "auto"); - - /* print-quality-default */ - if (!ippFindAttribute(printer->attrs, "print-quality-default", IPP_TAG_ZERO)) - ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "print-quality-default", IPP_QUALITY_NORMAL); - - /* print-quality-supported */ - if (!ippFindAttribute(printer->attrs, "print-quality-supported", IPP_TAG_ZERO)) - ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "print-quality-supported", (int)(sizeof(print_quality_supported) / sizeof(print_quality_supported[0])), print_quality_supported); - - /* printer-device-id */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "printer-device-id", NULL, device_id); - - /* printer-get-attributes-supported */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "printer-get-attributes-supported", NULL, "document-format"); - - /* printer-geo-location */ - if (!ippFindAttribute(printer->attrs, "printer-geo-location", IPP_TAG_ZERO)) - ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_UNKNOWN, "printer-geo-location", 0); - - /* printer-icons */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, - "printer-icons", NULL, icons); - - /* printer-is-accepting-jobs */ - ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1); - - /* printer-info */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", NULL, name); - - /* printer-location */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "printer-location", NULL, location); - - /* printer-make-and-model */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "printer-make-and-model", NULL, make_model); - - /* printer-mandatory-job-attributes */ - if (pin && !ippFindAttribute(printer->attrs, "", IPP_TAG_ZERO)) - { - static const char * const names[] = - { - "job-account-id", - "job-accounting-user-id", - "job-password" - }; - - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "printer-mandatory-job-attributes", - (int)(sizeof(names) / sizeof(names[0])), NULL, names); - } - - /* printer-more-info */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info", NULL, adminurl); - - /* printer-name */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL, name); - - /* printer-organization */ - if (!ippFindAttribute(printer->attrs, "printer-organization", IPP_TAG_ZERO)) - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-organization", NULL, "Apple Inc."); - - /* printer-organizational-unit */ - if (!ippFindAttribute(printer->attrs, "printer-organizational-unit", IPP_TAG_ZERO)) - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-organizational-unit", NULL, "Printing Engineering"); - - /* printer-resolution-default */ - if (!ippFindAttribute(printer->attrs, "printer-resolution-default", IPP_TAG_ZERO)) - ippAddResolution(printer->attrs, IPP_TAG_PRINTER, "printer-resolution-default", IPP_RES_PER_INCH, 600, 600); - - /* printer-resolution-supported */ - if (!ippFindAttribute(printer->attrs, "printer-resolutions-supported", IPP_TAG_ZERO)) - ippAddResolution(printer->attrs, IPP_TAG_PRINTER, "printer-resolution-supported", IPP_RES_PER_INCH, 600, 600); - - /* printer-supply-description */ - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-supply-description", (int)(sizeof(printer_supplies) / sizeof(printer_supplies[0])), NULL, printer_supplies); - - /* printer-supply-info-uri */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-supply-info-uri", NULL, supplyurl); - - /* printer-uri-supported */ -#ifdef HAVE_SSL - uris[0] = uri; - uris[1] = securi; - - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", 2, NULL, (const char **)uris); - -#else - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", NULL, uri); -#endif /* HAVE_SSL */ - - /* printer-uuid */ - httpAssembleUUID(printer->hostname, port, name, 0, uuid, sizeof(uuid)); - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uuid", NULL, uuid); - - /* pwg-raster-document-xxx-supported */ - for (i = 0; i < num_formats; i ++) - if (!strcasecmp(formats[i], "image/pwg-raster")) - break; - - if (i < num_formats) - { - if (!ippFindAttribute(printer->attrs, "pwg-raster-document-resolution-supported", IPP_TAG_ZERO)) - ippAddResolutions(printer->attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", (int)(sizeof(pwg_raster_document_resolution_supported) / sizeof(pwg_raster_document_resolution_supported[0])), IPP_RES_PER_INCH, pwg_raster_document_resolution_supported, pwg_raster_document_resolution_supported); - if (!ippFindAttribute(printer->attrs, "pwg-raster-document-sheet-back", IPP_TAG_ZERO)) - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "pwg-raster-document-sheet-back", NULL, "normal"); - if (!ippFindAttribute(printer->attrs, "pwg-raster-document-type-supported", IPP_TAG_ZERO)) - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "pwg-raster-document-type-supported", (int)(sizeof(pwg_raster_document_type_supported) / sizeof(pwg_raster_document_type_supported[0])), NULL, pwg_raster_document_type_supported); - } - - /* reference-uri-scheme-supported */ - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_URISCHEME), "reference-uri-schemes-supported", (int)(sizeof(reference_uri_schemes_supported) / sizeof(reference_uri_schemes_supported[0])), NULL, reference_uri_schemes_supported); - - /* sides-default */ - if (!ippFindAttribute(printer->attrs, "sides-default", IPP_TAG_ZERO)) - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-default", NULL, "one-sided"); - - /* sides-supported */ - if (!ippFindAttribute(printer->attrs, "sides-supported", IPP_TAG_ZERO)) - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-supported", duplex ? 3 : 1, NULL, sides_supported); - - /* urf-supported */ - for (i = 0; i < num_formats; i ++) - if (!strcasecmp(formats[i], "image/urf")) - break; - - if (i < num_formats && !ippFindAttribute(printer->attrs, "urf-supported", IPP_TAG_ZERO)) - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "urf-supported", (int)(sizeof(urf_supported) / sizeof(urf_supported[0])) - !duplex, NULL, urf_supported); - - /* uri-authentication-supported */ -#ifdef HAVE_SSL - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "uri-authentication-supported", 2, NULL, uri_authentication_supported); -#else - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "uri-authentication-supported", NULL, "none"); -#endif /* HAVE_SSL */ - - /* uri-security-supported */ -#ifdef HAVE_SSL - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "uri-security-supported", 2, NULL, uri_security_supported); -#else - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "uri-security-supported", NULL, "none"); -#endif /* HAVE_SSL */ - - /* which-jobs-supported */ - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "which-jobs-supported", sizeof(which_jobs) / sizeof(which_jobs[0]), NULL, which_jobs); - - free(formats[0]); - - debug_attributes("Printer", printer->attrs, 0); - - /* - * Register the printer with Bonjour... - */ - - if (!register_printer(printer, location, make, model, docformats, adminurl, uuid + 9, ppm_color > 0, duplex, subtype)) - goto bad_printer; - - /* - * Return it! - */ - - return (printer); - - - /* - * If we get here we were unable to create the printer... - */ - - bad_printer: - - delete_printer(printer); - return (NULL); -} - - -/* - * 'debug_attributes()' - Print attributes in a request or response. - */ - -static void -debug_attributes(const char *title, /* I - Title */ - ipp_t *ipp, /* I - Request/response */ - int type) /* I - 0 = object, 1 = request, 2 = response */ -{ - ipp_tag_t group_tag; /* Current group */ - ipp_attribute_t *attr; /* Current attribute */ - char buffer[2048]; /* String buffer for value */ - int major, minor; /* Version */ - - - if (Verbosity <= 1) - return; - - fprintf(stderr, "%s:\n", title); - major = ippGetVersion(ipp, &minor); - fprintf(stderr, " version=%d.%d\n", major, minor); - if (type == 1) - fprintf(stderr, " operation-id=%s(%04x)\n", - ippOpString(ippGetOperation(ipp)), ippGetOperation(ipp)); - else if (type == 2) - fprintf(stderr, " status-code=%s(%04x)\n", - ippErrorString(ippGetStatusCode(ipp)), ippGetStatusCode(ipp)); - fprintf(stderr, " request-id=%d\n\n", ippGetRequestId(ipp)); - - for (attr = ippFirstAttribute(ipp), group_tag = IPP_TAG_ZERO; - attr; - attr = ippNextAttribute(ipp)) - { - if (ippGetGroupTag(attr) != group_tag) - { - group_tag = ippGetGroupTag(attr); - fprintf(stderr, " %s\n", ippTagString(group_tag)); - } - - if (ippGetName(attr)) - { - ippAttributeString(attr, buffer, sizeof(buffer)); - fprintf(stderr, " %s (%s%s) %s\n", ippGetName(attr), - ippGetCount(attr) > 1 ? "1setOf " : "", - ippTagString(ippGetValueTag(attr)), buffer); - } - } -} - - -/* - * 'delete_client()' - Close the socket and free all memory used by a client - * object. - */ - -static void -delete_client(_ipp_client_t *client) /* I - Client */ -{ - if (Verbosity) - fprintf(stderr, "Closing connection from %s\n", client->hostname); - - /* - * Flush pending writes before closing... - */ - - httpFlushWrite(client->http); - - /* - * Free memory... - */ - - httpClose(client->http); - - ippDelete(client->request); - ippDelete(client->response); - - free(client); -} - - -/* - * 'delete_job()' - Remove from the printer and free all memory used by a job - * object. - */ - -static void -delete_job(_ipp_job_t *job) /* I - Job */ -{ - if (Verbosity) - fprintf(stderr, "Removing job #%d from history.\n", job->id); - - ippDelete(job->attrs); - - if (job->filename) - { - if (!KeepFiles) - unlink(job->filename); - - free(job->filename); - } - - free(job); -} - - -/* - * 'delete_printer()' - Unregister, close listen sockets, and free all memory - * used by a printer object. - */ - -static void -delete_printer(_ipp_printer_t *printer) /* I - Printer */ -{ - if (printer->ipv4 >= 0) - close(printer->ipv4); - - if (printer->ipv6 >= 0) - close(printer->ipv6); - -#if HAVE_DNSSD - if (printer->printer_ref) - DNSServiceRefDeallocate(printer->printer_ref); - if (printer->ipp_ref) - DNSServiceRefDeallocate(printer->ipp_ref); - if (printer->ipps_ref) - DNSServiceRefDeallocate(printer->ipps_ref); - if (printer->http_ref) - DNSServiceRefDeallocate(printer->http_ref); -#elif defined(HAVE_AVAHI) - avahi_threaded_poll_lock(DNSSDMaster); - - if (printer->printer_ref) - avahi_entry_group_free(printer->printer_ref); - if (printer->ipp_ref) - avahi_entry_group_free(printer->ipp_ref); - if (printer->ipps_ref) - avahi_entry_group_free(printer->ipps_ref); - if (printer->http_ref) - avahi_entry_group_free(printer->http_ref); - - avahi_threaded_poll_unlock(DNSSDMaster); -#endif /* HAVE_DNSSD */ - - if (printer->dnssd_name) - free(printer->dnssd_name); - if (printer->name) - free(printer->name); - if (printer->icon) - free(printer->icon); - if (printer->command) - free(printer->command); - if (printer->directory) - free(printer->directory); - if (printer->hostname) - free(printer->hostname); - if (printer->uri) - free(printer->uri); - - ippDelete(printer->attrs); - cupsArrayDelete(printer->jobs); - - free(printer); -} - - -#ifdef HAVE_DNSSD -/* - * 'dnssd_callback()' - Handle Bonjour registration events. - */ - -static void DNSSD_API -dnssd_callback( - DNSServiceRef sdRef, /* I - Service reference */ - DNSServiceFlags flags, /* I - Status flags */ - DNSServiceErrorType errorCode, /* I - Error, if any */ - const char *name, /* I - Service name */ - const char *regtype, /* I - Service type */ - const char *domain, /* I - Domain for service */ - _ipp_printer_t *printer) /* I - Printer */ -{ - (void)sdRef; - (void)flags; - (void)domain; - - if (errorCode) - { - fprintf(stderr, "DNSServiceRegister for %s failed with error %d.\n", - regtype, (int)errorCode); - return; - } - else if (strcasecmp(name, printer->dnssd_name)) - { - if (Verbosity) - fprintf(stderr, "Now using DNS-SD service name \"%s\".\n", name); - - /* No lock needed since only the main thread accesses/changes this */ - free(printer->dnssd_name); - printer->dnssd_name = strdup(name); - } -} - - -#elif defined(HAVE_AVAHI) -/* - * 'dnssd_callback()' - Handle Bonjour registration events. - */ - -static void -dnssd_callback( - AvahiEntryGroup *srv, /* I - Service */ - AvahiEntryGroupState state, /* I - Registration state */ - void *context) /* I - Printer */ -{ - (void)srv; - (void)state; - (void)context; -} - - -/* - * 'dnssd_client_cb()' - Client callback for Avahi. - * - * Called whenever the client or server state changes... - */ - -static void -dnssd_client_cb( - AvahiClient *c, /* I - Client */ - AvahiClientState state, /* I - Current state */ - void *userdata) /* I - User data (unused) */ -{ - (void)userdata; - - if (!c) - return; - - switch (state) - { - default : - fprintf(stderr, "Ignore Avahi state %d.\n", state); - break; - - case AVAHI_CLIENT_FAILURE: - if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) - { - fputs("Avahi server crashed, exiting.\n", stderr); - exit(1); - } - break; - } -} -#endif /* HAVE_DNSSD */ - - -/* - * 'dnssd_init()' - Initialize the DNS-SD service connections... - */ - -static void -dnssd_init(void) -{ -#ifdef HAVE_DNSSD - if (DNSServiceCreateConnection(&DNSSDMaster) != kDNSServiceErr_NoError) - { - fputs("Error: Unable to initialize Bonjour.\n", stderr); - exit(1); - } - -#elif defined(HAVE_AVAHI) - int error; /* Error code, if any */ - - if ((DNSSDMaster = avahi_threaded_poll_new()) == NULL) - { - fputs("Error: Unable to initialize Bonjour.\n", stderr); - exit(1); - } - - if ((DNSSDClient = avahi_client_new(avahi_threaded_poll_get(DNSSDMaster), AVAHI_CLIENT_NO_FAIL, dnssd_client_cb, NULL, &error)) == NULL) - { - fputs("Error: Unable to initialize Bonjour.\n", stderr); - exit(1); - } - - avahi_threaded_poll_start(DNSSDMaster); -#endif /* HAVE_DNSSD */ -} - - -/* - * 'filter_cb()' - Filter printer attributes based on the requested array. - */ - -static int /* O - 1 to copy, 0 to ignore */ -filter_cb(_ipp_filter_t *filter, /* I - Filter parameters */ - ipp_t *dst, /* I - Destination (unused) */ - ipp_attribute_t *attr) /* I - Source attribute */ -{ - /* - * Filter attributes as needed... - */ - -#ifndef WIN32 /* Avoid MS compiler bug */ - (void)dst; -#endif /* !WIN32 */ - - ipp_tag_t group = ippGetGroupTag(attr); - const char *name = ippGetName(attr); - - if ((filter->group_tag != IPP_TAG_ZERO && group != filter->group_tag && group != IPP_TAG_ZERO) || !name || (!strcmp(name, "media-col-database") && !cupsArrayFind(filter->ra, (void *)name))) - return (0); - - return (!filter->ra || cupsArrayFind(filter->ra, (void *)name) != NULL); -} - - -/* - * 'find_job()' - Find a job specified in a request. - */ - -static _ipp_job_t * /* O - Job or NULL */ -find_job(_ipp_client_t *client) /* I - Client */ -{ - ipp_attribute_t *attr; /* job-id or job-uri attribute */ - _ipp_job_t key, /* Job search key */ - *job; /* Matching job, if any */ - - - if ((attr = ippFindAttribute(client->request, "job-uri", IPP_TAG_URI)) != NULL) - { - const char *uri = ippGetString(attr, 0, NULL); - - if (!strncmp(uri, client->printer->uri, client->printer->urilen) && - uri[client->printer->urilen] == '/') - key.id = atoi(uri + client->printer->urilen + 1); - else - return (NULL); - } - else if ((attr = ippFindAttribute(client->request, "job-id", IPP_TAG_INTEGER)) != NULL) - key.id = ippGetInteger(attr, 0); - - _cupsRWLockRead(&(client->printer->rwlock)); - job = (_ipp_job_t *)cupsArrayFind(client->printer->jobs, &key); - _cupsRWUnlock(&(client->printer->rwlock)); - - return (job); -} - - -/* - * 'get_collection()' - Get a collection value from a file. - */ - -static ipp_t * /* O - Collection value */ -get_collection(FILE *fp, /* I - File to read from */ - const char *filename, /* I - Attributes filename */ - int *linenum) /* IO - Line number */ -{ - char token[1024], /* Token from file */ - attr[128]; /* Attribute name */ - ipp_tag_t value; /* Current value type */ - ipp_t *col = ippNew(); /* Collection value */ - ipp_attribute_t *lastcol = NULL; /* Last collection attribute */ - - - while (get_token(fp, token, sizeof(token), linenum) != NULL) - { - if (!strcmp(token, "}")) - break; - else if (!strcmp(token, "{") && lastcol) - { - /* - * Another collection value - */ - - ipp_t *subcol = get_collection(fp, filename, linenum); - /* Collection value */ - - if (subcol) - ippSetCollection(col, &lastcol, ippGetCount(lastcol), subcol); - else - goto col_error; - } - else if (!_cups_strcasecmp(token, "MEMBER")) - { - /* - * Attribute... - */ - - lastcol = NULL; - - if (!get_token(fp, token, sizeof(token), linenum)) - { - fprintf(stderr, "ippserver: Missing MEMBER value tag on line %d of \"%s\".\n", *linenum, filename); - goto col_error; - } - - if ((value = ippTagValue(token)) == IPP_TAG_ZERO) - { - fprintf(stderr, "ippserver: Bad MEMBER value tag \"%s\" on line %d of \"%s\".\n", token, *linenum, filename); - goto col_error; - } - - if (!get_token(fp, attr, sizeof(attr), linenum)) - { - fprintf(stderr, "ippserver: Missing MEMBER name on line %d of \"%s\".\n", *linenum, filename); - goto col_error; - } - - if (!get_token(fp, token, sizeof(token), linenum)) - { - fprintf(stderr, "ippserver: Missing MEMBER value on line %d of \"%s\".\n", *linenum, filename); - goto col_error; - } - - switch (value) - { - case IPP_TAG_BOOLEAN : - if (!_cups_strcasecmp(token, "true")) - ippAddBoolean(col, IPP_TAG_ZERO, attr, 1); - else - ippAddBoolean(col, IPP_TAG_ZERO, attr, (char)atoi(token)); - break; - - case IPP_TAG_INTEGER : - case IPP_TAG_ENUM : - ippAddInteger(col, IPP_TAG_ZERO, value, attr, atoi(token)); - break; - - case IPP_TAG_RESOLUTION : - { - int xres, /* X resolution */ - yres; /* Y resolution */ - char units[6]; /* Units */ - - if (sscanf(token, "%dx%d%5s", &xres, &yres, units) != 3 || - (_cups_strcasecmp(units, "dpi") && - _cups_strcasecmp(units, "dpc") && - _cups_strcasecmp(units, "dpcm") && - _cups_strcasecmp(units, "other"))) - { - fprintf(stderr, "ippserver: Bad resolution value \"%s\" on line %d of \"%s\".\n", token, *linenum, filename); - goto col_error; - } - - if (!_cups_strcasecmp(units, "dpi")) - ippAddResolution(col, IPP_TAG_ZERO, attr, IPP_RES_PER_INCH, xres, yres); - else if (!_cups_strcasecmp(units, "dpc") || - !_cups_strcasecmp(units, "dpcm")) - ippAddResolution(col, IPP_TAG_ZERO, attr, IPP_RES_PER_CM, xres, yres); - else - ippAddResolution(col, IPP_TAG_ZERO, attr, (ipp_res_t)0, xres, yres); - } - break; - - case IPP_TAG_RANGE : - { - int lowers[4], /* Lower value */ - uppers[4], /* Upper values */ - num_vals; /* Number of values */ - - - num_vals = sscanf(token, "%d-%d,%d-%d,%d-%d,%d-%d", - lowers + 0, uppers + 0, - lowers + 1, uppers + 1, - lowers + 2, uppers + 2, - lowers + 3, uppers + 3); - - if ((num_vals & 1) || num_vals == 0) - { - fprintf(stderr, "ippserver: Bad rangeOfInteger value \"%s\" on line %d of \"%s\".\n", token, *linenum, filename); - goto col_error; - } - - ippAddRanges(col, IPP_TAG_ZERO, attr, num_vals / 2, lowers, - uppers); - } - break; - - case IPP_TAG_BEGIN_COLLECTION : - if (!strcmp(token, "{")) - { - ipp_t *subcol = get_collection(fp, filename, linenum); - /* Collection value */ - - if (subcol) - { - lastcol = ippAddCollection(col, IPP_TAG_ZERO, attr, subcol); - ippDelete(subcol); - } - else - goto col_error; - } - else - { - fprintf(stderr, "ippserver: Bad collection value on line %d of \"%s\".\n", *linenum, filename); - goto col_error; - } - break; - case IPP_TAG_STRING : - ippAddOctetString(col, IPP_TAG_ZERO, attr, token, (int)strlen(token)); - break; - - default : - if (!strchr(token, ',')) - ippAddString(col, IPP_TAG_ZERO, value, attr, NULL, token); - else - { - /* - * Multiple string values... - */ - - int num_values; /* Number of values */ - char *values[100], /* Values */ - *ptr; /* Pointer to next value */ - - - values[0] = token; - num_values = 1; - - for (ptr = strchr(token, ','); ptr; ptr = strchr(ptr, ',')) - { - *ptr++ = '\0'; - values[num_values] = ptr; - num_values ++; - if (num_values >= (int)(sizeof(values) / sizeof(values[0]))) - break; - } - - ippAddStrings(col, IPP_TAG_ZERO, value, attr, num_values, - NULL, (const char **)values); - } - break; - } - } - } - - return (col); - - /* - * If we get here there was a parse error; free memory and return. - */ - - col_error: - - ippDelete(col); - - return (NULL); -} - - -/* - * 'get_token()' - Get a token from a file. - */ - -static char * /* O - Token from file or NULL on EOF */ -get_token(FILE *fp, /* I - File to read from */ - char *buf, /* I - Buffer to read into */ - int buflen, /* I - Length of buffer */ - int *linenum) /* IO - Current line number */ -{ - int ch, /* Character from file */ - quote; /* Quoting character */ - char *bufptr, /* Pointer into buffer */ - *bufend; /* End of buffer */ - - - for (;;) - { - /* - * Skip whitespace... - */ - - while (isspace(ch = getc(fp))) - { - if (ch == '\n') - (*linenum) ++; - } - - /* - * Read a token... - */ - - if (ch == EOF) - return (NULL); - else if (ch == '\'' || ch == '\"') - { - /* - * Quoted text or regular expression... - */ - - quote = ch; - bufptr = buf; - bufend = buf + buflen - 1; - - while ((ch = getc(fp)) != EOF) - { - if (ch == '\\') - { - /* - * Escape next character... - */ - - if (bufptr < bufend) - *bufptr++ = (char)ch; - - if ((ch = getc(fp)) != EOF && bufptr < bufend) - *bufptr++ = (char)ch; - } - else if (ch == quote) - break; - else if (bufptr < bufend) - *bufptr++ = (char)ch; - } - - *bufptr = '\0'; - - return (buf); - } - else if (ch == '#') - { - /* - * Comment... - */ - - while ((ch = getc(fp)) != EOF) - if (ch == '\n') - break; - - (*linenum) ++; - } - else if (ch == '{' || ch == '}' || ch == ',') - { - buf[0] = (char)ch; - buf[1] = '\0'; - - return (buf); - } - else - { - /* - * Whitespace delimited text... - */ - - ungetc(ch, fp); - - bufptr = buf; - bufend = buf + buflen - 1; - - while ((ch = getc(fp)) != EOF) - if (isspace(ch) || ch == '#') - break; - else if (bufptr < bufend) - *bufptr++ = (char)ch; - - if (ch == '#') - ungetc(ch, fp); - else if (ch == '\n') - (*linenum) ++; - - *bufptr = '\0'; - - return (buf); - } - } -} - - -/* - * 'html_escape()' - Write a HTML-safe string. - */ - -static void -html_escape(_ipp_client_t *client, /* I - Client */ - const char *s, /* I - String to write */ - size_t slen) /* I - Number of characters to write */ -{ - const char *start, /* Start of segment */ - *end; /* End of string */ - - - start = s; - end = s + (slen > 0 ? slen : strlen(s)); - - while (*s && s < end) - { - if (*s == '&' || *s == '<') - { - if (s > start) - httpWrite2(client->http, start, (size_t)(s - start)); - - if (*s == '&') - httpWrite2(client->http, "&", 5); - else - httpWrite2(client->http, "<", 4); - - start = s + 1; - } - - s ++; - } - - if (s > start) - httpWrite2(client->http, start, (size_t)(s - start)); -} - - -/* - * 'html_footer()' - Show the web interface footer. - * - * This function also writes the trailing 0-length chunk. - */ - -static void -html_footer(_ipp_client_t *client) /* I - Client */ -{ - html_printf(client, - "\n" - "\n" - "\n"); - httpWrite2(client->http, "", 0); -} - - -/* - * 'html_header()' - Show the web interface header and title. - */ - -static void -html_header(_ipp_client_t *client, /* I - Client */ - const char *title) /* I - Title */ -{ - html_printf(client, - "\n" - "\n" - "\n" - "%s\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "" - "" - "" - "" - "
StatusSuppliesMedia
\n" - "
\n", title, !strcmp(client->uri, "/") ? " sel" : "", !strcmp(client->uri, "/supplies") ? " sel" : "", !strcmp(client->uri, "/media") ? " sel" : ""); -} - - -/* - * 'html_printf()' - Send formatted text to the client, quoting as needed. - */ - -static void -html_printf(_ipp_client_t *client, /* I - Client */ - const char *format, /* I - Printf-style format string */ - ...) /* I - Additional arguments as needed */ -{ - va_list ap; /* Pointer to arguments */ - const char *start; /* Start of string */ - char size, /* Size character (h, l, L) */ - type; /* Format type character */ - int width, /* Width of field */ - prec; /* Number of characters of precision */ - char tformat[100], /* Temporary format string for sprintf() */ - *tptr, /* Pointer into temporary format */ - temp[1024]; /* Buffer for formatted numbers */ - char *s; /* Pointer to string */ - - - /* - * Loop through the format string, formatting as needed... - */ - - va_start(ap, format); - start = format; - - while (*format) - { - if (*format == '%') - { - if (format > start) - httpWrite2(client->http, start, (size_t)(format - start)); - - tptr = tformat; - *tptr++ = *format++; - - if (*format == '%') - { - httpWrite2(client->http, "%", 1); - format ++; - start = format; - continue; - } - else if (strchr(" -+#\'", *format)) - *tptr++ = *format++; - - if (*format == '*') - { - /* - * Get width from argument... - */ - - format ++; - width = va_arg(ap, int); - - snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", width); - tptr += strlen(tptr); - } - else - { - width = 0; - - while (isdigit(*format & 255)) - { - if (tptr < (tformat + sizeof(tformat) - 1)) - *tptr++ = *format; - - width = width * 10 + *format++ - '0'; - } - } - - if (*format == '.') - { - if (tptr < (tformat + sizeof(tformat) - 1)) - *tptr++ = *format; - - format ++; - - if (*format == '*') - { - /* - * Get precision from argument... - */ - - format ++; - prec = va_arg(ap, int); - - snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", prec); - tptr += strlen(tptr); - } - else - { - prec = 0; - - while (isdigit(*format & 255)) - { - if (tptr < (tformat + sizeof(tformat) - 1)) - *tptr++ = *format; - - prec = prec * 10 + *format++ - '0'; - } - } - } - - if (*format == 'l' && format[1] == 'l') - { - size = 'L'; - - if (tptr < (tformat + sizeof(tformat) - 2)) - { - *tptr++ = 'l'; - *tptr++ = 'l'; - } - - format += 2; - } - else if (*format == 'h' || *format == 'l' || *format == 'L') - { - if (tptr < (tformat + sizeof(tformat) - 1)) - *tptr++ = *format; - - size = *format++; - } - else - size = 0; - - - if (!*format) - { - start = format; - break; - } - - if (tptr < (tformat + sizeof(tformat) - 1)) - *tptr++ = *format; - - type = *format++; - *tptr = '\0'; - start = format; - - switch (type) - { - case 'E' : /* Floating point formats */ - case 'G' : - case 'e' : - case 'f' : - case 'g' : - if ((size_t)(width + 2) > sizeof(temp)) - break; - - sprintf(temp, tformat, va_arg(ap, double)); - - httpWrite2(client->http, temp, strlen(temp)); - break; - - case 'B' : /* Integer formats */ - case 'X' : - case 'b' : - case 'd' : - case 'i' : - case 'o' : - case 'u' : - case 'x' : - if ((size_t)(width + 2) > sizeof(temp)) - break; - -# ifdef HAVE_LONG_LONG - if (size == 'L') - sprintf(temp, tformat, va_arg(ap, long long)); - else -# endif /* HAVE_LONG_LONG */ - if (size == 'l') - sprintf(temp, tformat, va_arg(ap, long)); - else - sprintf(temp, tformat, va_arg(ap, int)); - - httpWrite2(client->http, temp, strlen(temp)); - break; - - case 'p' : /* Pointer value */ - if ((size_t)(width + 2) > sizeof(temp)) - break; - - sprintf(temp, tformat, va_arg(ap, void *)); - - httpWrite2(client->http, temp, strlen(temp)); - break; - - case 'c' : /* Character or character array */ - if (width <= 1) - { - temp[0] = (char)va_arg(ap, int); - temp[1] = '\0'; - html_escape(client, temp, 1); - } - else - html_escape(client, va_arg(ap, char *), (size_t)width); - break; - - case 's' : /* String */ - if ((s = va_arg(ap, char *)) == NULL) - s = "(null)"; - - html_escape(client, s, strlen(s)); - break; - } - } - else - format ++; - } - - if (format > start) - httpWrite2(client->http, start, (size_t)(format - start)); - - va_end(ap); -} - - -/* - * 'ipp_cancel_job()' - Cancel a job. - */ - -static void -ipp_cancel_job(_ipp_client_t *client) /* I - Client */ -{ - _ipp_job_t *job; /* Job information */ - - - /* - * Get the job... - */ - - if ((job = find_job(client)) == NULL) - { - respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job does not exist."); - return; - } - - /* - * See if the job is already completed, canceled, or aborted; if so, - * we can't cancel... - */ - - switch (job->state) - { - case IPP_JSTATE_CANCELED : - respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, - "Job #%d is already canceled - can\'t cancel.", job->id); - break; - - case IPP_JSTATE_ABORTED : - respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, - "Job #%d is already aborted - can\'t cancel.", job->id); - break; - - case IPP_JSTATE_COMPLETED : - respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, - "Job #%d is already completed - can\'t cancel.", job->id); - break; - - default : - /* - * Cancel the job... - */ - - _cupsRWLockWrite(&(client->printer->rwlock)); - - if (job->state == IPP_JSTATE_PROCESSING || - (job->state == IPP_JSTATE_HELD && job->fd >= 0)) - job->cancel = 1; - else - { - job->state = IPP_JSTATE_CANCELED; - job->completed = time(NULL); - } - - _cupsRWUnlock(&(client->printer->rwlock)); - - respond_ipp(client, IPP_STATUS_OK, NULL); - break; - } -} - - -/* - * 'ipp_close_job()' - Close an open job. - */ - -static void -ipp_close_job(_ipp_client_t *client) /* I - Client */ -{ - _ipp_job_t *job; /* Job information */ - - - /* - * Get the job... - */ - - if ((job = find_job(client)) == NULL) - { - respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job does not exist."); - return; - } - - /* - * See if the job is already completed, canceled, or aborted; if so, - * we can't cancel... - */ - - switch (job->state) - { - case IPP_JSTATE_CANCELED : - respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, - "Job #%d is canceled - can\'t close.", job->id); - break; - - case IPP_JSTATE_ABORTED : - respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, - "Job #%d is aborted - can\'t close.", job->id); - break; - - case IPP_JSTATE_COMPLETED : - respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, - "Job #%d is completed - can\'t close.", job->id); - break; - - case IPP_JSTATE_PROCESSING : - case IPP_JSTATE_STOPPED : - respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, - "Job #%d is already closed.", job->id); - break; - - default : - respond_ipp(client, IPP_STATUS_OK, NULL); - break; - } -} - - -/* - * 'ipp_create_job()' - Create a job object. - */ - -static void -ipp_create_job(_ipp_client_t *client) /* I - Client */ -{ - _ipp_job_t *job; /* New job */ - cups_array_t *ra; /* Attributes to send in response */ - - - /* - * Validate print job attributes... - */ - - if (!valid_job_attributes(client)) - { - httpFlush(client->http); - return; - } - - /* - * Do we have a file to print? - */ - - if (httpGetState(client->http) == HTTP_STATE_POST_RECV) - { - respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, - "Unexpected document data following request."); - return; - } - - /* - * Create the job... - */ - - if ((job = create_job(client)) == NULL) - { - respond_ipp(client, IPP_STATUS_ERROR_BUSY, - "Currently printing another job."); - return; - } - - /* - * Return the job info... - */ - - respond_ipp(client, IPP_STATUS_OK, NULL); - - ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); - cupsArrayAdd(ra, "job-id"); - cupsArrayAdd(ra, "job-state"); - cupsArrayAdd(ra, "job-state-message"); - cupsArrayAdd(ra, "job-state-reasons"); - cupsArrayAdd(ra, "job-uri"); - - copy_job_attributes(client, job, ra); - cupsArrayDelete(ra); -} - - -/* - * 'ipp_get_job_attributes()' - Get the attributes for a job object. - */ - -static void -ipp_get_job_attributes( - _ipp_client_t *client) /* I - Client */ -{ - _ipp_job_t *job; /* Job */ - cups_array_t *ra; /* requested-attributes */ - - - if ((job = find_job(client)) == NULL) - { - respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job not found."); - return; - } - - respond_ipp(client, IPP_STATUS_OK, NULL); - - ra = ippCreateRequestedArray(client->request); - copy_job_attributes(client, job, ra); - cupsArrayDelete(ra); -} - - -/* - * 'ipp_get_jobs()' - Get a list of job objects. - */ - -static void -ipp_get_jobs(_ipp_client_t *client) /* I - Client */ -{ - ipp_attribute_t *attr; /* Current attribute */ - const char *which_jobs = NULL; - /* which-jobs values */ - int job_comparison; /* Job comparison */ - ipp_jstate_t job_state; /* job-state value */ - int first_job_id, /* First job ID */ - limit, /* Maximum number of jobs to return */ - count; /* Number of jobs that match */ - const char *username; /* Username */ - _ipp_job_t *job; /* Current job pointer */ - cups_array_t *ra; /* Requested attributes array */ - - - /* - * See if the "which-jobs" attribute have been specified... - */ - - if ((attr = ippFindAttribute(client->request, "which-jobs", - IPP_TAG_KEYWORD)) != NULL) - { - which_jobs = ippGetString(attr, 0, NULL); - fprintf(stderr, "%s Get-Jobs which-jobs=%s", client->hostname, which_jobs); - } - - if (!which_jobs || !strcmp(which_jobs, "not-completed")) - { - job_comparison = -1; - job_state = IPP_JSTATE_STOPPED; - } - else if (!strcmp(which_jobs, "completed")) - { - job_comparison = 1; - job_state = IPP_JSTATE_CANCELED; - } - else if (!strcmp(which_jobs, "aborted")) - { - job_comparison = 0; - job_state = IPP_JSTATE_ABORTED; - } - else if (!strcmp(which_jobs, "all")) - { - job_comparison = 1; - job_state = IPP_JSTATE_PENDING; - } - else if (!strcmp(which_jobs, "canceled")) - { - job_comparison = 0; - job_state = IPP_JSTATE_CANCELED; - } - else if (!strcmp(which_jobs, "pending")) - { - job_comparison = 0; - job_state = IPP_JSTATE_PENDING; - } - else if (!strcmp(which_jobs, "pending-held")) - { - job_comparison = 0; - job_state = IPP_JSTATE_HELD; - } - else if (!strcmp(which_jobs, "processing")) - { - job_comparison = 0; - job_state = IPP_JSTATE_PROCESSING; - } - else if (!strcmp(which_jobs, "processing-stopped")) - { - job_comparison = 0; - job_state = IPP_JSTATE_STOPPED; - } - else - { - respond_ipp(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, - "The which-jobs value \"%s\" is not supported.", which_jobs); - ippAddString(client->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, - "which-jobs", NULL, which_jobs); - return; - } - - /* - * See if they want to limit the number of jobs reported... - */ - - if ((attr = ippFindAttribute(client->request, "limit", - IPP_TAG_INTEGER)) != NULL) - { - limit = ippGetInteger(attr, 0); - - fprintf(stderr, "%s Get-Jobs limit=%d", client->hostname, limit); - } - else - limit = 0; - - if ((attr = ippFindAttribute(client->request, "first-job-id", - IPP_TAG_INTEGER)) != NULL) - { - first_job_id = ippGetInteger(attr, 0); - - fprintf(stderr, "%s Get-Jobs first-job-id=%d", client->hostname, - first_job_id); - } - else - first_job_id = 1; - - /* - * See if we only want to see jobs for a specific user... - */ - - username = NULL; - - if ((attr = ippFindAttribute(client->request, "my-jobs", - IPP_TAG_BOOLEAN)) != NULL) - { - int my_jobs = ippGetBoolean(attr, 0); - - fprintf(stderr, "%s Get-Jobs my-jobs=%s\n", client->hostname, - my_jobs ? "true" : "false"); - - if (my_jobs) - { - if ((attr = ippFindAttribute(client->request, "requesting-user-name", - IPP_TAG_NAME)) == NULL) - { - respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, - "Need requesting-user-name with my-jobs."); - return; - } - - username = ippGetString(attr, 0, NULL); - - fprintf(stderr, "%s Get-Jobs requesting-user-name=\"%s\"\n", - client->hostname, username); - } - } - - /* - * OK, build a list of jobs for this printer... - */ - - ra = ippCreateRequestedArray(client->request); - - respond_ipp(client, IPP_STATUS_OK, NULL); - - _cupsRWLockRead(&(client->printer->rwlock)); - - for (count = 0, job = (_ipp_job_t *)cupsArrayFirst(client->printer->jobs); - (limit <= 0 || count < limit) && job; - job = (_ipp_job_t *)cupsArrayNext(client->printer->jobs)) - { - /* - * Filter out jobs that don't match... - */ - - if ((job_comparison < 0 && job->state > job_state) || - (job_comparison == 0 && job->state != job_state) || - (job_comparison > 0 && job->state < job_state) || - job->id < first_job_id || - (username && job->username && - strcasecmp(username, job->username))) - continue; - - if (count > 0) - ippAddSeparator(client->response); - - count ++; - copy_job_attributes(client, job, ra); - } - - cupsArrayDelete(ra); - - _cupsRWUnlock(&(client->printer->rwlock)); -} - - -/* - * 'ipp_get_printer_attributes()' - Get the attributes for a printer object. - */ - -static void -ipp_get_printer_attributes( - _ipp_client_t *client) /* I - Client */ -{ - cups_array_t *ra; /* Requested attributes array */ - _ipp_printer_t *printer; /* Printer */ - - - /* - * Send the attributes... - */ - - ra = ippCreateRequestedArray(client->request); - printer = client->printer; - - respond_ipp(client, IPP_STATUS_OK, NULL); - - _cupsRWLockRead(&(printer->rwlock)); - - copy_attributes(client->response, printer->attrs, ra, IPP_TAG_ZERO, - IPP_TAG_CUPS_CONST); - - if (!ra || cupsArrayFind(ra, "media-col-ready")) - { - int i, /* Looping var */ - num_ready = 0; /* Number of ready media */ - ipp_t *ready[3]; /* Ready media */ - - if (printer->main_size != _IPP_MEDIA_SIZE_NONE) - { - if (printer->main_type != _IPP_MEDIA_TYPE_NONE) - ready[num_ready ++] = create_media_col(media_supported[printer->main_size], "main", media_type_supported[printer->main_type], media_col_sizes[printer->main_size][0], media_col_sizes[printer->main_size][1], 635); - else - ready[num_ready ++] = create_media_col(media_supported[printer->main_size], "main", NULL, media_col_sizes[printer->main_size][0], media_col_sizes[printer->main_size][1], 635); - } - if (printer->envelope_size != _IPP_MEDIA_SIZE_NONE) - ready[num_ready ++] = create_media_col(media_supported[printer->envelope_size], "envelope", NULL, media_col_sizes[printer->envelope_size][0], media_col_sizes[printer->envelope_size][1], 635); - if (printer->photo_size != _IPP_MEDIA_SIZE_NONE) - { - if (printer->photo_type != _IPP_MEDIA_TYPE_NONE) - ready[num_ready ++] = create_media_col(media_supported[printer->photo_size], "photo", media_type_supported[printer->photo_type], media_col_sizes[printer->photo_size][0], media_col_sizes[printer->photo_size][1], 0); - else - ready[num_ready ++] = create_media_col(media_supported[printer->photo_size], "photo", NULL, media_col_sizes[printer->photo_size][0], media_col_sizes[printer->photo_size][1], 0); - } - - if (num_ready) - { - ippAddCollections(client->response, IPP_TAG_PRINTER, "media-col-ready", num_ready, (const ipp_t **)ready); - for (i = 0; i < num_ready; i ++) - ippDelete(ready[i]); - } - else - ippAddOutOfBand(client->response, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, "media-col-ready"); - } - - if (!ra || cupsArrayFind(ra, "media-ready")) - { - int num_ready = 0; /* Number of ready media */ - const char *ready[3]; /* Ready media */ - - if (printer->main_size != _IPP_MEDIA_SIZE_NONE) - ready[num_ready ++] = media_supported[printer->main_size]; - - if (printer->envelope_size != _IPP_MEDIA_SIZE_NONE) - ready[num_ready ++] = media_supported[printer->envelope_size]; - - if (printer->photo_size != _IPP_MEDIA_SIZE_NONE) - ready[num_ready ++] = media_supported[printer->photo_size]; - - if (num_ready) - ippAddStrings(client->response, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-ready", num_ready, NULL, ready); - else - ippAddOutOfBand(client->response, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, "media-ready"); - } - - if (!ra || cupsArrayFind(ra, "printer-config-change-date-time")) - ippAddDate(client->response, IPP_TAG_PRINTER, "printer-config-change-date-time", ippTimeToDate(printer->config_time)); - - if (!ra || cupsArrayFind(ra, "printer-config-change-time")) - ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-config-change-time", (int)(printer->config_time - printer->start_time)); - - if (!ra || cupsArrayFind(ra, "printer-current-time")) - ippAddDate(client->response, IPP_TAG_PRINTER, "printer-current-time", ippTimeToDate(time(NULL))); - - - if (!ra || cupsArrayFind(ra, "printer-state")) - ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, - "printer-state", printer->state); - - if (!ra || cupsArrayFind(ra, "printer-state-change-date-time")) - ippAddDate(client->response, IPP_TAG_PRINTER, "printer-state-change-date-time", ippTimeToDate(printer->state_time)); - - if (!ra || cupsArrayFind(ra, "printer-state-change-time")) - ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-state-change-time", (int)(printer->state_time - printer->start_time)); - - if (!ra || cupsArrayFind(ra, "printer-state-message")) - { - static const char * const messages[] = { "Idle.", "Printing.", "Stopped." }; - - ippAddString(client->response, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-state-message", NULL, messages[printer->state - IPP_PSTATE_IDLE]); - } - - if (!ra || cupsArrayFind(ra, "printer-state-reasons")) - { - if (printer->state_reasons == _IPP_PREASON_NONE) - ippAddString(client->response, IPP_TAG_PRINTER, - IPP_CONST_TAG(IPP_TAG_KEYWORD), - "printer-state-reasons", NULL, "none"); - else - { - ipp_attribute_t *attr = NULL; /* printer-state-reasons */ - _ipp_preason_t bit; /* Reason bit */ - int i; /* Looping var */ - char reason[32]; /* Reason string */ - - for (i = 0, bit = 1; i < (int)(sizeof(_ipp_preason_strings) / sizeof(_ipp_preason_strings[0])); i ++, bit *= 2) - { - if (printer->state_reasons & bit) - { - snprintf(reason, sizeof(reason), "%s-%s", _ipp_preason_strings[i], printer->state == IPP_PSTATE_IDLE ? "report" : printer->state == IPP_PSTATE_PROCESSING ? "warning" : "error"); - if (attr) - ippSetString(client->response, &attr, ippGetCount(attr), reason); - else - attr = ippAddString(client->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "printer-state-reasons", NULL, reason); - } - } - } - } - - if (!ra || cupsArrayFind(ra, "printer-supply")) - { - int i; /* Looping var */ - char buffer[256]; /* Supply value buffer */ - ipp_attribute_t *attr = NULL; /* Attribute */ - static const char * const colorants[] = { "cyan", "magenta", "yellow", "black", "unknown" }; - - for (i = 0; i < 5; i ++) - { - snprintf(buffer, sizeof(buffer), "index=%d;class=%s;type=%s;unit=percent;maxcapacity=100;level=%d;colorantname=%s;", i + 1, i < 4 ? "supplyThatIsConsumed" : "receptacleThatIsFilled", i < 4 ? "toner" : "wasteToner", printer->supplies[i], colorants[i]); - - if (!attr) - attr = ippAddOctetString(client->response, IPP_TAG_PRINTER, "printer-supply", buffer, (int)strlen(buffer)); - else - ippSetOctetString(client->response, &attr, i, buffer, (int)strlen(buffer)); - } - } - - if (!ra || cupsArrayFind(ra, "printer-up-time")) - ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-up-time", (int)(time(NULL) - printer->start_time)); - - if (!ra || cupsArrayFind(ra, "queued-job-count")) - ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "queued-job-count", printer->active_job && printer->active_job->state < IPP_JSTATE_CANCELED); - - _cupsRWUnlock(&(printer->rwlock)); - - cupsArrayDelete(ra); -} - - -/* - * 'ipp_identify_printer()' - Beep or display a message. - */ - -static void -ipp_identify_printer( - _ipp_client_t *client) /* I - Client */ -{ - ipp_attribute_t *actions, /* identify-actions */ - *message; /* message */ - - - actions = ippFindAttribute(client->request, "identify-actions", IPP_TAG_KEYWORD); - message = ippFindAttribute(client->request, "message", IPP_TAG_TEXT); - - if (!actions || ippContainsString(actions, "sound")) - { - putchar(0x07); - fflush(stdout); - } - - if (ippContainsString(actions, "display")) - printf("IDENTIFY from %s: %s\n", client->hostname, message ? ippGetString(message, 0, NULL) : "No message supplied"); - - respond_ipp(client, IPP_STATUS_OK, NULL); -} - - -/* - * 'ipp_print_job()' - Create a job object with an attached document. - */ - -static void -ipp_print_job(_ipp_client_t *client) /* I - Client */ -{ - _ipp_job_t *job; /* New job */ - char filename[1024], /* Filename buffer */ - buffer[4096]; /* Copy buffer */ - ssize_t bytes; /* Bytes read */ - cups_array_t *ra; /* Attributes to send in response */ - _cups_thread_t t; /* Thread */ - - - /* - * Validate print job attributes... - */ - - if (!valid_job_attributes(client)) - { - httpFlush(client->http); - return; - } - - /* - * Do we have a file to print? - */ - - if (httpGetState(client->http) == HTTP_STATE_POST_SEND) - { - respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "No file in request."); - return; - } - - /* - * Print the job... - */ - - if ((job = create_job(client)) == NULL) - { - respond_ipp(client, IPP_STATUS_ERROR_BUSY, - "Currently printing another job."); - return; - } - - /* - * Create a file for the request data... - */ - - create_job_filename(client->printer, job, filename, sizeof(filename)); - - if (Verbosity) - fprintf(stderr, "Creating job file \"%s\", format \"%s\".\n", filename, job->format); - - if ((job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) - { - job->state = IPP_JSTATE_ABORTED; - - respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, - "Unable to create print file: %s", strerror(errno)); - return; - } - - while ((bytes = httpRead2(client->http, buffer, sizeof(buffer))) > 0) - { - if (write(job->fd, buffer, (size_t)bytes) < bytes) - { - int error = errno; /* Write error */ - - job->state = IPP_JSTATE_ABORTED; - - close(job->fd); - job->fd = -1; - - unlink(filename); - - respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, - "Unable to write print file: %s", strerror(error)); - return; - } - } - - if (bytes < 0) - { - /* - * Got an error while reading the print data, so abort this job. - */ - - job->state = IPP_JSTATE_ABORTED; - - close(job->fd); - job->fd = -1; - - unlink(filename); - - respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, - "Unable to read print file."); - return; - } - - if (close(job->fd)) - { - int error = errno; /* Write error */ - - job->state = IPP_JSTATE_ABORTED; - job->fd = -1; - - unlink(filename); - - respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, - "Unable to write print file: %s", strerror(error)); - return; - } - - job->fd = -1; - job->filename = strdup(filename); - job->state = IPP_JSTATE_PENDING; - - /* - * Process the job... - */ - - t = _cupsThreadCreate((_cups_thread_func_t)process_job, job); - - if (t) - { - _cupsThreadDetach(t); - } - else - { - job->state = IPP_JSTATE_ABORTED; - respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to process job."); - return; - } - - /* - * Return the job info... - */ - - respond_ipp(client, IPP_STATUS_OK, NULL); - - ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); - cupsArrayAdd(ra, "job-id"); - cupsArrayAdd(ra, "job-state"); - cupsArrayAdd(ra, "job-state-message"); - cupsArrayAdd(ra, "job-state-reasons"); - cupsArrayAdd(ra, "job-uri"); - - copy_job_attributes(client, job, ra); - cupsArrayDelete(ra); -} - - -/* - * 'ipp_print_uri()' - Create a job object with a referenced document. - */ - -static void -ipp_print_uri(_ipp_client_t *client) /* I - Client */ -{ - _ipp_job_t *job; /* New job */ - ipp_attribute_t *uri; /* document-uri */ - char scheme[256], /* URI scheme */ - userpass[256], /* Username and password info */ - hostname[256], /* Hostname */ - resource[1024]; /* Resource path */ - int port; /* Port number */ - http_uri_status_t uri_status; /* URI decode status */ - http_encryption_t encryption; /* Encryption to use, if any */ - http_t *http; /* Connection for http/https URIs */ - http_status_t status; /* Access status for http/https URIs */ - int infile; /* Input file for local file URIs */ - char filename[1024], /* Filename buffer */ - buffer[4096]; /* Copy buffer */ - ssize_t bytes; /* Bytes read */ - cups_array_t *ra; /* Attributes to send in response */ - static const char * const uri_status_strings[] = - { /* URI decode errors */ - "URI too large.", - "Bad arguments to function.", - "Bad resource in URI.", - "Bad port number in URI.", - "Bad hostname in URI.", - "Bad username in URI.", - "Bad scheme in URI.", - "Bad/empty URI." - }; - - - /* - * Validate print job attributes... - */ - - if (!valid_job_attributes(client)) - { - httpFlush(client->http); - return; - } - - /* - * Do we have a file to print? - */ - - if (httpGetState(client->http) == HTTP_STATE_POST_RECV) - { - respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, - "Unexpected document data following request."); - return; - } - - /* - * Do we have a document URI? - */ - - if ((uri = ippFindAttribute(client->request, "document-uri", - IPP_TAG_URI)) == NULL) - { - respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Missing document-uri."); - return; - } - - if (ippGetCount(uri) != 1) - { - respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, - "Too many document-uri values."); - return; - } - - uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, ippGetString(uri, 0, NULL), - scheme, sizeof(scheme), userpass, - sizeof(userpass), hostname, sizeof(hostname), - &port, resource, sizeof(resource)); - if (uri_status < HTTP_URI_STATUS_OK) - { - respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad document-uri: %s", - uri_status_strings[uri_status - HTTP_URI_STATUS_OVERFLOW]); - return; - } - - if (strcmp(scheme, "file") && -#ifdef HAVE_SSL - strcmp(scheme, "https") && -#endif /* HAVE_SSL */ - strcmp(scheme, "http")) - { - respond_ipp(client, IPP_STATUS_ERROR_URI_SCHEME, - "URI scheme \"%s\" not supported.", scheme); - return; - } - - if (!strcmp(scheme, "file") && access(resource, R_OK)) - { - respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, - "Unable to access URI: %s", strerror(errno)); - return; - } - - /* - * Print the job... - */ - - if ((job = create_job(client)) == NULL) - { - respond_ipp(client, IPP_STATUS_ERROR_BUSY, - "Currently printing another job."); - return; - } - - /* - * Create a file for the request data... - */ - - if (!strcasecmp(job->format, "image/jpeg")) - snprintf(filename, sizeof(filename), "%s/%d.jpg", - client->printer->directory, job->id); - else if (!strcasecmp(job->format, "image/png")) - snprintf(filename, sizeof(filename), "%s/%d.png", - client->printer->directory, job->id); - else if (!strcasecmp(job->format, "application/pdf")) - snprintf(filename, sizeof(filename), "%s/%d.pdf", - client->printer->directory, job->id); - else if (!strcasecmp(job->format, "application/postscript")) - snprintf(filename, sizeof(filename), "%s/%d.ps", - client->printer->directory, job->id); - else - snprintf(filename, sizeof(filename), "%s/%d.prn", - client->printer->directory, job->id); - - if ((job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) - { - job->state = IPP_JSTATE_ABORTED; - - respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, - "Unable to create print file: %s", strerror(errno)); - return; - } - - if (!strcmp(scheme, "file")) - { - if ((infile = open(resource, O_RDONLY)) < 0) - { - respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, - "Unable to access URI: %s", strerror(errno)); - return; - } - - do - { - if ((bytes = read(infile, buffer, sizeof(buffer))) < 0 && - (errno == EAGAIN || errno == EINTR)) - bytes = 1; - else if (bytes > 0 && write(job->fd, buffer, (size_t)bytes) < bytes) - { - int error = errno; /* Write error */ - - job->state = IPP_JSTATE_ABORTED; - - close(job->fd); - job->fd = -1; - - unlink(filename); - close(infile); - - respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, - "Unable to write print file: %s", strerror(error)); - return; - } - } - while (bytes > 0); - - close(infile); - } - else - { -#ifdef HAVE_SSL - if (port == 443 || !strcmp(scheme, "https")) - encryption = HTTP_ENCRYPTION_ALWAYS; - else -#endif /* HAVE_SSL */ - encryption = HTTP_ENCRYPTION_IF_REQUESTED; - - if ((http = httpConnect2(hostname, port, NULL, AF_UNSPEC, encryption, - 1, 30000, NULL)) == NULL) - { - respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, - "Unable to connect to %s: %s", hostname, - cupsLastErrorString()); - job->state = IPP_JSTATE_ABORTED; - - close(job->fd); - job->fd = -1; - - unlink(filename); - return; - } - - httpClearFields(http); - httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); - if (httpGet(http, resource)) - { - respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, - "Unable to GET URI: %s", strerror(errno)); - - job->state = IPP_JSTATE_ABORTED; - - close(job->fd); - job->fd = -1; - - unlink(filename); - httpClose(http); - return; - } - - while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); - - if (status != HTTP_STATUS_OK) - { - respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, - "Unable to GET URI: %s", httpStatus(status)); - - job->state = IPP_JSTATE_ABORTED; - - close(job->fd); - job->fd = -1; - - unlink(filename); - httpClose(http); - return; - } - - while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0) - { - if (write(job->fd, buffer, (size_t)bytes) < bytes) - { - int error = errno; /* Write error */ - - job->state = IPP_JSTATE_ABORTED; - - close(job->fd); - job->fd = -1; - - unlink(filename); - httpClose(http); - - respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, - "Unable to write print file: %s", strerror(error)); - return; - } - } - - httpClose(http); - } - - if (close(job->fd)) - { - int error = errno; /* Write error */ - - job->state = IPP_JSTATE_ABORTED; - job->fd = -1; - - unlink(filename); - - respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, - "Unable to write print file: %s", strerror(error)); - return; - } - - job->fd = -1; - job->filename = strdup(filename); - job->state = IPP_JSTATE_PENDING; - - /* - * Process the job... - */ - - process_job(job); - - /* - * Return the job info... - */ - - respond_ipp(client, IPP_STATUS_OK, NULL); - - ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); - cupsArrayAdd(ra, "job-id"); - cupsArrayAdd(ra, "job-state"); - cupsArrayAdd(ra, "job-state-reasons"); - cupsArrayAdd(ra, "job-uri"); - - copy_job_attributes(client, job, ra); - cupsArrayDelete(ra); -} - - -/* - * 'ipp_send_document()' - Add an attached document to a job object created with - * Create-Job. - */ - -static void -ipp_send_document(_ipp_client_t *client)/* I - Client */ -{ - _ipp_job_t *job; /* Job information */ - char filename[1024], /* Filename buffer */ - buffer[4096]; /* Copy buffer */ - ssize_t bytes; /* Bytes read */ - ipp_attribute_t *attr; /* Current attribute */ - cups_array_t *ra; /* Attributes to send in response */ - - - /* - * Get the job... - */ - - if ((job = find_job(client)) == NULL) - { - respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job does not exist."); - httpFlush(client->http); - return; - } - - /* - * See if we already have a document for this job or the job has already - * in a non-pending state... - */ - - if (job->state > IPP_JSTATE_HELD) - { - respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, - "Job is not in a pending state."); - httpFlush(client->http); - return; - } - else if (job->filename || job->fd >= 0) - { - respond_ipp(client, IPP_STATUS_ERROR_MULTIPLE_JOBS_NOT_SUPPORTED, - "Multiple document jobs are not supported."); - httpFlush(client->http); - return; - } - - if ((attr = ippFindAttribute(client->request, "last-document", - IPP_TAG_ZERO)) == NULL) - { - respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, - "Missing required last-document attribute."); - httpFlush(client->http); - return; - } - else if (ippGetValueTag(attr) != IPP_TAG_BOOLEAN || ippGetCount(attr) != 1 || - !ippGetBoolean(attr, 0)) - { - respond_unsupported(client, attr); - httpFlush(client->http); - return; - } - - /* - * Validate document attributes... - */ - - if (!valid_doc_attributes(client)) - { - httpFlush(client->http); - return; - } - - copy_attributes(job->attrs, client->request, NULL, IPP_TAG_JOB, 0); - - /* - * Get the document format for the job... - */ - - _cupsRWLockWrite(&(client->printer->rwlock)); - - if ((attr = ippFindAttribute(job->attrs, "document-format-detected", IPP_TAG_MIMETYPE)) != NULL) - job->format = ippGetString(attr, 0, NULL); - else if ((attr = ippFindAttribute(job->attrs, "document-format-supplied", IPP_TAG_MIMETYPE)) != NULL) - job->format = ippGetString(attr, 0, NULL); - else - job->format = "application/octet-stream"; - - /* - * Create a file for the request data... - */ - - create_job_filename(client->printer, job, filename, sizeof(filename)); - - if (Verbosity) - fprintf(stderr, "Creating job file \"%s\", format \"%s\".\n", filename, job->format); - - job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); - - _cupsRWUnlock(&(client->printer->rwlock)); - - if (job->fd < 0) - { - job->state = IPP_JSTATE_ABORTED; - - respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, - "Unable to create print file: %s", strerror(errno)); - return; - } - - while ((bytes = httpRead2(client->http, buffer, sizeof(buffer))) > 0) - { - if (write(job->fd, buffer, (size_t)bytes) < bytes) - { - int error = errno; /* Write error */ - - job->state = IPP_JSTATE_ABORTED; - - close(job->fd); - job->fd = -1; - - unlink(filename); - - respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, - "Unable to write print file: %s", strerror(error)); - return; - } - } - - if (bytes < 0) - { - /* - * Got an error while reading the print data, so abort this job. - */ - - job->state = IPP_JSTATE_ABORTED; - - close(job->fd); - job->fd = -1; - - unlink(filename); - - respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, - "Unable to read print file."); - return; - } - - if (close(job->fd)) - { - int error = errno; /* Write error */ - - job->state = IPP_JSTATE_ABORTED; - job->fd = -1; - - unlink(filename); - - respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, - "Unable to write print file: %s", strerror(error)); - return; - } - - _cupsRWLockWrite(&(client->printer->rwlock)); - - job->fd = -1; - job->filename = strdup(filename); - job->state = IPP_JSTATE_PENDING; - - _cupsRWUnlock(&(client->printer->rwlock)); - - /* - * Process the job... - */ - - process_job(job); - - /* - * Return the job info... - */ - - respond_ipp(client, IPP_STATUS_OK, NULL); - - ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); - cupsArrayAdd(ra, "job-id"); - cupsArrayAdd(ra, "job-state"); - cupsArrayAdd(ra, "job-state-reasons"); - cupsArrayAdd(ra, "job-uri"); - - copy_job_attributes(client, job, ra); - cupsArrayDelete(ra); -} - - -/* - * 'ipp_send_uri()' - Add a referenced document to a job object created with - * Create-Job. - */ - -static void -ipp_send_uri(_ipp_client_t *client) /* I - Client */ -{ - _ipp_job_t *job; /* Job information */ - ipp_attribute_t *uri; /* document-uri */ - char scheme[256], /* URI scheme */ - userpass[256], /* Username and password info */ - hostname[256], /* Hostname */ - resource[1024]; /* Resource path */ - int port; /* Port number */ - http_uri_status_t uri_status; /* URI decode status */ - http_encryption_t encryption; /* Encryption to use, if any */ - http_t *http; /* Connection for http/https URIs */ - http_status_t status; /* Access status for http/https URIs */ - int infile; /* Input file for local file URIs */ - char filename[1024], /* Filename buffer */ - buffer[4096]; /* Copy buffer */ - ssize_t bytes; /* Bytes read */ - ipp_attribute_t *attr; /* Current attribute */ - cups_array_t *ra; /* Attributes to send in response */ - static const char * const uri_status_strings[] = - { /* URI decode errors */ - "URI too large.", - "Bad arguments to function.", - "Bad resource in URI.", - "Bad port number in URI.", - "Bad hostname in URI.", - "Bad username in URI.", - "Bad scheme in URI.", - "Bad/empty URI." - }; - - - /* - * Get the job... - */ - - if ((job = find_job(client)) == NULL) - { - respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job does not exist."); - httpFlush(client->http); - return; - } - - /* - * See if we already have a document for this job or the job has already - * in a non-pending state... - */ - - if (job->state > IPP_JSTATE_HELD) - { - respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, - "Job is not in a pending state."); - httpFlush(client->http); - return; - } - else if (job->filename || job->fd >= 0) - { - respond_ipp(client, IPP_STATUS_ERROR_MULTIPLE_JOBS_NOT_SUPPORTED, - "Multiple document jobs are not supported."); - httpFlush(client->http); - return; - } - - if ((attr = ippFindAttribute(client->request, "last-document", - IPP_TAG_ZERO)) == NULL) - { - respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, - "Missing required last-document attribute."); - httpFlush(client->http); - return; - } - else if (ippGetValueTag(attr) != IPP_TAG_BOOLEAN || ippGetCount(attr) != 1 || - !ippGetBoolean(attr, 0)) - { - respond_unsupported(client, attr); - httpFlush(client->http); - return; - } - - /* - * Validate document attributes... - */ - - if (!valid_doc_attributes(client)) - { - httpFlush(client->http); - return; - } - - /* - * Do we have a file to print? - */ - - if (httpGetState(client->http) == HTTP_STATE_POST_RECV) - { - respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, - "Unexpected document data following request."); - return; - } - - /* - * Do we have a document URI? - */ - - if ((uri = ippFindAttribute(client->request, "document-uri", - IPP_TAG_URI)) == NULL) - { - respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Missing document-uri."); - return; - } - - if (ippGetCount(uri) != 1) - { - respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, - "Too many document-uri values."); - return; - } - - uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, ippGetString(uri, 0, NULL), - scheme, sizeof(scheme), userpass, - sizeof(userpass), hostname, sizeof(hostname), - &port, resource, sizeof(resource)); - if (uri_status < HTTP_URI_STATUS_OK) - { - respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad document-uri: %s", - uri_status_strings[uri_status - HTTP_URI_STATUS_OVERFLOW]); - return; - } - - if (strcmp(scheme, "file") && -#ifdef HAVE_SSL - strcmp(scheme, "https") && -#endif /* HAVE_SSL */ - strcmp(scheme, "http")) - { - respond_ipp(client, IPP_STATUS_ERROR_URI_SCHEME, - "URI scheme \"%s\" not supported.", scheme); - return; - } - - if (!strcmp(scheme, "file") && access(resource, R_OK)) - { - respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, - "Unable to access URI: %s", strerror(errno)); - return; - } - - /* - * Get the document format for the job... - */ - - _cupsRWLockWrite(&(client->printer->rwlock)); - - if ((attr = ippFindAttribute(job->attrs, "document-format", - IPP_TAG_MIMETYPE)) != NULL) - job->format = ippGetString(attr, 0, NULL); - else - job->format = "application/octet-stream"; - - /* - * Create a file for the request data... - */ - - if (!strcasecmp(job->format, "image/jpeg")) - snprintf(filename, sizeof(filename), "%s/%d.jpg", - client->printer->directory, job->id); - else if (!strcasecmp(job->format, "image/png")) - snprintf(filename, sizeof(filename), "%s/%d.png", - client->printer->directory, job->id); - else if (!strcasecmp(job->format, "application/pdf")) - snprintf(filename, sizeof(filename), "%s/%d.pdf", - client->printer->directory, job->id); - else if (!strcasecmp(job->format, "application/postscript")) - snprintf(filename, sizeof(filename), "%s/%d.ps", - client->printer->directory, job->id); - else - snprintf(filename, sizeof(filename), "%s/%d.prn", - client->printer->directory, job->id); - - job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); - - _cupsRWUnlock(&(client->printer->rwlock)); - - if (job->fd < 0) - { - job->state = IPP_JSTATE_ABORTED; - - respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, - "Unable to create print file: %s", strerror(errno)); - return; - } - - if (!strcmp(scheme, "file")) - { - if ((infile = open(resource, O_RDONLY)) < 0) - { - respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, - "Unable to access URI: %s", strerror(errno)); - return; - } - - do - { - if ((bytes = read(infile, buffer, sizeof(buffer))) < 0 && - (errno == EAGAIN || errno == EINTR)) - bytes = 1; - else if (bytes > 0 && write(job->fd, buffer, (size_t)bytes) < bytes) - { - int error = errno; /* Write error */ - - job->state = IPP_JSTATE_ABORTED; - - close(job->fd); - job->fd = -1; - - unlink(filename); - close(infile); - - respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, - "Unable to write print file: %s", strerror(error)); - return; - } - } - while (bytes > 0); - - close(infile); - } - else - { -#ifdef HAVE_SSL - if (port == 443 || !strcmp(scheme, "https")) - encryption = HTTP_ENCRYPTION_ALWAYS; - else -#endif /* HAVE_SSL */ - encryption = HTTP_ENCRYPTION_IF_REQUESTED; - - if ((http = httpConnect2(hostname, port, NULL, AF_UNSPEC, encryption, - 1, 30000, NULL)) == NULL) - { - respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, - "Unable to connect to %s: %s", hostname, - cupsLastErrorString()); - job->state = IPP_JSTATE_ABORTED; - - close(job->fd); - job->fd = -1; - - unlink(filename); - return; - } - - httpClearFields(http); - httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); - if (httpGet(http, resource)) - { - respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, - "Unable to GET URI: %s", strerror(errno)); - - job->state = IPP_JSTATE_ABORTED; - - close(job->fd); - job->fd = -1; - - unlink(filename); - httpClose(http); - return; - } - - while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); - - if (status != HTTP_STATUS_OK) - { - respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, - "Unable to GET URI: %s", httpStatus(status)); - - job->state = IPP_JSTATE_ABORTED; - - close(job->fd); - job->fd = -1; - - unlink(filename); - httpClose(http); - return; - } - - while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0) - { - if (write(job->fd, buffer, (size_t)bytes) < bytes) - { - int error = errno; /* Write error */ - - job->state = IPP_JSTATE_ABORTED; - - close(job->fd); - job->fd = -1; - - unlink(filename); - httpClose(http); - - respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, - "Unable to write print file: %s", strerror(error)); - return; - } - } - - httpClose(http); - } - - if (close(job->fd)) - { - int error = errno; /* Write error */ - - job->state = IPP_JSTATE_ABORTED; - job->fd = -1; - - unlink(filename); - - respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, - "Unable to write print file: %s", strerror(error)); - return; - } - - _cupsRWLockWrite(&(client->printer->rwlock)); - - job->fd = -1; - job->filename = strdup(filename); - job->state = IPP_JSTATE_PENDING; - - _cupsRWUnlock(&(client->printer->rwlock)); - - /* - * Process the job... - */ - - process_job(job); - - /* - * Return the job info... - */ - - respond_ipp(client, IPP_STATUS_OK, NULL); - - ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); - cupsArrayAdd(ra, "job-id"); - cupsArrayAdd(ra, "job-state"); - cupsArrayAdd(ra, "job-state-reasons"); - cupsArrayAdd(ra, "job-uri"); - - copy_job_attributes(client, job, ra); - cupsArrayDelete(ra); -} - - -/* - * 'ipp_validate_job()' - Validate job creation attributes. - */ - -static void -ipp_validate_job(_ipp_client_t *client) /* I - Client */ -{ - if (valid_job_attributes(client)) - respond_ipp(client, IPP_STATUS_OK, NULL); -} - - -/* - * 'load_attributes()' - Load printer attributes from a file. - * - * Syntax is based on ipptool format: - * - * ATTR value-tag name value - */ - -static void -load_attributes(const char *filename, /* I - File to load */ - ipp_t *attrs) /* I - Printer attributes */ -{ - int linenum = 0; /* Current line number */ - FILE *fp = NULL; /* Test file */ - char attr[128], /* Attribute name */ - token[1024], /* Token from file */ - *tokenptr; /* Pointer into token */ - ipp_tag_t value; /* Current value type */ - ipp_attribute_t *attrptr, /* Attribute pointer */ - *lastcol = NULL; /* Last collection attribute */ - - - if ((fp = fopen(filename, "r")) == NULL) - { - fprintf(stderr, "ippserver: Unable to open \"%s\": %s\n", filename, strerror(errno)); - exit(1); - } - - while (get_token(fp, token, sizeof(token), &linenum) != NULL) - { - if (!_cups_strcasecmp(token, "ATTR")) - { - /* - * Attribute... - */ - - if (!get_token(fp, token, sizeof(token), &linenum)) - { - fprintf(stderr, "ippserver: Missing ATTR value tag on line %d of \"%s\".\n", linenum, filename); - exit(1); - } - - if ((value = ippTagValue(token)) == IPP_TAG_ZERO) - { - fprintf(stderr, "ippserver: Bad ATTR value tag \"%s\" on line %d of \"%s\".\n", token, linenum, filename); - exit(1); - } - - if (!get_token(fp, attr, sizeof(attr), &linenum)) - { - fprintf(stderr, "ippserver: Missing ATTR name on line %d of \"%s\".\n", linenum, filename); - exit(1); - } - - if (!get_token(fp, token, sizeof(token), &linenum)) - { - fprintf(stderr, "ippserver: Missing ATTR value on line %d of \"%s\".\n", linenum, filename); - exit(1); - } - - attrptr = NULL; - - switch (value) - { - case IPP_TAG_BOOLEAN : - if (!_cups_strcasecmp(token, "true")) - attrptr = ippAddBoolean(attrs, IPP_TAG_PRINTER, attr, 1); - else - attrptr = ippAddBoolean(attrs, IPP_TAG_PRINTER, attr, (char)atoi(token)); - break; - - case IPP_TAG_INTEGER : - case IPP_TAG_ENUM : - if (!strchr(token, ',')) - attrptr = ippAddInteger(attrs, IPP_TAG_PRINTER, value, attr, (int)strtol(token, &tokenptr, 0)); - else - { - int values[100], /* Values */ - num_values = 1; /* Number of values */ - - values[0] = (int)strtol(token, &tokenptr, 10); - while (tokenptr && *tokenptr && - num_values < (int)(sizeof(values) / sizeof(values[0]))) - { - if (*tokenptr == ',') - tokenptr ++; - else if (!isdigit(*tokenptr & 255) && *tokenptr != '-') - break; - - values[num_values] = (int)strtol(tokenptr, &tokenptr, 0); - num_values ++; - } - - attrptr = ippAddIntegers(attrs, IPP_TAG_PRINTER, value, attr, num_values, values); - } - - if (!tokenptr || *tokenptr) - { - fprintf(stderr, "ippserver: Bad %s value \"%s\" on line %d of \"%s\".\n", ippTagString(value), token, linenum, filename); - exit(1); - } - break; - - case IPP_TAG_RESOLUTION : - { - int xres, /* X resolution */ - yres; /* Y resolution */ - ipp_res_t units; /* Units */ - char *start, /* Start of value */ - *ptr, /* Pointer into value */ - *next = NULL; /* Next value */ - - for (start = token; start; start = next) - { - xres = yres = (int)strtol(start, (char **)&ptr, 10); - if (ptr > start && xres > 0) - { - if (*ptr == 'x') - yres = (int)strtol(ptr + 1, (char **)&ptr, 10); - } - - if (ptr && (next = strchr(ptr, ',')) != NULL) - *next++ = '\0'; - - if (ptr <= start || xres <= 0 || yres <= 0 || !ptr || - (_cups_strcasecmp(ptr, "dpi") && - _cups_strcasecmp(ptr, "dpc") && - _cups_strcasecmp(ptr, "dpcm") && - _cups_strcasecmp(ptr, "other"))) - { - fprintf(stderr, "ippserver: Bad resolution value \"%s\" on line %d of \"%s\".\n", token, linenum, filename); - exit(1); - } - - if (!_cups_strcasecmp(ptr, "dpc") || !_cups_strcasecmp(ptr, "dpcm")) - units = IPP_RES_PER_CM; - else - units = IPP_RES_PER_INCH; - - if (attrptr) - ippSetResolution(attrs, &attrptr, ippGetCount(attrptr), units, xres, yres); - else - attrptr = ippAddResolution(attrs, IPP_TAG_PRINTER, attr, units, xres, yres); - } - } - break; - - case IPP_TAG_RANGE : - { - int lowers[4], /* Lower value */ - uppers[4], /* Upper values */ - num_vals; /* Number of values */ - - - num_vals = sscanf(token, "%d-%d,%d-%d,%d-%d,%d-%d", - lowers + 0, uppers + 0, - lowers + 1, uppers + 1, - lowers + 2, uppers + 2, - lowers + 3, uppers + 3); - - if ((num_vals & 1) || num_vals == 0) - { - fprintf(stderr, "ippserver: Bad rangeOfInteger value \"%s\" on line %d of \"%s\".", token, linenum, filename); - exit(1); - } - - attrptr = ippAddRanges(attrs, IPP_TAG_PRINTER, attr, num_vals / 2, lowers, - uppers); - } - break; - - case IPP_TAG_BEGIN_COLLECTION : - if (!strcmp(token, "{")) - { - ipp_t *col = get_collection(fp, filename, &linenum); - /* Collection value */ - - if (col) - { - attrptr = lastcol = ippAddCollection(attrs, IPP_TAG_PRINTER, attr, col); - ippDelete(col); - } - else - exit(1); - } - else - { - fprintf(stderr, "ippserver: Bad ATTR collection value on line %d of \"%s\".\n", linenum, filename); - exit(1); - } - - do - { - ipp_t *col; /* Collection value */ - long pos = ftell(fp); /* Save position of file */ - - if (!get_token(fp, token, sizeof(token), &linenum)) - break; - - if (strcmp(token, ",")) - { - fseek(fp, pos, SEEK_SET); - break; - } - - if (!get_token(fp, token, sizeof(token), &linenum) || strcmp(token, "{")) - { - fprintf(stderr, "ippserver: Unexpected \"%s\" on line %d of \"%s\".\n", token, linenum, filename); - exit(1); - } - - if ((col = get_collection(fp, filename, &linenum)) == NULL) - break; - - ippSetCollection(attrs, &attrptr, ippGetCount(attrptr), col); - } - while (!strcmp(token, "{")); - break; - - case IPP_TAG_STRING : - attrptr = ippAddOctetString(attrs, IPP_TAG_PRINTER, attr, token, (int)strlen(token)); - break; - - default : - fprintf(stderr, "ippserver: Unsupported ATTR value tag %s on line %d of \"%s\".\n", ippTagString(value), linenum, filename); - exit(1); - - 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 : - if (!strchr(token, ',')) - attrptr = ippAddString(attrs, IPP_TAG_PRINTER, value, attr, NULL, token); - else - { - /* - * Multiple string values... - */ - - int num_values; /* Number of values */ - char *values[100], /* Values */ - *ptr; /* Pointer to next value */ - - - values[0] = token; - num_values = 1; - - for (ptr = strchr(token, ','); ptr; ptr = strchr(ptr, ',')) - { - if (ptr > token && ptr[-1] == '\\') - _cups_strcpy(ptr - 1, ptr); - else - { - *ptr++ = '\0'; - values[num_values] = ptr; - num_values ++; - if (num_values >= (int)(sizeof(values) / sizeof(values[0]))) - break; - } - } - - attrptr = ippAddStrings(attrs, IPP_TAG_PRINTER, value, attr, num_values, NULL, (const char **)values); - } - break; - } - - if (!attrptr) - { - fprintf(stderr, "ippserver: Unable to add attribute on line %d of \"%s\": %s\n", linenum, filename, cupsLastErrorString()); - exit(1); - } - } - else - { - fprintf(stderr, "ippserver: Unknown directive \"%s\" on line %d of \"%s\".\n", token, linenum, filename); - exit(1); - } - } - - fclose(fp); -} - - -/* - * 'parse_options()' - Parse URL options into CUPS options. - * - * The client->options string is destroyed by this function. - */ - -static int /* O - Number of options */ -parse_options(_ipp_client_t *client, /* I - Client */ - cups_option_t **options) /* O - Options */ -{ - char *name, /* Name */ - *value, /* Value */ - *next; /* Next name=value pair */ - int num_options = 0; /* Number of options */ - - - *options = NULL; - - for (name = client->options; name && *name; name = next) - { - if ((value = strchr(name, '=')) == NULL) - break; - - *value++ = '\0'; - if ((next = strchr(value, '&')) != NULL) - *next++ = '\0'; - - num_options = cupsAddOption(name, value, num_options, options); - } - - return (num_options); -} - - -/* - * 'process_attr_message()' - Process an ATTR: message from a command. - */ - -static void -process_attr_message( - _ipp_job_t *job, /* I - Job */ - char *message) /* I - Message */ -{ - (void)job; - (void)message; -} - - -/* - * 'process_client()' - Process client requests on a thread. - */ - -static void * /* O - Exit status */ -process_client(_ipp_client_t *client) /* I - Client */ -{ - /* - * Loop until we are out of requests or timeout (30 seconds)... - */ - -#ifdef HAVE_SSL - int first_time = 1; /* First time request? */ -#endif /* HAVE_SSL */ - - while (httpWait(client->http, 30000)) - { -#ifdef HAVE_SSL - if (first_time) - { - /* - * See if we need to negotiate a TLS connection... - */ - - char buf[1]; /* First byte from client */ - - if (recv(httpGetFd(client->http), buf, 1, MSG_PEEK) == 1 && (!buf[0] || !strchr("DGHOPT", buf[0]))) - { - fprintf(stderr, "%s Starting HTTPS session.\n", client->hostname); - - if (httpEncryption(client->http, HTTP_ENCRYPTION_ALWAYS)) - { - fprintf(stderr, "%s Unable to encrypt connection: %s\n", client->hostname, cupsLastErrorString()); - break; - } - - fprintf(stderr, "%s Connection now encrypted.\n", client->hostname); - } - - first_time = 0; - } -#endif /* HAVE_SSL */ - - if (!process_http(client)) - break; - } - - /* - * Close the conection to the client and return... - */ - - delete_client(client); - - return (NULL); -} - - -/* - * 'process_http()' - Process a HTTP request. - */ - -int /* O - 1 on success, 0 on failure */ -process_http(_ipp_client_t *client) /* I - Client connection */ -{ - char uri[1024]; /* URI */ - http_state_t http_state; /* HTTP state */ - http_status_t http_status; /* HTTP status */ - ipp_state_t ipp_state; /* State of IPP transfer */ - char scheme[32], /* Method/scheme */ - userpass[128], /* Username:password */ - hostname[HTTP_MAX_HOST]; - /* Hostname */ - int port; /* Port number */ - const char *encoding; /* Content-Encoding value */ - static const char * const http_states[] = - { /* Strings for logging HTTP method */ - "WAITING", - "OPTIONS", - "GET", - "GET_SEND", - "HEAD", - "POST", - "POST_RECV", - "POST_SEND", - "PUT", - "PUT_RECV", - "DELETE", - "TRACE", - "CONNECT", - "STATUS", - "UNKNOWN_METHOD", - "UNKNOWN_VERSION" - }; - - - /* - * Clear state variables... - */ - - ippDelete(client->request); - ippDelete(client->response); - - client->request = NULL; - client->response = NULL; - client->operation = HTTP_STATE_WAITING; - - /* - * Read a request from the connection... - */ - - while ((http_state = httpReadRequest(client->http, uri, - sizeof(uri))) == HTTP_STATE_WAITING) - usleep(1); - - /* - * Parse the request line... - */ - - if (http_state == HTTP_STATE_ERROR) - { - if (httpError(client->http) == EPIPE) - fprintf(stderr, "%s Client closed connection.\n", client->hostname); - else - fprintf(stderr, "%s Bad request line (%s).\n", client->hostname, - strerror(httpError(client->http))); - - return (0); - } - else if (http_state == HTTP_STATE_UNKNOWN_METHOD) - { - fprintf(stderr, "%s Bad/unknown operation.\n", client->hostname); - respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); - return (0); - } - else if (http_state == HTTP_STATE_UNKNOWN_VERSION) - { - fprintf(stderr, "%s Bad HTTP version.\n", client->hostname); - respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); - return (0); - } - - fprintf(stderr, "%s %s %s\n", client->hostname, http_states[http_state], - uri); - - /* - * Separate the URI into its components... - */ - - if (httpSeparateURI(HTTP_URI_CODING_MOST, uri, scheme, sizeof(scheme), - userpass, sizeof(userpass), - hostname, sizeof(hostname), &port, - client->uri, sizeof(client->uri)) < HTTP_URI_STATUS_OK && - (http_state != HTTP_STATE_OPTIONS || strcmp(uri, "*"))) - { - fprintf(stderr, "%s Bad URI \"%s\".\n", client->hostname, uri); - respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); - return (0); - } - - if ((client->options = strchr(client->uri, '?')) != NULL) - *(client->options)++ = '\0'; - - /* - * Process the request... - */ - - client->start = time(NULL); - client->operation = httpGetState(client->http); - - /* - * Parse incoming parameters until the status changes... - */ - - while ((http_status = httpUpdate(client->http)) == HTTP_STATUS_CONTINUE); - - if (http_status != HTTP_STATUS_OK) - { - respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); - return (0); - } - - if (!httpGetField(client->http, HTTP_FIELD_HOST)[0] && - httpGetVersion(client->http) >= HTTP_VERSION_1_1) - { - /* - * HTTP/1.1 and higher require the "Host:" field... - */ - - respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); - return (0); - } - - /* - * Handle HTTP Upgrade... - */ - - if (!strcasecmp(httpGetField(client->http, HTTP_FIELD_CONNECTION), - "Upgrade")) - { -#ifdef HAVE_SSL - if (strstr(httpGetField(client->http, HTTP_FIELD_UPGRADE), "TLS/") != NULL && !httpIsEncrypted(client->http)) - { - if (!respond_http(client, HTTP_STATUS_SWITCHING_PROTOCOLS, NULL, NULL, 0)) - return (0); - - fprintf(stderr, "%s Upgrading to encrypted connection.\n", client->hostname); - - if (httpEncryption(client->http, HTTP_ENCRYPTION_REQUIRED)) - { - fprintf(stderr, "%s Unable to encrypt connection: %s\n", client->hostname, cupsLastErrorString()); - return (0); - } - - fprintf(stderr, "%s Connection now encrypted.\n", client->hostname); - } - else -#endif /* HAVE_SSL */ - - if (!respond_http(client, HTTP_STATUS_NOT_IMPLEMENTED, NULL, NULL, 0)) - return (0); - } - - /* - * Handle HTTP Expect... - */ - - if (httpGetExpect(client->http) && - (client->operation == HTTP_STATE_POST || - client->operation == HTTP_STATE_PUT)) - { - if (httpGetExpect(client->http) == HTTP_STATUS_CONTINUE) - { - /* - * Send 100-continue header... - */ - - if (!respond_http(client, HTTP_STATUS_CONTINUE, NULL, NULL, 0)) - return (0); - } - else - { - /* - * Send 417-expectation-failed header... - */ - - if (!respond_http(client, HTTP_STATUS_EXPECTATION_FAILED, NULL, NULL, 0)) - return (0); - } - } - - /* - * Handle new transfers... - */ - - encoding = httpGetContentEncoding(client->http); - - switch (client->operation) - { - case HTTP_STATE_OPTIONS : - /* - * Do OPTIONS command... - */ - - return (respond_http(client, HTTP_STATUS_OK, NULL, NULL, 0)); - - case HTTP_STATE_HEAD : - if (!strcmp(client->uri, "/icon.png")) - return (respond_http(client, HTTP_STATUS_OK, NULL, "image/png", 0)); - else if (!strcmp(client->uri, "/") || !strcmp(client->uri, "/media") || !strcmp(client->uri, "/supplies")) - return (respond_http(client, HTTP_STATUS_OK, NULL, "text/html", 0)); - else - return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0)); - - case HTTP_STATE_GET : - if (!strcmp(client->uri, "/icon.png")) - { - /* - * Send PNG icon file. - */ - - int fd; /* Icon file */ - struct stat fileinfo; /* Icon file information */ - char buffer[4096]; /* Copy buffer */ - ssize_t bytes; /* Bytes */ - - fprintf(stderr, "Icon file is \"%s\".\n", client->printer->icon); - - if (!stat(client->printer->icon, &fileinfo) && - (fd = open(client->printer->icon, O_RDONLY)) >= 0) - { - if (!respond_http(client, HTTP_STATUS_OK, NULL, "image/png", - (size_t)fileinfo.st_size)) - { - close(fd); - return (0); - } - - while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) - httpWrite2(client->http, buffer, (size_t)bytes); - - httpFlushWrite(client->http); - - close(fd); - } - else - return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0)); - } - else if (!strcmp(client->uri, "/")) - { - /* - * Show web status page... - */ - - _ipp_job_t *job; /* Current job */ - int i; /* Looping var */ - _ipp_preason_t reason; /* Current reason */ - static const char * const reasons[] = - { /* Reason strings */ - "Other", - "Cover Open", - "Input Tray Missing", - "Marker Supply Empty", - "Marker Supply Low", - "Marker Waste Almost Full", - "Marker Waste Full", - "Media Empty", - "Media Jam", - "Media Low", - "Media Needed", - "Moving to Paused", - "Paused", - "Spool Area Full", - "Toner Empty", - "Toner Low" - }; - - if (!respond_http(client, HTTP_STATUS_OK, encoding, "text/html", 0)) - return (0); - - html_header(client, client->printer->name); - html_printf(client, - "

ippserver (" CUPS_SVERSION ")

\n" - "

%s, %d job(s).", client->printer->state == IPP_PSTATE_IDLE ? "Idle" : client->printer->state == IPP_PSTATE_PROCESSING ? "Printing" : "Stopped", cupsArrayCount(client->printer->jobs)); - for (i = 0, reason = 1; i < (int)(sizeof(reasons) / sizeof(reasons[0])); i ++, reason <<= 1) - if (client->printer->state_reasons & reason) - html_printf(client, "\n
    %s", reasons[i]); - html_printf(client, "

\n"); - - if (cupsArrayCount(client->printer->jobs) > 0) - { - _cupsRWLockRead(&(client->printer->rwlock)); - - html_printf(client, "\n"); - for (job = (_ipp_job_t *)cupsArrayFirst(client->printer->jobs); job; job = (_ipp_job_t *)cupsArrayNext(client->printer->jobs)) - { - char when[256], /* When job queued/started/finished */ - hhmmss[64]; /* Time HH:MM:SS */ - - switch (job->state) - { - case IPP_JSTATE_PENDING : - case IPP_JSTATE_HELD : - snprintf(when, sizeof(when), "Queued at %s", time_string(job->created, hhmmss, sizeof(hhmmss))); - break; - case IPP_JSTATE_PROCESSING : - case IPP_JSTATE_STOPPED : - snprintf(when, sizeof(when), "Started at %s", time_string(job->processing, hhmmss, sizeof(hhmmss))); - break; - case IPP_JSTATE_ABORTED : - snprintf(when, sizeof(when), "Aborted at %s", time_string(job->completed, hhmmss, sizeof(hhmmss))); - break; - case IPP_JSTATE_CANCELED : - snprintf(when, sizeof(when), "Canceled at %s", time_string(job->completed, hhmmss, sizeof(hhmmss))); - break; - case IPP_JSTATE_COMPLETED : - snprintf(when, sizeof(when), "Completed at %s", time_string(job->completed, hhmmss, sizeof(hhmmss))); - break; - } - - html_printf(client, "\n", job->id, job->name, job->username, when); - } - html_printf(client, "
Job #NameOwnerWhen
%d%s%s%s
\n"); - - _cupsRWUnlock(&(client->printer->rwlock)); - } - html_footer(client); - - return (1); - } - else if (!strcmp(client->uri, "/media")) - { - /* - * Show web media page... - */ - - int i, /* Looping var */ - num_options; /* Number of form options */ - cups_option_t *options; /* Form options */ - static const char * const sizes[] = - { /* Size strings */ - "ISO A4", - "ISO A5", - "ISO A6", - "DL Envelope", - "US Legal", - "US Letter", - "#10 Envelope", - "3x5 Photo", - "3.5x5 Photo", - "4x6 Photo", - "5x7 Photo" - }; - static const char * const types[] = - /* Type strings */ - { - "Auto", - "Cardstock", - "Envelope", - "Labels", - "Other", - "Glossy Photo", - "High-Gloss Photo", - "Matte Photo", - "Satin Photo", - "Semi-Gloss Photo", - "Plain", - "Letterhead", - "Transparency" - }; - static const int sheets[] = /* Number of sheets */ - { - 250, - 100, - 25, - 5, - 0 - }; - - if (!respond_http(client, HTTP_STATUS_OK, encoding, "text/html", 0)) - return (0); - - html_header(client, client->printer->name); - - if ((num_options = parse_options(client, &options)) > 0) - { - /* - * WARNING: A real printer/server implementation MUST NOT implement - * media updates via a GET request - GET requests are supposed to be - * idempotent (without side-effects) and we obviously are not - * authenticating access here. This form is provided solely to - * enable testing and development! - */ - - const char *val; /* Form value */ - - if ((val = cupsGetOption("main_size", num_options, options)) != NULL) - client->printer->main_size = atoi(val); - if ((val = cupsGetOption("main_type", num_options, options)) != NULL) - client->printer->main_type = atoi(val); - if ((val = cupsGetOption("main_level", num_options, options)) != NULL) - client->printer->main_level = atoi(val); - - if ((val = cupsGetOption("envelope_size", num_options, options)) != NULL) - client->printer->envelope_size = atoi(val); - if ((val = cupsGetOption("envelope_level", num_options, options)) != NULL) - client->printer->envelope_level = atoi(val); - - if ((val = cupsGetOption("photo_size", num_options, options)) != NULL) - client->printer->photo_size = atoi(val); - if ((val = cupsGetOption("photo_type", num_options, options)) != NULL) - client->printer->photo_type = atoi(val); - if ((val = cupsGetOption("photo_level", num_options, options)) != NULL) - client->printer->photo_level = atoi(val); - - if ((client->printer->main_level < 100 && client->printer->main_level > 0) || (client->printer->envelope_level < 25 && client->printer->envelope_level > 0) || (client->printer->photo_level < 25 && client->printer->photo_level > 0)) - client->printer->state_reasons |= _IPP_PREASON_MEDIA_LOW; - else - client->printer->state_reasons &= (_ipp_preason_t)~_IPP_PREASON_MEDIA_LOW; - - if ((client->printer->main_level == 0 && client->printer->main_size > _IPP_MEDIA_SIZE_NONE) || (client->printer->envelope_level == 0 && client->printer->envelope_size > _IPP_MEDIA_SIZE_NONE) || (client->printer->photo_level == 0 && client->printer->photo_size > _IPP_MEDIA_SIZE_NONE)) - { - client->printer->state_reasons |= _IPP_PREASON_MEDIA_EMPTY; - if (client->printer->active_job) - client->printer->state_reasons |= _IPP_PREASON_MEDIA_NEEDED; - } - else - client->printer->state_reasons &= (_ipp_preason_t)~(_IPP_PREASON_MEDIA_EMPTY | _IPP_PREASON_MEDIA_NEEDED); - - html_printf(client, "
Media updated.
\n"); - } - - html_printf(client, "
\n"); - - html_printf(client, "\n"); - html_printf(client, "\n"); - - html_printf(client, - "\n"); - - html_printf(client, - "\n"); - - html_printf(client, "
Main Tray:
Envelope Feeder:
Photo Tray:
\n"); - html_footer(client); - - return (1); - } - else if (!strcmp(client->uri, "/supplies")) - { - /* - * Show web supplies page... - */ - - int i, j, /* Looping vars */ - num_options; /* Number of form options */ - cups_option_t *options; /* Form options */ - static const int levels[] = { 0, 5, 10, 25, 50, 75, 90, 95, 100 }; - - if (!respond_http(client, HTTP_STATUS_OK, encoding, "text/html", 0)) - return (0); - - html_header(client, client->printer->name); - - if ((num_options = parse_options(client, &options)) > 0) - { - /* - * WARNING: A real printer/server implementation MUST NOT implement - * supply updates via a GET request - GET requests are supposed to be - * idempotent (without side-effects) and we obviously are not - * authenticating access here. This form is provided solely to - * enable testing and development! - */ - - char name[64]; /* Form field */ - const char *val; /* Form value */ - - client->printer->state_reasons &= (_ipp_preason_t)~(_IPP_PREASON_MARKER_SUPPLY_EMPTY | _IPP_PREASON_MARKER_SUPPLY_LOW | _IPP_PREASON_MARKER_WASTE_ALMOST_FULL | _IPP_PREASON_MARKER_WASTE_FULL | _IPP_PREASON_TONER_EMPTY | _IPP_PREASON_TONER_LOW); - - for (i = 0; i < (int)(sizeof(printer_supplies) / sizeof(printer_supplies[0])); i ++) - { - snprintf(name, sizeof(name), "supply_%d", i); - if ((val = cupsGetOption(name, num_options, options)) != NULL) - { - int level = client->printer->supplies[i] = atoi(val); - /* New level */ - - if (i < 4) - { - if (level == 0) - client->printer->state_reasons |= _IPP_PREASON_TONER_EMPTY; - else if (level < 10) - client->printer->state_reasons |= _IPP_PREASON_TONER_LOW; - } - else - { - if (level == 100) - client->printer->state_reasons |= _IPP_PREASON_MARKER_WASTE_FULL; - else if (level > 90) - client->printer->state_reasons |= _IPP_PREASON_MARKER_WASTE_ALMOST_FULL; - } - } - } - - html_printf(client, "
Supplies updated.
\n"); - } - - html_printf(client, "
\n"); - - html_printf(client, "\n"); - for (i = 0; i < (int)(sizeof(printer_supplies) / sizeof(printer_supplies[0])); i ++) - { - html_printf(client, "\n"); - } - html_printf(client, "\n
%s:
\n
\n"); - html_footer(client); - - return (1); - } - else - return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0)); - break; - - case HTTP_STATE_POST : - if (strcmp(httpGetField(client->http, HTTP_FIELD_CONTENT_TYPE), - "application/ipp")) - { - /* - * Not an IPP request... - */ - - return (respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0)); - } - - /* - * Read the IPP request... - */ - - client->request = ippNew(); - - while ((ipp_state = ippRead(client->http, - client->request)) != IPP_STATE_DATA) - { - if (ipp_state == IPP_STATE_ERROR) - { - fprintf(stderr, "%s IPP read error (%s).\n", client->hostname, - cupsLastErrorString()); - respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); - return (0); - } - } - - /* - * Now that we have the IPP request, process the request... - */ - - return (process_ipp(client)); - - default : - break; /* Anti-compiler-warning-code */ - } - - return (1); -} - - -/* - * 'process_ipp()' - Process an IPP request. - */ - -static int /* O - 1 on success, 0 on error */ -process_ipp(_ipp_client_t *client) /* I - Client */ -{ - ipp_tag_t group; /* Current group tag */ - ipp_attribute_t *attr; /* Current attribute */ - ipp_attribute_t *charset; /* Character set attribute */ - ipp_attribute_t *language; /* Language attribute */ - ipp_attribute_t *uri; /* Printer URI attribute */ - int major, minor; /* Version number */ - const char *name; /* Name of attribute */ - - - debug_attributes("Request", client->request, 1); - - /* - * First build an empty response message for this request... - */ - - client->operation_id = ippGetOperation(client->request); - client->response = ippNewResponse(client->request); - - /* - * Then validate the request header and required attributes... - */ - - major = ippGetVersion(client->request, &minor); - - if (major < 1 || major > 2) - { - /* - * Return an error, since we only support IPP 1.x and 2.x. - */ - - respond_ipp(client, IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED, - "Bad request version number %d.%d.", major, minor); - } - else if (ippGetRequestId(client->request) <= 0) - respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad request-id %d.", - ippGetRequestId(client->request)); - else if (!ippFirstAttribute(client->request)) - respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, - "No attributes in request."); - else - { - /* - * Make sure that the attributes are provided in the correct order and - * don't repeat groups... - */ - - for (attr = ippFirstAttribute(client->request), - group = ippGetGroupTag(attr); - attr; - attr = ippNextAttribute(client->request)) - { - if (ippGetGroupTag(attr) < group && ippGetGroupTag(attr) != IPP_TAG_ZERO) - { - /* - * Out of order; return an error... - */ - - respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, - "Attribute groups are out of order (%x < %x).", - ippGetGroupTag(attr), group); - break; - } - else - group = ippGetGroupTag(attr); - } - - if (!attr) - { - /* - * Then make sure that the first three attributes are: - * - * attributes-charset - * attributes-natural-language - * printer-uri/job-uri - */ - - attr = ippFirstAttribute(client->request); - name = ippGetName(attr); - if (attr && name && !strcmp(name, "attributes-charset") && - ippGetValueTag(attr) == IPP_TAG_CHARSET) - charset = attr; - else - charset = NULL; - - attr = ippNextAttribute(client->request); - name = ippGetName(attr); - - if (attr && name && !strcmp(name, "attributes-natural-language") && - ippGetValueTag(attr) == IPP_TAG_LANGUAGE) - language = attr; - else - language = NULL; - - if ((attr = ippFindAttribute(client->request, "printer-uri", - IPP_TAG_URI)) != NULL) - uri = attr; - else if ((attr = ippFindAttribute(client->request, "job-uri", - IPP_TAG_URI)) != NULL) - uri = attr; - else - uri = NULL; - - if (charset && - strcasecmp(ippGetString(charset, 0, NULL), "us-ascii") && - strcasecmp(ippGetString(charset, 0, NULL), "utf-8")) - { - /* - * Bad character set... - */ - - respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, - "Unsupported character set \"%s\".", - ippGetString(charset, 0, NULL)); - } - else if (!charset || !language || !uri) - { - /* - * Return an error, since attributes-charset, - * attributes-natural-language, and printer-uri/job-uri are required - * for all operations. - */ - - respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, - "Missing required attributes."); - } - else - { - char scheme[32], /* URI scheme */ - userpass[32], /* Username/password in URI */ - host[256], /* Host name in URI */ - resource[256]; /* Resource path in URI */ - int port; /* Port number in URI */ - - name = ippGetName(uri); - - if (httpSeparateURI(HTTP_URI_CODING_ALL, ippGetString(uri, 0, NULL), - scheme, sizeof(scheme), - userpass, sizeof(userpass), - host, sizeof(host), &port, - resource, sizeof(resource)) < HTTP_URI_STATUS_OK) - respond_ipp(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, - "Bad %s value '%s'.", name, ippGetString(uri, 0, NULL)); - else if ((!strcmp(name, "job-uri") && - strncmp(resource, "/ipp/print/", 11)) || - (!strcmp(name, "printer-uri") && - strcmp(resource, "/ipp/print"))) - respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "%s %s not found.", - name, ippGetString(uri, 0, NULL)); - else - { - /* - * Try processing the operation... - */ - - switch (ippGetOperation(client->request)) - { - case IPP_OP_PRINT_JOB : - ipp_print_job(client); - break; - - case IPP_OP_PRINT_URI : - ipp_print_uri(client); - break; - - case IPP_OP_VALIDATE_JOB : - ipp_validate_job(client); - break; - - case IPP_OP_CREATE_JOB : - ipp_create_job(client); - break; - - case IPP_OP_SEND_DOCUMENT : - ipp_send_document(client); - break; - - case IPP_OP_SEND_URI : - ipp_send_uri(client); - break; - - case IPP_OP_CANCEL_JOB : - ipp_cancel_job(client); - break; - - case IPP_OP_GET_JOB_ATTRIBUTES : - ipp_get_job_attributes(client); - break; - - case IPP_OP_GET_JOBS : - ipp_get_jobs(client); - break; - - case IPP_OP_GET_PRINTER_ATTRIBUTES : - ipp_get_printer_attributes(client); - break; - - case IPP_OP_CLOSE_JOB : - ipp_close_job(client); - break; - - case IPP_OP_IDENTIFY_PRINTER : - ipp_identify_printer(client); - break; - - default : - respond_ipp(client, IPP_STATUS_ERROR_OPERATION_NOT_SUPPORTED, - "Operation not supported."); - break; - } - } - } - } - } - - /* - * Send the HTTP header and return... - */ - - if (httpGetState(client->http) != HTTP_STATE_POST_SEND) - httpFlush(client->http); /* Flush trailing (junk) data */ - - return (respond_http(client, HTTP_STATUS_OK, NULL, "application/ipp", - ippLength(client->response))); -} - - -/* - * 'process_job()' - Process a print job. - */ - -static void * /* O - Thread exit status */ -process_job(_ipp_job_t *job) /* I - Job */ -{ - job->state = IPP_JSTATE_PROCESSING; - job->printer->state = IPP_PSTATE_PROCESSING; - job->processing = time(NULL); - - while (job->printer->state_reasons & _IPP_PREASON_MEDIA_EMPTY) - { - job->printer->state_reasons |= _IPP_PREASON_MEDIA_NEEDED; - - sleep(1); - } - - job->printer->state_reasons &= (_ipp_preason_t)~_IPP_PREASON_MEDIA_NEEDED; - - if (job->printer->command) - { - /* - * Execute a command with the job spool file and wait for it to complete... - */ - - int pid, /* Process ID */ - status; /* Exit status */ - time_t start, /* Start time */ - end; /* End time */ - char *myargv[3], /* Command-line arguments */ - *myenvp[200]; /* Environment variables */ - int myenvc; /* Number of environment variables */ - ipp_attribute_t *attr; /* Job attribute */ - char val[1280], /* IPP_NAME=value */ - *valptr; /* Pointer into string */ -#ifndef WIN32 - int mypipe[2]; /* Pipe for stderr */ - char line[2048], /* Line from stderr */ - *ptr, /* Pointer into line */ - *endptr; /* End of line */ - ssize_t bytes; /* Bytes read */ -#endif /* !WIN32 */ - - fprintf(stderr, "Running command \"%s %s\".\n", job->printer->command, - job->filename); - time(&start); - - /* - * Setup the command-line arguments... - */ - - myargv[0] = job->printer->command; - myargv[1] = job->filename; - myargv[2] = NULL; - - /* - * Copy the current environment, then add ENV variables for every Job - * attribute... - */ - - for (myenvc = 0; environ[myenvc] && myenvc < (int)(sizeof(myenvp) / sizeof(myenvp[0]) - 1); myenvc ++) - myenvp[myenvc] = strdup(environ[myenvc]); - - for (attr = ippFirstAttribute(job->attrs); attr && myenvc < (int)(sizeof(myenvp) / sizeof(myenvp[0]) - 1); attr = ippNextAttribute(job->attrs)) - { - /* - * Convert "attribute-name" to "IPP_ATTRIBUTE_NAME=" and then add the - * value(s) from the attribute. - */ - - const char *name = ippGetName(attr); - if (!name) - continue; - - valptr = val; - *valptr++ = 'I'; - *valptr++ = 'P'; - *valptr++ = 'P'; - *valptr++ = '_'; - while (*name && valptr < (val + sizeof(val) - 2)) - { - if (*name == '-') - *valptr++ = '_'; - else - *valptr++ = (char)toupper(*name & 255); - - name ++; - } - *valptr++ = '='; - ippAttributeString(attr, valptr, sizeof(val) - (size_t)(valptr - val)); - - myenvp[myenvc++] = strdup(val); - } - myenvp[myenvc] = NULL; - - /* - * Now run the program... - */ - -#ifdef WIN32 - status = _spawnvpe(_P_WAIT, job->printer->command, myargv, myenvp); - -#else - if (pipe(mypipe)) - { - perror("Unable to create pipe for stderr"); - mypipe[0] = mypipe[1] = -1; - } - - if ((pid = fork()) == 0) - { - /* - * Child comes here... - */ - - close(2); - dup2(mypipe[1], 2); - close(mypipe[0]); - close(mypipe[1]); - - execve(job->printer->command, myargv, myenvp); - exit(errno); - } - else if (pid < 0) - { - /* - * Unable to fork process... - */ - - perror("Unable to start job processing command"); - status = -1; - - close(mypipe[0]); - close(mypipe[1]); - - /* - * Free memory used for environment... - */ - - while (myenvc > 0) - free(myenvp[-- myenvc]); - } - else - { - /* - * Free memory used for environment... - */ - - while (myenvc > 0) - free(myenvp[-- myenvc]); - - /* - * If the pipe exists, read from it until EOF... - */ - - if (mypipe[0] >= 0) - { - close(mypipe[1]); - - endptr = line; - while ((bytes = read(mypipe[0], endptr, sizeof(line) - (size_t)(endptr - line) - 1)) > 0) - { - endptr += bytes; - *endptr = '\0'; - - while ((ptr = strchr(line, '\n')) != NULL) - { - *ptr++ = '\0'; - - if (!strncmp(line, "STATE:", 6)) - { - /* - * Process printer-state-reasons keywords. - */ - - process_state_message(job, line); - } - else if (!strncmp(line, "ATTR:", 5)) - { - /* - * Process printer attribute update. - */ - - process_attr_message(job, line); - } - else if (Verbosity > 1) - fprintf(stderr, "%s: %s\n", job->printer->command, line); - - bytes = ptr - line; - if (ptr < endptr) - memmove(line, ptr, (size_t)(endptr - ptr)); - endptr -= bytes; - *endptr = '\0'; - } - } - - close(mypipe[0]); - } - - /* - * Wait for child to complete... - */ - -# ifdef HAVE_WAITPID - while (waitpid(pid, &status, 0) < 0); -# else - while (wait(&status) < 0); -# endif /* HAVE_WAITPID */ - } -#endif /* WIN32 */ - - if (status) - { -#ifndef WIN32 - if (WIFEXITED(status)) -#endif /* !WIN32 */ - fprintf(stderr, "Command \"%s\" exited with status %d.\n", - job->printer->command, WEXITSTATUS(status)); -#ifndef WIN32 - else - fprintf(stderr, "Command \"%s\" terminated with signal %d.\n", - job->printer->command, WTERMSIG(status)); -#endif /* !WIN32 */ - job->state = IPP_JSTATE_ABORTED; - } - else if (status < 0) - job->state = IPP_JSTATE_ABORTED; - else - fprintf(stderr, "Command \"%s\" completed successfully.\n", - job->printer->command); - - /* - * Make sure processing takes at least 5 seconds... - */ - - time(&end); - if ((end - start) < 5) - sleep(5); - } - else - { - /* - * Sleep for a random amount of time to simulate job processing. - */ - - sleep((unsigned)(5 + (rand() % 11))); - } - - if (job->cancel) - job->state = IPP_JSTATE_CANCELED; - else if (job->state == IPP_JSTATE_PROCESSING) - job->state = IPP_JSTATE_COMPLETED; - - job->completed = time(NULL); - job->printer->state = IPP_PSTATE_IDLE; - job->printer->active_job = NULL; - - return (NULL); -} - - -/* - * 'process_state_message()' - Process a STATE: message from a command. - */ - -static void -process_state_message( - _ipp_job_t *job, /* I - Job */ - char *message) /* I - Message */ -{ - int i; /* Looping var */ - _ipp_preason_t state_reasons, /* printer-state-reasons values */ - bit; /* Current reason bit */ - char *ptr, /* Pointer into message */ - *next; /* Next keyword in message */ - int remove; /* Non-zero if we are removing keywords */ - - - /* - * Skip leading "STATE:" and any whitespace... - */ - - for (message += 6; *message; message ++) - if (*message != ' ' && *message != '\t') - break; - - /* - * Support the following forms of message: - * - * "keyword[,keyword,...]" to set the printer-state-reasons value(s). - * - * "-keyword[,keyword,...]" to remove keywords. - * - * "+keyword[,keyword,...]" to add keywords. - * - * Keywords may or may not have a suffix (-report, -warning, -error) per - * RFC 2911. - */ - - if (*message == '-') - { - remove = 1; - state_reasons = job->printer->state_reasons; - message ++; - } - else if (*message == '+') - { - remove = 0; - state_reasons = job->printer->state_reasons; - message ++; - } - else - { - remove = 0; - state_reasons = _IPP_PREASON_NONE; - } - - while (*message) - { - if ((next = strchr(message, ',')) != NULL) - *next++ = '\0'; - - if ((ptr = strstr(message, "-error")) != NULL) - *ptr = '\0'; - else if ((ptr = strstr(message, "-report")) != NULL) - *ptr = '\0'; - else if ((ptr = strstr(message, "-warning")) != NULL) - *ptr = '\0'; - - for (i = 0, bit = 1; i < (int)(sizeof(_ipp_preason_strings) / sizeof(_ipp_preason_strings[0])); i ++, bit *= 2) - { - if (!strcmp(message, _ipp_preason_strings[i])) - { - if (remove) - state_reasons &= ~bit; - else - state_reasons |= bit; - } - } - - if (next) - message = next; - else - break; - } - - job->printer->state_reasons = state_reasons; -} - - -/* - * 'register_printer()' - Register a printer object via Bonjour. - */ - -static int /* O - 1 on success, 0 on error */ -register_printer( - _ipp_printer_t *printer, /* I - Printer */ - const char *location, /* I - Location */ - const char *make, /* I - Manufacturer */ - const char *model, /* I - Model name */ - const char *formats, /* I - Supported formats */ - const char *adminurl, /* I - Web interface URL */ - const char *uuid, /* I - Printer UUID */ - int color, /* I - 1 = color, 0 = monochrome */ - int duplex, /* I - 1 = duplex, 0 = simplex */ - const char *subtype) /* I - Service subtype */ -{ -#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) - _ipp_txt_t ipp_txt; /* Bonjour IPP TXT record */ -#endif /* HAVE_DNSSD || HAVE_AVAHI */ -#ifdef HAVE_DNSSD - DNSServiceErrorType error; /* Error from Bonjour */ - char make_model[256],/* Make and model together */ - product[256], /* Product string */ - regtype[256]; /* Bonjour service type */ - - - /* - * Build the TXT record for IPP... - */ - - snprintf(make_model, sizeof(make_model), "%s %s", make, model); - snprintf(product, sizeof(product), "(%s)", model); - - TXTRecordCreate(&ipp_txt, 1024, NULL); - TXTRecordSetValue(&ipp_txt, "rp", 9, "ipp/print"); - TXTRecordSetValue(&ipp_txt, "ty", (uint8_t)strlen(make_model), - make_model); - TXTRecordSetValue(&ipp_txt, "adminurl", (uint8_t)strlen(adminurl), - adminurl); - if (*location) - TXTRecordSetValue(&ipp_txt, "note", (uint8_t)strlen(location), - location); - TXTRecordSetValue(&ipp_txt, "product", (uint8_t)strlen(product), - product); - TXTRecordSetValue(&ipp_txt, "pdl", (uint8_t)strlen(formats), - formats); - TXTRecordSetValue(&ipp_txt, "Color", 1, color ? "T" : "F"); - TXTRecordSetValue(&ipp_txt, "Duplex", 1, duplex ? "T" : "F"); - TXTRecordSetValue(&ipp_txt, "usb_MFG", (uint8_t)strlen(make), - make); - TXTRecordSetValue(&ipp_txt, "usb_MDL", (uint8_t)strlen(model), - model); - TXTRecordSetValue(&ipp_txt, "UUID", (uint8_t)strlen(uuid), uuid); -# ifdef HAVE_SSL - TXTRecordSetValue(&ipp_txt, "TLS", 3, "1.2"); -# endif /* HAVE_SSL */ - if (strstr(formats, "image/urf")) - TXTRecordSetValue(&ipp_txt, "URF", 66, "CP1,IS1-5-7,MT1-2-3-4-5-6-8-9-10-11-12-13,RS300,SRGB24,V1.4,W8,DM1"); - - TXTRecordSetValue(&ipp_txt, "txtvers", 1, "1"); - TXTRecordSetValue(&ipp_txt, "qtotal", 1, "1"); - - /* - * Register the _printer._tcp (LPD) service type with a port number of 0 to - * defend our service name but not actually support LPD... - */ - - printer->printer_ref = DNSSDMaster; - - if ((error = DNSServiceRegister(&(printer->printer_ref), - kDNSServiceFlagsShareConnection, - 0 /* interfaceIndex */, printer->dnssd_name, - "_printer._tcp", NULL /* domain */, - NULL /* host */, 0 /* port */, 0 /* txtLen */, - NULL /* txtRecord */, - (DNSServiceRegisterReply)dnssd_callback, - printer)) != kDNSServiceErr_NoError) - { - fprintf(stderr, "Unable to register \"%s._printer._tcp\": %d\n", - printer->dnssd_name, error); - return (0); - } - - /* - * Then register the _ipp._tcp (IPP) service type with the real port number to - * advertise our IPP printer... - */ - - printer->ipp_ref = DNSSDMaster; - - if (subtype && *subtype) - snprintf(regtype, sizeof(regtype), "_ipp._tcp,%s", subtype); - else - strlcpy(regtype, "_ipp._tcp", sizeof(regtype)); - - if ((error = DNSServiceRegister(&(printer->ipp_ref), - kDNSServiceFlagsShareConnection, - 0 /* interfaceIndex */, printer->dnssd_name, - regtype, NULL /* domain */, - NULL /* host */, htons(printer->port), - TXTRecordGetLength(&ipp_txt), - TXTRecordGetBytesPtr(&ipp_txt), - (DNSServiceRegisterReply)dnssd_callback, - printer)) != kDNSServiceErr_NoError) - { - fprintf(stderr, "Unable to register \"%s.%s\": %d\n", - printer->dnssd_name, regtype, error); - return (0); - } - -# ifdef HAVE_SSL - /* - * Then register the _ipps._tcp (IPP) service type with the real port number to - * advertise our IPPS printer... - */ - - printer->ipps_ref = DNSSDMaster; - - if (subtype && *subtype) - snprintf(regtype, sizeof(regtype), "_ipps._tcp,%s", subtype); - else - strlcpy(regtype, "_ipps._tcp", sizeof(regtype)); - - if ((error = DNSServiceRegister(&(printer->ipps_ref), - kDNSServiceFlagsShareConnection, - 0 /* interfaceIndex */, printer->dnssd_name, - regtype, NULL /* domain */, - NULL /* host */, htons(printer->port), - TXTRecordGetLength(&ipp_txt), - TXTRecordGetBytesPtr(&ipp_txt), - (DNSServiceRegisterReply)dnssd_callback, - printer)) != kDNSServiceErr_NoError) - { - fprintf(stderr, "Unable to register \"%s.%s\": %d\n", - printer->dnssd_name, regtype, error); - return (0); - } -# endif /* HAVE_SSL */ - - /* - * Similarly, register the _http._tcp,_printer (HTTP) service type with the - * real port number to advertise our IPP printer... - */ - - printer->http_ref = DNSSDMaster; - - if ((error = DNSServiceRegister(&(printer->http_ref), - kDNSServiceFlagsShareConnection, - 0 /* interfaceIndex */, printer->dnssd_name, - "_http._tcp,_printer", NULL /* domain */, - NULL /* host */, htons(printer->port), - 0 /* txtLen */, NULL, /* txtRecord */ - (DNSServiceRegisterReply)dnssd_callback, - printer)) != kDNSServiceErr_NoError) - { - fprintf(stderr, "Unable to register \"%s.%s\": %d\n", - printer->dnssd_name, regtype, error); - return (0); - } - - TXTRecordDeallocate(&ipp_txt); - -#elif defined(HAVE_AVAHI) - char temp[256]; /* Subtype service string */ - - /* - * Create the TXT record... - */ - - ipp_txt = NULL; - ipp_txt = avahi_string_list_add_printf(ipp_txt, "rp=ipp/print"); - ipp_txt = avahi_string_list_add_printf(ipp_txt, "ty=%s %s", make, model); - ipp_txt = avahi_string_list_add_printf(ipp_txt, "adminurl=%s", adminurl); - if (*location) - ipp_txt = avahi_string_list_add_printf(ipp_txt, "note=%s", location); - ipp_txt = avahi_string_list_add_printf(ipp_txt, "product=(%s)", model); - ipp_txt = avahi_string_list_add_printf(ipp_txt, "pdl=%s", formats); - ipp_txt = avahi_string_list_add_printf(ipp_txt, "Color=%s", color ? "T" : "F"); - ipp_txt = avahi_string_list_add_printf(ipp_txt, "Duplex=%s", duplex ? "T" : "F"); - ipp_txt = avahi_string_list_add_printf(ipp_txt, "usb_MFG=%s", make); - ipp_txt = avahi_string_list_add_printf(ipp_txt, "usb_MDL=%s", model); - ipp_txt = avahi_string_list_add_printf(ipp_txt, "UUID=%s", uuid); -# ifdef HAVE_SSL - ipp_txt = avahi_string_list_add_printf(ipp_txt, "TLS=1.2"); -# endif /* HAVE_SSL */ - - /* - * Register _printer._tcp (LPD) with port 0 to reserve the service name... - */ - - avahi_threaded_poll_lock(DNSSDMaster); - - printer->ipp_ref = avahi_entry_group_new(DNSSDClient, dnssd_callback, NULL); - - avahi_entry_group_add_service_strlst(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_printer._tcp", NULL, NULL, 0, NULL); - - /* - * Then register the _ipp._tcp (IPP)... - */ - - avahi_entry_group_add_service_strlst(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_ipp._tcp", NULL, NULL, printer->port, ipp_txt); - if (subtype && *subtype) - { - snprintf(temp, sizeof(temp), "%s._sub._ipp._tcp", subtype); - avahi_entry_group_add_service_subtype(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_ipp._tcp", NULL, temp); - } - -#ifdef HAVE_SSL - /* - * _ipps._tcp (IPPS) for secure printing... - */ - - avahi_entry_group_add_service_strlst(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_ipps._tcp", NULL, NULL, printer->port, ipp_txt); - if (subtype && *subtype) - { - snprintf(temp, sizeof(temp), "%s._sub._ipps._tcp", subtype); - avahi_entry_group_add_service_subtype(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_ipps._tcp", NULL, temp); - } -#endif /* HAVE_SSL */ - - /* - * Finally _http.tcp (HTTP) for the web interface... - */ - - avahi_entry_group_add_service_strlst(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_http._tcp", NULL, NULL, printer->port, NULL); - avahi_entry_group_add_service_subtype(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_http._tcp", NULL, "_printer._sub._http._tcp"); - - /* - * Commit it... - */ - - avahi_entry_group_commit(printer->ipp_ref); - avahi_threaded_poll_unlock(DNSSDMaster); - - avahi_string_list_free(ipp_txt); -#endif /* HAVE_DNSSD */ - - return (1); -} - - -/* - * 'respond_http()' - Send a HTTP response. - */ - -int /* O - 1 on success, 0 on failure */ -respond_http( - _ipp_client_t *client, /* I - Client */ - http_status_t code, /* I - HTTP status of response */ - const char *content_encoding, /* I - Content-Encoding of response */ - const char *type, /* I - MIME media type of response */ - size_t length) /* I - Length of response */ -{ - char message[1024]; /* Text message */ - - - fprintf(stderr, "%s %s\n", client->hostname, httpStatus(code)); - - if (code == HTTP_STATUS_CONTINUE) - { - /* - * 100-continue doesn't send any headers... - */ - - return (httpWriteResponse(client->http, HTTP_STATUS_CONTINUE) == 0); - } - - /* - * Format an error message... - */ - - if (!type && !length && code != HTTP_STATUS_OK && code != HTTP_STATUS_SWITCHING_PROTOCOLS) - { - snprintf(message, sizeof(message), "%d - %s\n", code, httpStatus(code)); - - type = "text/plain"; - length = strlen(message); - } - else - message[0] = '\0'; - - /* - * Send the HTTP response header... - */ - - httpClearFields(client->http); - - if (code == HTTP_STATUS_METHOD_NOT_ALLOWED || - client->operation == HTTP_STATE_OPTIONS) - httpSetField(client->http, HTTP_FIELD_ALLOW, "GET, HEAD, OPTIONS, POST"); - - if (type) - { - if (!strcmp(type, "text/html")) - httpSetField(client->http, HTTP_FIELD_CONTENT_TYPE, - "text/html; charset=utf-8"); - else - httpSetField(client->http, HTTP_FIELD_CONTENT_TYPE, type); - - if (content_encoding) - httpSetField(client->http, HTTP_FIELD_CONTENT_ENCODING, content_encoding); - } - - httpSetLength(client->http, length); - - if (httpWriteResponse(client->http, code) < 0) - return (0); - - /* - * Send the response data... - */ - - if (message[0]) - { - /* - * Send a plain text message. - */ - - if (httpPrintf(client->http, "%s", message) < 0) - return (0); - - if (httpWrite2(client->http, "", 0) < 0) - return (0); - } - else if (client->response) - { - /* - * Send an IPP response... - */ - - debug_attributes("Response", client->response, 2); - - ippSetState(client->response, IPP_STATE_IDLE); - - if (ippWrite(client->http, client->response) != IPP_STATE_DATA) - return (0); - } - - return (1); -} - - -/* - * 'respond_ipp()' - Send an IPP response. - */ - -static void -respond_ipp(_ipp_client_t *client, /* I - Client */ - ipp_status_t status, /* I - status-code */ - const char *message, /* I - printf-style status-message */ - ...) /* I - Additional args as needed */ -{ - const char *formatted = NULL; /* Formatted message */ - - - ippSetStatusCode(client->response, status); - - if (message) - { - va_list ap; /* Pointer to additional args */ - ipp_attribute_t *attr; /* New status-message attribute */ - - va_start(ap, message); - if ((attr = ippFindAttribute(client->response, "status-message", - IPP_TAG_TEXT)) != NULL) - ippSetStringfv(client->response, &attr, 0, message, ap); - else - attr = ippAddStringfv(client->response, IPP_TAG_OPERATION, IPP_TAG_TEXT, - "status-message", NULL, message, ap); - va_end(ap); - - formatted = ippGetString(attr, 0, NULL); - } - - if (formatted) - fprintf(stderr, "%s %s %s (%s)\n", client->hostname, - ippOpString(client->operation_id), ippErrorString(status), - formatted); - else - fprintf(stderr, "%s %s %s\n", client->hostname, - ippOpString(client->operation_id), ippErrorString(status)); -} - - -/* - * 'respond_unsupported()' - Respond with an unsupported attribute. - */ - -static void -respond_unsupported( - _ipp_client_t *client, /* I - Client */ - ipp_attribute_t *attr) /* I - Atribute */ -{ - ipp_attribute_t *temp; /* Copy of attribute */ - - - respond_ipp(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, - "Unsupported %s %s%s value.", ippGetName(attr), - ippGetCount(attr) > 1 ? "1setOf " : "", - ippTagString(ippGetValueTag(attr))); - - temp = ippCopyAttribute(client->response, attr, 0); - ippSetGroupTag(client->response, &temp, IPP_TAG_UNSUPPORTED_GROUP); -} - - -/* - * 'run_printer()' - Run the printer service. - */ - -static void -run_printer(_ipp_printer_t *printer) /* I - Printer */ -{ - int num_fds; /* Number of file descriptors */ - struct pollfd polldata[3]; /* poll() data */ - int timeout; /* Timeout for poll() */ - _ipp_client_t *client; /* New client */ - - - /* - * Setup poll() data for the Bonjour service socket and IPv4/6 listeners... - */ - - polldata[0].fd = printer->ipv4; - polldata[0].events = POLLIN; - - polldata[1].fd = printer->ipv6; - polldata[1].events = POLLIN; - - num_fds = 2; - -#ifdef HAVE_DNSSD - polldata[num_fds ].fd = DNSServiceRefSockFD(DNSSDMaster); - polldata[num_fds ++].events = POLLIN; -#endif /* HAVE_DNSSD */ - - /* - * Loop until we are killed or have a hard error... - */ - - for (;;) - { - if (cupsArrayCount(printer->jobs)) - timeout = 10; - else - timeout = -1; - - if (poll(polldata, (nfds_t)num_fds, timeout) < 0 && errno != EINTR) - { - perror("poll() failed"); - break; - } - - if (polldata[0].revents & POLLIN) - { - if ((client = create_client(printer, printer->ipv4)) != NULL) - { - _cups_thread_t t = _cupsThreadCreate((_cups_thread_func_t)process_client, client); - - if (t) - { - _cupsThreadDetach(t); - } - else - { - perror("Unable to create client thread"); - delete_client(client); - } - } - } - - if (polldata[1].revents & POLLIN) - { - if ((client = create_client(printer, printer->ipv6)) != NULL) - { - _cups_thread_t t = _cupsThreadCreate((_cups_thread_func_t)process_client, client); - - if (t) - { - _cupsThreadDetach(t); - } - else - { - perror("Unable to create client thread"); - delete_client(client); - } - } - } - -#ifdef HAVE_DNSSD - if (polldata[2].revents & POLLIN) - DNSServiceProcessResult(DNSSDMaster); -#endif /* HAVE_DNSSD */ - - /* - * Clean out old jobs... - */ - - clean_jobs(printer); - } -} - - -/* - * 'time_string()' - Return the local time in hours, minutes, and seconds. - */ - -static char * -time_string(time_t tv, /* I - Time value */ - char *buffer, /* I - Buffer */ - size_t bufsize) /* I - Size of buffer */ -{ - struct tm *curtime = localtime(&tv); - /* Local time */ - - strftime(buffer, bufsize, "%X", curtime); - return (buffer); -} - - -/* - * 'usage()' - Show program usage. - */ - -static void -usage(int status) /* O - Exit status */ -{ - if (!status) - { - puts(CUPS_SVERSION " - Copyright 2010-2015 by Apple Inc. All rights " - "reserved."); - puts(""); - } - - puts("Usage: ippserver [options] \"name\""); - puts(""); - puts("Options:"); - puts("-2 Supports 2-sided printing (default=1-sided)"); - puts("-M manufacturer Manufacturer name (default=Test)"); - puts("-P PIN printing mode"); - puts("-a attributes-file Load printer attributes from file"); - puts("-c command Run command for every print job"); - printf("-d spool-directory Spool directory " - "(default=/tmp/ippserver.%d)\n", (int)getpid()); - puts("-f type/subtype[,...] List of supported types " - "(default=application/pdf,image/jpeg)"); - puts("-h Show program help"); - puts("-i iconfile.png PNG icon file (default=printer.png)"); - puts("-k Keep job spool files"); - puts("-l location Location of printer (default=empty string)"); - puts("-m model Model name (default=Printer)"); - puts("-n hostname Hostname for printer"); - puts("-p port Port number (default=auto)"); - puts("-r subtype Bonjour service subtype (default=_print)"); - puts("-s speed[,color-speed] Speed in pages per minute (default=10,0)"); - puts("-v[vvv] Be (very) verbose"); - - exit(status); -} - - -/* - * 'valid_doc_attributes()' - Determine whether the document attributes are - * valid. - * - * When one or more document attributes are invalid, this function adds a - * suitable response and attributes to the unsupported group. - */ - -static int /* O - 1 if valid, 0 if not */ -valid_doc_attributes( - _ipp_client_t *client) /* I - Client */ -{ - int valid = 1; /* Valid attributes? */ - ipp_op_t op = ippGetOperation(client->request); - /* IPP operation */ - const char *op_name = ippOpString(op); - /* IPP operation name */ - ipp_attribute_t *attr, /* Current attribute */ - *supported; /* xxx-supported attribute */ - const char *compression = NULL, - /* compression value */ - *format = NULL; /* document-format value */ - - - /* - * Check operation attributes... - */ - - if ((attr = ippFindAttribute(client->request, "compression", IPP_TAG_ZERO)) != NULL) - { - /* - * If compression is specified, only accept a supported value in a Print-Job - * or Send-Document request... - */ - - compression = ippGetString(attr, 0, NULL); - supported = ippFindAttribute(client->printer->attrs, - "compression-supported", IPP_TAG_KEYWORD); - - if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_KEYWORD || - ippGetGroupTag(attr) != IPP_TAG_OPERATION || - (op != IPP_OP_PRINT_JOB && op != IPP_OP_SEND_DOCUMENT && - op != IPP_OP_VALIDATE_JOB) || - !ippContainsString(supported, compression)) - { - respond_unsupported(client, attr); - valid = 0; - } - else - { - fprintf(stderr, "%s %s compression=\"%s\"\n", client->hostname, op_name, compression); - - ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "compression-supplied", NULL, compression); - - if (strcmp(compression, "none")) - { - if (Verbosity) - fprintf(stderr, "Receiving job file with \"%s\" compression.\n", compression); - httpSetField(client->http, HTTP_FIELD_CONTENT_ENCODING, compression); - } - } - } - - /* - * Is it a format we support? - */ - - if ((attr = ippFindAttribute(client->request, "document-format", IPP_TAG_ZERO)) != NULL) - { - if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_MIMETYPE || - ippGetGroupTag(attr) != IPP_TAG_OPERATION) - { - respond_unsupported(client, attr); - valid = 0; - } - else - { - format = ippGetString(attr, 0, NULL); - - fprintf(stderr, "%s %s document-format=\"%s\"\n", - client->hostname, op_name, format); - - ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-supplied", NULL, format); - } - } - else - { - format = ippGetString(ippFindAttribute(client->printer->attrs, "document-format-default", IPP_TAG_MIMETYPE), 0, NULL); - if (!format) - format = "application/octet-stream"; /* Should never happen */ - - attr = ippAddString(client->request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, format); - } - - if (format && !strcmp(format, "application/octet-stream") && (ippGetOperation(client->request) == IPP_OP_PRINT_JOB || ippGetOperation(client->request) == IPP_OP_SEND_DOCUMENT)) - { - /* - * Auto-type the file using the first 8 bytes of the file... - */ - - unsigned char header[8]; /* First 8 bytes of file */ - - memset(header, 0, sizeof(header)); - httpPeek(client->http, (char *)header, sizeof(header)); - - if (!memcmp(header, "%PDF", 4)) - format = "application/pdf"; - else if (!memcmp(header, "%!", 2)) - format = "application/postscript"; - else if (!memcmp(header, "\377\330\377", 3) && header[3] >= 0xe0 && header[3] <= 0xef) - format = "image/jpeg"; - else if (!memcmp(header, "\211PNG", 4)) - format = "image/png"; - else if (!memcmp(header, "RAS2", 4)) - format = "image/pwg-raster"; - else if (!memcmp(header, "UNIRAST", 8)) - format = "image/urf"; - else - format = NULL; - - if (format) - { - fprintf(stderr, "%s %s Auto-typed document-format=\"%s\"\n", - client->hostname, op_name, format); - - ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-detected", NULL, format); - } - } - - if (op != IPP_OP_CREATE_JOB && (supported = ippFindAttribute(client->printer->attrs, "document-format-supported", IPP_TAG_MIMETYPE)) != NULL && !ippContainsString(supported, format)) - { - respond_unsupported(client, attr); - valid = 0; - } - - /* - * document-name - */ - - if ((attr = ippFindAttribute(client->request, "document-name", IPP_TAG_NAME)) != NULL) - ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_NAME, "document-name-supplied", NULL, ippGetString(attr, 0, NULL)); - - return (valid); -} - - -/* - * 'valid_job_attributes()' - Determine whether the job attributes are valid. - * - * When one or more job attributes are invalid, this function adds a suitable - * response and attributes to the unsupported group. - */ - -static int /* O - 1 if valid, 0 if not */ -valid_job_attributes( - _ipp_client_t *client) /* I - Client */ -{ - int i, /* Looping var */ - count, /* Number of values */ - valid = 1; /* Valid attributes? */ - ipp_attribute_t *attr, /* Current attribute */ - *supported; /* xxx-supported attribute */ - - - /* - * Check operation attributes... - */ - - valid = valid_doc_attributes(client); - - /* - * Check the various job template attributes... - */ - - if ((attr = ippFindAttribute(client->request, "copies", IPP_TAG_ZERO)) != NULL) - { - if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_INTEGER || - ippGetInteger(attr, 0) < 1 || ippGetInteger(attr, 0) > 999) - { - respond_unsupported(client, attr); - valid = 0; - } - } - - if ((attr = ippFindAttribute(client->request, "ipp-attribute-fidelity", IPP_TAG_ZERO)) != NULL) - { - if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_BOOLEAN) - { - respond_unsupported(client, attr); - valid = 0; - } - } - - if ((attr = ippFindAttribute(client->request, "job-hold-until", IPP_TAG_ZERO)) != NULL) - { - if (ippGetCount(attr) != 1 || - (ippGetValueTag(attr) != IPP_TAG_NAME && - ippGetValueTag(attr) != IPP_TAG_NAMELANG && - ippGetValueTag(attr) != IPP_TAG_KEYWORD) || - strcmp(ippGetString(attr, 0, NULL), "no-hold")) - { - respond_unsupported(client, attr); - valid = 0; - } - } - - if ((attr = ippFindAttribute(client->request, "job-impressions", IPP_TAG_ZERO)) != NULL) - { - if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetInteger(attr, 0) < 0) - { - respond_unsupported(client, attr); - valid = 0; - } - } - - if ((attr = ippFindAttribute(client->request, "job-name", IPP_TAG_ZERO)) != NULL) - { - if (ippGetCount(attr) != 1 || - (ippGetValueTag(attr) != IPP_TAG_NAME && - ippGetValueTag(attr) != IPP_TAG_NAMELANG)) - { - respond_unsupported(client, attr); - valid = 0; - } - - ippSetGroupTag(client->request, &attr, IPP_TAG_JOB); - } - else - ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled"); - - if ((attr = ippFindAttribute(client->request, "job-priority", IPP_TAG_ZERO)) != NULL) - { - if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_INTEGER || - ippGetInteger(attr, 0) < 1 || ippGetInteger(attr, 0) > 100) - { - respond_unsupported(client, attr); - valid = 0; - } - } - - if ((attr = ippFindAttribute(client->request, "job-sheets", IPP_TAG_ZERO)) != NULL) - { - if (ippGetCount(attr) != 1 || - (ippGetValueTag(attr) != IPP_TAG_NAME && - ippGetValueTag(attr) != IPP_TAG_NAMELANG && - ippGetValueTag(attr) != IPP_TAG_KEYWORD) || - strcmp(ippGetString(attr, 0, NULL), "none")) - { - respond_unsupported(client, attr); - valid = 0; - } - } - - if ((attr = ippFindAttribute(client->request, "media", IPP_TAG_ZERO)) != NULL) - { - if (ippGetCount(attr) != 1 || - (ippGetValueTag(attr) != IPP_TAG_NAME && - ippGetValueTag(attr) != IPP_TAG_NAMELANG && - ippGetValueTag(attr) != IPP_TAG_KEYWORD)) - { - respond_unsupported(client, attr); - valid = 0; - } - else - { - supported = ippFindAttribute(client->printer->attrs, "media-supported", IPP_TAG_KEYWORD); - - if (!ippContainsString(supported, ippGetString(attr, 0, NULL))) - { - respond_unsupported(client, attr); - valid = 0; - } - } - } - - if ((attr = ippFindAttribute(client->request, "media-col", IPP_TAG_ZERO)) != NULL) - { - ipp_t *col, /* media-col collection */ - *size; /* media-size collection */ - ipp_attribute_t *member, /* Member attribute */ - *x_dim, /* x-dimension */ - *y_dim; /* y-dimension */ - int x_value, /* y-dimension value */ - y_value; /* x-dimension value */ - - if (ippGetCount(attr) != 1 || - ippGetValueTag(attr) != IPP_TAG_BEGIN_COLLECTION) - { - respond_unsupported(client, attr); - valid = 0; - } - - col = ippGetCollection(attr, 0); - - if ((member = ippFindAttribute(col, "media-size-name", IPP_TAG_ZERO)) != NULL) - { - if (ippGetCount(member) != 1 || - (ippGetValueTag(member) != IPP_TAG_NAME && - ippGetValueTag(member) != IPP_TAG_NAMELANG && - ippGetValueTag(member) != IPP_TAG_KEYWORD)) - { - respond_unsupported(client, attr); - valid = 0; - } - else - { - supported = ippFindAttribute(client->printer->attrs, "media-supported", IPP_TAG_KEYWORD); - - if (!ippContainsString(supported, ippGetString(member, 0, NULL))) - { - respond_unsupported(client, attr); - valid = 0; - } - } - } - else if ((member = ippFindAttribute(col, "media-size", IPP_TAG_BEGIN_COLLECTION)) != NULL) - { - if (ippGetCount(member) != 1) - { - respond_unsupported(client, attr); - valid = 0; - } - else - { - size = ippGetCollection(member, 0); - - if ((x_dim = ippFindAttribute(size, "x-dimension", IPP_TAG_INTEGER)) == NULL || ippGetCount(x_dim) != 1 || - (y_dim = ippFindAttribute(size, "y-dimension", IPP_TAG_INTEGER)) == NULL || ippGetCount(y_dim) != 1) - { - respond_unsupported(client, attr); - valid = 0; - } - else - { - x_value = ippGetInteger(x_dim, 0); - y_value = ippGetInteger(y_dim, 0); - supported = ippFindAttribute(client->printer->attrs, "media-size-supported", IPP_TAG_BEGIN_COLLECTION); - count = ippGetCount(supported); - - for (i = 0; i < count ; i ++) - { - size = ippGetCollection(supported, i); - x_dim = ippFindAttribute(size, "x-dimension", IPP_TAG_ZERO); - y_dim = ippFindAttribute(size, "y-dimension", IPP_TAG_ZERO); - - if (ippContainsInteger(x_dim, x_value) && ippContainsInteger(y_dim, y_value)) - break; - } - - if (i >= count) - { - respond_unsupported(client, attr); - valid = 0; - } - } - } - } - } - - if ((attr = ippFindAttribute(client->request, "multiple-document-handling", IPP_TAG_ZERO)) != NULL) - { - if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_KEYWORD || - (strcmp(ippGetString(attr, 0, NULL), - "separate-documents-uncollated-copies") && - strcmp(ippGetString(attr, 0, NULL), - "separate-documents-collated-copies"))) - { - respond_unsupported(client, attr); - valid = 0; - } - } - - if ((attr = ippFindAttribute(client->request, "orientation-requested", IPP_TAG_ZERO)) != NULL) - { - if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_ENUM || - ippGetInteger(attr, 0) < IPP_ORIENT_PORTRAIT || - ippGetInteger(attr, 0) > IPP_ORIENT_REVERSE_PORTRAIT) - { - respond_unsupported(client, attr); - valid = 0; - } - } - - if ((attr = ippFindAttribute(client->request, "page-ranges", IPP_TAG_ZERO)) != NULL) - { - if (ippGetValueTag(attr) != IPP_TAG_RANGE) - { - respond_unsupported(client, attr); - valid = 0; - } - } - - if ((attr = ippFindAttribute(client->request, "print-quality", IPP_TAG_ZERO)) != NULL) - { - if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_ENUM || - ippGetInteger(attr, 0) < IPP_QUALITY_DRAFT || - ippGetInteger(attr, 0) > IPP_QUALITY_HIGH) - { - respond_unsupported(client, attr); - valid = 0; - } - } - - if ((attr = ippFindAttribute(client->request, "printer-resolution", IPP_TAG_ZERO)) != NULL) - { - supported = ippFindAttribute(client->printer->attrs, "printer-resolution-supported", IPP_TAG_RESOLUTION); - - if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_RESOLUTION || - !supported) - { - respond_unsupported(client, attr); - valid = 0; - } - else - { - int xdpi, /* Horizontal resolution for job template attribute */ - ydpi, /* Vertical resolution for job template attribute */ - sydpi; /* Vertical resolution for supported value */ - ipp_res_t units, /* Units for job template attribute */ - sunits; /* Units for supported value */ - - xdpi = ippGetResolution(attr, 0, &ydpi, &units); - count = ippGetCount(supported); - - for (i = 0; i < count; i ++) - { - if (xdpi == ippGetResolution(supported, i, &sydpi, &sunits) && ydpi == sydpi && units == sunits) - break; - } - - if (i >= count) - { - respond_unsupported(client, attr); - valid = 0; - } - } - } - - if ((attr = ippFindAttribute(client->request, "sides", IPP_TAG_ZERO)) != NULL) - { - const char *sides = ippGetString(attr, 0, NULL); - /* "sides" value... */ - - if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_KEYWORD) - { - respond_unsupported(client, attr); - valid = 0; - } - else if ((supported = ippFindAttribute(client->printer->attrs, "sides-supported", IPP_TAG_KEYWORD)) != NULL) - { - if (!ippContainsString(supported, sides)) - { - respond_unsupported(client, attr); - valid = 0; - } - } - else if (strcmp(sides, "one-sided")) - { - respond_unsupported(client, attr); - valid = 0; - } - } - - return (valid); -} diff --git a/tools/ipptool.c b/tools/ipptool.c index 1b15f5c4..13746076 100644 --- a/tools/ipptool.c +++ b/tools/ipptool.c @@ -12,7 +12,6 @@ * Include necessary headers... */ -#define _IPP_PRIVATE_STRUCTURES 0 /* Disable private IPP stuff */ #include #include #include @@ -166,7 +165,7 @@ static int Cancel = 0; /* Cancel test? */ * Local functions... */ -static void add_stringf(cups_array_t *a, const char *s, ...) __attribute__ ((__format__ (__printf__, 2, 3))); +static void add_stringf(cups_array_t *a, const char *s, ...) _CUPS_FORMAT(2, 3); static int compare_uris(const char *a, const char *b); static void copy_hex_string(char *buffer, unsigned char *data, int datalen, size_t bufsize); static int do_test(_ipp_file_t *f, _ipp_vars_t *vars, _cups_testdata_t *data); @@ -180,7 +179,7 @@ static char *iso_date(const ipp_uchar_t *date); static void pause_message(const char *message); static void print_attr(cups_file_t *outfile, int output, ipp_attribute_t *attr, ipp_tag_t *group); static void print_csv(_cups_testdata_t *data, ipp_t *ipp, ipp_attribute_t *attr, int num_displayed, char **displayed, size_t *widths); -static void print_fatal_error(_cups_testdata_t *data, const char *s, ...) __attribute__ ((__format__ (__printf__, 2, 3))); +static void print_fatal_error(_cups_testdata_t *data, const char *s, ...) _CUPS_FORMAT(2, 3); static void print_ippserver_attr(_cups_testdata_t *data, ipp_attribute_t *attr, int indent); static void print_ippserver_string(_cups_testdata_t *data, const char *s, size_t len); static void print_line(_cups_testdata_t *data, ipp_t *ipp, ipp_attribute_t *attr, int num_displayed, char **displayed, size_t *widths); @@ -192,7 +191,7 @@ static void sigterm_handler(int sig); #endif /* WIN32 */ static int timeout_cb(http_t *http, void *user_data); static int token_cb(_ipp_file_t *f, _ipp_vars_t *vars, _cups_testdata_t *data, const char *token); -static void usage(void) __attribute__((noreturn)); +static void usage(void) _CUPS_NORETURN; static const char *with_flags_string(int flags); static int with_value(_cups_testdata_t *data, cups_array_t *errors, char *value, int flags, ipp_attribute_t *attr, char *matchbuf, size_t matchlen); static int with_value_from(cups_array_t *errors, ipp_attribute_t *fromattr, ipp_attribute_t *attr, char *matchbuf, size_t matchlen); @@ -3788,6 +3787,7 @@ token_cb(_ipp_file_t *f, /* I - IPP file data */ !_cups_strcasecmp(token, "WITH-VALUE")) { off_t lastpos; /* Last file position */ + int lastline; /* Last line number */ if (data->last_expect) { @@ -3817,8 +3817,9 @@ token_cb(_ipp_file_t *f, /* I - IPP file data */ for (;;) { - lastpos = cupsFileTell(f->fp); - ptr += strlen(ptr); + lastpos = cupsFileTell(f->fp); + lastline = f->linenum; + ptr += strlen(ptr); if (!_ippFileReadToken(f, ptr, (sizeof(temp) - (size_t)(ptr - temp)))) break; @@ -3841,6 +3842,7 @@ token_cb(_ipp_file_t *f, /* I - IPP file data */ */ cupsFileSeek(f->fp, lastpos); + f->linenum = lastline; *ptr = '\0'; break; } From 9cecef0ea8055ac3e6631178b9de0533a663cb02 Mon Sep 17 00:00:00 2001 From: Aakash Lahoti Date: Sat, 21 Jul 2018 10:55:40 +0530 Subject: [PATCH 05/10] case LANG ipp-file.c/parse_value(), case STRING : hex support --- cups/ipp-file.c | 74 ++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/cups/ipp-file.c b/cups/ipp-file.c index bf763260..79d28804 100644 --- a/cups/ipp-file.c +++ b/cups/ipp-file.c @@ -647,31 +647,37 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ { if(value[0]=='<') /* Input is binary(in form of hex) values*/ { - memmove(value, value+1, strlen(value)); /* Eliminate the '<' sign */ - char value_concat[50000]; /* Concatenated string with hexadecimal values without whitespace */ - int starting_line_number = f->linenum; - while(value[strlen(value)-1] != '>') - { - strcat(value_concat,value); - if (!_ippFileReadToken(f, value, sizeof(value))) - { - report_error(f, v, user_data, "hexadecimal value not terminated starting line %d of \"%s\".", starting_line_number, f->filename); - return (0); - } - } - value[(strlen(value)-1)]='\0'; /* Eliminate the last '>' sign */ - strcat(value_concat,value); /* Final concatenation for hexadecimal value to be complete*/ - int i; /* Iterating variable*/ - for(i=0;i= '0' && value_concat[i]<= '9') || (value_concat[i]>='a' && value_concat[i]<='f')) - { - report_error(f, v, user_data, "Bad hexadecimal value \"%s\" on line %d of \"%s\".", value_concat, starting_line_number, f->filename); - return (0); - } - } - return (ippSetOctetString(ipp, attr, element, value_concat, (int)strlen(value_concat))); - } + unsigned char data[32767], *dataptr = data; /*data: decoded hex, dataptr:iterating pointer */ + char *valptr = value + 1; /*Value iterating pointer*/ + while (1) + { + while (isxdigit(valptr[0]) && isxdigit(valptr[1])) + { + char c = valptr[0], d=valptr[1]; + /*decode hex pair into 8 bit string */ + dataptr = (d>='a')?(10+d-'a'):(d-'0') + (c>= 'a') ? ((10+c -'a') << 4) : ((c-'0') <<4); + valptr += 2; + dataptr ++; + if (dataptr >= (data + sizeof(data))) + break; + } + if (*valptr == '>') + break; + else if (*valptr) /*If string is not in pairs, or has a non-hex digit*/ + { + report_error(f, v, user_data, "Bad hexadecimal value \"%s\" on line %d of \"%s\".", value+1, f->linenum, f->filename); + return (0); + } + if (!_ippFileReadToken(f, value, sizeof(value))) + { + report_error(f, v, user_data, "Missing value on line %d of \"%s\".", f->linenum, f->filename); + return (0); + } + valptr = value; + } + return (ippSetOctetString(ipp, attr, element, data, (int)strlen(data))); + } + else { return (ippSetOctetString(ipp, attr, element, value, (int)strlen(value))); /* If a quoted string like "..", pass it on */ @@ -682,19 +688,6 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ break; case IPP_TAG_TEXTLANG : - { - (*attr)->values[element].string.text = _cupsStrAlloc(value); - if (!_ippFileReadToken(f, value, sizeof(value))) - { - report_error(f, v, user_data, "No Language Data in line %d of \"%s\".", f->linenum, f->filename); - return (0); - } - memmove(value, value+1, strlen(value)); - value[strlen(value)-1]='\0'; /* Purge parenthesis */ - (*attr)->values[element].string.language = _cupsStrAlloc(value); - - } - break; case IPP_TAG_NAMELANG : { (*attr)->values[element].string.text = _cupsStrAlloc(value); @@ -703,6 +696,11 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ report_error(f, v, user_data, "No Language Data in line %d of \"%s\".", f->linenum, f->filename); return (0); } + if (!(value[0] == '(' && value[strlen(value)-1] == ')')) + { + report_error(f, v, user_data, "Bad Language Value in line %d of \"%s\".", f->linenum, f->filename); + return (0); + } memmove(value, value+1, strlen(value)); value[strlen(value)-1]='\0'; /* Purge parenthesis */ (*attr)->values[element].string.language = _cupsStrAlloc(value); From 25873ac204f4dfd8b0dca81be374033553478b2b Mon Sep 17 00:00:00 2001 From: Aakash Lahoti Date: Tue, 24 Jul 2018 12:48:11 +0530 Subject: [PATCH 06/10] Added support for capital hex values --- cups/ipp-file.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cups/ipp-file.c b/cups/ipp-file.c index 79d28804..63a0e0cb 100644 --- a/cups/ipp-file.c +++ b/cups/ipp-file.c @@ -163,6 +163,7 @@ _ippFileParse( } } + else if (attr && !_cups_strcasecmp(token, ",")) { /* @@ -653,9 +654,10 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ { while (isxdigit(valptr[0]) && isxdigit(valptr[1])) { - char c = valptr[0], d=valptr[1]; + char c = tolower(valptr[0]), d=tolower(valptr[1]); + /*decode hex pair into 8 bit string */ - dataptr = (d>='a')?(10+d-'a'):(d-'0') + (c>= 'a') ? ((10+c -'a') << 4) : ((c-'0') <<4); + dataptr = (d>='a')?(10+d-'a'):(d-'0') | (c>= 'a') ? ((10+c -'a') << 4) : ((c-'0') <<4); valptr += 2; dataptr ++; if (dataptr >= (data + sizeof(data))) @@ -680,8 +682,8 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ else { - return (ippSetOctetString(ipp, attr, element, value, (int)strlen(value))); /* If a quoted string like "..", pass it on */ - } + report_error(f, v, user_data, "Hexadecimal value needs to begin with <, on line %d of \"%s\".", f->linenum, f->filename); + } } From 83b39b3492751e871259e132733eae4dc28d12b7 Mon Sep 17 00:00:00 2001 From: Aakash Lahoti Date: Tue, 24 Jul 2018 15:38:32 +0530 Subject: [PATCH 07/10] ippAddOctetString2() has been added for taking in non IPP_TAG_STRING attributes. --- cups/ipp.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/cups/ipp.c b/cups/ipp.c index 325de02b..37fbb3a3 100644 --- a/cups/ipp.c +++ b/cups/ipp.c @@ -547,6 +547,64 @@ ippAddOctetString(ipp_t *ipp, /* I - IPP message */ return (attr); } +/* + * 'ippAddOctetString2()' - Add unspecified format octetString value tag(0x30) to an IPP message. + * Or Add Vendor Extension (0x40000000 to 0x7fffffff) to an IPP message. + * + * The @code ipp@ parameter refers to an IPP message previously created using + * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. + * + * The @code group@ parameter specifies the IPP attribute group tag: none + * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), + * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation + * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription + * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). + * + * @since CUPS 1.2/macOS 10.5@ + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddOctetString2(ipp_t *ipp, /* I - IPP message */ + ipp_tag_t group, /* I - IPP group */ + ipp_tag_t value_tag, /* I - Type of attribute */ + const char *name, /* I - Name of attribute */ + const void *data, /* I - octetString data */ + int datalen) /* I - Length of data in bytes */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + if (!ipp || !name || group < IPP_TAG_ZERO || + group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || + datalen < 0 || datalen > IPP_MAX_LENGTH) + return (NULL); + + if ((attr = ipp_add_attr(ipp, name, group, value_tag, 1)) == NULL) + return (NULL); + + /* + * Initialize the attribute data... + */ + + attr->values[0].unknown.length = datalen; + + if (data) + { + if ((attr->values[0].unknown.data = malloc((size_t)datalen)) == NULL) + { + ippDeleteAttribute(ipp, attr); + return (NULL); + } + + memcpy(attr->values[0].unknown.data, data, (size_t)datalen); + } + + /* + * Return the new attribute... + */ + + return (attr); +} /* * 'ippAddOutOfBand()' - Add an out-of-band value to an IPP message. From c976be5b7d08c9e953ce5764c2174c76b7fc75c8 Mon Sep 17 00:00:00 2001 From: Aakash Lahoti Date: Tue, 24 Jul 2018 16:04:08 +0530 Subject: [PATCH 08/10] Group_tag functionality added in _ippFileParse() Minor changes in parse_value() --- cups/ipp-file.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/cups/ipp-file.c b/cups/ipp-file.c index 63a0e0cb..f0650658 100644 --- a/cups/ipp-file.c +++ b/cups/ipp-file.c @@ -93,6 +93,24 @@ _ippFileParse( break; } } + else if (f.attrs && !_cups_strcasecmp(token, "GROUP")) + { + char syntax[128]; /* Attribute syntax (value tag) */ + ipp_tag_t group_tag; /* Group tag */ + + if (!_ippFileReadToken(&f, syntax, sizeof(syntax))) + { + report_error(&f, v, user_data, "Missing GROUP syntax on line %d of \"%s\".", f.linenum, f.filename); + break; + } + else if ((group_tag = ippTagValue(syntax)) > IPP_TAG_SYSTEM || group_tag < IPP_TAG_ZERO ) + { + report_error(&f, v, user_data, "Bad GROUP syntax \"%s\" on line %d of \"%s\".", syntax, f.linenum, f.filename); + break; + } + f.group_tag = group_tag; + } + else if (f.attrs && !_cups_strcasecmp(token, "ATTR")) { /* @@ -171,7 +189,7 @@ _ippFileParse( */ if (!parse_value(&f, v, user_data, attrs, &attr, ippGetCount(attr))) - break; + break; } else { @@ -657,7 +675,7 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ char c = tolower(valptr[0]), d=tolower(valptr[1]); /*decode hex pair into 8 bit string */ - dataptr = (d>='a')?(10+d-'a'):(d-'0') | (c>= 'a') ? ((10+c -'a') << 4) : ((c-'0') <<4); + *dataptr = (d>='a')?(10+d-'a'):(d-'0') | (c>= 'a') ? ((10+c -'a') << 4) : ((c-'0') <<4); valptr += 2; dataptr ++; if (dataptr >= (data + sizeof(data))) @@ -677,7 +695,7 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ } valptr = value; } - return (ippSetOctetString(ipp, attr, element, data, (int)strlen(data))); + return (ippSetOctetString(ipp, attr, element, data, (int) (dataptr-data))); } else From faf04bf3936e74b6f685e753188d5b312e7e5786 Mon Sep 17 00:00:00 2001 From: Aakash Lahoti Date: Thu, 2 Aug 2018 04:09:50 +0530 Subject: [PATCH 09/10] Full Support for assigned data types --- cups/ipp-file.c | 63 ++++++++++++++++++++++++++------------- cups/ipp-support.c | 73 ++++++++++++++++++++++++++++++++++++++++++---- cups/ipp.c | 43 ++++++++++++++++++++------- 3 files changed, 144 insertions(+), 35 deletions(-) diff --git a/cups/ipp-file.c b/cups/ipp-file.c index f0650658..8eaf5986 100644 --- a/cups/ipp-file.c +++ b/cups/ipp-file.c @@ -118,7 +118,8 @@ _ippFileParse( */ char syntax[128], /* Attribute syntax (value tag) */ - name[128]; /* Attribute name */ + name[128], /* Attribute name */ + syntax_value[128]; /*Variable Expanded Value*/ ipp_tag_t value_tag; /* Value tag */ attr = NULL; @@ -128,7 +129,9 @@ _ippFileParse( report_error(&f, v, user_data, "Missing ATTR syntax on line %d of \"%s\".", f.linenum, f.filename); break; } - else if ((value_tag = ippTagValue(syntax)) < IPP_TAG_UNSUPPORTED_VALUE) + _ippVarsExpand(v, syntax_value, syntax, sizeof(syntax_value)); + + if ((value_tag = ippTagValue(syntax_value)) < IPP_TAG_UNSUPPORTED_VALUE) { report_error(&f, v, user_data, "Bad ATTR syntax \"%s\" on line %d of \"%s\".", syntax, f.linenum, f.filename); break; @@ -160,7 +163,7 @@ _ippFileParse( attrs = ignored; } - if (value_tag < IPP_TAG_INTEGER) + if (value_tag < IPP_TAG_INTEGER-1) { /* * Add out-of-band attribute - no value string needed... @@ -376,15 +379,15 @@ _ippFileReadToken(_ipp_file_t *f, /* I - File to read from */ if ((ch = cupsFileGetChar(f->fp)) == EOF) { - *token = '\0'; - DEBUG_puts("1_ippFileReadToken: EOF"); - return (0); - } - else if (ch == '\n') - { - f->linenum ++; - DEBUG_printf(("1_ippFileReadToken: quoted LF, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp))); - } + *token = '\0'; + DEBUG_puts("1_ippFileReadToken: EOF"); + return (0); + } + else if (ch == '\n') + { + f->linenum ++; + DEBUG_printf(("1_ippFileReadToken: quoted LF, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp))); + } } if (tokptr < tokend) @@ -457,7 +460,8 @@ parse_collection( */ char syntax[128], /* Attribute syntax (value tag) */ - name[128]; /* Attribute name */ + name[128], /* Attribute name */ + syntax_value[128]; /*Variable Expanded Value*/ ipp_tag_t value_tag; /* Value tag */ attr = NULL; @@ -468,8 +472,9 @@ parse_collection( ippDelete(col); col = NULL; break; + _ippVarsExpand(v, syntax_value, syntax, sizeof(syntax_value)); } - else if ((value_tag = ippTagValue(syntax)) < IPP_TAG_UNSUPPORTED_VALUE) + if ((value_tag = ippTagValue(syntax_value)) < IPP_TAG_UNSUPPORTED_VALUE) { report_error(f, v, user_data, "Bad ATTR syntax \"%s\" on line %d of \"%s\".", syntax, f->linenum, f->filename); ippDelete(col); @@ -485,7 +490,7 @@ parse_collection( break; } - if (value_tag < IPP_TAG_INTEGER) + if (value_tag < IPP_TAG_INTEGER-1) { /* * Add out-of-band attribute - no value string needed... @@ -556,6 +561,7 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ { char value[1024], /* Value string */ temp[1024]; /* Temporary string */ + ipp_tag_t value_tag; if (!_ippFileReadToken(f, temp, sizeof(temp))) @@ -566,7 +572,22 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ _ippVarsExpand(v, value, temp, sizeof(value)); - switch (ippGetValueTag(*attr)) +/* value_tag processing to support unassigned tag values */ + value_tag = ippGetValueTag(*attr); + if (value_tag == 0x20 || (value_tag >= 0x24 && value_tag <= 0x2f)) + value_tag = IPP_TAG_INTEGER; + else + if (value_tag >= 0x38 && value_tag <= 0x3f) + value_tag = IPP_TAG_STRING; + else + if (value_tag == 0x40 || (value_tag >= 0x4b && value_tag <= 0x5f)) + value_tag = IPP_TAG_RESERVED_STRING; + else + if (value_tag >= 0x40000000 && value_tag <= 0x7fffffff) + value_tag = IPP_TAG_STRING; + + + switch (value_tag) { case IPP_TAG_BOOLEAN : return (ippSetBoolean(ipp, attr, element, !_cups_strcasecmp(value, "true"))); @@ -606,7 +627,7 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ { utc_offset = -utc_offset; date[8] = (ipp_uchar_t)'-'; - } + } else { date[8] = (ipp_uchar_t)'+'; @@ -700,10 +721,10 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ else { - report_error(f, v, user_data, "Hexadecimal value needs to begin with <, on line %d of \"%s\".", f->linenum, f->filename); - } + return (ippSetOctetString(ipp, attr, element, value, (int)strlen(value))); - } + } + } break; @@ -729,12 +750,14 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ break; case IPP_TAG_TEXT : case IPP_TAG_NAME : + case IPP_TAG_RESERVED_STRING : case IPP_TAG_KEYWORD : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : + case IPP_TAG_MEMBERNAME : return (ippSetString(ipp, attr, element, value)); break; diff --git a/cups/ipp-support.c b/cups/ipp-support.c index 47a64550..06e65c9f 100644 --- a/cups/ipp-support.c +++ b/cups/ipp-support.c @@ -358,7 +358,28 @@ static const char * const ipp_std_ops[] = "charset", /* 0x47 */ "naturalLanguage", /* 0x48 */ "mimeMediaType", /* 0x49 */ - "memberAttrName" /* 0x4a */ + "memberAttrName", /* 0x4a */ + "0x4b", /* 0x4b */ + "0x4c", /* 0x4c */ + "0x4d", /* 0x4d */ + "0x4e", /* 0x4e */ + "0x4f", /* 0x4f */ + "0x50", /* 0x50 */ + "0x51", /* 0x51 */ + "0x52", /* 0x52 */ + "0x53", /* 0x53 */ + "0x54", /* 0x54 */ + "0x55", /* 0x55 */ + "0x56", /* 0x56 */ + "0x57", /* 0x57 */ + "0x58", /* 0x58 */ + "0x59", /* 0x59 */ + "0x5a", /* 0x5a */ + "0x5b", /* 0x5b */ + "0x5c", /* 0x5c */ + "0x5d", /* 0x5d */ + "0x5e", /* 0x5e */ + "0x5f" /* 0x5f */ }; static const char * const ipp_document_states[] = { /* document-state-enums */ @@ -2461,7 +2482,19 @@ ipp_tag_t /* O - Tag value */ ippTagValue(const char *name) /* I - Tag name */ { size_t i; /* Looping var */ - + int itr, /* Name iterator*/ + flag = 0, /*Integer detector*/ + hex_val = 0; /*Convert hex to int */ + for(itr = 0; itr < strlen(name) ; itr++) + { + if(!(name[itr] >= '0'&& name[itr]<='9')) + { + flag = 1; + break; + } + } + if(flag == 0) + return ((ipp_tag_t)atoi(name)); for (i = 0; i < (sizeof(ipp_tag_names) / sizeof(ipp_tag_names[0])); i ++) if (!_cups_strcasecmp(name, ipp_tag_names[i])) @@ -2489,9 +2522,39 @@ ippTagValue(const char *name) /* I - Tag name */ return (IPP_TAG_TEXT); else if (!_cups_strcasecmp(name, "begCollection")) return (IPP_TAG_BEGIN_COLLECTION); - else - return (IPP_TAG_ZERO); -} + else { + /* Detecting hex string of the form "0x********" between 0x40000000" and 0x7fffffff*/ + flag = 0, itr = 0; + if(strlen(name) == 10 && name[0] == '0' && name [1]== 'x' ) + { + hex_val = 0; + for(itr = 2; itr < strlen(name) ; itr++) + { + char c_flag = tolower(name[itr]); + if (!(( c_flag >= 'a' && c_flag <= 'f' )|| ( c_flag >= '0' && c_flag <= '9'))) + { + flag = 1; + break; + } + else + { + hex_val = hex_val*16 + ((c_flag >= 'a' && c_flag <= 'f') ? (c_flag - 'a') : (c_flag - '0')); + } + } + if( flag == 0 && name[2] >= '4' && name[2] <= '7') + flag = 0; + else + flag = 1; + } + else + flag = 1; + + if(flag == 0) + return hex_val; + else + return (IPP_TAG_ZERO); + } + } /* diff --git a/cups/ipp.c b/cups/ipp.c index 37fbb3a3..09efc2a8 100644 --- a/cups/ipp.c +++ b/cups/ipp.c @@ -2369,11 +2369,18 @@ int /* O - Value or 0 on error */ ippGetInteger(ipp_attribute_t *attr, /* I - IPP attribute */ int element) /* I - Value number (0-based) */ { + + /* Support Unassigned Value Tags*/ + + ipp_tag_t pvalue_tag = (attr)->value_tag; + + if (pvalue_tag == 0x20 || (pvalue_tag >= 0x24 && pvalue_tag <= 0x2f)) + pvalue_tag = IPP_TAG_INTEGER; /* * Range check input... */ - if (!attr || (attr->value_tag != IPP_TAG_INTEGER && attr->value_tag != IPP_TAG_ENUM) || + if (!attr || (pvalue_tag != IPP_TAG_INTEGER && pvalue_tag != IPP_TAG_ENUM) || element < 0 || element >= attr->num_values) return (0); @@ -2424,11 +2431,17 @@ ippGetOctetString( int element, /* I - Value number (0-based) */ int *datalen) /* O - Length of octetString data */ { + + /* Support Unassigned Values*/ + ipp_tag_t pvalue_tag = (attr)->value_tag; + + if ((pvalue_tag >= 0x38 && pvalue_tag <= 0x3f)|| (pvalue_tag >= 0x40000000 && pvalue_tag <= 0x7fffffff)) + pvalue_tag = IPP_TAG_STRING; /* * Range check input... */ - if (!attr || attr->value_tag != IPP_TAG_STRING || + if (!attr || pvalue_tag != IPP_TAG_STRING || element < 0 || element >= attr->num_values) { if (datalen) @@ -2651,7 +2664,7 @@ ippGetString(ipp_attribute_t *attr, /* I - IPP attribute */ tag = ippGetValueTag(attr); - if (!attr || element < 0 || element >= attr->num_values || (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG && (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE))) + if (!attr || element < 0 || element >= attr->num_values || tag < 0x40 || tag > 0x5f ) return (NULL); /* @@ -3979,13 +3992,18 @@ ippSetInteger(ipp_t *ipp, /* I - IPP message */ { _ipp_value_t *value; /* Current value */ +/* Support Unassigned Value Tags*/ + + ipp_tag_t pvalue_tag = (*attr)->value_tag; + + if (pvalue_tag == 0x20 || (pvalue_tag >= 0x24 && pvalue_tag <= 0x2f)) + pvalue_tag = IPP_TAG_INTEGER; /* * Range check input... */ - - if (!ipp || !attr || !*attr || - ((*attr)->value_tag != IPP_TAG_INTEGER && (*attr)->value_tag != IPP_TAG_ENUM) || + if (!ipp || !attr || !*attr || + (pvalue_tag != IPP_TAG_INTEGER && pvalue_tag != IPP_TAG_ENUM) || element < 0 || element > (*attr)->num_values) return (0); @@ -4066,12 +4084,17 @@ ippSetOctetString( { _ipp_value_t *value; /* Current value */ + /* Support Unassigned Values*/ + ipp_tag_t pvalue_tag = (*attr)->value_tag; + + if ((pvalue_tag >= 0x38 && pvalue_tag <= 0x3f)|| (pvalue_tag >= 0x40000000 && pvalue_tag <= 0x7fffffff)) + pvalue_tag = IPP_TAG_STRING; /* * Range check input... */ - if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_STRING || + if (!ipp || !attr || !*attr || pvalue_tag != IPP_TAG_STRING || element < 0 || element > (*attr)->num_values || datalen < 0 || datalen > IPP_MAX_LENGTH) return (0); @@ -4382,10 +4405,10 @@ ippSetString(ipp_t *ipp, /* I - IPP message */ else value_tag = IPP_TAG_ZERO; + if (!ipp || !attr || !*attr || - (value_tag < IPP_TAG_TEXT && value_tag != IPP_TAG_TEXTLANG && - value_tag != IPP_TAG_NAMELANG) || value_tag > IPP_TAG_MIMETYPE || - !strvalue) + (value_tag < 0x40 || value_tag > 0x5f) || + !strvalue) return (0); /* From 6a1629eef04bd92d11bf7e8f9518eecfc8926cb0 Mon Sep 17 00:00:00 2001 From: Aakash Lahoti Date: Thu, 2 Aug 2018 06:13:55 +0530 Subject: [PATCH 10/10] Fixed a small error ipp-file.c line 475 --- cups/ipp-file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cups/ipp-file.c b/cups/ipp-file.c index 8eaf5986..bd040835 100644 --- a/cups/ipp-file.c +++ b/cups/ipp-file.c @@ -472,8 +472,9 @@ parse_collection( ippDelete(col); col = NULL; break; - _ippVarsExpand(v, syntax_value, syntax, sizeof(syntax_value)); + } + _ippVarsExpand(v, syntax_value, syntax, sizeof(syntax_value)); if ((value_tag = ippTagValue(syntax_value)) < IPP_TAG_UNSUPPORTED_VALUE) { report_error(f, v, user_data, "Bad ATTR syntax \"%s\" on line %d of \"%s\".", syntax, f->linenum, f->filename);