summaryrefslogtreecommitdiff
path: root/test/ippeveprinter.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/ippeveprinter.c')
-rw-r--r--test/ippeveprinter.c8080
1 files changed, 0 insertions, 8080 deletions
diff --git a/test/ippeveprinter.c b/test/ippeveprinter.c
deleted file mode 100644
index 177e9a61a..000000000
--- a/test/ippeveprinter.c
+++ /dev/null
@@ -1,8080 +0,0 @@
-/*
- * IPP Everywhere printer application for CUPS.
- *
- * Copyright © 2010-2019 by Apple Inc.
- *
- * Licensed under Apache License v2.0. See the file "LICENSE" for more
- * information.º
- *
- * Note: This program began life as the "ippserver" sample code that first
- * appeared in CUPS 1.4. The name has been changed in order to distinguish it
- * from the PWG's much more ambitious "ippserver" program, which supports
- * different kinds of IPP services and multiple services per instance - the
- * "ippeveprinter" program exposes a single print service conforming to the
- * current IPP Everywhere specification, thus the new name.
- */
-
-/*
- * Include necessary headers...
- */
-
-#include <cups/cups-private.h>
-#if !CUPS_LITE
-# include <cups/ppd-private.h>
-#endif /* !CUPS_LITE */
-
-#include <limits.h>
-#include <sys/stat.h>
-
-#ifdef _WIN32
-# include <fcntl.h>
-# include <io.h>
-# include <process.h>
-# define WEXITSTATUS(s) (s)
-# include <winsock2.h>
-typedef ULONG nfds_t;
-# define poll WSAPoll
-#else
-extern char **environ;
-
-# include <sys/fcntl.h>
-# include <sys/wait.h>
-# include <poll.h>
-#endif /* _WIN32 */
-
-#ifdef HAVE_DNSSD
-# include <dns_sd.h>
-#elif defined(HAVE_AVAHI)
-# include <avahi-client/client.h>
-# include <avahi-client/publish.h>
-# include <avahi-common/error.h>
-# include <avahi-common/thread-watch.h>
-#endif /* HAVE_DNSSD */
-#ifdef HAVE_SYS_MOUNT_H
-# include <sys/mount.h>
-#endif /* HAVE_SYS_MOUNT_H */
-#ifdef HAVE_SYS_STATFS_H
-# include <sys/statfs.h>
-#endif /* HAVE_SYS_STATFS_H */
-#ifdef HAVE_SYS_STATVFS_H
-# include <sys/statvfs.h>
-#endif /* HAVE_SYS_STATVFS_H */
-#ifdef HAVE_SYS_VFS_H
-# include <sys/vfs.h>
-#endif /* HAVE_SYS_VFS_H */
-
-#include "printer-png.h"
-
-
-/*
- * Constants...
- */
-
-enum ippeve_preason_e /* printer-state-reasons bit values */
-{
- IPPEVE_PREASON_NONE = 0x0000, /* none */
- IPPEVE_PREASON_OTHER = 0x0001, /* other */
- IPPEVE_PREASON_COVER_OPEN = 0x0002, /* cover-open */
- IPPEVE_PREASON_INPUT_TRAY_MISSING = 0x0004,
- /* input-tray-missing */
- IPPEVE_PREASON_MARKER_SUPPLY_EMPTY = 0x0008,
- /* marker-supply-empty */
- IPPEVE_PREASON_MARKER_SUPPLY_LOW = 0x0010,
- /* marker-supply-low */
- IPPEVE_PREASON_MARKER_WASTE_ALMOST_FULL = 0x0020,
- /* marker-waste-almost-full */
- IPPEVE_PREASON_MARKER_WASTE_FULL = 0x0040,
- /* marker-waste-full */
- IPPEVE_PREASON_MEDIA_EMPTY = 0x0080, /* media-empty */
- IPPEVE_PREASON_MEDIA_JAM = 0x0100, /* media-jam */
- IPPEVE_PREASON_MEDIA_LOW = 0x0200, /* media-low */
- IPPEVE_PREASON_MEDIA_NEEDED = 0x0400, /* media-needed */
- IPPEVE_PREASON_MOVING_TO_PAUSED = 0x0800,
- /* moving-to-paused */
- IPPEVE_PREASON_PAUSED = 0x1000, /* paused */
- IPPEVE_PREASON_SPOOL_AREA_FULL = 0x2000,/* spool-area-full */
- IPPEVE_PREASON_TONER_EMPTY = 0x4000, /* toner-empty */
- IPPEVE_PREASON_TONER_LOW = 0x8000 /* toner-low */
-};
-typedef unsigned int ippeve_preason_t; /* Bitfield for printer-state-reasons */
-static const char * const ippeve_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"
-};
-
-
-/*
- * 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 ippeve_srv_t; /* Service reference */
-typedef TXTRecordRef ippeve_txt_t; /* TXT record */
-
-#elif defined(HAVE_AVAHI)
-typedef AvahiEntryGroup *ippeve_srv_t; /* Service reference */
-typedef AvahiStringList *ippeve_txt_t; /* TXT record */
-
-#else
-typedef void *ippeve_srv_t; /* Service reference */
-typedef void *ippeve_txt_t; /* TXT record */
-#endif /* HAVE_DNSSD */
-
-typedef struct ippeve_filter_s /**** Attribute filter ****/
-{
- cups_array_t *ra; /* Requested attributes */
- ipp_tag_t group_tag; /* Group to copy */
-} ippeve_filter_t;
-
-typedef struct ippeve_job_s ippeve_job_t;
-
-typedef struct ippeve_printer_s /**** Printer data ****/
-{
- /* TODO: One IPv4 and one IPv6 listener are really not sufficient */
- int ipv4, /* IPv4 listener */
- ipv6; /* IPv6 listener */
- ippeve_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 */
- *device_uri, /* Device URI (if any) */
-#if !CUPS_LITE
- *ppdfile, /* PPD file (if any) */
-#endif /* !CUPS_LITE */
- *command; /* Command to run with job file */
- int port; /* Port */
- int web_forms; /* Enable web interface forms? */
- 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 */
- ippeve_preason_t state_reasons; /* printer-state-reasons values */
- time_t state_time; /* printer-state-change-time */
- cups_array_t *jobs; /* Jobs */
- ippeve_job_t *active_job; /* Current active/pending job */
- int next_job_id; /* Next job-id value */
- _cups_rwlock_t rwlock; /* Printer lock */
-} ippeve_printer_t;
-
-struct ippeve_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 */
- char *message; /* job-state-message value */
- int msglevel; /* job-state-message log level (0=error, 1=info) */
- 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 */
- ippeve_printer_t *printer; /* Printer */
-};
-
-typedef struct ippeve_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 */
- ippeve_printer_t *printer; /* Printer */
- ippeve_job_t *job; /* Current job, if any */
-} ippeve_client_t;
-
-
-/*
- * Local functions...
- */
-
-static void clean_jobs(ippeve_printer_t *printer);
-static int compare_jobs(ippeve_job_t *a, ippeve_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(ippeve_client_t *client, ippeve_job_t *job, cups_array_t *ra);
-static ippeve_client_t *create_client(ippeve_printer_t *printer, int sock);
-static ippeve_job_t *create_job(ippeve_client_t *client);
-static int create_job_file(ippeve_job_t *job, char *fname, size_t fnamesize, const char *dir, const char *ext);
-static int create_listener(const char *name, int port, int family);
-static ipp_t *create_media_col(const char *media, const char *source, const char *type, int width, int length, int bottom, int left, int right, int top);
-static ipp_t *create_media_size(int width, int length);
-static ippeve_printer_t *create_printer(const char *servername, int serverport, const char *name, const char *location, const char *icon, cups_array_t *docformats, const char *subtypes, const char *directory, const char *command, const char *device_uri, ipp_t *attrs);
-static void debug_attributes(const char *title, ipp_t *ipp, int response);
-static void delete_client(ippeve_client_t *client);
-static void delete_job(ippeve_job_t *job);
-static void delete_printer(ippeve_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, ippeve_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(ippeve_filter_t *filter, ipp_t *dst, ipp_attribute_t *attr);
-static ippeve_job_t *find_job(ippeve_client_t *client);
-static void finish_document_data(ippeve_client_t *client, ippeve_job_t *job);
-static void finish_document_uri(ippeve_client_t *client, ippeve_job_t *job);
-static void html_escape(ippeve_client_t *client, const char *s, size_t slen);
-static void html_footer(ippeve_client_t *client);
-static void html_header(ippeve_client_t *client, const char *title, int refresh);
-static void html_printf(ippeve_client_t *client, const char *format, ...) _CUPS_FORMAT(2, 3);
-static void ipp_cancel_job(ippeve_client_t *client);
-static void ipp_close_job(ippeve_client_t *client);
-static void ipp_create_job(ippeve_client_t *client);
-static void ipp_get_job_attributes(ippeve_client_t *client);
-static void ipp_get_jobs(ippeve_client_t *client);
-static void ipp_get_printer_attributes(ippeve_client_t *client);
-static void ipp_identify_printer(ippeve_client_t *client);
-static void ipp_print_job(ippeve_client_t *client);
-static void ipp_print_uri(ippeve_client_t *client);
-static void ipp_send_document(ippeve_client_t *client);
-static void ipp_send_uri(ippeve_client_t *client);
-static void ipp_validate_job(ippeve_client_t *client);
-static ipp_t *load_ippserver_attributes(const char *servername, int serverport, const char *filename, cups_array_t *docformats);
-static ipp_t *load_legacy_attributes(const char *make, const char *model, int ppm, int ppm_color, int duplex, cups_array_t *docformats);
-#if !CUPS_LITE
-static ipp_t *load_ppd_attributes(const char *ppdfile, cups_array_t *docformats);
-#endif /* !CUPS_LITE */
-static int parse_options(ippeve_client_t *client, cups_option_t **options);
-static void process_attr_message(ippeve_job_t *job, char *message);
-static void *process_client(ippeve_client_t *client);
-static int process_http(ippeve_client_t *client);
-static int process_ipp(ippeve_client_t *client);
-static void *process_job(ippeve_job_t *job);
-static void process_state_message(ippeve_job_t *job, char *message);
-static int register_printer(ippeve_printer_t *printer, const char *subtypes);
-static int respond_http(ippeve_client_t *client, http_status_t code, const char *content_coding, const char *type, size_t length);
-static void respond_ipp(ippeve_client_t *client, ipp_status_t status, const char *message, ...) _CUPS_FORMAT(3, 4);
-static void respond_unsupported(ippeve_client_t *client, ipp_attribute_t *attr);
-static void run_printer(ippeve_printer_t *printer);
-static int show_media(ippeve_client_t *client);
-static int show_status(ippeve_client_t *client);
-static int show_supplies(ippeve_client_t *client);
-static char *time_string(time_t tv, char *buffer, size_t bufsize);
-static void usage(int status) _CUPS_NORETURN;
-static int valid_doc_attributes(ippeve_client_t *client);
-static int valid_job_attributes(ippeve_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, /* Keep spooled job files? */
- MaxVersion = 20,/* Maximum IPP version (20 = 2.0, 11 = 1.1, etc.) */
- Verbosity = 0; /* Verbosity level */
-
-
-/*
- * '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, /* ippserver attributes file */
- *command = NULL, /* Command to run with job files */
- *device_uri = NULL, /* Device URI */
- *icon = NULL, /* Icon file */
-#ifdef HAVE_SSL
- *keypath = NULL, /* Keychain path */
-#endif /* HAVE_SSL */
- *location = "", /* Location of printer */
- *make = "Example", /* Manufacturer */
- *model = "Printer", /* Model */
- *name = NULL, /* Printer name */
-#if !CUPS_LITE
- *ppdfile = NULL, /* PPD file */
-#endif /* !CUPS_LITE */
- *subtypes = "_print"; /* DNS-SD service subtype */
- int legacy = 0, /* Legacy mode? */
- duplex = 0, /* Duplex mode */
- ppm = 10, /* Pages per minute for mono */
- ppm_color = 0, /* Pages per minute for color */
- web_forms = 1; /* Enable web site forms? */
- ipp_t *attrs = NULL; /* Printer attributes */
- char directory[1024] = ""; /* Spool directory */
- cups_array_t *docformats = NULL; /* Supported formats */
- const char *servername = NULL; /* Server host name */
- int serverport = 0; /* Server port number (0 = auto) */
- ippeve_printer_t *printer; /* Printer object */
-
-
- /*
- * Parse command-line arguments...
- */
-
- for (i = 1; i < argc; i ++)
- {
- if (!strcmp(argv[i], "--help"))
- {
- usage(0);
- }
- else if (!strcmp(argv[i], "--no-web-forms"))
- {
- web_forms = 0;
- }
- else if (!strcmp(argv[i], "--version"))
- {
- puts(CUPS_SVERSION);
- return (0);
- }
- else if (!strncmp(argv[i], "--", 2))
- {
- _cupsLangPrintf(stderr, _("%s: Unknown option \"%s\"."), argv[0], argv[i]);
- usage(1);
- }
- else if (argv[i][0] == '-')
- {
- for (opt = argv[i] + 1; *opt; opt ++)
- {
- switch (*opt)
- {
- case '2' : /* -2 (enable 2-sided printing) */
- duplex = 1;
- legacy = 1;
- break;
-
- case 'D' : /* -D device-uri */
- i ++;
- if (i >= argc)
- usage(1);
-
- device_uri = argv[i];
- 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];
- legacy = 1;
- break;
-
-#if !CUPS_LITE
- case 'P' : /* -P filename.ppd */
- i ++;
- if (i >= argc)
- usage(1);
-
- ppdfile = argv[i];
- break;
-#endif /* !CUPS_LITE */
-
- case 'V' : /* -V max-version */
- i ++;
- if (i >= argc)
- usage(1);
-
- if (!strcmp(argv[i], "2.0"))
- MaxVersion = 20;
- else if (!strcmp(argv[i], "1.1"))
- MaxVersion = 11;
- else
- usage(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);
-
- docformats = _cupsArrayNewStrings(argv[i], ',');
- legacy = 1;
- break;
-
- 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];
- legacy = 1;
- 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);
-
- serverport = atoi(argv[i]);
- break;
-
- case 'r' : /* -r subtype */
- i ++;
- if (i >= argc)
- usage(1);
-
- subtypes = 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);
-
- legacy = 1;
- break;
-
- case 'v' : /* -v (be verbose) */
- Verbosity ++;
- break;
-
- default : /* Unknown */
- _cupsLangPrintf(stderr, _("%s: Unknown option \"-%c\"."), argv[0], *opt);
- usage(1);
- }
- }
- }
- else if (!name)
- {
- name = argv[i];
- }
- else
- {
- _cupsLangPrintf(stderr, _("%s: Unknown option \"%s\"."), argv[0], argv[i]);
- usage(1);
- }
- }
-
- if (!name)
- usage(1);
-
-#if CUPS_LITE
- if (attrfile != NULL && legacy)
- usage(1);
-#else
- if (((ppdfile != NULL) + (attrfile != NULL) + legacy) > 1)
- usage(1);
-#endif /* CUPS_LITE */
-
- /*
- * Apply defaults as needed...
- */
-
- if (!serverport)
- {
-#ifdef _WIN32
- /*
- * Windows is almost always used as a single user system, so use a default
- * port number of 8631.
- */
-
- serverport = 8631;
-
-#else
- /*
- * Use 8000 + UID mod 1000 for the default port number...
- */
-
- serverport = 8000 + ((int)getuid() % 1000);
-#endif /* _WIN32 */
-
- _cupsLangPrintf(stderr, _("Listening on port %d."), serverport);
- }
-
- if (!directory[0])
- {
- const char *tmpdir; /* Temporary directory */
-
-#ifdef _WIN32
- if ((tmpdir = getenv("TEMP")) == NULL)
- tmpdir = "C:/TEMP";
-#elif defined(__APPLE__) && TARGET_OS_OSX
- if ((tmpdir = getenv("TMPDIR")) == NULL)
- tmpdir = "/private/tmp";
-#else
- if ((tmpdir = getenv("TMPDIR")) == NULL)
- tmpdir = "/tmp";
-#endif /* _WIN32 */
-
- snprintf(directory, sizeof(directory), "%s/ippeveprinter.%d", tmpdir, (int)getpid());
-
- if (mkdir(directory, 0755) && errno != EEXIST)
- {
- _cupsLangPrintf(stderr, _("Unable to create spool directory \"%s\": %s"), directory, strerror(errno));
- usage(1);
- }
-
- if (Verbosity)
- _cupsLangPrintf(stderr, _("Using spool directory \"%s\"."), directory);
- }
-
-#ifdef HAVE_SSL
- cupsSetServerCredentials(keypath, servername, 1);
-#endif /* HAVE_SSL */
-
- /*
- * Initialize DNS-SD...
- */
-
- dnssd_init();
-
- /*
- * Create the printer...
- */
-
- if (!docformats)
- docformats = _cupsArrayNewStrings(ppm_color > 0 ? "image/jpeg,image/pwg-raster,image/urf": "image/pwg-raster,image/urf", ',');
-
- if (attrfile)
- attrs = load_ippserver_attributes(servername, serverport, attrfile, docformats);
-#if !CUPS_LITE
- else if (ppdfile)
- {
- attrs = load_ppd_attributes(ppdfile, docformats);
-
- if (!command)
- command = "ippeveps";
- }
-#endif /* !CUPS_LITE */
- else
- attrs = load_legacy_attributes(make, model, ppm, ppm_color, duplex, docformats);
-
- if ((printer = create_printer(servername, serverport, name, location, icon, docformats, subtypes, directory, command, device_uri, attrs)) == NULL)
- return (1);
-
- printer->web_forms = web_forms;
-
-#if !CUPS_LITE
- if (ppdfile)
- printer->ppdfile = strdup(ppdfile);
-#endif /* !CUPS_LITE */
-
- /*
- * 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(ippeve_printer_t *printer) /* I - Printer */
-{
- ippeve_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 = (ippeve_job_t *)cupsArrayFirst(printer->jobs);
- job;
- job = (ippeve_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(ippeve_job_t *a, /* I - First job */
- ippeve_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? */
-{
- ippeve_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(
- ippeve_client_t *client, /* I - Client */
- ippeve_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", (int)job->state);
-
- if (!ra || cupsArrayFind(ra, "job-state-message"))
- {
- if (job->message)
- {
- ippAddString(client->response, IPP_TAG_JOB, IPP_TAG_TEXT, "job-state-message", NULL, job->message);
- }
- else
- {
- 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 ippeve_client_t * /* O - Client */
-create_client(ippeve_printer_t *printer, /* I - Printer */
- int sock) /* I - Listen socket */
-{
- ippeve_client_t *client; /* Client */
-
-
- if ((client = calloc(1, sizeof(ippeve_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 ippeve_job_t * /* O - Job */
-create_job(ippeve_client_t *client) /* I - Client */
-{
- ippeve_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(ippeve_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_file()' - Create a file for the document in a job.
- */
-
-static int /* O - File descriptor or -1 on error */
-create_job_file(
- ippeve_job_t *job, /* I - Job */
- char *fname, /* I - Filename buffer */
- size_t fnamesize, /* I - Size of filename buffer */
- const char *directory, /* I - Directory to store in */
- const char *ext) /* I - Extension (`NULL` for default) */
-{
- char name[256], /* "Safe" filename */
- *nameptr; /* Pointer into filename */
- const char *job_name; /* job-name value */
-
-
- /*
- * Make a name from the job-name attribute...
- */
-
- if ((job_name = ippGetString(ippFindAttribute(job->attrs, "job-name", IPP_TAG_NAME), 0, NULL)) == NULL)
- 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++ = '_';
-
- while (job_name[1] && !isalnum(job_name[1] & 255) && job_name[1] != '-')
- job_name ++;
- }
- }
-
- *nameptr = '\0';
-
- /*
- * Figure out the extension...
- */
-
- if (!ext)
- {
- 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 = "pwg";
- 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 if (!strcasecmp(job->format, "application/vnd.hp-pcl"))
- ext = "pcl";
- else
- ext = "dat";
- }
-
- /*
- * Create a filename with the job-id, job-name, and document-format (extension)...
- */
-
- snprintf(fname, fnamesize, "%s/%d-%s.%s", directory, job->id, name, ext);
-
- return (open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0666));
-}
-
-
-/*
- * 'create_listener()' - Create a listener socket.
- */
-
-static int /* O - Listener socket or -1 on error */
-create_listener(const char *name, /* I - Host name (`NULL` for any address) */
- int port, /* I - Port number */
- int family) /* I - Address family */
-{
- int sock; /* Listener socket */
- http_addrlist_t *addrlist; /* Listen address */
- char service[255]; /* Service port */
-
-
- snprintf(service, sizeof(service), "%d", port);
- if ((addrlist = httpAddrGetList(name, 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, if any */
- const char *type, /* I - Media type, if any */
- int width, /* I - x-dimension in 2540ths */
- int length, /* I - y-dimension in 2540ths */
- int bottom, /* I - Bottom margin in 2540ths */
- int left, /* I - Left margin in 2540ths */
- int right, /* I - Right margin in 2540ths */
- int top) /* I - Top margin in 2540ths */
-{
- 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 */
- const char *media_key_suffix = ""; /* media-key suffix */
-
-
- if (bottom == 0 && left == 0 && right == 0 && top == 0)
- media_key_suffix = "_borderless";
-
- if (type && source)
- snprintf(media_key, sizeof(media_key), "%s_%s_%s%s", media, source, type, media_key_suffix);
- else if (type)
- snprintf(media_key, sizeof(media_key), "%s__%s%s", media, type, media_key_suffix);
- else if (source)
- snprintf(media_key, sizeof(media_key), "%s_%s%s", media, source, media_key_suffix);
- else
- snprintf(media_key, sizeof(media_key), "%s%s", media, media_key_suffix);
-
- 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);
- if (bottom >= 0)
- ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-bottom-margin", bottom);
- if (left >= 0)
- ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-left-margin", left);
- if (right >= 0)
- ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-right-margin", right);
- if (top >= 0)
- ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-top-margin", top);
- 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 ippeve_printer_t * /* O - Printer */
-create_printer(
- const char *servername, /* I - Server hostname (NULL for default) */
- int serverport, /* I - Server port */
- const char *name, /* I - printer-name */
- const char *location, /* I - printer-location */
- const char *icon, /* I - printer-icons */
- cups_array_t *docformats, /* I - document-format-supported */
- const char *subtypes, /* I - Bonjour service subtype(s) */
- const char *directory, /* I - Spool directory */
- const char *command, /* I - Command to run on job files, if any */
- const char *device_uri, /* I - Output device, if any */
- ipp_t *attrs) /* I - Capability attributes */
-{
- ippeve_printer_t *printer; /* Printer */
- int i; /* Looping var */
-#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 */
- uuid[128]; /* printer-uuid */
- int k_supported; /* Maximum file size supported */
- int num_formats; /* Number of supported document formats */
- const char *formats[100], /* Supported document formats */
- *format; /* Current format */
- int num_job_attrs; /* Number of supported job attributes */
- const char *job_attrs[100];/* Job attributes */
- char xxx_supported[256];
- /* Name of -supported attribute */
- _cups_globals_t *cg = _cupsGlobals();
- /* Global path values */
-#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 char * const versions[] =/* ipp-versions-supported values */
- {
- "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",
- "document-password",
- "finishings",
- "finishings-col",
- "job-password",
- "job-password-encryption",
- "orientation-requested",
- "output-bin",
- "overrides",
- "page-ranges",
- "print-color-mode",
- "print-content-optimize",
- "print-rendering-intent",
- "print-quality",
- "printer-resolution",
- "sides"
- };
- static const char * const media_col_supported[] =
- { /* media-col-supported values */
- "media-bottom-margin",
- "media-left-margin",
- "media-right-margin",
- "media-size",
- "media-size-name",
- "media-source",
- "media-top-margin",
- "media-type"
- };
- static const char * const multiple_document_handling[] =
- { /* multiple-document-handling-supported values */
- "separate-documents-uncollated-copies",
- "separate-documents-collated-copies"
- };
- static const char * const reference_uri_schemes_supported[] =
- { /* reference-uri-schemes-supported */
- "file",
- "ftp",
- "http"
-#ifdef HAVE_SSL
- , "https"
-#endif /* HAVE_SSL */
- };
-#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))
- {
- _cupsLangPrintf(stderr, _("Unable to execute command \"%s\": %s"), command, strerror(errno));
- return (NULL);
- }
- }
- else
- {
- snprintf(path, sizeof(path), "%s/ippeveprinter/%s", cg->cups_serverbin, command);
-
- if (access(command, X_OK))
- {
- _cupsLangPrintf(stderr, _("Unable to execute command \"%s\": %s"), command, strerror(errno));
- return (NULL);
- }
-
- command = path;
- }
- }
-#endif /* !_WIN32 */
-
- /*
- * Allocate memory for the printer...
- */
-
- if ((printer = calloc(1, sizeof(ippeve_printer_t))) == NULL)
- {
- _cupsLangPrintError(NULL, _("Unable to allocate memory for printer"));
- return (NULL);
- }
-
- printer->ipv4 = -1;
- printer->ipv6 = -1;
- printer->name = strdup(name);
- printer->dnssd_name = strdup(name);
- printer->command = command ? strdup(command) : NULL;
- printer->device_uri = device_uri ? strdup(device_uri) : NULL;
- printer->directory = strdup(directory);
- printer->icon = icon ? strdup(icon) : NULL;
- printer->port = serverport;
- printer->start_time = time(NULL);
- printer->config_time = printer->start_time;
- printer->state = IPP_PSTATE_IDLE;
- printer->state_reasons = IPPEVE_PREASON_NONE;
- printer->state_time = printer->start_time;
- printer->jobs = cupsArrayNew((cups_array_func_t)compare_jobs, NULL);
- printer->next_job_id = 1;
-
- if (servername)
- {
- printer->hostname = strdup(servername);
- }
- else
- {
- char temp[1024]; /* Temporary string */
-
- printer->hostname = strdup(httpGetHostname(NULL, temp, sizeof(temp)));
- }
-
- _cupsRWInit(&(printer->rwlock));
-
- /*
- * Create the listener sockets...
- */
-
- if ((printer->ipv4 = create_listener(servername, printer->port, AF_INET)) < 0)
- {
- perror("Unable to create IPv4 listener");
- goto bad_printer;
- }
-
- if ((printer->ipv6 = create_listener(servername, printer->port, AF_INET6)) < 0)
- {
- perror("Unable to create IPv6 listener");
- goto bad_printer;
- }
-
- /*
- * Prepare URI values for the printer attributes...
- */
-
- 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 */
-
- 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");
- httpAssembleUUID(printer->hostname, serverport, name, 0, uuid, sizeof(uuid));
-
- if (Verbosity)
- {
- fprintf(stderr, "printer-more-info=\"%s\"\n", adminurl);
- fprintf(stderr, "printer-supply-info-uri=\"%s\"\n", supplyurl);
-#ifdef HAVE_SSL
- fprintf(stderr, "printer-uri=\"%s\"\n", uri);
-#else
- fprintf(stderr, "printer-uri=\"%s\",\"%s\"\n", uri, securi);
-#endif /* HAVE_SSL */
- }
-
- /*
- * 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 */
-
- /*
- * Assemble the final list of document formats...
- */
-
- if (!cupsArrayFind(docformats, (void *)"application/octet-stream"))
- cupsArrayAdd(docformats, (void *)"application/octet-stream");
-
- for (num_formats = 0, format = (const char *)cupsArrayFirst(docformats); format && num_formats < (int)(sizeof(formats) / sizeof(formats[0])); format = (const char *)cupsArrayNext(docformats))
- formats[num_formats ++] = format;
-
- /*
- * Get the list of attributes that can be used when creating a job...
- */
-
- num_job_attrs = 0;
- job_attrs[num_job_attrs ++] = "ipp-attribute-fidelity";
- job_attrs[num_job_attrs ++] = "job-name";
- job_attrs[num_job_attrs ++] = "job-priority";
- job_attrs[num_job_attrs ++] = "media";
- job_attrs[num_job_attrs ++] = "media-col";
- job_attrs[num_job_attrs ++] = "multiple-document-handling";
-
- for (i = 0; i < (int)(sizeof(job_creation) / sizeof(job_creation[0])) && num_job_attrs < (int)(sizeof(job_attrs) / sizeof(job_attrs[0])); i ++)
- {
- snprintf(xxx_supported, sizeof(xxx_supported), "%s-supported", job_creation[i]);
- if (ippFindAttribute(attrs, xxx_supported, IPP_TAG_ZERO))
- job_attrs[num_job_attrs ++] = job_creation[i];
- }
-
- /*
- * Fill out the rest of the printer attributes.
- */
-
- printer->attrs = 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);
-
- /* 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);
-
- /* document-format-default */
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_MIMETYPE), "document-format-default", NULL, "application/octet-stream");
-
- /* document-format-supported */
- ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, "document-format-supported", num_formats, NULL, formats);
-
- /* 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 */
- ippAddString (printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "identify-actions-default", NULL, "sound");
-
- /* identify-actions-supported */
- 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 */
- 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 (MaxVersion == 11)
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "ipp-versions-supported", NULL, "1.1");
- else
- ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "ipp-versions-supported", (int)(sizeof(versions) / sizeof(versions[0])), NULL, versions);
-
- /* job-creation-attributes-supported */
- ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-creation-attributes-supported", num_job_attrs, NULL, job_attrs);
-
- /* 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-priority-default */
- ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-priority-default", 50);
-
- /* job-priority-supported */
- ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-priority-supported", 1);
-
- /* job-sheets-default */
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "job-sheets-default", NULL, "none");
-
- /* job-sheets-supported */
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "job-sheets-supported", NULL, "none");
-
- /* media-col-supported */
- 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);
-
- /* 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");
-
- /* operations-supported */
- ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "operations-supported", sizeof(ops) / sizeof(ops[0]), ops);
-
- /* pdl-override-supported */
- 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);
-
- /* 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 */
- ippAddOutOfBand(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_UNKNOWN, "printer-geo-location");
-
- /* 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-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 */
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-organization", NULL, "");
-
- /* printer-organizational-unit */
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-organizational-unit", NULL, "");
-
- /* 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 */
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uuid", NULL, uuid);
-
- /* 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);
-
- /* 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);
-
- debug_attributes("Printer", printer->attrs, 0);
-
- /*
- * Register the printer with Bonjour...
- */
-
- if (!register_printer(printer, subtypes))
- 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(ippeve_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(ippeve_job_t *job) /* I - Job */
-{
- if (Verbosity)
- fprintf(stderr, "[Job %d] Removing job from history.\n", job->id);
-
- ippDelete(job->attrs);
-
- if (job->message)
- free(job->message);
-
- 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(ippeve_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->device_uri)
- free(printer->device_uri);
-#if !CUPS_LITE
- if (printer->ppdfile)
- free(printer->ppdfile);
-#endif /* !CUPS_LITE */
- 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 */
- ippeve_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, "Ignored 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(ippeve_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 ippeve_job_t * /* O - Job or NULL */
-find_job(ippeve_client_t *client) /* I - Client */
-{
- ipp_attribute_t *attr; /* job-id or job-uri attribute */
- ippeve_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 = (ippeve_job_t *)cupsArrayFind(client->printer->jobs, &key);
- _cupsRWUnlock(&(client->printer->rwlock));
-
- return (job);
-}
-
-
-/*
- * 'finish_document()' - Finish receiving a document file and start processing.
- */
-
-static void
-finish_document_data(
- ippeve_client_t *client, /* I - Client */
- ippeve_job_t *job) /* I - 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 */
-
-
- /*
- * Create a file for the request data...
- *
- * TODO: Update code to support piping large raster data to the print command.
- */
-
- if ((job->fd = create_job_file(job, filename, sizeof(filename), client->printer->directory, NULL)) < 0)
- {
- respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to create print file: %s", strerror(errno));
-
- goto abort_job;
- }
-
- if (Verbosity)
- fprintf(stderr, "Created job file \"%s\", format \"%s\".\n", filename, job->format);
-
- while ((bytes = httpRead2(client->http, buffer, sizeof(buffer))) > 0)
- {
- if (write(job->fd, buffer, (size_t)bytes) < bytes)
- {
- int error = errno; /* Write error */
-
- close(job->fd);
- job->fd = -1;
-
- unlink(filename);
-
- respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error));
-
- goto abort_job;
- }
- }
-
- if (bytes < 0)
- {
- /*
- * Got an error while reading the print data, so abort this job.
- */
-
- close(job->fd);
- job->fd = -1;
-
- unlink(filename);
-
- respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to read print file.");
-
- goto abort_job;
- }
-
- if (close(job->fd))
- {
- int error = errno; /* Write error */
-
- job->fd = -1;
-
- unlink(filename);
-
- respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error));
-
- goto abort_job;
- }
-
- 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
- {
- respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to process job.");
- goto abort_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-message");
- cupsArrayAdd(ra, "job-state-reasons");
- cupsArrayAdd(ra, "job-uri");
-
- copy_job_attributes(client, job, ra);
- cupsArrayDelete(ra);
- return;
-
- /*
- * If we get here we had to abort the job...
- */
-
- abort_job:
-
- job->state = IPP_JSTATE_ABORTED;
- job->completed = time(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);
-}
-
-
-/*
- * 'finish_uri()' - Finish fetching a document URI and start processing.
- */
-
-static void
-finish_document_uri(
- ippeve_client_t *client, /* I - Client */
- ippeve_job_t *job) /* I - 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 */
- ipp_attribute_t *attr; /* Current attribute */
- cups_array_t *ra; /* Attributes to send in response */
-
-
- /*
- * 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.");
-
- goto abort_job;
- }
-
- /*
- * 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.");
-
- goto abort_job;
- }
-
- if (ippGetCount(uri) != 1)
- {
- respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Too many document-uri values.");
-
- goto abort_job;
- }
-
- 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", httpURIStatusString(uri_status));
-
- goto abort_job;
- }
-
- 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);
-
- goto abort_job;
- }
-
- if (!strcmp(scheme, "file") && access(resource, R_OK))
- {
- respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to access URI: %s", strerror(errno));
-
- goto abort_job;
- }
-
- /*
- * 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 ((job->fd = create_job_file(job, filename, sizeof(filename), client->printer->directory, NULL)) < 0)
- {
- _cupsRWUnlock(&(client->printer->rwlock));
-
- respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to create print file: %s", strerror(errno));
-
- goto abort_job;
- }
-
- _cupsRWUnlock(&(client->printer->rwlock));
-
- 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));
-
- goto abort_job;
- }
-
- 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 */
-
- 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));
-
- goto abort_job;
- }
- }
- 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());
-
- close(job->fd);
- job->fd = -1;
-
- unlink(filename);
-
- goto abort_job;
- }
-
- 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));
-
- close(job->fd);
- job->fd = -1;
-
- unlink(filename);
- httpClose(http);
-
- goto abort_job;
- }
-
- 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));
-
- close(job->fd);
- job->fd = -1;
-
- unlink(filename);
- httpClose(http);
-
- goto abort_job;
- }
-
- while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
- {
- if (write(job->fd, buffer, (size_t)bytes) < bytes)
- {
- int error = errno; /* Write error */
-
- 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));
-
- goto abort_job;
- }
- }
-
- httpClose(http);
- }
-
- if (close(job->fd))
- {
- int error = errno; /* Write error */
-
- job->fd = -1;
-
- unlink(filename);
-
- respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error));
-
- goto abort_job;
- }
-
- _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);
- return;
-
- /*
- * If we get here we had to abort the job...
- */
-
- abort_job:
-
- job->state = IPP_JSTATE_ABORTED;
- job->completed = time(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);
-}
-
-
-/*
- * 'html_escape()' - Write a HTML-safe string.
- */
-
-static void
-html_escape(ippeve_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, "&amp;", 5);
- else
- httpWrite2(client->http, "&lt;", 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(ippeve_client_t *client) /* I - Client */
-{
- html_printf(client,
- "</div>\n"
- "</body>\n"
- "</html>\n");
- httpWrite2(client->http, "", 0);
-}
-
-
-/*
- * 'html_header()' - Show the web interface header and title.
- */
-
-static void
-html_header(ippeve_client_t *client, /* I - Client */
- const char *title, /* I - Title */
- int refresh) /* I - Refresh timer, if any */
-{
- html_printf(client,
- "<!doctype html>\n"
- "<html>\n"
- "<head>\n"
- "<title>%s</title>\n"
- "<link rel=\"shortcut icon\" href=\"/icon.png\" type=\"image/png\">\n"
- "<link rel=\"apple-touch-icon\" href=\"/icon.png\" type=\"image/png\">\n"
- "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=9\">\n", title);
- if (refresh > 0)
- html_printf(client, "<meta http-equiv=\"refresh\" content=\"%d\">\n", refresh);
- html_printf(client,
- "<meta name=\"viewport\" content=\"width=device-width\">\n"
- "<style>\n"
- "body { font-family: sans-serif; margin: 0; }\n"
- "div.body { padding: 0px 10px 10px; }\n"
- "span.badge { background: #090; border-radius: 5px; color: #fff; padding: 5px 10px; }\n"
- "span.bar { box-shadow: 0px 1px 5px #333; font-size: 75%%; }\n"
- "table.form { border-collapse: collapse; margin-left: auto; margin-right: auto; margin-top: 10px; width: auto; }\n"
- "table.form td, table.form th { padding: 5px 2px; }\n"
- "table.form td.meter { border-right: solid 1px #ccc; padding: 0px; width: 400px; }\n"
- "table.form th { text-align: right; }\n"
- "table.striped { border-bottom: solid thin black; border-collapse: collapse; width: 100%%; }\n"
- "table.striped tr:nth-child(even) { background: #fcfcfc; }\n"
- "table.striped tr:nth-child(odd) { background: #f0f0f0; }\n"
- "table.striped th { background: white; border-bottom: solid thin black; text-align: left; vertical-align: bottom; }\n"
- "table.striped td { margin: 0; padding: 5px; vertical-align: top; }\n"
- "table.nav { border-collapse: collapse; width: 100%%; }\n"
- "table.nav td { margin: 0; text-align: center; }\n"
- "td.nav a, td.nav a:active, td.nav a:hover, td.nav a:hover:link, td.nav a:hover:link:visited, td.nav a:link, td.nav a:link:visited, td.nav a:visited { background: inherit; color: inherit; font-size: 80%%; text-decoration: none; }\n"
- "td.nav { background: #333; color: #fff; padding: 4px 8px; width: 33%%; }\n"
- "td.nav.sel { background: #fff; color: #000; font-weight: bold; }\n"
- "td.nav:hover { background: #666; color: #fff; }\n"
- "td.nav:active { background: #000; color: #ff0; }\n"
- "</style>\n"
- "</head>\n"
- "<body>\n"
- "<table class=\"nav\"><tr>"
- "<td class=\"nav%s\"><a href=\"/\">Status</a></td>"
- "<td class=\"nav%s\"><a href=\"/supplies\">Supplies</a></td>"
- "<td class=\"nav%s\"><a href=\"/media\">Media</a></td>"
- "</tr></table>\n"
- "<div class=\"body\">\n", !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(ippeve_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(ippeve_client_t *client) /* I - Client */
-{
- ippeve_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(ippeve_client_t *client) /* I - Client */
-{
- ippeve_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(ippeve_client_t *client) /* I - Client */
-{
- ippeve_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(
- ippeve_client_t *client) /* I - Client */
-{
- ippeve_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(ippeve_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 */
- ippeve_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 = (ippeve_job_t *)cupsArrayFirst(client->printer->jobs);
- (limit <= 0 || count < limit) && job;
- job = (ippeve_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(
- ippeve_client_t *client) /* I - Client */
-{
- cups_array_t *ra; /* Requested attributes array */
- ippeve_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, "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", (int)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 == IPPEVE_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 */
- ippeve_preason_t bit; /* Reason bit */
- int i; /* Looping var */
- char reason[32]; /* Reason string */
-
- for (i = 0, bit = 1; i < (int)(sizeof(ippeve_preason_strings) / sizeof(ippeve_preason_strings[0])); i ++, bit *= 2)
- {
- if (printer->state_reasons & bit)
- {
- snprintf(reason, sizeof(reason), "%s-%s", ippeve_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-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(
- ippeve_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(ippeve_client_t *client) /* I - Client */
-{
- ippeve_job_t *job; /* New job */
-
-
- /*
- * 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;
- }
-
- /*
- * Create the job...
- */
-
- if ((job = create_job(client)) == NULL)
- {
- respond_ipp(client, IPP_STATUS_ERROR_BUSY, "Currently printing another job.");
- return;
- }
-
- /*
- * Then finish getting the document data and process things...
- */
-
- finish_document_data(client, job);
-}
-
-
-/*
- * 'ipp_print_uri()' - Create a job object with a referenced document.
- */
-
-static void
-ipp_print_uri(ippeve_client_t *client) /* I - Client */
-{
- ippeve_job_t *job; /* New job */
-
-
- /*
- * Validate print job attributes...
- */
-
- if (!valid_job_attributes(client))
- {
- httpFlush(client->http);
- return;
- }
-
- /*
- * Create the job...
- */
-
- if ((job = create_job(client)) == NULL)
- {
- respond_ipp(client, IPP_STATUS_ERROR_BUSY, "Currently printing another job.");
- return;
- }
-
- /*
- * Then finish getting the document data and process things...
- */
-
- finish_document_uri(client, job);
-}
-
-
-/*
- * 'ipp_send_document()' - Add an attached document to a job object created with
- * Create-Job.
- */
-
-static void
-ipp_send_document(
- ippeve_client_t *client) /* I - Client */
-{
- ippeve_job_t *job; /* Job information */
- ipp_attribute_t *attr; /* Current attribute */
-
-
- /*
- * 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;
- }
-
- /*
- * Make sure we have the "last-document" operation attribute...
- */
-
- 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 (ippGetGroupTag(attr) != IPP_TAG_OPERATION)
- {
- respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "The last-document attribute is not in the operation group.");
- 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;
- }
-
- /*
- * Then finish getting the document data and process things...
- */
-
- _cupsRWLockWrite(&(client->printer->rwlock));
-
- copy_attributes(job->attrs, client->request, NULL, IPP_TAG_JOB, 0);
-
- 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";
-
- _cupsRWUnlock(&(client->printer->rwlock));
-
- finish_document_data(client, job);
-}
-
-
-/*
- * 'ipp_send_uri()' - Add a referenced document to a job object created with
- * Create-Job.
- */
-
-static void
-ipp_send_uri(ippeve_client_t *client) /* I - Client */
-{
- ippeve_job_t *job; /* Job information */
- ipp_attribute_t *attr; /* Current attribute */
-
-
- /*
- * 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 (ippGetGroupTag(attr) != IPP_TAG_OPERATION)
- {
- respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "The last-document attribute is not in the operation group.");
- 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;
- }
-
- /*
- * Then finish getting the document data and process things...
- */
-
- _cupsRWLockWrite(&(client->printer->rwlock));
-
- copy_attributes(job->attrs, client->request, NULL, IPP_TAG_JOB, 0);
-
- 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";
-
- _cupsRWUnlock(&(client->printer->rwlock));
-
- finish_document_uri(client, job);
-}
-
-
-/*
- * 'ipp_validate_job()' - Validate job creation attributes.
- */
-
-static void
-ipp_validate_job(ippeve_client_t *client) /* I - Client */
-{
- if (valid_job_attributes(client))
- respond_ipp(client, IPP_STATUS_OK, NULL);
-}
-
-
-/*
- * 'ippserver_attr_cb()' - Determine whether an attribute should be loaded.
- */
-
-static int /* O - 1 to use, 0 to ignore */
-ippserver_attr_cb(
- _ipp_file_t *f, /* I - IPP file */
- void *user_data, /* I - User data pointer (unused) */
- const char *attr) /* I - Attribute name */
-{
- int i, /* Current element */
- result; /* Result of comparison */
- static const char * const ignored[] =
- { /* Ignored attributes */
- "attributes-charset",
- "attributes-natural-language",
- "charset-configured",
- "charset-supported",
- "device-service-count",
- "device-uuid",
- "document-format-varying-attributes",
- "generated-natural-language-supported",
- "identify-actions-default",
- "identify-actions-supported",
- "ipp-features-supported",
- "ipp-versions-supproted",
- "ippget-event-life",
- "job-hold-until-supported",
- "job-hold-until-time-supported",
- "job-ids-supported",
- "job-k-octets-supported",
- "job-settable-attributes-supported",
- "multiple-document-jobs-supported",
- "multiple-operation-time-out",
- "multiple-operation-time-out-action",
- "natural-language-configured",
- "notify-attributes-supported",
- "notify-events-default",
- "notify-events-supported",
- "notify-lease-duration-default",
- "notify-lease-duration-supported",
- "notify-max-events-supported",
- "notify-pull-method-supported",
- "operations-supported",
- "printer-alert",
- "printer-alert-description",
- "printer-camera-image-uri",
- "printer-charge-info",
- "printer-charge-info-uri",
- "printer-config-change-date-time",
- "printer-config-change-time",
- "printer-current-time",
- "printer-detailed-status-messages",
- "printer-dns-sd-name",
- "printer-fax-log-uri",
- "printer-get-attributes-supported",
- "printer-icons",
- "printer-id",
- "printer-info",
- "printer-is-accepting-jobs",
- "printer-message-date-time",
- "printer-message-from-operator",
- "printer-message-time",
- "printer-more-info",
- "printer-service-type",
- "printer-settable-attributes-supported",
- "printer-state",
- "printer-state-message",
- "printer-state-reasons",
- "printer-static-resource-directory-uri",
- "printer-static-resource-k-octets-free",
- "printer-static-resource-k-octets-supported",
- "printer-strings-languages-supported",
- "printer-strings-uri",
- "printer-supply-info-uri",
- "printer-up-time",
- "printer-uri-supported",
- "printer-xri-supported",
- "queued-job-count",
- "reference-uri-scheme-supported",
- "uri-authentication-supported",
- "uri-security-supported",
- "which-jobs-supported",
- "xri-authentication-supported",
- "xri-security-supported",
- "xri-uri-scheme-supported"
- };
-
-
- (void)f;
- (void)user_data;
-
- for (i = 0, result = 1; i < (int)(sizeof(ignored) / sizeof(ignored[0])); i ++)
- {
- if ((result = strcmp(attr, ignored[i])) <= 0)
- break;
- }
-
- return (result != 0);
-}
-
-
-/*
- * 'ippserver_error_cb()' - Log an error message.
- */
-
-static int /* O - 1 to continue, 0 to stop */
-ippserver_error_cb(
- _ipp_file_t *f, /* I - IPP file data */
- void *user_data, /* I - User data pointer (unused) */
- const char *error) /* I - Error message */
-{
- (void)f;
- (void)user_data;
-
- _cupsLangPrintf(stderr, "%s\n", error);
-
- return (1);
-}
-
-
-/*
- * 'ippserver_token_cb()' - Process ippserver-specific config file tokens.
- */
-
-static int /* O - 1 to continue, 0 to stop */
-ippserver_token_cb(
- _ipp_file_t *f, /* I - IPP file data */
- _ipp_vars_t *vars, /* I - IPP variables */
- void *user_data, /* I - User data pointer (unused) */
- const char *token) /* I - Current token */
-{
- (void)vars;
- (void)user_data;
-
- if (!token)
- {
- /*
- * NULL token means do the initial setup - create an empty IPP message and
- * return...
- */
-
- f->attrs = ippNew();
- f->group_tag = IPP_TAG_PRINTER;
- }
- else
- {
- _cupsLangPrintf(stderr, _("Unknown directive \"%s\" on line %d of \"%s\" ignored."), token, f->linenum, f->filename);
- }
-
- return (1);
-}
-
-
-/*
- * 'load_ippserver_attributes()' - Load IPP attributes from an ippserver file.
- */
-
-static ipp_t * /* O - IPP attributes or `NULL` on error */
-load_ippserver_attributes(
- const char *servername, /* I - Server name or `NULL` for default */
- int serverport, /* I - Server port number */
- const char *filename, /* I - ippserver attribute filename */
- cups_array_t *docformats) /* I - document-format-supported values */
-{
- ipp_t *attrs; /* IPP attributes */
- _ipp_vars_t vars; /* IPP variables */
- char temp[256]; /* Temporary string */
-
-
- (void)docformats; /* for now */
-
- /*
- * Setup callbacks and variables for the printer configuration file...
- *
- * The following additional variables are supported:
- *
- * - SERVERNAME: The host name of the server.
- * - SERVERPORT: The default port of the server.
- */
-
- _ippVarsInit(&vars, (_ipp_fattr_cb_t)ippserver_attr_cb, (_ipp_ferror_cb_t)ippserver_error_cb, (_ipp_ftoken_cb_t)ippserver_token_cb);
-
- if (servername)
- {
- _ippVarsSet(&vars, "SERVERNAME", servername);
- }
- else
- {
- httpGetHostname(NULL, temp, sizeof(temp));
- _ippVarsSet(&vars, "SERVERNAME", temp);
- }
-
- snprintf(temp, sizeof(temp), "%d", serverport);
- _ippVarsSet(&vars, "SERVERPORT", temp);
-
- /*
- * Load attributes and values for the printer...
- */
-
- attrs = _ippFileParse(&vars, filename, NULL);
-
- /*
- * Free memory and return...
- */
-
- _ippVarsDeinit(&vars);
-
- return (attrs);
-}
-
-
-/*
- * 'load_legacy_attributes()' - Load IPP attributes using the old ippserver
- * options.
- */
-
-static ipp_t * /* O - IPP attributes or `NULL` on error */
-load_legacy_attributes(
- const char *make, /* I - Manufacturer name */
- const char *model, /* I - Model name */
- int ppm, /* I - pages-per-minute */
- int ppm_color, /* I - pages-per-minute-color */
- int duplex, /* I - Duplex support? */
- cups_array_t *docformats) /* I - document-format-supported values */
-{
- int i; /* Looping var */
- ipp_t *attrs, /* IPP attributes */
- *col; /* Collection value */
- ipp_attribute_t *attr; /* Current attribute */
- char device_id[1024],/* printer-device-id */
- *ptr, /* Pointer into device ID */
- make_model[128];/* printer-make-and-model */
- const char *format, /* Current document format */
- *prefix; /* Prefix for device ID */
- int num_media; /* Number of media */
- const char * const *media; /* List of media */
- int num_ready; /* Number of loaded media */
- const char * const *ready; /* List of loaded media */
- pwg_media_t *pwg; /* PWG media size information */
- static const char * const media_supported[] =
- { /* media-supported values */
- "na_letter_8.5x11in", /* Letter */
- "na_legal_8.5x14in", /* Legal */
- "iso_a4_210x297mm", /* A4 */
- "na_number-10_4.125x9.5in", /* #10 Envelope */
- "iso_dl_110x220mm" /* DL Envelope */
- };
- static const char * const media_supported_color[] =
- { /* media-supported values */
- "na_letter_8.5x11in", /* Letter */
- "na_legal_8.5x14in", /* Legal */
- "iso_a4_210x297mm", /* A4 */
- "na_number-10_4.125x9.5in", /* #10 Envelope */
- "iso_dl_110x220mm", /* DL Envelope */
- "na_index-3x5_3x5in", /* Photo 3x5 */
- "oe_photo-l_3.5x5in", /* Photo L */
- "na_index-4x6_4x6in", /* Photo 4x6 */
- "iso_a6_105x148mm", /* A6 */
- "na_5x7_5x7in" /* Photo 5x7 aka 2L */
- "iso_a5_148x210mm", /* A5 */
- };
- static const char * const media_ready[] =
- { /* media-ready values */
- "na_letter_8.5x11in", /* Letter */
- "na_number-10_4.125x9.5in" /* #10 */
- };
- static const char * const media_ready_color[] =
- { /* media-ready values */
- "na_letter_8.5x11in", /* Letter */
- "na_index-4x6_4x6in" /* Photo 4x6 */
- };
- static const char * const media_source_supported[] =
- { /* media-source-supported values */
- "auto",
- "main",
- "manual",
- "by-pass-tray" /* AKA multi-purpose tray */
- };
- static const char * const media_source_supported_color[] =
- { /* media-source-supported values */
- "auto",
- "main",
- "photo"
- };
- static const char * const media_type_supported[] =
- { /* media-type-supported values */
- "auto",
- "cardstock",
- "envelope",
- "labels",
- "other",
- "stationery",
- "stationery-letterhead",
- "transparency"
- };
- static const char * const media_type_supported_color[] =
- { /* media-type-supported values */
- "auto",
- "cardstock",
- "envelope",
- "labels",
- "other",
- "stationery",
- "stationery-letterhead",
- "transparency",
- "photographic-glossy",
- "photographic-high-gloss",
- "photographic-matte",
- "photographic-satin",
- "photographic-semi-gloss"
- };
- static const int media_bottom_margin_supported[] =
- { /* media-bottom-margin-supported values */
- 635 /* 1/4" */
- };
- static const int media_bottom_margin_supported_color[] =
- { /* media-bottom/top-margin-supported values */
- 0, /* Borderless */
- 1168 /* 0.46" (common HP inkjet bottom margin) */
- };
- static const int media_lr_margin_supported[] =
- { /* media-left/right-margin-supported values */
- 340, /* 3.4mm (historical HP PCL A4 margin) */
- 635 /* 1/4" */
- };
- static const int media_lr_margin_supported_color[] =
- { /* media-left/right-margin-supported values */
- 0, /* Borderless */
- 340, /* 3.4mm (historical HP PCL A4 margin) */
- 635 /* 1/4" */
- };
- static const int media_top_margin_supported[] =
- { /* media-top-margin-supported values */
- 635 /* 1/4" */
- };
- static const int media_top_margin_supported_color[] =
- { /* media-top/top-margin-supported values */
- 0, /* Borderless */
- 102 /* 0.04" (common HP inkjet top margin */
- };
- static const int orientation_requested_supported[4] =
- { /* orientation-requested-supported values */
- IPP_ORIENT_PORTRAIT,
- IPP_ORIENT_LANDSCAPE,
- IPP_ORIENT_REVERSE_LANDSCAPE,
- IPP_ORIENT_REVERSE_PORTRAIT
- };
- static const char * const overrides_supported[] =
- { /* overrides-supported values */
- "document-numbers",
- "media",
- "media-col",
- "orientation-requested",
- "pages"
- };
- static const char * const print_color_mode_supported[] =
- { /* print-color-mode-supported values */
- "monochrome"
- };
- static const char * const print_color_mode_supported_color[] =
- { /* 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 char * const printer_input_tray[] =
- { /* printer-input-tray values */
- "type=sheetFeedAutoRemovableTray;mediafeed=0;mediaxfeed=0;maxcapacity=-2;level=-2;status=0;name=auto",
- "type=sheetFeedAutoRemovableTray;mediafeed=0;mediaxfeed=0;maxcapacity=250;level=100;status=0;name=main",
- "type=sheetFeedManual;mediafeed=0;mediaxfeed=0;maxcapacity=1;level=-2;status=0;name=manual",
- "type=sheetFeedAutoNonRemovableTray;mediafeed=0;mediaxfeed=0;maxcapacity=25;level=-2;status=0;name=by-pass-tray"
- };
- static const char * const printer_input_tray_color[] =
- { /* printer-input-tray values */
- "type=sheetFeedAutoRemovableTray;mediafeed=0;mediaxfeed=0;maxcapacity=-2;level=-2;status=0;name=auto",
- "type=sheetFeedAutoRemovableTray;mediafeed=0;mediaxfeed=0;maxcapacity=250;level=-2;status=0;name=main",
- "type=sheetFeedAutoRemovableTray;mediafeed=0;mediaxfeed=0;maxcapacity=25;level=-2;status=0;name=photo"
- };
- static const char * const printer_supply[] =
- { /* printer-supply values */
- "index=1;class=receptacleThatIsFilled;type=wasteToner;unit=percent;"
- "maxcapacity=100;level=25;colorantname=unknown;",
- "index=2;class=supplyThatIsConsumed;type=toner;unit=percent;"
- "maxcapacity=100;level=75;colorantname=black;"
- };
- static const char * const printer_supply_color[] =
- { /* printer-supply values */
- "index=1;class=receptacleThatIsFilled;type=wasteInk;unit=percent;"
- "maxcapacity=100;level=25;colorantname=unknown;",
- "index=2;class=supplyThatIsConsumed;type=ink;unit=percent;"
- "maxcapacity=100;level=75;colorantname=black;",
- "index=3;class=supplyThatIsConsumed;type=ink;unit=percent;"
- "maxcapacity=100;level=50;colorantname=cyan;",
- "index=4;class=supplyThatIsConsumed;type=ink;unit=percent;"
- "maxcapacity=100;level=33;colorantname=magenta;",
- "index=5;class=supplyThatIsConsumed;type=ink;unit=percent;"
- "maxcapacity=100;level=67;colorantname=yellow;"
- };
- static const char * const printer_supply_description[] =
- { /* printer-supply-description values */
- "Toner Waste Tank",
- "Black Toner"
- };
- static const char * const printer_supply_description_color[] =
- { /* printer-supply-description values */
- "Ink Waste Tank",
- "Black Ink",
- "Cyan Ink",
- "Magenta Ink",
- "Yellow Ink"
- };
- static const int pwg_raster_document_resolution_supported[] =
- {
- 300,
- 600
- };
- static const char * const pwg_raster_document_type_supported[] =
- {
- "black_1",
- "sgray_8"
- };
- static const char * const pwg_raster_document_type_supported_color[] =
- {
- "black_1",
- "sgray_8",
- "srgb_8",
- "srgb_16"
- };
- 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-4-5-19",
- "MT1-2-3-4-5-6",
- "RS600",
- "V1.4",
- "W8"
- };
- static const char * const urf_supported_color[] =
- { /* urf-supported values */
- "CP1",
- "IS1-4-5-7-19",
- "MT1-2-3-4-5-6-8-9-10-11-12-13",
- "RS600",
- "SRGB24",
- "V1.4",
- "W8"
- };
- static const char * const urf_supported_color_duplex[] =
- { /* urf-supported values */
- "CP1",
- "IS1-4-5-7-19",
- "MT1-2-3-4-5-6-8-9-10-11-12-13",
- "RS600",
- "SRGB24",
- "V1.4",
- "W8",
- "DM3"
- };
- static const char * const urf_supported_duplex[] =
- { /* urf-supported values */
- "CP1",
- "IS1-4-5-19",
- "MT1-2-3-4-5-6",
- "RS600",
- "V1.4",
- "W8",
- "DM1"
- };
-
-
- attrs = ippNew();
-
- if (ppm_color > 0)
- {
- num_media = (int)(sizeof(media_supported_color) / sizeof(media_supported_color[0]));
- media = media_supported_color;
- num_ready = (int)(sizeof(media_ready_color) / sizeof(media_ready_color[0]));
- ready = media_ready_color;
- }
- else
- {
- num_media = (int)(sizeof(media_supported) / sizeof(media_supported[0]));
- media = media_supported;
- num_ready = (int)(sizeof(media_ready) / sizeof(media_ready[0]));
- ready = media_ready;
- }
-
- /* color-supported */
- ippAddBoolean(attrs, IPP_TAG_PRINTER, "color-supported", ppm_color > 0);
-
- /* copies-default */
- ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default", 1);
-
- /* copies-supported */
- ippAddRange(attrs, IPP_TAG_PRINTER, "copies-supported", 1, (cupsArrayFind(docformats, (void *)"application/pdf") != NULL || cupsArrayFind(docformats, (void *)"image/jpeg") != NULL) ? 999 : 1);
-
- /* document-password-supported */
- if (cupsArrayFind(docformats, (void *)"application/pdf"))
- ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "document-password-supported", 1023);
-
- /* finishings-default */
- ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "finishings-default", IPP_FINISHINGS_NONE);
-
- /* finishings-supported */
- ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "finishings-supported", IPP_FINISHINGS_NONE);
-
- /* media-bottom-margin-supported */
- if (ppm_color > 0)
- ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-bottom-margin-supported", (int)(sizeof(media_bottom_margin_supported) / sizeof(media_bottom_margin_supported[0])), media_bottom_margin_supported);
- else
- ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-bottom-margin-supported", (int)(sizeof(media_bottom_margin_supported_color) / sizeof(media_bottom_margin_supported_color[0])), media_bottom_margin_supported_color);
-
- /* media-col-database and media-col-default */
- attr = ippAddCollections(attrs, IPP_TAG_PRINTER, "media-col-database", num_media, NULL);
- for (i = 0; i < num_media; i ++)
- {
- int bottom, left, /* media-xxx-margins */
- right, top;
- const char *source; /* media-source, if any */
-
- pwg = pwgMediaForPWG(media[i]);
-
- if (pwg->width < 21000 && pwg->length < 21000)
- {
- source = "photo"; /* Photo size media from photo tray */
- bottom = /* Borderless margins */
- left =
- right =
- top = 0;
- }
- else if (pwg->width < 21000)
- {
- source = "by-pass-tray"; /* Envelopes from multi-purpose tray */
- bottom = ppm_color > 0 ? media_bottom_margin_supported_color[1] : media_bottom_margin_supported[0];
- left = /* Left/right margins are standard */
- right = media_lr_margin_supported[1];
- top = ppm_color > 0 ? media_top_margin_supported_color[1] : media_top_margin_supported[0];
- }
- else if (pwg->width == 21000)
- {
- source = NULL; /* A4 from any tray */
- bottom = ppm_color > 0 ? media_bottom_margin_supported_color[1] : media_bottom_margin_supported[0];
- left = /* Left/right margins are reduced */
- right = media_lr_margin_supported[0];
- top = ppm_color > 0 ? media_top_margin_supported_color[1] : media_top_margin_supported[0];
- }
- else
- {
- source = NULL; /* Other size media from any tray */
- bottom = ppm_color > 0 ? media_bottom_margin_supported_color[1] : media_bottom_margin_supported[0];
- left = /* Left/right margins are standard */
- right = media_lr_margin_supported[1];
- top = ppm_color > 0 ? media_top_margin_supported_color[1] : media_top_margin_supported[0];
- }
-
- col = create_media_col(media[i], source, NULL, pwg->width, pwg->length, bottom, left, right, top);
- ippSetCollection(attrs, &attr, i, col);
-
- ippDelete(col);
- }
-
- /* media-col-default */
- pwg = pwgMediaForPWG(ready[0]);
-
- if (pwg->width == 21000)
- col = create_media_col(ready[0], "main", "stationery", pwg->width, pwg->length, ppm_color > 0 ? media_bottom_margin_supported_color[1] : media_bottom_margin_supported[0], media_lr_margin_supported[0], media_lr_margin_supported[0], ppm_color > 0 ? media_top_margin_supported_color[1] : media_top_margin_supported[0]);
- else
- col = create_media_col(ready[0], "main", "stationery", pwg->width, pwg->length, ppm_color > 0 ? media_bottom_margin_supported_color[1] : media_bottom_margin_supported[0], media_lr_margin_supported[1], media_lr_margin_supported[1], ppm_color > 0 ? media_top_margin_supported_color[1] : media_top_margin_supported[0]);
-
- ippAddCollection(attrs, IPP_TAG_PRINTER, "media-col-default", col);
-
- ippDelete(col);
-
- /* media-col-ready */
- attr = ippAddCollections(attrs, IPP_TAG_PRINTER, "media-col-ready", num_ready, NULL);
- for (i = 0; i < num_ready; i ++)
- {
- int bottom, left, /* media-xxx-margins */
- right, top;
- const char *source, /* media-source */
- *type; /* media-type */
-
- pwg = pwgMediaForPWG(ready[i]);
-
- if (pwg->width < 21000 && pwg->length < 21000)
- {
- source = "photo"; /* Photo size media from photo tray */
- type = "photographic-glossy"; /* Glossy photo paper */
- bottom = /* Borderless margins */
- left =
- right =
- top = 0;
- }
- else if (pwg->width < 21000)
- {
- source = "by-pass-tray"; /* Envelopes from multi-purpose tray */
- type = "envelope"; /* Envelope */
- bottom = ppm_color > 0 ? media_bottom_margin_supported_color[1] : media_bottom_margin_supported[0];
- left = /* Left/right margins are standard */
- right = media_lr_margin_supported[1];
- top = ppm_color > 0 ? media_top_margin_supported_color[1] : media_top_margin_supported[0];
- }
- else if (pwg->width == 21000)
- {
- source = "main"; /* A4 from main tray */
- type = "stationery"; /* Plain paper */
- bottom = ppm_color > 0 ? media_bottom_margin_supported_color[1] : media_bottom_margin_supported[0];
- left = /* Left/right margins are reduced */
- right = media_lr_margin_supported[0];
- top = ppm_color > 0 ? media_top_margin_supported_color[1] : media_top_margin_supported[0];
- }
- else
- {
- source = "main"; /* A4 from main tray */
- type = "stationery"; /* Plain paper */
- bottom = ppm_color > 0 ? media_bottom_margin_supported_color[1] : media_bottom_margin_supported[0];
- left = /* Left/right margins are standard */
- right = media_lr_margin_supported[1];
- top = ppm_color > 0 ? media_top_margin_supported_color[1] : media_top_margin_supported[0];
- }
-
- col = create_media_col(ready[i], source, type, pwg->width, pwg->length, bottom, left, right, top);
- ippSetCollection(attrs, &attr, i, col);
- ippDelete(col);
- }
-
- /* media-default */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-default", NULL, media[0]);
-
- /* media-left/right-margin-supported */
- if (ppm_color > 0)
- {
- ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-left-margin-supported", (int)(sizeof(media_lr_margin_supported_color) / sizeof(media_lr_margin_supported_color[0])), media_lr_margin_supported_color);
- ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-right-margin-supported", (int)(sizeof(media_lr_margin_supported_color) / sizeof(media_lr_margin_supported_color[0])), media_lr_margin_supported_color);
- }
- else
- {
- ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-left-margin-supported", (int)(sizeof(media_lr_margin_supported) / sizeof(media_lr_margin_supported[0])), media_lr_margin_supported);
- ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-right-margin-supported", (int)(sizeof(media_lr_margin_supported) / sizeof(media_lr_margin_supported[0])), media_lr_margin_supported);
- }
-
- /* media-ready */
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-ready", num_ready, NULL, ready);
-
- /* media-supported */
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-supported", num_media, NULL, media);
-
- /* media-size-supported */
- attr = ippAddCollections(attrs, IPP_TAG_PRINTER, "media-size-supported", num_media, NULL);
- for (i = 0; i < num_media; i ++)
- {
- pwg = pwgMediaForPWG(media[i]);
- col = create_media_size(pwg->width, pwg->length);
-
- ippSetCollection(attrs, &attr, i, col);
- ippDelete(col);
- }
-
- /* media-source-supported */
- if (ppm_color > 0)
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-source-supported", (int)(sizeof(media_source_supported_color) / sizeof(media_source_supported_color[0])), NULL, media_source_supported_color);
- else
- ippAddStrings(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 (ppm_color > 0)
- ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-top-margin-supported", (int)(sizeof(media_top_margin_supported) / sizeof(media_top_margin_supported[0])), media_top_margin_supported);
- else
- ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-top-margin-supported", (int)(sizeof(media_top_margin_supported_color) / sizeof(media_top_margin_supported_color[0])), media_top_margin_supported_color);
-
- /* media-type-supported */
- if (ppm_color > 0)
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-type-supported", (int)(sizeof(media_type_supported_color) / sizeof(media_type_supported_color[0])), NULL, media_type_supported_color);
- else
- ippAddStrings(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);
-
- /* orientation-requested-default */
- ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "orientation-requested-default", IPP_ORIENT_PORTRAIT);
-
- /* orientation-requested-supported */
- if (cupsArrayFind(docformats, (void *)"application/pdf") || cupsArrayFind(docformats, (void *)"image/jpeg"))
- ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "orientation-requested-supported", (int)(sizeof(orientation_requested_supported) / sizeof(orientation_requested_supported[0])), orientation_requested_supported);
- else
- ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "orientation-requested-supported", IPP_ORIENT_PORTRAIT);
-
- /* output-bin-default */
- if (ppm_color > 0)
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "output-bin-default", NULL, "face-up");
- else
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "output-bin-default", NULL, "face-down");
-
- /* output-bin-supported */
- if (ppm_color > 0)
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "output-bin-supported", NULL, "face-up");
- else
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "output-bin-supported", NULL, "face-down");
-
- /* overrides-supported */
- if (cupsArrayFind(docformats, (void *)"application/pdf"))
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "overrides-supported", (int)(sizeof(overrides_supported) / sizeof(overrides_supported[0])), NULL, overrides_supported);
-
- /* page-ranges-supported */
- ippAddBoolean(attrs, IPP_TAG_PRINTER, "page-ranges-supported", cupsArrayFind(docformats, (void *)"application/pdf") != NULL);
-
- /* pages-per-minute */
- ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "pages-per-minute", ppm);
-
- /* pages-per-minute-color */
- if (ppm_color > 0)
- ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "pages-per-minute-color", ppm_color);
-
- /* print-color-mode-default */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-color-mode-default", NULL, ppm_color > 0 ? "auto" : "monochrome");
-
- /* print-color-mode-supported */
- if (ppm_color > 0)
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-color-mode-supported", (int)(sizeof(print_color_mode_supported_color) / sizeof(print_color_mode_supported_color[0])), NULL, print_color_mode_supported_color);
- else
- ippAddStrings(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 */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-content-optimize-default", NULL, "auto");
-
- /* print-content-optimize-supported */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-content-optimize-supported", NULL, "auto");
-
- /* print-quality-default */
- ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "print-quality-default", IPP_QUALITY_NORMAL);
-
- /* print-quality-supported */
- ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "print-quality-supported", (int)(sizeof(print_quality_supported) / sizeof(print_quality_supported[0])), print_quality_supported);
-
- /* print-rendering-intent-default */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-rendering-intent-default", NULL, "auto");
-
- /* print-rendering-intent-supported */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-rendering-intent-supported", NULL, "auto");
-
- /* printer-device-id */
- snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;", make, model);
- ptr = device_id + strlen(device_id);
- prefix = "CMD:";
- for (format = (const char *)cupsArrayFirst(docformats); format; format = (const char *)cupsArrayNext(docformats))
- {
- if (!strcasecmp(format, "application/pdf"))
- snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPDF", prefix);
- else if (!strcasecmp(format, "application/postscript"))
- snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPS", prefix);
- else if (!strcasecmp(format, "application/vnd.hp-PCL"))
- snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPCL", prefix);
- else if (!strcasecmp(format, "image/jpeg"))
- snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sJPEG", prefix);
- else if (!strcasecmp(format, "image/png"))
- snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPNG", prefix);
- else if (!strcasecmp(format, "image/pwg-raster"))
- snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPWG", prefix);
- else if (!strcasecmp(format, "image/urf"))
- snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sURF", prefix);
- else
- continue;
-
- ptr += strlen(ptr);
- prefix = ",";
- }
- if (ptr < (device_id + sizeof(device_id) - 1))
- {
- *ptr++ = ';';
- *ptr = '\0';
- }
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-device-id", NULL, device_id);
-
- /* printer-input-tray */
- if (ppm_color > 0)
- {
- attr = ippAddOctetString(attrs, IPP_TAG_PRINTER, "printer-input-tray", printer_input_tray_color[0], strlen(printer_input_tray_color[0]));
- for (i = 1; i < (int)(sizeof(printer_input_tray_color) / sizeof(printer_input_tray_color[0])); i ++)
- ippSetOctetString(attrs, &attr, i, printer_input_tray_color[i], strlen(printer_input_tray_color[i]));
- }
- else
- {
- attr = ippAddOctetString(attrs, IPP_TAG_PRINTER, "printer-input-tray", printer_input_tray[0], strlen(printer_input_tray[0]));
- for (i = 1; i < (int)(sizeof(printer_input_tray) / sizeof(printer_input_tray[0])); i ++)
- ippSetOctetString(attrs, &attr, i, printer_input_tray[i], strlen(printer_input_tray[i]));
- }
-
- /* printer-make-and-model */
- snprintf(make_model, sizeof(make_model), "%s %s", make, model);
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-make-and-model", NULL, make_model);
-
- /* printer-resolution-default */
- ippAddResolution(attrs, IPP_TAG_PRINTER, "printer-resolution-default", IPP_RES_PER_INCH, 600, 600);
-
- /* printer-resolution-supported */
- ippAddResolution(attrs, IPP_TAG_PRINTER, "printer-resolution-supported", IPP_RES_PER_INCH, 600, 600);
-
- /* printer-supply and printer-supply-description */
- if (ppm_color > 0)
- {
- attr = ippAddOctetString(attrs, IPP_TAG_PRINTER, "printer-supply", printer_supply_color[0], strlen(printer_supply_color[0]));
- for (i = 1; i < (int)(sizeof(printer_supply_color) / sizeof(printer_supply_color[0])); i ++)
- ippSetOctetString(attrs, &attr, i, printer_supply_color[i], strlen(printer_supply_color[i]));
-
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-supply-description", (int)(sizeof(printer_supply_description_color) / sizeof(printer_supply_description_color[0])), NULL, printer_supply_description_color);
- }
- else
- {
- attr = ippAddOctetString(attrs, IPP_TAG_PRINTER, "printer-supply", printer_supply[0], strlen(printer_supply[0]));
- for (i = 1; i < (int)(sizeof(printer_supply) / sizeof(printer_supply[0])); i ++)
- ippSetOctetString(attrs, &attr, i, printer_supply[i], strlen(printer_supply[i]));
-
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-supply-description", (int)(sizeof(printer_supply_description) / sizeof(printer_supply_description[0])), NULL, printer_supply_description);
- }
-
- /* pwg-raster-document-xxx-supported */
- if (cupsArrayFind(docformats, (void *)"image/pwg-raster"))
- {
- ippAddResolutions(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 (ppm_color > 0 && duplex)
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pwg-raster-document-sheet-back", NULL, "rotated");
- else if (duplex)
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pwg-raster-document-sheet-back", NULL, "normal");
-
- if (ppm_color > 0)
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pwg-raster-document-type-supported", (int)(sizeof(pwg_raster_document_type_supported_color) / sizeof(pwg_raster_document_type_supported_color[0])), NULL, pwg_raster_document_type_supported_color);
- else
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(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);
- }
-
- /* sides-default */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-default", NULL, "one-sided");
-
- /* sides-supported */
- if (duplex)
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-supported", (int)(sizeof(sides_supported) / sizeof(sides_supported[0])), NULL, sides_supported);
- else
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-supported", NULL, "one-sided");
-
- /* urf-supported */
- if (cupsArrayFind(docformats, (void *)"image/urf"))
- {
- if (ppm_color > 0)
- {
- if (duplex)
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "urf-supported", (int)(sizeof(urf_supported_color_duplex) / sizeof(urf_supported_color_duplex[0])), NULL, urf_supported_color_duplex);
- else
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "urf-supported", (int)(sizeof(urf_supported_color) / sizeof(urf_supported_color[0])), NULL, urf_supported_color);
- }
- else if (duplex)
- {
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "urf-supported", (int)(sizeof(urf_supported_duplex) / sizeof(urf_supported_duplex[0])), NULL, urf_supported_duplex);
- }
- else
- {
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "urf-supported", (int)(sizeof(urf_supported) / sizeof(urf_supported[0])), NULL, urf_supported);
- }
- }
-
- return (attrs);
-}
-
-
-#if !CUPS_LITE
-/*
- * 'load_ppd_attributes()' - Load IPP attributes from a PPD file.
- */
-
-static ipp_t * /* O - IPP attributes or `NULL` on error */
-load_ppd_attributes(
- const char *ppdfile, /* I - PPD filename */
- cups_array_t *docformats) /* I - document-format-supported values */
-{
- int i, j; /* Looping vars */
- ipp_t *attrs; /* Attributes */
- ipp_attribute_t *attr; /* Current attribute */
- ipp_t *col; /* Current collection value */
- ppd_file_t *ppd; /* PPD data */
- ppd_attr_t *ppd_attr; /* PPD attribute */
- ppd_choice_t *ppd_choice; /* PPD choice */
- ppd_size_t *ppd_size; /* Default PPD size */
- pwg_size_t *pwg_size, /* Current PWG size */
- *default_size = NULL; /* Default PWG size */
- const char *default_source = NULL, /* Default media source */
- *default_type = NULL; /* Default media type */
- pwg_map_t *pwg_map; /* Mapping from PWG to PPD keywords */
- _ppd_cache_t *pc; /* PPD cache */
- _pwg_finishings_t *finishings; /* Current finishings value */
- const char *template; /* Current finishings-template value */
- int num_margins; /* Number of media-xxx-margin-supported values */
- int margins[10]; /* media-xxx-margin-supported values */
- int xres, /* Default horizontal resolution */
- yres; /* Default vertical resolution */
- int num_urf; /* Number of urf-supported values */
- const char *urf[10]; /* urf-supported values */
- char urf_rs[32]; /* RS value */
- static const int orientation_requested_supported[4] =
- { /* orientation-requested-supported values */
- IPP_ORIENT_PORTRAIT,
- IPP_ORIENT_LANDSCAPE,
- IPP_ORIENT_REVERSE_LANDSCAPE,
- IPP_ORIENT_REVERSE_PORTRAIT
- };
- static const char * const overrides_supported[] =
- { /* overrides-supported */
- "document-numbers",
- "media",
- "media-col",
- "orientation-requested",
- "pages"
- };
- static const char * const print_color_mode_supported[] =
- { /* print-color-mode-supported values */
- "monochrome"
- };
- static const char * const print_color_mode_supported_color[] =
- { /* 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 char * const printer_supply[] =
- { /* printer-supply values */
- "index=1;class=receptacleThatIsFilled;type=wasteToner;unit=percent;"
- "maxcapacity=100;level=25;colorantname=unknown;",
- "index=2;class=supplyThatIsConsumed;type=toner;unit=percent;"
- "maxcapacity=100;level=75;colorantname=black;"
- };
- static const char * const printer_supply_color[] =
- { /* printer-supply values */
- "index=1;class=receptacleThatIsFilled;type=wasteInk;unit=percent;"
- "maxcapacity=100;level=25;colorantname=unknown;",
- "index=2;class=supplyThatIsConsumed;type=ink;unit=percent;"
- "maxcapacity=100;level=75;colorantname=black;",
- "index=3;class=supplyThatIsConsumed;type=ink;unit=percent;"
- "maxcapacity=100;level=50;colorantname=cyan;",
- "index=4;class=supplyThatIsConsumed;type=ink;unit=percent;"
- "maxcapacity=100;level=33;colorantname=magenta;",
- "index=5;class=supplyThatIsConsumed;type=ink;unit=percent;"
- "maxcapacity=100;level=67;colorantname=yellow;"
- };
- static const char * const printer_supply_description[] =
- { /* printer-supply-description values */
- "Toner Waste Tank",
- "Black Toner"
- };
- static const char * const printer_supply_description_color[] =
- { /* printer-supply-description values */
- "Ink Waste Tank",
- "Black Ink",
- "Cyan Ink",
- "Magenta Ink",
- "Yellow Ink"
- };
- static const char * const pwg_raster_document_type_supported[] =
- {
- "black_1",
- "sgray_8"
- };
- static const char * const pwg_raster_document_type_supported_color[] =
- {
- "black_1",
- "sgray_8",
- "srgb_8",
- "srgb_16"
- };
- static const char * const sides_supported[] =
- { /* sides-supported values */
- "one-sided",
- "two-sided-long-edge",
- "two-sided-short-edge"
- };
-
-
- /*
- * Open the PPD file...
- */
-
- if ((ppd = ppdOpenFile(ppdfile)) == NULL)
- {
- ppd_status_t status; /* Load error */
-
- status = ppdLastError(&i);
- _cupsLangPrintf(stderr, _("ippeveprinter: Unable to open \"%s\": %s on line %d."), ppdfile, ppdErrorString(status), i);
- return (NULL);
- }
-
- ppdMarkDefaults(ppd);
-
- pc = _ppdCacheCreateWithPPD(ppd);
-
- if ((ppd_size = ppdPageSize(ppd, NULL)) != NULL)
- {
- /*
- * Look up default size...
- */
-
- for (i = 0, pwg_size = pc->sizes; i < pc->num_sizes; i ++, pwg_size ++)
- {
- if (!strcmp(pwg_size->map.ppd, ppd_size->name))
- {
- default_size = pwg_size;
- break;
- }
- }
- }
-
- if (!default_size)
- {
- /*
- * Default to A4 or Letter...
- */
-
- for (i = 0, pwg_size = pc->sizes; i < pc->num_sizes; i ++, pwg_size ++)
- {
- if (!strcmp(pwg_size->map.ppd, "Letter") || !strcmp(pwg_size->map.ppd, "A4"))
- {
- default_size = pwg_size;
- break;
- }
- }
-
- if (!default_size)
- default_size = pc->sizes; /* Last resort: first size */
- }
-
- if ((ppd_choice = ppdFindMarkedChoice(ppd, "InputSlot")) != NULL)
- default_source = _ppdCacheGetSource(pc, ppd_choice->choice);
-
- if ((ppd_choice = ppdFindMarkedChoice(ppd, "MediaType")) != NULL)
- default_source = _ppdCacheGetType(pc, ppd_choice->choice);
-
- if ((ppd_attr = ppdFindAttr(ppd, "DefaultResolution", NULL)) != NULL)
- {
- /*
- * Use the PPD-defined default resolution...
- */
-
- if ((i = sscanf(ppd_attr->value, "%dx%d", &xres, &yres)) == 1)
- yres = xres;
- else if (i < 0)
- xres = yres = 300;
- }
- else
- {
- /*
- * Use default of 300dpi...
- */
-
- xres = yres = 300;
- }
-
- snprintf(urf_rs, sizeof(urf_rs), "RS%d", yres < xres ? yres : xres);
-
- num_urf = 0;
- urf[num_urf ++] = "V1.4";
- urf[num_urf ++] = "CP1";
- urf[num_urf ++] = urf_rs;
- urf[num_urf ++] = "W8";
- if (pc->sides_2sided_long)
- urf[num_urf ++] = "DM1";
- if (ppd->color_device)
- urf[num_urf ++] = "SRGB24";
-
- /*
- * PostScript printers accept PDF via one of the CUPS PDF to PostScript
- * filters, along with PostScript (of course) and JPEG...
- */
-
- cupsArrayAdd(docformats, "application/pdf");
- cupsArrayAdd(docformats, "application/postscript");
- cupsArrayAdd(docformats, "image/jpeg");
-
- /*
- * Create the attributes...
- */
-
- attrs = ippNew();
-
- /* color-supported */
- ippAddBoolean(attrs, IPP_TAG_PRINTER, "color-supported", (char)ppd->color_device);
-
- /* copies-default */
- ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default", 1);
-
- /* copies-supported */
- ippAddRange(attrs, IPP_TAG_PRINTER, "copies-supported", 1, 999);
-
- /* document-password-supported */
- ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "document-password-supported", 127);
-
- /* finishing-template-supported */
- attr = ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "finishing-template-supported", cupsArrayCount(pc->templates) + 1, NULL, NULL);
- ippSetString(attrs, &attr, 0, "none");
- for (i = 1, template = (const char *)cupsArrayFirst(pc->templates); template; i ++, template = (const char *)cupsArrayNext(pc->templates))
- ippSetString(attrs, &attr, i, template);
-
- /* finishings-col-database */
- attr = ippAddCollections(attrs, IPP_TAG_PRINTER, "finishings-col-database", cupsArrayCount(pc->templates) + 1, NULL);
-
- col = ippNew();
- ippAddString(col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "finishing-template", NULL, "none");
- ippSetCollection(attrs, &attr, 0, col);
- ippDelete(col);
-
- for (i = 1, template = (const char *)cupsArrayFirst(pc->templates); template; i ++, template = (const char *)cupsArrayNext(pc->templates))
- {
- col = ippNew();
- ippAddString(col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "finishing-template", NULL, template);
- ippSetCollection(attrs, &attr, i, col);
- ippDelete(col);
- }
-
- /* finishings-col-default */
- col = ippNew();
- ippAddString(col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "finishing-template", NULL, "none");
- ippAddCollection(attrs, IPP_TAG_PRINTER, "finishings-col-default", col);
- ippDelete(col);
-
- /* finishings-col-ready */
- attr = ippAddCollections(attrs, IPP_TAG_PRINTER, "finishings-col-ready", cupsArrayCount(pc->templates) + 1, NULL);
-
- col = ippNew();
- ippAddString(col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "finishing-template", NULL, "none");
- ippSetCollection(attrs, &attr, 0, col);
- ippDelete(col);
-
- for (i = 1, template = (const char *)cupsArrayFirst(pc->templates); template; i ++, template = (const char *)cupsArrayNext(pc->templates))
- {
- col = ippNew();
- ippAddString(col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "finishing-template", NULL, template);
- ippSetCollection(attrs, &attr, i, col);
- ippDelete(col);
- }
-
- /* finishings-col-supported */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "finishings-col-supported", NULL, "finishing-template");
-
- /* finishings-default */
- ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "finishings-default", IPP_FINISHINGS_NONE);
-
- /* finishings-ready */
- attr = ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "finishings-ready", cupsArrayCount(pc->finishings) + 1, NULL);
- ippSetInteger(attrs, &attr, 0, IPP_FINISHINGS_NONE);
- for (i = 1, finishings = (_pwg_finishings_t *)cupsArrayFirst(pc->finishings); finishings; i ++, finishings = (_pwg_finishings_t *)cupsArrayNext(pc->finishings))
- ippSetInteger(attrs, &attr, i, finishings->value);
-
- /* finishings-supported */
- attr = ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "finishings-supported", cupsArrayCount(pc->finishings) + 1, NULL);
- ippSetInteger(attrs, &attr, 0, IPP_FINISHINGS_NONE);
- for (i = 1, finishings = (_pwg_finishings_t *)cupsArrayFirst(pc->finishings); finishings; i ++, finishings = (_pwg_finishings_t *)cupsArrayNext(pc->finishings))
- ippSetInteger(attrs, &attr, i, finishings->value);
-
- /* media-bottom-margin-supported */
- for (i = 0, num_margins = 0, pwg_size = pc->sizes; i < pc->num_sizes && num_margins < (int)(sizeof(margins) / sizeof(margins[0])); i ++, pwg_size ++)
- {
- for (j = 0; j < num_margins; j ++)
- {
- if (margins[j] == pwg_size->bottom)
- break;
- }
-
- if (j >= num_margins)
- margins[num_margins ++] = pwg_size->bottom;
- }
-
- for (i = 0; i < (num_margins - 1); i ++)
- {
- for (j = i + 1; j < num_margins; j ++)
- {
- if (margins[i] > margins[j])
- {
- int mtemp = margins[i];
-
- margins[i] = margins[j];
- margins[j] = mtemp;
- }
- }
- }
-
- ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-bottom-margin-supported", num_margins, margins);
-
- /* media-col-database */
- attr = ippAddCollections(attrs, IPP_TAG_PRINTER, "media-col-database", pc->num_sizes, NULL);
- for (i = 0, pwg_size = pc->sizes; i < pc->num_sizes; i ++, pwg_size ++)
- {
- col = create_media_col(pwg_size->map.pwg, NULL, NULL, pwg_size->width, pwg_size->length, pwg_size->bottom, pwg_size->left, pwg_size->right, pwg_size->top);
- ippSetCollection(attrs, &attr, i, col);
- ippDelete(col);
- }
-
- /* media-col-default */
- col = create_media_col(default_size->map.pwg, default_source, default_type, default_size->width, default_size->length, default_size->bottom, default_size->left, default_size->right, default_size->top);
- ippAddCollection(attrs, IPP_TAG_PRINTER, "media-col-default", col);
- ippDelete(col);
-
- /* media-col-ready */
- col = create_media_col(default_size->map.pwg, default_source, default_type, default_size->width, default_size->length, default_size->bottom, default_size->left, default_size->right, default_size->top);
- ippAddCollection(attrs, IPP_TAG_PRINTER, "media-col-ready", col);
- ippDelete(col);
-
- /* media-default */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default", NULL, default_size->map.pwg);
-
- /* media-left-margin-supported */
- for (i = 0, num_margins = 0, pwg_size = pc->sizes; i < pc->num_sizes && num_margins < (int)(sizeof(margins) / sizeof(margins[0])); i ++, pwg_size ++)
- {
- for (j = 0; j < num_margins; j ++)
- {
- if (margins[j] == pwg_size->left)
- break;
- }
-
- if (j >= num_margins)
- margins[num_margins ++] = pwg_size->left;
- }
-
- for (i = 0; i < (num_margins - 1); i ++)
- {
- for (j = i + 1; j < num_margins; j ++)
- {
- if (margins[i] > margins[j])
- {
- int mtemp = margins[i];
-
- margins[i] = margins[j];
- margins[j] = mtemp;
- }
- }
- }
-
- ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-left-margin-supported", num_margins, margins);
-
- /* media-ready */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-ready", NULL, default_size->map.pwg);
-
- /* media-right-margin-supported */
- for (i = 0, num_margins = 0, pwg_size = pc->sizes; i < pc->num_sizes && num_margins < (int)(sizeof(margins) / sizeof(margins[0])); i ++, pwg_size ++)
- {
- for (j = 0; j < num_margins; j ++)
- {
- if (margins[j] == pwg_size->right)
- break;
- }
-
- if (j >= num_margins)
- margins[num_margins ++] = pwg_size->right;
- }
-
- for (i = 0; i < (num_margins - 1); i ++)
- {
- for (j = i + 1; j < num_margins; j ++)
- {
- if (margins[i] > margins[j])
- {
- int mtemp = margins[i];
-
- margins[i] = margins[j];
- margins[j] = mtemp;
- }
- }
- }
-
- ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-right-margin-supported", num_margins, margins);
-
- /* media-supported */
- attr = ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-supported", pc->num_sizes, NULL, NULL);
- for (i = 0, pwg_size = pc->sizes; i < pc->num_sizes; i ++, pwg_size ++)
- ippSetString(attrs, &attr, i, pwg_size->map.pwg);
-
- /* media-size-supported */
- attr = ippAddCollections(attrs, IPP_TAG_PRINTER, "media-size-supported", pc->num_sizes, NULL);
- for (i = 0, pwg_size = pc->sizes; i < pc->num_sizes; i ++, pwg_size ++)
- {
- col = create_media_size(pwg_size->width, pwg_size->length);
- ippSetCollection(attrs, &attr, i, col);
- ippDelete(col);
- }
-
- /* media-source-supported */
- if (pc->num_sources > 0)
- {
- attr = ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-source-supported", pc->num_sources, NULL, NULL);
- for (i = 0, pwg_map = pc->sources; i < pc->num_sources; i ++, pwg_map ++)
- ippSetString(attrs, &attr, i, pwg_map->pwg);
- }
- else
- {
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-source-supported", NULL, "auto");
- }
-
- /* media-top-margin-supported */
- for (i = 0, num_margins = 0, pwg_size = pc->sizes; i < pc->num_sizes && num_margins < (int)(sizeof(margins) / sizeof(margins[0])); i ++, pwg_size ++)
- {
- for (j = 0; j < num_margins; j ++)
- {
- if (margins[j] == pwg_size->top)
- break;
- }
-
- if (j >= num_margins)
- margins[num_margins ++] = pwg_size->top;
- }
-
- for (i = 0; i < (num_margins - 1); i ++)
- {
- for (j = i + 1; j < num_margins; j ++)
- {
- if (margins[i] > margins[j])
- {
- int mtemp = margins[i];
-
- margins[i] = margins[j];
- margins[j] = mtemp;
- }
- }
- }
-
- ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-top-margin-supported", num_margins, margins);
-
- /* media-type-supported */
- if (pc->num_types > 0)
- {
- attr = ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-type-supported", pc->num_types, NULL, NULL);
- for (i = 0, pwg_map = pc->types; i < pc->num_types; i ++, pwg_map ++)
- ippSetString(attrs, &attr, i, pwg_map->pwg);
- }
- else
- {
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-type-supported", NULL, "auto");
- }
-
- /* orientation-requested-default */
- ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "orientation-requested-default", IPP_ORIENT_PORTRAIT);
-
- /* orientation-requested-supported */
- ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "orientation-requested-supported", (int)(sizeof(orientation_requested_supported) / sizeof(orientation_requested_supported[0])), orientation_requested_supported);
-
- /* output-bin-default */
- if (pc->num_bins > 0)
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "output-bin-default", NULL, pc->bins->pwg);
- else
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "output-bin-default", NULL, "face-down");
-
- /* output-bin-supported */
- if (pc->num_bins > 0)
- {
- attr = ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "output-bin-supported", pc->num_bins, NULL, NULL);
- for (i = 0, pwg_map = pc->bins; i < pc->num_bins; i ++, pwg_map ++)
- ippSetString(attrs, &attr, i, pwg_map->pwg);
- }
- else
- {
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "output-bin-supported", NULL, "face-down");
- }
-
- /* overrides-supported */
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "overrides-supported", (int)(sizeof(overrides_supported) / sizeof(overrides_supported[0])), NULL, overrides_supported);
-
- /* page-ranges-supported */
- ippAddBoolean(attrs, IPP_TAG_PRINTER, "page-ranges-supported", 1);
-
- /* pages-per-minute */
- ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "pages-per-minute", ppd->throughput);
-
- /* pages-per-minute-color */
- if (ppd->color_device)
- ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "pages-per-minute-color", ppd->throughput);
-
- /* print-color-mode-default */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-color-mode-default", NULL, ppd->color_device ? "auto" : "monochrome");
-
- /* print-color-mode-supported */
- if (ppd->color_device)
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-color-mode-supported", (int)(sizeof(print_color_mode_supported_color) / sizeof(print_color_mode_supported_color[0])), NULL, print_color_mode_supported_color);
- else
- ippAddStrings(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 */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-content-optimize-default", NULL, "auto");
-
- /* print-content-optimize-supported */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-content-optimize-supported", NULL, "auto");
-
- /* print-quality-default */
- ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "print-quality-default", IPP_QUALITY_NORMAL);
-
- /* print-quality-supported */
- ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "print-quality-supported", (int)(sizeof(print_quality_supported) / sizeof(print_quality_supported[0])), print_quality_supported);
-
- /* print-rendering-intent-default */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-rendering-intent-default", NULL, "auto");
-
- /* print-rendering-intent-supported */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-rendering-intent-supported", NULL, "auto");
-
- /* printer-device-id */
- if ((ppd_attr = ppdFindAttr(ppd, "1284DeviceId", NULL)) != NULL)
- {
- /*
- * Use the device ID string from the PPD...
- */
-
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-device-id", NULL, ppd_attr->value);
- }
- else
- {
- /*
- * Synthesize a device ID string...
- */
-
- char device_id[1024]; /* Device ID string */
-
- snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;CMD:PS;", ppd->manufacturer, ppd->modelname);
-
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-device-id", NULL, device_id);
- }
-
- /* printer-input-tray */
- if (pc->num_sources > 0)
- {
- for (i = 0, attr = NULL; i < pc->num_sources; i ++)
- {
- char input_tray[1024]; /* printer-input-tray value */
-
- if (!strcmp(pc->sources[i].pwg, "manual") || strstr(pc->sources[i].pwg, "-man") != NULL)
- snprintf(input_tray, sizeof(input_tray), "type=sheetFeedManual;mediafeed=0;mediaxfeed=0;maxcapacity=1;level=-2;status=0;name=%s", pc->sources[i].pwg);
- else
- snprintf(input_tray, sizeof(input_tray), "type=sheetFeedAutoRemovableTray;mediafeed=0;mediaxfeed=0;maxcapacity=250;level=125;status=0;name=%s", pc->sources[i].pwg);
-
- if (attr)
- ippSetOctetString(attrs, &attr, i, input_tray, (int)strlen(input_tray));
- else
- attr = ippAddOctetString(attrs, IPP_TAG_PRINTER, "printer-input-tray", input_tray, (int)strlen(input_tray));
- }
- }
- else
- {
- static const char *printer_input_tray = "type=sheetFeedAutoRemovableTray;mediafeed=0;mediaxfeed=0;maxcapacity=-2;level=-2;status=0;name=auto";
-
- ippAddOctetString(attrs, IPP_TAG_PRINTER, "printer-input-tray", printer_input_tray, (int)strlen(printer_input_tray));
- }
-
- /* printer-make-and-model */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-make-and-model", NULL, ppd->nickname);
-
- /* printer-resolution-default */
- ippAddResolution(attrs, IPP_TAG_PRINTER, "printer-resolution-default", IPP_RES_PER_INCH, xres, yres);
-
- /* printer-resolution-supported */
- ippAddResolution(attrs, IPP_TAG_PRINTER, "printer-resolution-supported", IPP_RES_PER_INCH, xres, yres);
-
- /* printer-supply and printer-supply-description */
- if (ppd->color_device)
- {
- attr = ippAddOctetString(attrs, IPP_TAG_PRINTER, "printer-supply", printer_supply_color[0], strlen(printer_supply_color[0]));
- for (i = 1; i < (int)(sizeof(printer_supply_color) / sizeof(printer_supply_color[0])); i ++)
- ippSetOctetString(attrs, &attr, i, printer_supply_color[i], strlen(printer_supply_color[i]));
-
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-supply-description", (int)(sizeof(printer_supply_description_color) / sizeof(printer_supply_description_color[0])), NULL, printer_supply_description_color);
- }
- else
- {
- attr = ippAddOctetString(attrs, IPP_TAG_PRINTER, "printer-supply", printer_supply[0], strlen(printer_supply[0]));
- for (i = 1; i < (int)(sizeof(printer_supply) / sizeof(printer_supply[0])); i ++)
- ippSetOctetString(attrs, &attr, i, printer_supply[i], strlen(printer_supply[i]));
-
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-supply-description", (int)(sizeof(printer_supply_description) / sizeof(printer_supply_description[0])), NULL, printer_supply_description);
- }
-
- /* pwg-raster-document-xxx-supported */
- if (cupsArrayFind(docformats, (void *)"image/pwg-raster"))
- {
- ippAddResolution(attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", IPP_RES_PER_INCH, xres, yres);
-
- if (pc->sides_2sided_long)
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pwg-raster-document-sheet-back", NULL, "normal");
-
- if (ppd->color_device)
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pwg-raster-document-type-supported", (int)(sizeof(pwg_raster_document_type_supported_color) / sizeof(pwg_raster_document_type_supported_color[0])), NULL, pwg_raster_document_type_supported_color);
- else
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(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);
- }
-
- /* sides-default */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-default", NULL, "one-sided");
-
- /* sides-supported */
- if (pc->sides_2sided_long)
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-supported", (int)(sizeof(sides_supported) / sizeof(sides_supported[0])), NULL, sides_supported);
- else
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-supported", NULL, "one-sided");
-
- /* urf-supported */
- if (cupsArrayFind(docformats, (void *)"image/urf"))
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "urf-supported", num_urf, NULL, urf);
-
- /*
- * Free the PPD file and return the attributes...
- */
-
- _ppdCacheDestroy(pc);
-
- ppdClose(ppd);
-
- return (attrs);
-}
-#endif /* !CUPS_LITE */
-
-
-/*
- * '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(ippeve_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(
- ippeve_job_t *job, /* I - Job */
- char *message) /* I - Message */
-{
- int i, /* Looping var */
- num_options = 0; /* Number of name=value pairs */
- cups_option_t *options = NULL, /* name=value pairs from message */
- *option; /* Current option */
- ipp_attribute_t *attr; /* Current attribute */
-
-
- /*
- * Grab attributes from the message line...
- */
-
- num_options = cupsParseOptions(message + 5, num_options, &options);
-
- /*
- * Loop through the options and record them in the printer or job objects...
- */
-
- for (i = num_options, option = options; i > 0; i --, option ++)
- {
- if (!strcmp(option->name, "job-impressions"))
- {
- /*
- * Update job-impressions attribute...
- */
-
- job->impressions = atoi(option->value);
- }
- else if (!strcmp(option->name, "job-impressions-completed"))
- {
- /*
- * Update job-impressions-completed attribute...
- */
-
- job->impcompleted = atoi(option->value);
- }
- else if (!strncmp(option->name, "marker-", 7) || !strcmp(option->name, "printer-alert") || !strcmp(option->name, "printer-alert-description") || !strcmp(option->name, "printer-supply") || !strcmp(option->name, "printer-supply-description"))
- {
- /*
- * Update Printer Status attribute...
- */
-
- _cupsRWLockWrite(&job->printer->rwlock);
-
- if ((attr = ippFindAttribute(job->printer->attrs, option->name, IPP_TAG_ZERO)) != NULL)
- ippDeleteAttribute(job->printer->attrs, attr);
-
- cupsEncodeOption(job->printer->attrs, IPP_TAG_PRINTER, option->name, option->value);
-
- _cupsRWUnlock(&job->printer->rwlock);
- }
- else
- {
- /*
- * Something else that isn't currently supported...
- */
-
- fprintf(stderr, "[Job %d] Ignoring update of attribute \"%s\" with value \"%s\".\n", job->id, option->name, option->value);
- }
- }
-
- cupsFreeOptions(num_options, options);
-}
-
-
-/*
- * 'process_client()' - Process client requests on a thread.
- */
-
-static void * /* O - Exit status */
-process_client(ippeve_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(ippeve_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 */
- 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...
- */
-
- 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.
- */
-
- if (client->printer->icon)
- {
- 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
- {
- fputs("Icon file is internal printer.png.\n", stderr);
-
- if (!respond_http(client, HTTP_STATUS_OK, NULL, "image/png", sizeof(printer_png)))
- return (0);
-
- httpWrite2(client->http, (const char *)printer_png, sizeof(printer_png));
- httpFlushWrite(client->http);
- }
- }
- else if (!strcmp(client->uri, "/"))
- {
- /*
- * Show web status page...
- */
-
- return (show_status(client));
- }
- else if (!strcmp(client->uri, "/media"))
- {
- /*
- * Show web media page...
- */
-
- return (show_media(client));
- }
- else if (!strcmp(client->uri, "/supplies"))
- {
- /*
- * Show web supplies page...
- */
-
- return (show_supplies(client));
- }
- 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(ippeve_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 ((major * 10 + minor) > MaxVersion)
- {
- if (httpGetState(client->http) != HTTP_STATE_POST_SEND)
- httpFlush(client->http); /* Flush trailing (junk) data */
-
- respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
- return (0);
- }
- 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(ippeve_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 & IPPEVE_PREASON_MEDIA_EMPTY)
- {
- job->printer->state_reasons |= IPPEVE_PREASON_MEDIA_NEEDED;
-
- sleep(1);
- }
-
- job->printer->state_reasons &= (ippeve_preason_t)~IPPEVE_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 */
- struct timeval start, /* Start time */
- end; /* End time */
- char *myargv[3], /* Command-line arguments */
- *myenvp[400]; /* 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 mystdout = -1; /* File for stdout */
- 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, "[Job %d] Running command \"%s %s\".\n", job->id, job->printer->command, job->filename);
- gettimeofday(&start, NULL);
-
- /*
- * Setup the command-line arguments...
- */
-
- myargv[0] = job->printer->command;
- myargv[1] = job->filename;
- myargv[2] = NULL;
-
- /*
- * Copy the current environment, then add environment variables for every
- * Job attribute and Printer -default attributes...
- */
-
- for (myenvc = 0; environ[myenvc] && myenvc < (int)(sizeof(myenvp) / sizeof(myenvp[0]) - 1); myenvc ++)
- myenvp[myenvc] = strdup(environ[myenvc]);
-
- if (myenvc > (int)(sizeof(myenvp) / sizeof(myenvp[0]) - 32))
- {
- fprintf(stderr, "[Job %d] Too many environment variables to process job.\n", job->id);
- job->state = IPP_JSTATE_ABORTED;
- goto error;
- }
-
- if (asprintf(myenvp + myenvc, "CONTENT_TYPE=%s", job->format) > 0)
- myenvc ++;
-
- if (job->printer->device_uri && asprintf(myenvp + myenvc, "DEVICE_URI=%s", job->printer->device_uri) > 0)
- myenvc ++;
-
-#if !CUPS_LITE
- if (job->printer->ppdfile && asprintf(myenvp + myenvc, "PPD=%s", job->printer->ppdfile) > 0)
- myenvc ++;
-#endif /* !CUPS_LITE */
-
- for (attr = ippFirstAttribute(job->printer->attrs); attr && myenvc < (int)(sizeof(myenvp) / sizeof(myenvp[0]) - 1); attr = ippNextAttribute(job->printer->attrs))
- {
- /*
- * Convert "attribute-name-default" to "IPP_ATTRIBUTE_NAME_DEFAULT=" and
- * then add the value(s) from the attribute.
- */
-
- const char *name = ippGetName(attr),
- /* Attribute name */
- *suffix = strstr(name, "-default");
- /* Suffix on attribute name */
-
- if (!suffix || suffix[8])
- 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);
- }
-
- 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);
- /* Attribute name */
-
- 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);
- }
-
- if (attr)
- {
- fprintf(stderr, "[Job %d] Too many environment variables to process job.\n", job->id);
- job->state = IPP_JSTATE_ABORTED;
- goto error;
- }
-
- myenvp[myenvc] = NULL;
-
- /*
- * Now run the program...
- */
-
-#ifdef _WIN32
- status = _spawnvpe(_P_WAIT, job->printer->command, myargv, myenvp);
-
-#else
- if (job->printer->device_uri)
- {
- char scheme[32], /* URI scheme */
- userpass[256], /* username:password (unused) */
- host[256], /* Hostname or IP address */
- resource[256]; /* Resource path */
- int port; /* Port number */
-
-
- if (httpSeparateURI(HTTP_URI_CODING_ALL, job->printer->device_uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
- {
- fprintf(stderr, "[Job %d] Bad device URI \"%s\".\n", job->id, job->printer->device_uri);
- }
- else if (!strcmp(scheme, "file"))
- {
- struct stat fileinfo; /* See if this is a file or directory... */
-
- if (stat(resource, &fileinfo))
- {
- if (errno == ENOENT)
- {
- if ((mystdout = open(resource, O_WRONLY | O_CREAT | O_TRUNC, 0666)) >= 0)
- fprintf(stderr, "[Job %d] Saving print command output to \"%s\".\n", job->id, resource);
- else
- fprintf(stderr, "[Job %d] Unable to create \"%s\": %s\n", job->id, resource, strerror(errno));
- }
- else
- fprintf(stderr, "[Job %d] Unable to access \"%s\": %s\n", job->id, resource, strerror(errno));
- }
- else if (S_ISDIR(fileinfo.st_mode))
- {
- if ((mystdout = create_job_file(job, line, sizeof(line), resource, "prn")) >= 0)
- fprintf(stderr, "[Job %d] Saving print command output to \"%s\".\n", job->id, line);
- else
- fprintf(stderr, "[Job %d] Unable to create \"%s\": %s\n", job->id, line, strerror(errno));
- }
- else if (!S_ISREG(fileinfo.st_mode))
- {
- if ((mystdout = open(resource, O_WRONLY | O_CREAT | O_TRUNC, 0666)) >= 0)
- fprintf(stderr, "[Job %d] Saving print command output to \"%s\".\n", job->id, resource);
- else
- fprintf(stderr, "[Job %d] Unable to create \"%s\": %s\n", job->id, resource, strerror(errno));
- }
- else if ((mystdout = open(resource, O_WRONLY)) >= 0)
- fprintf(stderr, "[Job %d] Saving print command output to \"%s\".\n", job->id, resource);
- else
- fprintf(stderr, "[Job %d] Unable to open \"%s\": %s\n", job->id, resource, strerror(errno));
- }
- else if (!strcmp(scheme, "socket"))
- {
- http_addrlist_t *addrlist; /* List of addresses */
- char service[32]; /* Service number */
-
- snprintf(service, sizeof(service), "%d", port);
-
- if ((addrlist = httpAddrGetList(host, AF_UNSPEC, service)) == NULL)
- fprintf(stderr, "[Job %d] Unable to find \"%s\": %s\n", job->id, host, cupsLastErrorString());
- else if (!httpAddrConnect2(addrlist, &mystdout, 30000, &(job->cancel)))
- fprintf(stderr, "[Job %d] Unable to connect to \"%s\": %s\n", job->id, host, cupsLastErrorString());
-
- httpAddrFreeList(addrlist);
- }
- else
- {
- fprintf(stderr, "[Job %d] Unsupported device URI scheme \"%s\".\n", job->id, scheme);
- }
- }
- else if ((mystdout = create_job_file(job, line, sizeof(line), job->printer->directory, "prn")) >= 0)
- {
- fprintf(stderr, "[Job %d] Saving print command output to \"%s\".\n", job->id, line);
- }
-
- if (mystdout < 0)
- mystdout = open("/dev/null", O_WRONLY);
-
- if (pipe(mypipe))
- {
- fprintf(stderr, "[Job %d] Unable to create pipe for stderr: %s\n", job->id, strerror(errno));
- mypipe[0] = mypipe[1] = -1;
- }
-
- if ((pid = fork()) == 0)
- {
- /*
- * Child comes here...
- */
-
- close(1);
- dup2(mystdout, 1);
- close(mystdout);
-
- 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...
- */
-
- fprintf(stderr, "[Job %d] Unable to start job processing command: %s\n", job->id, strerror(errno));
- status = -1;
-
- close(mystdout);
- 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]);
-
- /*
- * Close the output file in the parent process...
- */
-
- close(mystdout);
-
- /*
- * 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)
- {
- int level = 3; /* Message log level */
-
- *ptr++ = '\0';
-
- if (!strncmp(line, "ATTR:", 5))
- {
- /*
- * Process job/printer attribute updates.
- */
-
- process_attr_message(job, line);
- }
- else if (!strncmp(line, "DEBUG:", 6))
- {
- /*
- * Debug message...
- */
-
- level = 2;
- }
- else if (!strncmp(line, "ERROR:", 6))
- {
- /*
- * Error message...
- */
-
- level = 0;
- job->message = strdup(line + 6);
- job->msglevel = 0;
- }
- else if (!strncmp(line, "INFO:", 5))
- {
- /*
- * Informational/progress message...
- */
-
- level = 1;
- if (job->msglevel)
- {
- job->message = strdup(line + 5);
- job->msglevel = 1;
- }
- }
- else if (!strncmp(line, "STATE:", 6))
- {
- /*
- * Process printer-state-reasons keywords.
- */
-
- process_state_message(job, line);
- }
-
- if (Verbosity >= level)
- fprintf(stderr, "[Job %d] Command - %s\n", job->id, 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, "[Job %d] Command \"%s\" exited with status %d.\n", job->id, job->printer->command, WEXITSTATUS(status));
-#ifndef _WIN32
- else
- fprintf(stderr, "[Job %d] Command \"%s\" terminated with signal %d.\n", job->id, job->printer->command, WTERMSIG(status));
-#endif /* !_WIN32 */
- job->state = IPP_JSTATE_ABORTED;
- }
- else if (status < 0)
- job->state = IPP_JSTATE_ABORTED;
- else
- fprintf(stderr, "[Job %d] Command \"%s\" completed successfully.\n", job->id, job->printer->command);
-
- /*
- * Report the total processing time...
- */
-
- gettimeofday(&end, NULL);
-
- fprintf(stderr, "[Job %d] Processing time was %.3f seconds.\n", job->id, end.tv_sec - start.tv_sec + 0.000001 * (end.tv_usec - start.tv_usec));
- }
- 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;
-
- error:
-
- 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(
- ippeve_job_t *job, /* I - Job */
- char *message) /* I - Message */
-{
- int i; /* Looping var */
- ippeve_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 8011.
- */
-
- 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 = IPPEVE_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(ippeve_preason_strings) / sizeof(ippeve_preason_strings[0])); i ++, bit *= 2)
- {
- if (!strcmp(message, ippeve_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(
- ippeve_printer_t *printer, /* I - Printer */
- const char *subtypes) /* I - Service subtype(s) */
-{
-#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
- ippeve_txt_t ipp_txt; /* Bonjour IPP TXT record */
- int i, /* Looping var */
- count; /* Number of values */
- ipp_attribute_t *color_supported,
- *document_format_supported,
- *printer_location,
- *printer_make_and_model,
- *printer_more_info,
- *printer_uuid,
- *sides_supported,
- *urf_supported; /* Printer attributes */
- const char *value; /* Value string */
- char formats[252], /* List of supported formats */
- urf[252], /* List of supported URF values */
- *ptr; /* Pointer into string */
-
- color_supported = ippFindAttribute(printer->attrs, "color-supported", IPP_TAG_BOOLEAN);
- document_format_supported = ippFindAttribute(printer->attrs, "document-format-supported", IPP_TAG_MIMETYPE);
- printer_location = ippFindAttribute(printer->attrs, "printer-location", IPP_TAG_TEXT);
- printer_make_and_model = ippFindAttribute(printer->attrs, "printer-make-and-model", IPP_TAG_TEXT);
- printer_more_info = ippFindAttribute(printer->attrs, "printer-more-info", IPP_TAG_URI);
- printer_uuid = ippFindAttribute(printer->attrs, "printer-uuid", IPP_TAG_URI);
- sides_supported = ippFindAttribute(printer->attrs, "sides-supported", IPP_TAG_KEYWORD);
- urf_supported = ippFindAttribute(printer->attrs, "urf-supported", IPP_TAG_KEYWORD);
-
- for (i = 0, count = ippGetCount(document_format_supported), ptr = formats; i < count; i ++)
- {
- value = ippGetString(document_format_supported, i, NULL);
-
- if (!strcasecmp(value, "application/octet-stream"))
- continue;
-
- if (ptr > formats && ptr < (formats + sizeof(formats) - 1))
- *ptr++ = ',';
-
- strlcpy(ptr, value, sizeof(formats) - (size_t)(ptr - formats));
- ptr += strlen(ptr);
-
- if (ptr >= (formats + sizeof(formats) - 1))
- break;
- }
-
- urf[0] = '\0';
- for (i = 0, count = ippGetCount(urf_supported), ptr = urf; i < count; i ++)
- {
- value = ippGetString(urf_supported, i, NULL);
-
- if (ptr > urf && ptr < (urf + sizeof(urf) - 1))
- *ptr++ = ',';
-
- strlcpy(ptr, value, sizeof(urf) - (size_t)(ptr - urf));
- ptr += strlen(ptr);
-
- if (ptr >= (urf + sizeof(urf) - 1))
- break;
- }
-
-#endif /* HAVE_DNSSD || HAVE_AVAHI */
-#ifdef HAVE_DNSSD
- DNSServiceErrorType error; /* Error from Bonjour */
- char regtype[256]; /* Bonjour service type */
-
-
- /*
- * Build the TXT record for IPP...
- */
-
- TXTRecordCreate(&ipp_txt, 1024, NULL);
- TXTRecordSetValue(&ipp_txt, "rp", 9, "ipp/print");
- if ((value = ippGetString(printer_make_and_model, 0, NULL)) != NULL)
- TXTRecordSetValue(&ipp_txt, "ty", (uint8_t)strlen(value), value);
- if ((value = ippGetString(printer_more_info, 0, NULL)) != NULL)
- TXTRecordSetValue(&ipp_txt, "adminurl", (uint8_t)strlen(value), value);
- if ((value = ippGetString(printer_location, 0, NULL)) != NULL)
- TXTRecordSetValue(&ipp_txt, "note", (uint8_t)strlen(value), value);
- TXTRecordSetValue(&ipp_txt, "pdl", (uint8_t)strlen(formats), formats);
- TXTRecordSetValue(&ipp_txt, "Color", 1, ippGetBoolean(color_supported, 0) ? "T" : "F");
- TXTRecordSetValue(&ipp_txt, "Duplex", 1, ippGetCount(sides_supported) > 1 ? "T" : "F");
- if ((value = ippGetString(printer_uuid, 0, NULL)) != NULL)
- TXTRecordSetValue(&ipp_txt, "UUID", (uint8_t)strlen(value) - 9, value + 9);
-# ifdef HAVE_SSL
- TXTRecordSetValue(&ipp_txt, "TLS", 3, "1.2");
-# endif /* HAVE_SSL */
- if (urf[0])
- TXTRecordSetValue(&ipp_txt, "URF", (uint8_t)strlen(urf), urf);
- 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)
- {
- _cupsLangPrintf(stderr, _("Unable to register \"%s.%s\": %d"), printer->dnssd_name, "_printer._tcp", 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 (subtypes && *subtypes)
- snprintf(regtype, sizeof(regtype), "_ipp._tcp,%s", subtypes);
- 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)
- {
- _cupsLangPrintf(stderr, _("Unable to register \"%s.%s\": %d"), 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 (subtypes && *subtypes)
- snprintf(regtype, sizeof(regtype), "_ipps._tcp,%s", subtypes);
- 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)
- {
- _cupsLangPrintf(stderr, _("Unable to register \"%s.%s\": %d"), 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)
- {
- _cupsLangPrintf(stderr, _("Unable to register \"%s.%s\": %d"), printer->dnssd_name, "_http._tcp,_printer", 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");
- if ((value = ippGetString(printer_make_and_model, 0, NULL)) != NULL)
- ipp_txt = avahi_string_list_add_printf(ipp_txt, "ty=%s", value);
- if ((value = ippGetString(printer_more_info, 0, NULL)) != NULL)
- ipp_txt = avahi_string_list_add_printf(ipp_txt, "adminurl=%s", value);
- if ((value = ippGetString(printer_location, 0, NULL)) != NULL)
- ipp_txt = avahi_string_list_add_printf(ipp_txt, "note=%s", value);
- ipp_txt = avahi_string_list_add_printf(ipp_txt, "pdl=%s", formats);
- ipp_txt = avahi_string_list_add_printf(ipp_txt, "Color=%s", ippGetBoolean(color_supported, 0) ? "T" : "F");
- ipp_txt = avahi_string_list_add_printf(ipp_txt, "Duplex=%s", ippGetCount(sides_supported) > 1 ? "T" : "F");
- if ((value = ippGetString(printer_uuid, 0, NULL)) != NULL)
- ipp_txt = avahi_string_list_add_printf(ipp_txt, "UUID=%s", value + 9);
-# ifdef HAVE_SSL
- ipp_txt = avahi_string_list_add_printf(ipp_txt, "TLS=1.2");
-# endif /* HAVE_SSL */
- if (urf[0])
- ipp_txt = avahi_string_list_add_printf(ipp_txt, "URF=%s", urf);
- ipp_txt = avahi_string_list_add_printf(ipp_txt, "txtvers=1");
- ipp_txt = avahi_string_list_add_printf(ipp_txt, "qtotal=1");
-
- /*
- * 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 (subtypes && *subtypes)
- {
- char *temptypes = strdup(subtypes), *start, *end;
-
- for (start = temptypes; *start; start = end)
- {
- if ((end = strchr(start, ',')) != NULL)
- *end++ = '\0';
- else
- end = start + strlen(start);
-
- snprintf(temp, sizeof(temp), "%s._sub._ipp._tcp", start);
- avahi_entry_group_add_service_subtype(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_ipp._tcp", NULL, temp);
- }
-
- free(temptypes);
- }
-
-#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 (subtypes && *subtypes)
- {
- char *temptypes = strdup(subtypes), *start, *end;
-
- for (start = temptypes; *start; start = end)
- {
- if ((end = strchr(start, ',')) != NULL)
- *end++ = '\0';
- else
- end = start + strlen(start);
-
- snprintf(temp, sizeof(temp), "%s._sub._ipps._tcp", start);
- avahi_entry_group_add_service_subtype(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_ipps._tcp", NULL, temp);
- }
-
- free(temptypes);
- }
-#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(
- ippeve_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(ippeve_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(
- ippeve_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(ippeve_printer_t *printer) /* I - Printer */
-{
- int num_fds; /* Number of file descriptors */
- struct pollfd polldata[3]; /* poll() data */
- int timeout; /* Timeout for poll() */
- ippeve_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);
- }
-}
-
-
-/*
- * 'show_media()' - Show media load state.
- */
-
-static int /* O - 1 on success, 0 on failure */
-show_media(ippeve_client_t *client) /* I - Client connection */
-{
- ippeve_printer_t *printer = client->printer;
- /* Printer */
- int i, j, /* Looping vars */
- num_ready, /* Number of ready media */
- num_sizes, /* Number of media sizes */
- num_sources, /* Number of media sources */
- num_types; /* Number of media types */
- ipp_attribute_t *media_col_ready,/* media-col-ready attribute */
- *media_ready, /* media-ready attribute */
- *media_sizes, /* media-supported attribute */
- *media_sources, /* media-source-supported attribute */
- *media_types, /* media-type-supported attribute */
- *input_tray; /* printer-input-tray attribute */
- ipp_t *media_col; /* media-col value */
- const char *media_size, /* media value */
- *media_source, /* media-source value */
- *media_type, /* media-type value */
- *ready_size, /* media-col-ready media-size[-name] value */
- *ready_source, /* media-col-ready media-source value */
- *ready_tray, /* printer-input-tray value */
- *ready_type; /* media-col-ready media-type value */
- char tray_str[1024], /* printer-input-tray string value */
- *tray_ptr; /* Pointer into value */
- int tray_len; /* Length of printer-input-tray value */
- int ready_sheets; /* printer-input-tray sheets value */
- int num_options; /* Number of form options */
- cups_option_t *options; /* Form options */
- static const int sheets[] = /* Number of sheets */
- {
- 250,
- 125,
- 50,
- 25,
- 5,
- 0,
- -2
- };
-
-
- if (!respond_http(client, HTTP_STATUS_OK, NULL, "text/html", 0))
- return (0);
-
- html_header(client, printer->name, 0);
-
- if ((media_col_ready = ippFindAttribute(printer->attrs, "media-col-ready", IPP_TAG_BEGIN_COLLECTION)) == NULL)
- {
- html_printf(client, "<p>Error: No media-col-ready defined for printer.</p>\n");
- html_footer(client);
- return (1);
- }
-
- media_ready = ippFindAttribute(printer->attrs, "media-ready", IPP_TAG_ZERO);
-
- if ((media_sizes = ippFindAttribute(printer->attrs, "media-supported", IPP_TAG_ZERO)) == NULL)
- {
- html_printf(client, "<p>Error: No media-supported defined for printer.</p>\n");
- html_footer(client);
- return (1);
- }
-
- if ((media_sources = ippFindAttribute(printer->attrs, "media-source-supported", IPP_TAG_ZERO)) == NULL)
- {
- html_printf(client, "<p>Error: No media-source-supported defined for printer.</p>\n");
- html_footer(client);
- return (1);
- }
-
- if ((media_types = ippFindAttribute(printer->attrs, "media-type-supported", IPP_TAG_ZERO)) == NULL)
- {
- html_printf(client, "<p>Error: No media-type-supported defined for printer.</p>\n");
- html_footer(client);
- return (1);
- }
-
- if ((input_tray = ippFindAttribute(printer->attrs, "printer-input-tray", IPP_TAG_STRING)) == NULL)
- {
- html_printf(client, "<p>Error: No printer-input-tray defined for printer.</p>\n");
- html_footer(client);
- return (1);
- }
-
- num_ready = ippGetCount(media_col_ready);
- num_sizes = ippGetCount(media_sizes);
- num_sources = ippGetCount(media_sources);
- num_types = ippGetCount(media_types);
-
- if (num_sources != ippGetCount(input_tray))
- {
- html_printf(client, "<p>Error: Different number of trays in media-source-supported and printer-input-tray defined for printer.</p>\n");
- html_footer(client);
- return (1);
- }
-
- /*
- * Process form data if present...
- */
-
- if (printer->web_forms)
- num_options = parse_options(client, &options);
- else
- num_options = 0;
-
- if (num_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!
- */
-
- char name[255]; /* Form name */
- const char *val; /* Form value */
- pwg_media_t *media; /* Media info */
-
- _cupsRWLockWrite(&printer->rwlock);
-
- ippDeleteAttribute(printer->attrs, media_col_ready);
- media_col_ready = NULL;
-
- if (media_ready)
- {
- ippDeleteAttribute(printer->attrs, media_ready);
- media_ready = NULL;
- }
-
- printer->state_reasons &= (ippeve_preason_t)~(IPPEVE_PREASON_MEDIA_LOW | IPPEVE_PREASON_MEDIA_EMPTY | IPPEVE_PREASON_MEDIA_NEEDED);
-
- for (i = 0; i < num_sources; i ++)
- {
- media_source = ippGetString(media_sources, i, NULL);
-
- if (!strcmp(media_source, "auto") || !strcmp(media_source, "manual") || strstr(media_source, "-man") != NULL)
- continue;
-
- snprintf(name, sizeof(name), "size%d", i);
- if ((media_size = cupsGetOption(name, num_options, options)) != NULL && (media = pwgMediaForPWG(media_size)) != NULL)
- {
- snprintf(name, sizeof(name), "type%d", i);
- if ((media_type = cupsGetOption(name, num_options, options)) != NULL && !*media_type)
- media_type = NULL;
-
- if (media_ready)
- ippSetString(printer->attrs, &media_ready, ippGetCount(media_ready), media_size);
- else
- media_ready = ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-ready", NULL, media_size);
-
- media_col = create_media_col(media_size, media_source, media_type, media->width, media->length, -1, -1, -1, -1);
-
- if (media_col_ready)
- ippSetCollection(printer->attrs, &media_col_ready, ippGetCount(media_col_ready), media_col);
- else
- media_col_ready = ippAddCollection(printer->attrs, IPP_TAG_PRINTER, "media-col-ready", media_col);
- ippDelete(media_col);
- }
- else
- media = NULL;
-
- snprintf(name, sizeof(name), "level%d", i);
- if ((val = cupsGetOption(name, num_options, options)) != NULL)
- ready_sheets = atoi(val);
- else
- ready_sheets = 0;
-
- snprintf(tray_str, sizeof(tray_str), "type=sheetFeedAuto%sRemovableTray;mediafeed=%d;mediaxfeed=%d;maxcapacity=%d;level=%d;status=0;name=%s;", !strcmp(media_source, "by-pass-tray") ? "Non" : "", media ? media->length : 0, media ? media->width : 0, strcmp(media_source, "by-pass-tray") ? 250 : 25, ready_sheets, media_source);
-
- ippSetOctetString(printer->attrs, &input_tray, i, tray_str, (int)strlen(tray_str));
-
- if (ready_sheets == 0)
- {
- printer->state_reasons |= IPPEVE_PREASON_MEDIA_EMPTY;
- if (printer->active_job)
- printer->state_reasons |= IPPEVE_PREASON_MEDIA_NEEDED;
- }
- else if (ready_sheets < 25 && ready_sheets > 0)
- printer->state_reasons |= IPPEVE_PREASON_MEDIA_LOW;
- }
-
- if (!media_col_ready)
- media_col_ready = ippAddOutOfBand(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, "media-col-ready");
-
- if (!media_ready)
- media_ready = ippAddOutOfBand(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, "media-ready");
-
- _cupsRWUnlock(&printer->rwlock);
- }
-
- if (printer->web_forms)
- html_printf(client, "<form method=\"GET\" action=\"/media\">\n");
-
- html_printf(client, "<table class=\"form\" summary=\"Media\">\n");
- for (i = 0; i < num_sources; i ++)
- {
- media_source = ippGetString(media_sources, i, NULL);
-
- if (!strcmp(media_source, "auto") || !strcmp(media_source, "manual") || strstr(media_source, "-man") != NULL)
- continue;
-
- for (j = 0, ready_size = NULL, ready_type = NULL; j < num_ready; j ++)
- {
- media_col = ippGetCollection(media_col_ready, j);
- ready_size = ippGetString(ippFindAttribute(media_col, "media-size-name", IPP_TAG_ZERO), 0, NULL);
- ready_source = ippGetString(ippFindAttribute(media_col, "media-source", IPP_TAG_ZERO), 0, NULL);
- ready_type = ippGetString(ippFindAttribute(media_col, "media-type", IPP_TAG_ZERO), 0, NULL);
-
- if (ready_source && !strcmp(ready_source, media_source))
- break;
-
- ready_source = NULL;
- ready_size = NULL;
- ready_type = NULL;
- }
-
- html_printf(client, "<tr><th>%s:</th>", media_source);
-
- /*
- * Media size...
- */
-
- if (printer->web_forms)
- {
- html_printf(client, "<td><select name=\"size%d\"><option value=\"\">None</option>", i);
- for (j = 0; j < num_sizes; j ++)
- {
- media_size = ippGetString(media_sizes, j, NULL);
-
- html_printf(client, "<option%s>%s</option>", (ready_size && !strcmp(ready_size, media_size)) ? " selected" : "", media_size);
- }
- html_printf(client, "</select>");
- }
- else
- html_printf(client, "<td>%s", ready_size);
-
- /*
- * Media type...
- */
-
- if (printer->web_forms)
- {
- html_printf(client, " <select name=\"type%d\"><option value=\"\">None</option>", i);
- for (j = 0; j < num_types; j ++)
- {
- media_type = ippGetString(media_types, j, NULL);
-
- html_printf(client, "<option%s>%s</option>", (ready_type && !strcmp(ready_type, media_type)) ? " selected" : "", media_type);
- }
- html_printf(client, "</select>");
- }
- else
- html_printf(client, ", %s", ready_type);
-
- /*
- * Level/sheets loaded...
- */
-
- if ((ready_tray = ippGetOctetString(input_tray, i, &tray_len)) != NULL)
- {
- if (tray_len > (int)(sizeof(tray_str) - 1))
- tray_len = (int)sizeof(tray_str) - 1;
- memcpy(tray_str, ready_tray, (size_t)tray_len);
- tray_str[tray_len] = '\0';
-
- if ((tray_ptr = strstr(tray_str, "level=")) != NULL)
- ready_sheets = atoi(tray_ptr + 6);
- else
- ready_sheets = 0;
- }
- else
- ready_sheets = 0;
-
- if (printer->web_forms)
- {
- html_printf(client, " <select name=\"level%d\">", i);
- for (j = 0; j < (int)(sizeof(sheets) / sizeof(sheets[0])); j ++)
- {
- if (!strcmp(media_source, "by-pass-tray") && sheets[j] > 25)
- continue;
-
- if (sheets[j] < 0)
- html_printf(client, "<option value=\"%d\"%s>Unknown</option>", sheets[j], sheets[j] == ready_sheets ? " selected" : "");
- else
- html_printf(client, "<option value=\"%d\"%s>%d sheets</option>", sheets[j], sheets[j] == ready_sheets ? " selected" : "", sheets[j]);
- }
- html_printf(client, "</select></td></tr>\n");
- }
- else if (ready_sheets > 0)
- html_printf(client, ", %d sheets</td></tr>\n", ready_sheets);
- else
- html_printf(client, "</td></tr>\n");
- }
-
- if (printer->web_forms)
- {
- html_printf(client, "<tr><td></td><td><input type=\"submit\" value=\"Update Media\">");
- if (num_options > 0)
- html_printf(client, " <span class=\"badge\" id=\"status\">Media updated.</span>\n");
- html_printf(client, "</td></tr></table></form>\n");
-
- if (num_options > 0)
- html_printf(client, "<script>\n"
- "setTimeout(hide_status, 3000);\n"
- "function hide_status() {\n"
- " var status = document.getElementById('status');\n"
- " status.style.display = 'none';\n"
- "}\n"
- "</script>\n");
- }
- else
- html_printf(client, "</table>\n");
-
- html_footer(client);
-
- return (1);
-}
-
-
-/*
- * 'show_status()' - Show printer/system state.
- */
-
-static int /* O - 1 on success, 0 on failure */
-show_status(ippeve_client_t *client) /* I - Client connection */
-{
- ippeve_printer_t *printer = client->printer;
- /* Printer */
- ippeve_job_t *job; /* Current job */
- int i; /* Looping var */
- ippeve_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"
- };
- static const char * const state_colors[] =
- { /* State colors */
- "#0C0", /* Idle */
- "#EE0", /* Processing */
- "#C00" /* Stopped */
- };
-
-
- if (!respond_http(client, HTTP_STATUS_OK, NULL, "text/html", 0))
- return (0);
-
- html_header(client, printer->name, printer->state == IPP_PSTATE_PROCESSING ? 5 : 15);
- html_printf(client, "<h1><img style=\"background: %s; border-radius: 10px; float: left; margin-right: 10px; padding: 10px;\" src=\"/icon.png\" width=\"64\" height=\"64\">%s Jobs</h1>\n", state_colors[printer->state - IPP_PSTATE_IDLE], printer->name);
- html_printf(client, "<p>%s, %d job(s).", printer->state == IPP_PSTATE_IDLE ? "Idle" : printer->state == IPP_PSTATE_PROCESSING ? "Printing" : "Stopped", cupsArrayCount(printer->jobs));
- for (i = 0, reason = 1; i < (int)(sizeof(reasons) / sizeof(reasons[0])); i ++, reason <<= 1)
- if (printer->state_reasons & reason)
- html_printf(client, "\n<br>&nbsp;&nbsp;&nbsp;&nbsp;%s", reasons[i]);
- html_printf(client, "</p>\n");
-
- if (cupsArrayCount(printer->jobs) > 0)
- {
- _cupsRWLockRead(&(printer->rwlock));
-
- html_printf(client, "<table class=\"striped\" summary=\"Jobs\"><thead><tr><th>Job #</th><th>Name</th><th>Owner</th><th>Status</th></tr></thead><tbody>\n");
- for (job = (ippeve_job_t *)cupsArrayFirst(printer->jobs); job; job = (ippeve_job_t *)cupsArrayNext(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, "<tr><td>%d</td><td>%s</td><td>%s</td><td>%s</td></tr>\n", job->id, job->name, job->username, when);
- }
- html_printf(client, "</tbody></table>\n");
-
- _cupsRWUnlock(&(printer->rwlock));
- }
-
- html_footer(client);
-
- return (1);
-}
-
-
-/*
- * 'show_supplies()' - Show printer supplies.
- */
-
-static int /* O - 1 on success, 0 on failure */
-show_supplies(
- ippeve_client_t *client) /* I - Client connection */
-{
- ippeve_printer_t *printer = client->printer;
- /* Printer */
- int i, /* Looping var */
- num_supply; /* Number of supplies */
- ipp_attribute_t *supply, /* printer-supply attribute */
- *supply_desc; /* printer-supply-description attribute */
- int num_options; /* Number of form options */
- cups_option_t *options; /* Form options */
- int supply_len, /* Length of supply value */
- level; /* Supply level */
- const char *supply_value; /* Supply value */
- char supply_text[1024], /* Supply string */
- *supply_ptr; /* Pointer into supply string */
- static const char * const printer_supply[] =
- { /* printer-supply values */
- "index=1;class=receptacleThatIsFilled;type=wasteToner;unit=percent;"
- "maxcapacity=100;level=%d;colorantname=unknown;",
- "index=2;class=supplyThatIsConsumed;type=toner;unit=percent;"
- "maxcapacity=100;level=%d;colorantname=black;",
- "index=3;class=supplyThatIsConsumed;type=toner;unit=percent;"
- "maxcapacity=100;level=%d;colorantname=cyan;",
- "index=4;class=supplyThatIsConsumed;type=toner;unit=percent;"
- "maxcapacity=100;level=%d;colorantname=magenta;",
- "index=5;class=supplyThatIsConsumed;type=toner;unit=percent;"
- "maxcapacity=100;level=%d;colorantname=yellow;"
- };
- static const char * const backgrounds[] =
- { /* Background colors for the supply-level bars */
- "#777 linear-gradient(#333,#777)",
- "#000 linear-gradient(#666,#000)",
- "#0FF linear-gradient(#6FF,#0FF)",
- "#F0F linear-gradient(#F6F,#F0F)",
- "#CC0 linear-gradient(#EE6,#EE0)"
- };
- static const char * const colors[] = /* Text colors for the supply-level bars */
- {
- "#fff",
- "#fff",
- "#000",
- "#000",
- "#000"
- };
-
-
- if (!respond_http(client, HTTP_STATUS_OK, NULL, "text/html", 0))
- return (0);
-
- html_header(client, printer->name, 0);
-
- if ((supply = ippFindAttribute(printer->attrs, "printer-supply", IPP_TAG_STRING)) == NULL)
- {
- html_printf(client, "<p>Error: No printer-supply defined for printer.</p>\n");
- html_footer(client);
- return (1);
- }
-
- num_supply = ippGetCount(supply);
-
- if ((supply_desc = ippFindAttribute(printer->attrs, "printer-supply-description", IPP_TAG_TEXT)) == NULL)
- {
- html_printf(client, "<p>Error: No printer-supply-description defined for printer.</p>\n");
- html_footer(client);
- return (1);
- }
-
- if (num_supply != ippGetCount(supply_desc))
- {
- html_printf(client, "<p>Error: Different number of values for printer-supply and printer-supply-description defined for printer.</p>\n");
- html_footer(client);
- return (1);
- }
-
- if (printer->web_forms)
- num_options = parse_options(client, &options);
- else
- num_options = 0;
-
- if (num_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 */
-
- _cupsRWLockWrite(&printer->rwlock);
-
- ippDeleteAttribute(printer->attrs, supply);
- supply = NULL;
-
- printer->state_reasons &= (ippeve_preason_t)~(IPPEVE_PREASON_MARKER_SUPPLY_EMPTY | IPPEVE_PREASON_MARKER_SUPPLY_LOW | IPPEVE_PREASON_MARKER_WASTE_ALMOST_FULL | IPPEVE_PREASON_MARKER_WASTE_FULL | IPPEVE_PREASON_TONER_EMPTY | IPPEVE_PREASON_TONER_LOW);
-
- for (i = 0; i < num_supply; i ++)
- {
- snprintf(name, sizeof(name), "supply%d", i);
- if ((val = cupsGetOption(name, num_options, options)) != NULL)
- {
- level = atoi(val); /* New level */
-
- snprintf(supply_text, sizeof(supply_text), printer_supply[i], level);
- if (supply)
- ippSetOctetString(printer->attrs, &supply, ippGetCount(supply), supply_text, (int)strlen(supply_text));
- else
- supply = ippAddOctetString(printer->attrs, IPP_TAG_PRINTER, "printer-supply", supply_text, (int)strlen(supply_text));
-
- if (i == 0)
- {
- if (level == 100)
- printer->state_reasons |= IPPEVE_PREASON_MARKER_WASTE_FULL;
- else if (level > 90)
- printer->state_reasons |= IPPEVE_PREASON_MARKER_WASTE_ALMOST_FULL;
- }
- else
- {
- if (level == 0)
- printer->state_reasons |= IPPEVE_PREASON_TONER_EMPTY;
- else if (level < 10)
- printer->state_reasons |= IPPEVE_PREASON_TONER_LOW;
- }
- }
- }
-
- _cupsRWUnlock(&printer->rwlock);
- }
-
- if (printer->web_forms)
- html_printf(client, "<form method=\"GET\" action=\"/supplies\">\n");
-
- html_printf(client, "<table class=\"form\" summary=\"Supplies\">\n");
- for (i = 0; i < num_supply; i ++)
- {
- supply_value = ippGetOctetString(supply, i, &supply_len);
- if (supply_len > (int)(sizeof(supply_text) - 1))
- supply_len = (int)sizeof(supply_text) - 1;
-
- memcpy(supply_text, supply_value, (size_t)supply_len);
- supply_text[supply_len] = '\0';
-
- if ((supply_ptr = strstr(supply_text, "level=")) != NULL)
- level = atoi(supply_ptr + 6);
- else
- level = 50;
-
- if (printer->web_forms)
- html_printf(client, "<tr><th>%s:</th><td><input name=\"supply%d\" size=\"3\" value=\"%d\"></td>", ippGetString(supply_desc, i, NULL), i, level);
- else
- html_printf(client, "<tr><th>%s:</th>", ippGetString(supply_desc, i, NULL));
-
- if (level < 10)
- html_printf(client, "<td class=\"meter\"><span class=\"bar\" style=\"background: %s; padding: 5px %dpx;\"></span>&nbsp;%d%%</td></tr>\n", backgrounds[i], level * 2, level);
- else
- html_printf(client, "<td class=\"meter\"><span class=\"bar\" style=\"background: %s; color: %s; padding: 5px %dpx;\">%d%%</span></td></tr>\n", backgrounds[i], colors[i], level * 2, level);
- }
-
- if (printer->web_forms)
- {
- html_printf(client, "<tr><td></td><td colspan=\"2\"><input type=\"submit\" value=\"Update Supplies\">");
- if (num_options > 0)
- html_printf(client, " <span class=\"badge\" id=\"status\">Supplies updated.</span>\n");
- html_printf(client, "</td></tr>\n</table>\n</form>\n");
-
- if (num_options > 0)
- html_printf(client, "<script>\n"
- "setTimeout(hide_status, 3000);\n"
- "function hide_status() {\n"
- " var status = document.getElementById('status');\n"
- " status.style.display = 'none';\n"
- "}\n"
- "</script>\n");
- }
- else
- html_printf(client, "</table>\n");
-
- html_footer(client);
-
- return (1);
-}
-
-
-/*
- * '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 */
-{
- _cupsLangPuts(stdout, _("Usage: ippeveprinter [options] \"name\""));
- _cupsLangPuts(stdout, _("Options:"));
- _cupsLangPuts(stderr, _("--help Show program help"));
- _cupsLangPuts(stderr, _("--no-web-forms Disable web forms for media and supplies"));
- _cupsLangPuts(stderr, _("--version Show program version"));
- _cupsLangPuts(stdout, _("-2 Set 2-sided printing support (default=1-sided)"));
- _cupsLangPuts(stdout, _("-D device-uri Set the device URI for the printer"));
-#ifdef HAVE_SSL
- _cupsLangPuts(stdout, _("-K keypath Set location of server X.509 certificates and keys."));
-#endif /* HAVE_SSL */
- _cupsLangPuts(stdout, _("-M manufacturer Set manufacturer name (default=Test)"));
- _cupsLangPuts(stdout, _("-P filename.ppd Load printer attributes from PPD file"));
- _cupsLangPuts(stdout, _("-V version Set default IPP version"));
- _cupsLangPuts(stdout, _("-a filename.conf Load printer attributes from conf file"));
- _cupsLangPuts(stdout, _("-c command Set print command"));
- _cupsLangPuts(stdout, _("-d spool-directory Set spool directory"));
- _cupsLangPuts(stdout, _("-f type/subtype[,...] Set supported file types"));
- _cupsLangPuts(stdout, _("-i iconfile.png Set icon file"));
- _cupsLangPuts(stdout, _("-k Keep job spool files"));
- _cupsLangPuts(stdout, _("-l location Set location of printer"));
- _cupsLangPuts(stdout, _("-m model Set model name (default=Printer)"));
- _cupsLangPuts(stdout, _("-n hostname Set hostname for printer"));
- _cupsLangPuts(stdout, _("-p port Set port number for printer"));
- _cupsLangPuts(stdout, _("-r subtype,[subtype] Set DNS-SD service subtype"));
- _cupsLangPuts(stdout, _("-s speed[,color-speed] Set speed in pages per minute"));
- _cupsLangPuts(stderr, _("-v Be 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(
- ippeve_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(
- ippeve_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);
-}