X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=scheduler%2Fprinters.c;h=3a68ee193bde503c6edfd6189c7bd21864238476;hb=4bc478876dcf088530811dc949861861f38cc292;hp=876231d45e9001baf9794602063633afa1794d06;hpb=f8b3a85b79b8eb74c37c839079ecbf8266a6f4ed;p=thirdparty%2Fcups.git diff --git a/scheduler/printers.c b/scheduler/printers.c index 876231d45..3a68ee193 100644 --- a/scheduler/printers.c +++ b/scheduler/printers.c @@ -1,61 +1,11 @@ /* - * "$Id: printers.c 7968 2008-09-19 23:03:01Z mike $" + * Printer routines for the CUPS scheduler. * - * Printer routines for the Common UNIX Printing System (CUPS). + * Copyright © 2007-2018 by Apple Inc. + * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * - * Copyright 2007-2010 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. - * - * These coded instructions, statements, and computer programs are the - * property of Apple Inc. and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "LICENSE.txt" - * which should have been included with this file. If this file is - * file is missing or damaged, see the license at "http://www.cups.org/". - * - * Contents: - * - * cupsdAddPrinter() - Add a printer to the system. - * cupsdAddPrinterHistory() - Add the current printer state to the history. - * cupsdAddPrinterUser() - Add a user to the ACL. - * cupsdCreateCommonData() - Create the common printer data. - * cupsdDeleteAllPrinters() - Delete all printers from the system. - * cupsdDeletePrinter() - Delete a printer from the system. - * cupsdFindDest() - Find a destination in the list. - * cupsdFindPrinter() - Find a printer in the list. - * cupsdFreePrinterUsers() - Free allow/deny users. - * cupsdLoadAllPrinters() - Load printers from the printers.conf file. - * cupsdRenamePrinter() - Rename a printer. - * cupsdSaveAllPrinters() - Save all printer definitions to the - * printers.conf file. - * cupsdSetAuthInfoRequired() - Set the required authentication info. - * cupsdSetDeviceURI() - Set the device URI for a printer. - * cupsdSetPrinterAttr() - Set a printer attribute. - * cupsdSetPrinterAttrs() - Set printer attributes based upon the PPD - * file. - * cupsdSetPrinterReasons() - Set/update the reasons strings. - * cupsdSetPrinterState() - Update the current state of a printer. - * cupsdStopPrinter() - Stop a printer from printing any jobs... - * cupsdUpdatePrinterPPD() - Update keywords in a printer's PPD file. - * cupsdUpdatePrinters() - Update printers after a partial reload. - * cupsdValidateDest() - Validate a printer/class destination. - * cupsdWritePrintcap() - Write a pseudo-printcap file for older - * applications that need it... - * add_printer_defaults() - Add name-default attributes to the printer - * attributes. - * add_printer_filter() - Add a MIME filter for a printer. - * add_printer_formats() - Add document-format-supported values for a - * printer. - * add_string_array() - Add a string to an array of CUPS strings. - * compare_printers() - Compare two printers. - * delete_printer_filters() - Delete all MIME filters for a printer. - * delete_string_array() - Delete an array of CUPS strings. - * load_ppd() - Load a cached PPD file, updating the cache as - * needed. - * write_irix_config() - Update the config files used by the IRIX - * desktop tools. - * write_irix_state() - Update the status files used by IRIX printing - * desktop tools. - * write_xml_string() - Write a string with XML escaping. + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* @@ -64,7 +14,23 @@ #include "cupsd.h" #include -#include +#ifdef HAVE_APPLICATIONSERVICES_H +# include +#endif /* HAVE_APPLICATIONSERVICES_H */ +#ifdef HAVE_SYS_MOUNT_H +# include +#endif /* HAVE_SYS_MOUNT_H */ +#ifdef HAVE_SYS_STATVFS_H +# include +#elif defined(HAVE_SYS_STATFS_H) +# include +#endif /* HAVE_SYS_STATVFS_H */ +#ifdef HAVE_SYS_VFS_H +# include +#endif /* HAVE_SYS_VFS_H */ +#ifdef __APPLE__ +# include +#endif /* __APPLE__ */ /* @@ -75,15 +41,12 @@ static void add_printer_defaults(cupsd_printer_t *p); static void add_printer_filter(cupsd_printer_t *p, mime_type_t *type, const char *filter); static void add_printer_formats(cupsd_printer_t *p); -static void add_string_array(cups_array_t **a, const char *s); static int compare_printers(void *first, void *second, void *data); static void delete_printer_filters(cupsd_printer_t *p); -static void delete_string_array(cups_array_t **a); +static void dirty_printer(cupsd_printer_t *p); static void load_ppd(cupsd_printer_t *p); -#ifdef __sgi -static void write_irix_config(cupsd_printer_t *p); -static void write_irix_state(cupsd_printer_t *p); -#endif /* __sgi */ +static ipp_t *new_media_col(pwg_size_t *size, const char *source, + const char *type); static void write_xml_string(cups_file_t *fp, const char *s); @@ -95,6 +58,8 @@ cupsd_printer_t * /* O - New printer */ cupsdAddPrinter(const char *name) /* I - Name of printer */ { cupsd_printer_t *p; /* New printer */ + char uri[1024], /* Printer URI */ + uuid[64]; /* Printer UUID */ /* @@ -114,19 +79,25 @@ cupsdAddPrinter(const char *name) /* I - Name of printer */ return (NULL); } + _cupsRWInit(&p->lock); + cupsdSetString(&p->name, name); cupsdSetString(&p->info, name); cupsdSetString(&p->hostname, ServerName); - cupsdSetStringf(&p->uri, "ipp://%s:%d/printers/%s", ServerName, RemotePort, - name); + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, + ServerName, RemotePort, "/printers/%s", name); + cupsdSetString(&p->uri, uri); + cupsdSetString(&p->uuid, httpAssembleUUID(ServerName, RemotePort, name, 0, + uuid, sizeof(uuid))); cupsdSetDeviceURI(p, "file:///dev/null"); - p->state = IPP_PRINTER_STOPPED; - p->state_time = time(NULL); - p->accepting = 0; - p->shared = DefaultShared; - p->filetype = mimeAddType(MimeDatabase, "printer", name); + p->config_time = time(NULL); + p->state = IPP_PRINTER_STOPPED; + p->state_time = time(NULL); + p->accepting = 0; + p->shared = DefaultShared; + p->filetype = mimeAddType(MimeDatabase, "printer", name); cupsdSetString(&p->job_sheets[0], "none"); cupsdSetString(&p->job_sheets[1], "none"); @@ -136,9 +107,6 @@ cupsdAddPrinter(const char *name) /* I - Name of printer */ p->op_policy_ptr = DefaultPolicyPtr; - if (MaxPrinterHistory) - p->history = calloc(MaxPrinterHistory, sizeof(ipp_t *)); - /* * Insert the printer in the printer list alphabetically... */ @@ -150,9 +118,6 @@ cupsdAddPrinter(const char *name) /* I - Name of printer */ "cupsdAddPrinter: Adding %s to Printers", p->name); cupsArrayAdd(Printers, p); - if (!ImplicitPrinters) - ImplicitPrinters = cupsArrayNew(compare_printers, NULL); - /* * Return the new printer... */ @@ -161,98 +126,6 @@ cupsdAddPrinter(const char *name) /* I - Name of printer */ } -/* - * 'cupsdAddPrinterHistory()' - Add the current printer state to the history. - */ - -void -cupsdAddPrinterHistory( - cupsd_printer_t *p) /* I - Printer */ -{ - ipp_t *history; /* History collection */ - - - /* - * Stop early if we aren't keeping history data... - */ - - if (MaxPrinterHistory <= 0) - return; - - /* - * Retire old history data as needed... - */ - - p->sequence_number ++; - - if (p->num_history >= MaxPrinterHistory) - { - p->num_history --; - ippDelete(p->history[0]); - memmove(p->history, p->history + 1, p->num_history * sizeof(ipp_t *)); - } - - /* - * Create a collection containing the current printer-state, printer-up-time, - * printer-state-message, and printer-state-reasons attributes. - */ - - history = ippNew(); - ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", - p->state); - ippAddBoolean(history, IPP_TAG_PRINTER, "printer-is-accepting-jobs", - p->accepting); - ippAddBoolean(history, IPP_TAG_PRINTER, "printer-is-shared", p->shared); - ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-state-message", - NULL, p->state_message); - if (p->num_reasons == 0) - ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "printer-state-reasons", NULL, "none"); - else - ippAddStrings(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "printer-state-reasons", p->num_reasons, NULL, - (const char * const *)p->reasons); - ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "printer-state-change-time", p->state_time); - ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "printer-state-sequence-number", p->sequence_number); - - p->history[p->num_history] = history; - p->num_history ++; -} - - -/* - * 'cupsdAddPrinterUser()' - Add a user to the ACL. - */ - -void -cupsdAddPrinterUser( - cupsd_printer_t *p, /* I - Printer */ - const char *username) /* I - User */ -{ - const char **temp; /* Temporary array pointer */ - - - if (!p || !username) - return; - - if (p->num_users == 0) - temp = malloc(sizeof(char **)); - else - temp = realloc(p->users, sizeof(char **) * (p->num_users + 1)); - - if (!temp) - return; - - p->users = temp; - temp += p->num_users; - - if ((*temp = strdup(username)) != NULL) - p->num_users ++; -} - - /* * 'cupsdCreateCommonData()' - Create the common printer data. */ @@ -268,8 +141,40 @@ cupsdCreateCommonData(void) char filename[1024], /* Filename */ *notifier; /* Current notifier */ cupsd_policy_t *p; /* Current policy */ - static const int nups[] = /* number-up-supported values */ + int k_supported; /* Maximum file size supported */ +#ifdef HAVE_STATVFS + struct statvfs spoolinfo; /* FS info for spool directory */ + double spoolsize; /* FS size */ +#elif defined(HAVE_STATFS) + struct statfs spoolinfo; /* FS info for spool directory */ + double spoolsize; /* FS size */ +#endif /* HAVE_STATVFS */ + static const char * const page_delivery[] = + { /* page-delivery-supported values */ + "reverse-order", + "same-order" + }; + static const char * const print_scaling[] = + { /* print-scaling-supported values */ + "auto", + "auto-fit", + "fill", + "fit", + "none" + }; + static const int number_up[] = /* number-up-supported values */ { 1, 2, 4, 6, 9, 16 }; + static const char * const number_up_layout[] = + { /* number-up-layout-supported values */ + "btlr", + "btrl", + "lrbt", + "lrtb", + "rlbt", + "rltb", + "tblr", + "tbrl" + }; static const int orients[4] =/* orientation-requested-supported values */ { IPP_PORTRAIT, @@ -288,6 +193,10 @@ cupsdCreateCommonData(void) "third-shift", "weekend" }; + static const char * const features[] =/* ipp-features-supported values */ + { + "subscription-object" + }; static const char * const versions[] =/* ipp-versions-supported values */ { "1.0", @@ -297,50 +206,53 @@ cupsdCreateCommonData(void) }; static const int ops[] = /* operations-supported values */ { - IPP_PRINT_JOB, - IPP_VALIDATE_JOB, - IPP_CREATE_JOB, - IPP_SEND_DOCUMENT, - IPP_CANCEL_JOB, - IPP_GET_JOB_ATTRIBUTES, - IPP_GET_JOBS, - IPP_GET_PRINTER_ATTRIBUTES, - IPP_HOLD_JOB, - IPP_RELEASE_JOB, - IPP_PAUSE_PRINTER, - IPP_RESUME_PRINTER, - IPP_PURGE_JOBS, - IPP_SET_PRINTER_ATTRIBUTES, - IPP_SET_JOB_ATTRIBUTES, - IPP_GET_PRINTER_SUPPORTED_VALUES, - IPP_CREATE_PRINTER_SUBSCRIPTION, - IPP_CREATE_JOB_SUBSCRIPTION, - IPP_GET_SUBSCRIPTION_ATTRIBUTES, - IPP_GET_SUBSCRIPTIONS, - IPP_RENEW_SUBSCRIPTION, - IPP_CANCEL_SUBSCRIPTION, - IPP_GET_NOTIFICATIONS, - IPP_ENABLE_PRINTER, - IPP_DISABLE_PRINTER, - IPP_HOLD_NEW_JOBS, - IPP_RELEASE_HELD_NEW_JOBS, - CUPS_GET_DEFAULT, - CUPS_GET_PRINTERS, - CUPS_ADD_PRINTER, - CUPS_DELETE_PRINTER, - CUPS_GET_CLASSES, - CUPS_ADD_CLASS, - CUPS_DELETE_CLASS, - CUPS_ACCEPT_JOBS, - CUPS_REJECT_JOBS, - CUPS_SET_DEFAULT, - CUPS_GET_DEVICES, - CUPS_GET_PPDS, - CUPS_MOVE_JOB, - CUPS_AUTHENTICATE_JOB, - CUPS_GET_PPD, - CUPS_GET_DOCUMENT, - IPP_RESTART_JOB + IPP_OP_PRINT_JOB, + IPP_OP_VALIDATE_JOB, + IPP_OP_CREATE_JOB, + IPP_OP_SEND_DOCUMENT, + IPP_OP_CANCEL_JOB, + IPP_OP_GET_JOB_ATTRIBUTES, + IPP_OP_GET_JOBS, + IPP_OP_GET_PRINTER_ATTRIBUTES, + IPP_OP_HOLD_JOB, + IPP_OP_RELEASE_JOB, + IPP_OP_PAUSE_PRINTER, + IPP_OP_RESUME_PRINTER, + IPP_OP_PURGE_JOBS, + IPP_OP_SET_PRINTER_ATTRIBUTES, + IPP_OP_SET_JOB_ATTRIBUTES, + IPP_OP_GET_PRINTER_SUPPORTED_VALUES, + IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS, + IPP_OP_CREATE_JOB_SUBSCRIPTIONS, + IPP_OP_GET_SUBSCRIPTION_ATTRIBUTES, + IPP_OP_GET_SUBSCRIPTIONS, + IPP_OP_RENEW_SUBSCRIPTION, + IPP_OP_CANCEL_SUBSCRIPTION, + IPP_OP_GET_NOTIFICATIONS, + IPP_OP_ENABLE_PRINTER, + IPP_OP_DISABLE_PRINTER, + IPP_OP_HOLD_NEW_JOBS, + IPP_OP_RELEASE_HELD_NEW_JOBS, + IPP_OP_CANCEL_JOBS, + IPP_OP_CANCEL_MY_JOBS, + IPP_OP_CLOSE_JOB, + IPP_OP_CUPS_GET_DEFAULT, + IPP_OP_CUPS_GET_PRINTERS, + IPP_OP_CUPS_ADD_MODIFY_PRINTER, + IPP_OP_CUPS_DELETE_PRINTER, + IPP_OP_CUPS_GET_CLASSES, + IPP_OP_CUPS_ADD_MODIFY_CLASS, + IPP_OP_CUPS_DELETE_CLASS, + IPP_OP_CUPS_ACCEPT_JOBS, + IPP_OP_CUPS_REJECT_JOBS, + IPP_OP_CUPS_SET_DEFAULT, + IPP_OP_CUPS_GET_DEVICES, + IPP_OP_CUPS_GET_PPDS, + IPP_OP_CUPS_MOVE_JOB, + IPP_OP_CUPS_AUTHENTICATE_JOB, + IPP_OP_CUPS_GET_PPD, + IPP_OP_CUPS_GET_DOCUMENT, + IPP_OP_RESTART_JOB }; static const char * const charsets[] =/* charset-supported values */ { @@ -356,9 +268,12 @@ cupsdCreateCommonData(void) }; static const char * const media_col_supported[] = { /* media-col-supported values */ - "media-color", - "media-key", + "media-bottom-margin", + "media-left-margin", + "media-right-margin", "media-size", + "media-source", + "media-top-margin", "media-type" }; static const char * const multiple_document_handling[] = @@ -396,26 +311,82 @@ cupsdCreateCommonData(void) "server-started", "server-stopped" }; + static const char * const job_creation[] = + { /* job-creation-attributes-supported */ + "copies", + "finishings", + "finishings-col", + "ipp-attribute-fidelity", + "job-hold-until", + "job-name", + "job-priority", + "job-sheets", + "media", + "media-col", + "multiple-document-handling", + "number-up", + "number-up-layout", + "orientation-requested", + "output-bin", + "page-delivery", + "page-ranges", + "print-color-mode", + "print-quality", + "print-scaling", + "printer-resolution", + "sides" + }; static const char * const job_settable[] = { /* job-settable-attributes-supported */ "copies", "finishings", "job-hold-until", + "job-name", "job-priority", "media", + "media-col", "multiple-document-handling", "number-up", + "output-bin", "orientation-requested", "page-ranges", + "print-color-mode", "print-quality", "printer-resolution", "sides" }; + static const char * const pdf_versions[] = + { /* pdf-versions-supported */ + "adobe-1.2", + "adobe-1.3", + "adobe-1.4", + "adobe-1.5", + "adobe-1.6", + "adobe-1.7", + "iso-19005-1_2005", + "iso-32000-1_2008", + "pwg-5102.3" + }; static const char * const printer_settable[] = { /* printer-settable-attributes-supported */ + "printer-geo-location", "printer-info", - "printer-location" + "printer-location", + "printer-organization", + "printer-organizational-unit" }; + static const char * const which_jobs[] = + { /* which-jobs-supported values */ + "completed", + "not-completed", + "aborted", + "all", + "canceled", + "pending", + "pending-held", + "processing", + "processing-stopped" + }; if (CommonData) @@ -423,6 +394,34 @@ cupsdCreateCommonData(void) CommonData = ippNew(); + /* + * Get the maximum spool size based on the size of the filesystem used for + * the RequestRoot 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(RequestRoot, &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(RequestRoot, &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 */ + /* * This list of attributes is sorted to improve performance when the * client provides a requested-attributes attribute... @@ -454,16 +453,40 @@ cupsdCreateCommonData(void) ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE, "generated-natural-language-supported", NULL, DefaultLanguage); + /* ipp-features-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "ipp-features-supported", sizeof(features) / sizeof(features[0]), NULL, features); + /* ipp-versions-supported */ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]), NULL, versions); + /* ippget-event-life */ + ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "ippget-event-life", 15); + + /* job-cancel-after-supported */ + ippAddRange(CommonData, IPP_TAG_PRINTER, "job-cancel-after-supported", + 0, INT_MAX); + + /* job-creation-attributes-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, + "job-creation-attributes-supported", + sizeof(job_creation) / sizeof(job_creation[0]), + NULL, job_creation); + /* job-hold-until-supported */ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-hold-until-supported", sizeof(holds) / sizeof(holds[0]), NULL, holds); + /* job-ids-supported */ + ippAddBoolean(CommonData, IPP_TAG_PRINTER, "job-ids-supported", 1); + + /* job-k-octets-supported */ + ippAddRange(CommonData, IPP_TAG_PRINTER, "job-k-octets-supported", 0, + k_supported); + /* job-priority-supported */ ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-priority-supported", 100); @@ -512,6 +535,18 @@ cupsdCreateCommonData(void) ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY, "job-sheets-supported", NULL, "none"); + /* jpeg-k-octets-supported */ + ippAddRange(CommonData, IPP_TAG_PRINTER, "jpeg-k-octets-supported", 0, + k_supported); + + /* jpeg-x-dimension-supported */ + ippAddRange(CommonData, IPP_TAG_PRINTER, "jpeg-x-dimension-supported", 0, + 65535); + + /* jpeg-y-dimension-supported */ + ippAddRange(CommonData, IPP_TAG_PRINTER, "jpeg-y-dimension-supported", 1, + 65535); + /* media-col-supported */ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, "media-col-supported", @@ -534,6 +569,9 @@ cupsdCreateCommonData(void) ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "multiple-operation-time-out", MultipleOperationTimeout); + /* multiple-operation-time-out-action */ + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "multiple-operation-time-out-action", NULL, "process-job"); + /* natural-language-configured (no IPP_TAG_COPY) */ ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE, "natural-language-configured", NULL, DefaultLanguage); @@ -592,23 +630,44 @@ cupsdCreateCommonData(void) /* number-up-supported */ ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "number-up-supported", sizeof(nups) / sizeof(nups[0]), nups); + "number-up-supported", sizeof(number_up) / sizeof(number_up[0]), number_up); + + /* number-up-layout-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "number-up-layout-supported", sizeof(number_up_layout) / sizeof(number_up_layout[0]), NULL, number_up_layout); /* operations-supported */ ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM, - "operations-supported", - sizeof(ops) / sizeof(ops[0]) + JobFiles - 1, ops); + "operations-supported", sizeof(ops) / sizeof(ops[0]), ops); /* orientation-requested-supported */ ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM, "orientation-requested-supported", 4, orients); + /* page-delivery-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "page-delivery-supported", sizeof(page_delivery) / sizeof(page_delivery[0]), NULL, page_delivery); + /* page-ranges-supported */ ippAddBoolean(CommonData, IPP_TAG_PRINTER, "page-ranges-supported", 1); - /* pdf-override-supported */ + /* pdf-k-octets-supported */ + ippAddRange(CommonData, IPP_TAG_PRINTER, "pdf-k-octets-supported", 0, + k_supported); + + /* pdf-versions-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, + "pdf-versions-supported", + sizeof(pdf_versions) / sizeof(pdf_versions[0]), NULL, + pdf_versions); + + /* pdl-override-supported */ ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, - "pdl-override-supported", NULL, "not-attempted"); + "pdl-override-supported", NULL, "attempted"); + + /* print-scaling-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-scaling-supported", sizeof(print_scaling) / sizeof(print_scaling[0]), NULL, print_scaling); + + /* printer-get-attributes-supported */ + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "printer-get-attributes-supported", NULL, "document-format"); /* printer-op-policy-supported */ attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY, @@ -628,6 +687,11 @@ cupsdCreateCommonData(void) /* server-is-sharing-printers */ ippAddBoolean(CommonData, IPP_TAG_PRINTER, "server-is-sharing-printers", BrowseLocalProtocols != 0 && Browsing); + + /* which-jobs-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, + "which-jobs-supported", + sizeof(which_jobs) / sizeof(which_jobs[0]), NULL, which_jobs); } @@ -662,9 +726,6 @@ cupsdDeletePrinter( { int i, /* Looping var */ changed = 0; /* Class changed? */ -#ifdef __sgi - char filename[1024]; /* Interface script filename */ -#endif /* __sgi */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDeletePrinter(p=%p(%s), update=%d)", @@ -682,21 +743,13 @@ cupsdDeletePrinter( cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update); + p->state = IPP_PRINTER_STOPPED; /* Force for browsed printers */ + if (p->job) cupsdSetJobState(p->job, IPP_JOB_PENDING, CUPSD_JOB_FORCE, update ? "Job stopped due to printer being deleted." : "Job stopped."); - /* - * If this printer is the next for browsing, point to the next one... - */ - - if (p == BrowseNext) - { - cupsArrayFind(Printers, p); - BrowseNext = (cupsd_printer_t *)cupsArrayNext(Printers); - } - /* * Remove the printer from the list... */ @@ -705,80 +758,54 @@ cupsdDeletePrinter( "cupsdDeletePrinter: Removing %s from Printers", p->name); cupsArrayRemove(Printers, p); - if (p->type & CUPS_PRINTER_IMPLICIT) - { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdDeletePrinter: Removing %s from ImplicitPrinters", - p->name); - cupsArrayRemove(ImplicitPrinters, p); - } - /* - * Remove the dummy interface/icon/option files under IRIX... + * If p is the default printer, assign a different one... */ -#ifdef __sgi - snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name); - unlink(filename); - - snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui", - p->name); - unlink(filename); + if (p == DefaultPrinter) + DefaultPrinter = NULL; - snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name); - unlink(filename); + /* + * Remove this printer from any classes... + */ - snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name); - unlink(filename); + changed = cupsdDeletePrinterFromClasses(p); - snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name); - unlink(filename); + /* + * Deregister from any browse protocols... + */ - snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name); - unlink(filename); -#endif /* __sgi */ + cupsdDeregisterPrinter(p, 1); /* - * If p is the default printer, assign a different one... + * Remove support files if this is a temporary queue and deregister color + * profiles... */ - if (p == DefaultPrinter) + if (p->temporary) { - DefaultPrinter = NULL; - - if (UseNetworkDefault) - { - /* - * Find the first network default printer and use it... - */ - - cupsd_printer_t *dp; /* New default printer */ + char filename[1024]; /* Script/PPD filename */ + /* + * Remove any old PPD or script files... + */ - for (dp = (cupsd_printer_t *)cupsArrayFirst(Printers); - dp; - dp = (cupsd_printer_t *)cupsArrayNext(Printers)) - if (dp != p && (dp->type & CUPS_PRINTER_DEFAULT)) - { - DefaultPrinter = dp; - break; - } - } - } + snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, p->name); + unlink(filename); + snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd.O", ServerRoot, p->name); + unlink(filename); - /* - * Remove this printer from any classes... - */ + snprintf(filename, sizeof(filename), "%s/%s.png", CacheDir, p->name); + unlink(filename); - if (!(p->type & CUPS_PRINTER_IMPLICIT)) - { - changed = cupsdDeletePrinterFromClasses(p); + snprintf(filename, sizeof(filename), "%s/%s.data", CacheDir, p->name); + unlink(filename); /* - * Deregister from any browse protocols... + * Unregister color profiles... */ - cupsdDeregisterPrinter(p, 1); + cupsdUnregisterColor(p); } /* @@ -788,14 +815,6 @@ cupsdDeletePrinter( if (p->printers != NULL) free(p->printers); - if (MaxPrinterHistory) - { - for (i = 0; i < p->num_history; i ++) - ippDelete(p->history[i]); - - free(p->history); - } - delete_printer_filters(p); for (i = 0; i < p->num_reasons; i ++) @@ -807,16 +826,14 @@ cupsdDeletePrinter( mimeDeleteType(MimeDatabase, p->filetype); mimeDeleteType(MimeDatabase, p->prefiltertype); - delete_string_array(&(p->filters)); - delete_string_array(&(p->pre_filters)); - - cupsdFreePrinterUsers(p); + cupsdFreeStrings(&(p->users)); cupsdFreeQuotas(p); cupsdClearString(&p->uri); cupsdClearString(&p->hostname); cupsdClearString(&p->name); cupsdClearString(&p->location); + cupsdClearString(&p->geo_location); cupsdClearString(&p->make_model); cupsdClearString(&p->info); cupsdClearString(&p->job_sheets[0]); @@ -826,20 +843,18 @@ cupsdDeletePrinter( cupsdClearString(&p->port_monitor); cupsdClearString(&p->op_policy); cupsdClearString(&p->error_policy); + cupsdClearString(&p->strings); cupsdClearString(&p->alert); cupsdClearString(&p->alert_description); -#ifdef HAVE_DNSSD - cupsdClearString(&p->product); +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) cupsdClearString(&p->pdl); -#endif /* HAVE_DNSSD */ + cupsdClearString(&p->reg_name); +#endif /* HAVE_DNSSD || HAVE_AVAHI */ cupsArrayDelete(p->filetypes); - if (p->browse_attrs) - free(p->browse_attrs); - cupsFreeOptions(p->num_options, p->options); free(p); @@ -854,6 +869,32 @@ cupsdDeletePrinter( } +/* + * 'cupsdDeleteTemporaryPrinters()' - Delete unneeded temporary printers. + */ + +void +cupsdDeleteTemporaryPrinters(int force) /* I - Force deletion instead of auto? */ +{ + cupsd_printer_t *p; /* Current printer */ + time_t unused_time; /* Last time for printer state change */ + + + /* + * Allow temporary printers to stick around for 60 seconds after the last job + * completes. + */ + + unused_time = time(NULL) - 60; + + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) + { + if (p->temporary && (force || p->state_time < unused_time)) + cupsdDeletePrinter(p, 0); + } +} + + /* * 'cupsdFindDest()' - Find a destination in the list. */ @@ -886,30 +927,6 @@ cupsdFindPrinter(const char *name) /* I - Name of printer to find */ } -/* - * 'cupsdFreePrinterUsers()' - Free allow/deny users. - */ - -void -cupsdFreePrinterUsers( - cupsd_printer_t *p) /* I - Printer */ -{ - int i; /* Looping var */ - - - if (!p || !p->num_users) - return; - - for (i = 0; i < p->num_users; i ++) - free((void *)p->users[i]); - - free(p->users); - - p->num_users = 0; - p->users = NULL; -} - - /* * 'cupsdLoadAllPrinters()' - Load printers from the printers.conf file. */ @@ -931,13 +948,8 @@ cupsdLoadAllPrinters(void) */ snprintf(line, sizeof(line), "%s/printers.conf", ServerRoot); - if ((fp = cupsFileOpen(line, "r")) == NULL) - { - if (errno != ENOENT) - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open %s - %s", line, - strerror(errno)); + if ((fp = cupsdOpenConfFile(line)) == NULL) return; - } /* * Read printer configurations until we hit EOF... @@ -952,8 +964,14 @@ cupsdLoadAllPrinters(void) * Decode the directive... */ - if (!strcasecmp(line, " 0) + NextPrinterId = i; + else + cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); + } + else if (!_cups_strcasecmp(line, " or @@ -975,14 +993,14 @@ cupsdLoadAllPrinters(void) * Set the default printer as needed... */ - if (!strcasecmp(line, "")) + else if (!_cups_strcasecmp(line, "") || !_cups_strcasecmp(line, "")) { if (p != NULL) { @@ -990,18 +1008,21 @@ cupsdLoadAllPrinters(void) * Close out the current printer... */ + if (!p->printer_id) + { + p->printer_id = NextPrinterId ++; + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); + } + cupsdSetPrinterAttrs(p); - cupsdAddPrinterHistory(p); - if (strncmp(p->device_uri, "file:", 5) && - p->state != IPP_PRINTER_STOPPED) + if (strncmp(p->device_uri, "file:", 5) && p->state != IPP_PRINTER_STOPPED) { /* * See if the backend exists... */ - snprintf(line, sizeof(line), "%s/backend/%s", ServerBin, - p->device_uri); + snprintf(line, sizeof(line), "%s/backend/%s", ServerBin, p->device_uri); if ((valueptr = strchr(line + strlen(ServerBin), ':')) != NULL) *valueptr = '\0'; /* Chop everything but URI scheme */ @@ -1013,8 +1034,7 @@ cupsdLoadAllPrinters(void) */ p->state = IPP_PRINTER_STOPPED; - snprintf(p->state_message, sizeof(p->state_message), - "Backend %s does not exist!", line); + snprintf(p->state_message, sizeof(p->state_message), "Backend %s does not exist!", line); } } @@ -1029,29 +1049,59 @@ cupsdLoadAllPrinters(void) cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); } - else if (!strcasecmp(line, "AuthInfoRequired")) + else if (!_cups_strcasecmp(line, "PrinterId")) + { + if (value && (i = atoi(value)) > 0) + p->printer_id = i; + else + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad PrinterId on line %d of printers.conf.", linenum); + } + else if (!_cups_strcasecmp(line, "UUID")) + { + if (value && !strncmp(value, "urn:uuid:", 9)) + cupsdSetString(&(p->uuid), value); + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Bad UUID on line %d of printers.conf.", linenum); + } + else if (!_cups_strcasecmp(line, "AuthInfoRequired")) { if (!cupsdSetAuthInfoRequired(p, value, NULL)) cupsdLogMessage(CUPSD_LOG_ERROR, "Bad AuthInfoRequired on line %d of printers.conf.", linenum); } - else if (!strcasecmp(line, "Info")) + else if (!_cups_strcasecmp(line, "Info")) { if (value) cupsdSetString(&p->info, value); } - else if (!strcasecmp(line, "MakeModel")) + else if (!_cups_strcasecmp(line, "MakeModel")) { if (value) cupsdSetString(&p->make_model, value); } - else if (!strcasecmp(line, "Location")) + else if (!_cups_strcasecmp(line, "Location")) { if (value) cupsdSetString(&p->location, value); } - else if (!strcasecmp(line, "DeviceURI")) + else if (!_cups_strcasecmp(line, "GeoLocation")) + { + if (value) + cupsdSetString(&p->geo_location, value); + } + else if (!_cups_strcasecmp(line, "Organization")) + { + if (value) + cupsdSetString(&p->organization, value); + } + else if (!_cups_strcasecmp(line, "OrganizationalUnit")) + { + if (value) + cupsdSetString(&p->organizational_unit, value); + } + else if (!_cups_strcasecmp(line, "DeviceURI")) { if (value) cupsdSetDeviceURI(p, value); @@ -1059,7 +1109,7 @@ cupsdLoadAllPrinters(void) cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); } - else if (!strcasecmp(line, "Option") && value) + else if (!_cups_strcasecmp(line, "Option") && value) { /* * Option name value @@ -1078,7 +1128,7 @@ cupsdLoadAllPrinters(void) &(p->options)); } } - else if (!strcasecmp(line, "PortMonitor")) + else if (!_cups_strcasecmp(line, "PortMonitor")) { if (value && strcmp(value, "none")) cupsdSetString(&p->port_monitor, value); @@ -1088,7 +1138,7 @@ cupsdLoadAllPrinters(void) cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); } - else if (!strcasecmp(line, "Reason")) + else if (!_cups_strcasecmp(line, "Reason")) { if (value && strcmp(value, "connecting-to-device") && @@ -1110,15 +1160,15 @@ cupsdLoadAllPrinters(void) cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); } - else if (!strcasecmp(line, "State")) + else if (!_cups_strcasecmp(line, "State")) { /* * Set the initial queue state... */ - if (value && !strcasecmp(value, "idle")) + if (value && !_cups_strcasecmp(value, "idle")) p->state = IPP_PRINTER_IDLE; - else if (value && !strcasecmp(value, "stopped")) + else if (value && !_cups_strcasecmp(value, "stopped")) { p->state = IPP_PRINTER_STOPPED; @@ -1137,7 +1187,7 @@ cupsdLoadAllPrinters(void) cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); } - else if (!strcasecmp(line, "StateMessage")) + else if (!_cups_strcasecmp(line, "StateMessage")) { /* * Set the initial queue state message... @@ -1146,7 +1196,7 @@ cupsdLoadAllPrinters(void) if (value) strlcpy(p->state_message, value, sizeof(p->state_message)); } - else if (!strcasecmp(line, "StateTime")) + else if (!_cups_strcasecmp(line, "StateTime")) { /* * Set the state time... @@ -1155,93 +1205,64 @@ cupsdLoadAllPrinters(void) if (value) p->state_time = atoi(value); } - else if (!strcasecmp(line, "Accepting")) + else if (!_cups_strcasecmp(line, "ConfigTime")) + { + /* + * Set the config time... + */ + + if (value) + p->config_time = atoi(value); + } + else if (!_cups_strcasecmp(line, "Accepting")) { /* * Set the initial accepting state... */ if (value && - (!strcasecmp(value, "yes") || - !strcasecmp(value, "on") || - !strcasecmp(value, "true"))) + (!_cups_strcasecmp(value, "yes") || + !_cups_strcasecmp(value, "on") || + !_cups_strcasecmp(value, "true"))) p->accepting = 1; else if (value && - (!strcasecmp(value, "no") || - !strcasecmp(value, "off") || - !strcasecmp(value, "false"))) + (!_cups_strcasecmp(value, "no") || + !_cups_strcasecmp(value, "off") || + !_cups_strcasecmp(value, "false"))) p->accepting = 0; else cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); } - else if (!strcasecmp(line, "Type")) - { - if (value) - p->type = atoi(value); - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of printers.conf.", linenum); - } - else if (!strcasecmp(line, "Product")) - { - if (value) - { -#ifdef HAVE_DNSSD - p->product = _cupsStrAlloc(value); -#endif /* HAVE_DNSSD */ - } - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of printers.conf.", linenum); - } - else if (!strcasecmp(line, "Filter")) - { - if (value) - { - if (!p->filters) - p->filters = cupsArrayNew(NULL, NULL); - - cupsArrayAdd(p->filters, _cupsStrAlloc(value)); - } - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of printers.conf.", linenum); - } - else if (!strcasecmp(line, "PreFilter")) + else if (!_cups_strcasecmp(line, "Type")) { if (value) - { - if (!p->pre_filters) - p->pre_filters = cupsArrayNew(NULL, NULL); - - cupsArrayAdd(p->pre_filters, _cupsStrAlloc(value)); - } + p->type = (cups_ptype_t)atoi(value); else cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); } - else if (!strcasecmp(line, "Shared")) + else if (!_cups_strcasecmp(line, "Shared")) { /* * Set the initial shared state... */ if (value && - (!strcasecmp(value, "yes") || - !strcasecmp(value, "on") || - !strcasecmp(value, "true"))) + (!_cups_strcasecmp(value, "yes") || + !_cups_strcasecmp(value, "on") || + !_cups_strcasecmp(value, "true"))) p->shared = 1; else if (value && - (!strcasecmp(value, "no") || - !strcasecmp(value, "off") || - !strcasecmp(value, "false"))) + (!_cups_strcasecmp(value, "no") || + !_cups_strcasecmp(value, "off") || + !_cups_strcasecmp(value, "false"))) p->shared = 0; else cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); } - else if (!strcasecmp(line, "JobSheets")) + else if (!_cups_strcasecmp(line, "JobSheets")) { /* * Set the initial job sheets... @@ -1273,29 +1294,29 @@ cupsdLoadAllPrinters(void) cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); } - else if (!strcasecmp(line, "AllowUser")) + else if (!_cups_strcasecmp(line, "AllowUser")) { if (value) { p->deny_users = 0; - cupsdAddPrinterUser(p, value); + cupsdAddString(&(p->users), value); } else cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); } - else if (!strcasecmp(line, "DenyUser")) + else if (!_cups_strcasecmp(line, "DenyUser")) { if (value) { p->deny_users = 1; - cupsdAddPrinterUser(p, value); + cupsdAddString(&(p->users), value); } else cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); } - else if (!strcasecmp(line, "QuotaPeriod")) + else if (!_cups_strcasecmp(line, "QuotaPeriod")) { if (value) p->quota_period = atoi(value); @@ -1303,7 +1324,7 @@ cupsdLoadAllPrinters(void) cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); } - else if (!strcasecmp(line, "PageLimit")) + else if (!_cups_strcasecmp(line, "PageLimit")) { if (value) p->page_limit = atoi(value); @@ -1311,7 +1332,7 @@ cupsdLoadAllPrinters(void) cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); } - else if (!strcasecmp(line, "KLimit")) + else if (!_cups_strcasecmp(line, "KLimit")) { if (value) p->k_limit = atoi(value); @@ -1319,7 +1340,7 @@ cupsdLoadAllPrinters(void) cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); } - else if (!strcasecmp(line, "OpPolicy")) + else if (!_cups_strcasecmp(line, "OpPolicy")) { if (value) { @@ -1340,15 +1361,22 @@ cupsdLoadAllPrinters(void) cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); } - else if (!strcasecmp(line, "ErrorPolicy")) + else if (!_cups_strcasecmp(line, "ErrorPolicy")) { if (value) - cupsdSetString(&p->error_policy, value); + { + if (strcmp(value, "retry-current-job") && + strcmp(value, "abort-job") && + strcmp(value, "retry-job") && + strcmp(value, "stop-printer")) + cupsdLogMessage(CUPSD_LOG_ALERT, "Invalid ErrorPolicy \"%s\" on line %d or printers.conf.", ErrorPolicy, linenum); + else + cupsdSetString(&p->error_policy, value); + } else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of printers.conf.", linenum); + cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); } - else if (!strcasecmp(line, "Attribute") && value) + else if (!_cups_strcasecmp(line, "Attribute") && value) { for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++); @@ -1368,15 +1396,18 @@ cupsdLoadAllPrinters(void) cupsdSetPrinterAttr(p, value, valueptr); } } - else + else if (_cups_strcasecmp(line, "Filter") && + _cups_strcasecmp(line, "Prefilter") && + _cups_strcasecmp(line, "Product")) { /* - * Something else we don't understand... + * Something else we don't understand (and that wasn't used in a prior + * release of CUPS... */ cupsdLogMessage(CUPSD_LOG_ERROR, - "Unknown configuration directive %s on line %d of printers.conf.", - line, linenum); + "Unknown configuration directive %s on line %d of " + "printers.conf.", line, linenum); } } @@ -1401,14 +1432,6 @@ cupsdRenamePrinter( "cupsdRenamePrinter: Removing %s from Printers", p->name); cupsArrayRemove(Printers, p); - if (p->type & CUPS_PRINTER_IMPLICIT) - { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdRenamePrinter: Removing %s from ImplicitPrinters", - p->name); - cupsArrayRemove(ImplicitPrinters, p); - } - /* * Rename the printer type... */ @@ -1416,8 +1439,11 @@ cupsdRenamePrinter( mimeDeleteType(MimeDatabase, p->filetype); p->filetype = mimeAddType(MimeDatabase, "printer", name); - mimeDeleteType(MimeDatabase, p->prefiltertype); - p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", name); + if (p->prefiltertype) + { + mimeDeleteType(MimeDatabase, p->prefiltertype); + p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", name); + } /* * Rename the printer... @@ -1438,14 +1464,6 @@ cupsdRenamePrinter( cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdRenamePrinter: Adding %s to Printers", p->name); cupsArrayAdd(Printers, p); - - if (p->type & CUPS_PRINTER_IMPLICIT) - { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdRenamePrinter: Adding %s to ImplicitPrinters", - p->name); - cupsArrayAdd(ImplicitPrinters, p); - } } @@ -1459,10 +1477,11 @@ cupsdSaveAllPrinters(void) { int i; /* Looping var */ cups_file_t *fp; /* printers.conf file */ - char temp[1024], /* Temporary string */ - backup[1024], /* printers.conf.O file */ + char filename[1024], /* printers.conf filename */ + temp[1024], /* Temporary string */ value[2048], /* Value string */ - *ptr; /* Pointer into value */ + *ptr, /* Pointer into value */ + *name; /* Current user/group name */ cupsd_printer_t *printer; /* Current printer class */ time_t curtime; /* Current time */ struct tm *curdate; /* Current date */ @@ -1474,35 +1493,12 @@ cupsdSaveAllPrinters(void) * Create the printers.conf file... */ - snprintf(temp, sizeof(temp), "%s/printers.conf", ServerRoot); - snprintf(backup, sizeof(backup), "%s/printers.conf.O", ServerRoot); + snprintf(filename, sizeof(filename), "%s/printers.conf", ServerRoot); - if (rename(temp, backup)) - { - if (errno != ENOENT) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to backup printers.conf - %s", strerror(errno)); - } + if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm & 0600)) == NULL) + return; - if ((fp = cupsFileOpen(temp, "w")) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to save printers.conf - %s", strerror(errno)); - - if (rename(backup, temp)) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to restore printers.conf - %s", strerror(errno)); - return; - } - else - cupsdLogMessage(CUPSD_LOG_INFO, "Saving printers.conf..."); - - /* - * Restrict access to the file... - */ - - fchown(cupsFileNumber(fp), getuid(), Group); - fchmod(cupsFileNumber(fp), 0600); + cupsdLogMessage(CUPSD_LOG_INFO, "Saving printers.conf..."); /* * Write a small header to the file... @@ -1516,6 +1512,8 @@ cupsdSaveAllPrinters(void) cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp); cupsFilePuts(fp, "# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING\n"); + cupsFilePrintf(fp, "NextPrinterId %d\n", NextPrinterId); + /* * Write each local printer known to the system... */ @@ -1525,12 +1523,10 @@ cupsdSaveAllPrinters(void) printer = (cupsd_printer_t *)cupsArrayNext(Printers)) { /* - * Skip remote destinations and printer classes... + * Skip printer classes and temporary queues... */ - if ((printer->type & CUPS_PRINTER_DISCOVERED) || - (printer->type & CUPS_PRINTER_CLASS) || - (printer->type & CUPS_PRINTER_IMPLICIT)) + if ((printer->type & CUPS_PRINTER_CLASS) || printer->temporary) continue; /* @@ -1542,6 +1538,11 @@ cupsdSaveAllPrinters(void) else cupsFilePrintf(fp, "\n", printer->name); + if (printer->printer_id) + cupsFilePrintf(fp, "PrinterId %d\n", printer->printer_id); + + cupsFilePrintf(fp, "UUID %s\n", printer->uuid); + if (printer->num_auth_info_required > 0) { switch (printer->num_auth_info_required) @@ -1574,9 +1575,18 @@ cupsdSaveAllPrinters(void) if (printer->location) cupsFilePutConf(fp, "Location", printer->location); + if (printer->geo_location) + cupsFilePutConf(fp, "GeoLocation", printer->geo_location); + if (printer->make_model) cupsFilePutConf(fp, "MakeModel", printer->make_model); + if (printer->organization) + cupsFilePutConf(fp, "Organization", printer->organization); + + if (printer->organizational_unit) + cupsFilePutConf(fp, "OrganizationalUnit", printer->organizational_unit); + cupsFilePutConf(fp, "DeviceURI", printer->device_uri); if (printer->port_monitor) @@ -1586,13 +1596,14 @@ cupsdSaveAllPrinters(void) { cupsFilePuts(fp, "State Stopped\n"); - if (printer->state_message) + if (printer->state_message[0]) cupsFilePutConf(fp, "StateMessage", printer->state_message); } else cupsFilePuts(fp, "State Idle\n"); cupsFilePrintf(fp, "StateTime %d\n", (int)printer->state_time); + cupsFilePrintf(fp, "ConfigTime %d\n", (int)printer->config_time); for (i = 0; i < printer->num_reasons; i ++) if (strcmp(printer->reasons[i], "connecting-to-device") && @@ -1602,21 +1613,6 @@ cupsdSaveAllPrinters(void) cupsFilePrintf(fp, "Type %d\n", printer->type); -#ifdef HAVE_DNSSD - if (printer->product) - cupsFilePutConf(fp, "Product", printer->product); -#endif /* HAVE_DNSSD */ - - for (ptr = (char *)cupsArrayFirst(printer->filters); - ptr; - ptr = (char *)cupsArrayNext(printer->filters)) - cupsFilePutConf(fp, "Filter", ptr); - - for (ptr = (char *)cupsArrayFirst(printer->pre_filters); - ptr; - ptr = (char *)cupsArrayNext(printer->pre_filters)) - cupsFilePutConf(fp, "PreFilter", ptr); - if (printer->accepting) cupsFilePuts(fp, "Accepting Yes\n"); else @@ -1635,9 +1631,10 @@ cupsdSaveAllPrinters(void) cupsFilePrintf(fp, "PageLimit %d\n", printer->page_limit); cupsFilePrintf(fp, "KLimit %d\n", printer->k_limit); - for (i = 0; i < printer->num_users; i ++) - cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser", - printer->users[i]); + for (name = (char *)cupsArrayFirst(printer->users); + name; + name = (char *)cupsArrayNext(printer->users)) + cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser", name); if (printer->op_policy) cupsFilePutConf(fp, "OpPolicy", printer->op_policy); @@ -1664,8 +1661,7 @@ cupsdSaveAllPrinters(void) if (i) *ptr++ = ','; - strlcpy(ptr, marker->values[i].string.text, - value + sizeof(value) - ptr); + strlcpy(ptr, marker->values[i].string.text, (size_t)(value + sizeof(value) - ptr)); ptr += strlen(ptr); } @@ -1724,8 +1720,7 @@ cupsdSaveAllPrinters(void) if (i) *ptr++ = ','; - strlcpy(ptr, marker->values[i].string.text, - value + sizeof(value) - ptr); + strlcpy(ptr, marker->values[i].string.text, (size_t)(value + sizeof(value) - ptr)); ptr += strlen(ptr); } @@ -1745,8 +1740,7 @@ cupsdSaveAllPrinters(void) if (i) *ptr++ = ','; - strlcpy(ptr, marker->values[i].string.text, - value + sizeof(value) - ptr); + strlcpy(ptr, marker->values[i].string.text, (size_t)(value + sizeof(value) - ptr)); ptr += strlen(ptr); } @@ -1758,18 +1752,13 @@ cupsdSaveAllPrinters(void) cupsFilePrintf(fp, "Attribute marker-change-time %ld\n", (long)printer->marker_time); - cupsFilePuts(fp, "\n"); - -#ifdef __sgi - /* - * Make IRIX desktop & printer status happy - */ - - write_irix_state(printer); -#endif /* __sgi */ + if (printer == DefaultPrinter) + cupsFilePuts(fp, "\n"); + else + cupsFilePuts(fp, "\n"); } - cupsFileClose(fp); + cupsdCloseCreatedConfFile(fp, filename); } @@ -1823,6 +1812,16 @@ cupsdSetAuthInfoRequired( p->auth_info_required[p->num_auth_info_required] = "negotiate"; p->num_auth_info_required ++; + + /* + * Don't allow sharing of queues that require Kerberos authentication. + */ + + if (p->shared) + { + cupsdDeregisterPrinter(p, 1); + p->shared = 0; + } } else if ((end - values) == 6 && !strncmp(values, "domain", 6)) { @@ -1859,7 +1858,7 @@ cupsdSetAuthInfoRequired( strcmp(p->auth_info_required[0], "none")) p->type |= CUPS_PRINTER_AUTHENTICATED; else - p->type &= ~CUPS_PRINTER_AUTHENTICATED; + p->type &= (cups_ptype_t)~CUPS_PRINTER_AUTHENTICATED; return (1); } @@ -1871,16 +1870,6 @@ cupsdSetAuthInfoRequired( if (!attr || attr->num_values > 4) return (0); - /* - * Update the printer-type value as needed... - */ - - if (attr->num_values > 1 || - strcmp(attr->values[0].string.text, "none")) - p->type |= CUPS_PRINTER_AUTHENTICATED; - else - p->type &= ~CUPS_PRINTER_AUTHENTICATED; - for (i = 0; i < attr->num_values; i ++) { if (!strcmp(attr->values[i].string.text, "none")) @@ -1901,6 +1890,16 @@ cupsdSetAuthInfoRequired( p->auth_info_required[p->num_auth_info_required] = "negotiate"; p->num_auth_info_required ++; + /* + * Don't allow sharing of queues that require Kerberos authentication. + */ + + if (p->shared) + { + cupsdDeregisterPrinter(p, 1); + p->shared = 0; + } + return (1); } else if (!strcmp(attr->values[i].string.text, "domain")) @@ -2002,12 +2001,15 @@ void cupsdSetPrinterAttr( cupsd_printer_t *p, /* I - Printer */ const char *name, /* I - Attribute name */ - char *value) /* I - Attribute value string */ + const char *value) /* I - Attribute value string */ { ipp_attribute_t *attr; /* Attribute */ int i, /* Looping var */ count; /* Number of values */ - char *ptr; /* Pointer into value */ + char *temp, /* Temporary copy of value string */ + *ptr, /* Pointer into value */ + *start, /* Start of value */ + quote; /* Quote character */ ipp_tag_t value_tag; /* Value tag for this attribute */ @@ -2021,13 +2023,36 @@ cupsdSetPrinterAttr( return; } + /* + * Copy the value string so we can do what we want with it... + */ + + if ((temp = strdup(value)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to duplicate value for \"%s\" attribute.", name); + return; + } + /* * Count the number of values... */ - for (count = 1, ptr = value; - (ptr = strchr(ptr, ',')) != NULL; - ptr ++, count ++); + for (count = 1, quote = '\0', ptr = temp; + *ptr; + ptr ++) + { + if (*ptr == quote) + quote = '\0'; + else if (quote) + continue; + else if (*ptr == '\\' && ptr[1]) + ptr ++; + else if (*ptr == '\'' || *ptr == '\"') + quote = *ptr; + else if (*ptr == ',') + count ++; + } /* * Then add or update the attribute as needed... @@ -2055,21 +2080,22 @@ cupsdSetPrinterAttr( if (!attr) { + free(temp); cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to allocate memory for printer attribute " "(%d values)", count); return; } - for (i = 0; i < count; i ++) + for (i = 0, start = temp; i < count; i ++) { - if ((ptr = strchr(value, ',')) != NULL) + if ((ptr = strchr(start, ',')) != NULL) *ptr++ = '\0'; - attr->values[i].integer = strtol(value, NULL, 10); + attr->values[i].integer = strtol(start, NULL, 10); if (ptr) - value = ptr; + start = ptr; } } else @@ -2105,21 +2131,113 @@ cupsdSetPrinterAttr( if (!attr) { + free(temp); cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to allocate memory for printer attribute " "(%d values)", count); return; } + for (i = 0, quote = '\0', ptr = temp; i < count; i ++) + { + for (start = ptr; *ptr; ptr ++) + { + if (*ptr == quote) + *ptr = quote = '\0'; + else if (quote) + continue; + else if (*ptr == '\\' && ptr[1]) + _cups_strcpy(ptr, ptr + 1); + else if (*ptr == '\'' || *ptr == '\"') + { + quote = *ptr; + + if (ptr == start) + start ++; + else + _cups_strcpy(ptr, ptr + 1); + } + else if (*ptr == ',') + { + *ptr++ = '\0'; + break; + } + } + + attr->values[i].string.text = _cupsStrAlloc(start); + } + } + + free(temp); + + /* + * Update the printer-supply and printer-supply-description, as needed... + */ + + if (!strcmp(name, "marker-names")) + { + ipp_attribute_t *supply_desc = ippFindAttribute(p->attrs, "printer-supply-description", IPP_TAG_TEXT); + /* printer-supply-description attribute */ + + if (supply_desc != NULL) + ippDeleteAttribute(p->attrs, supply_desc); + + supply_desc = ippCopyAttribute(p->attrs, attr, 0); + ippSetName(p->attrs, &supply_desc, "printer-supply-description"); + ippSetValueTag(p->attrs, &supply_desc, IPP_TAG_TEXT); + } + else if (!strcmp(name, "marker-colors") || !strcmp(name, "marker-levels") || !strcmp(name, "marker-types")) + { + char buffer[256], /* printer-supply values */ + pstype[64], /* printer-supply type value */ + *psptr; /* Pointer into type */ + const char *color, /* marker-colors value */ + *type; /* marker-types value */ + int level; /* marker-levels value */ + ipp_attribute_t *colors = ippFindAttribute(p->attrs, "marker-colors", IPP_TAG_NAME); + /* marker-colors attribute */ + ipp_attribute_t *levels = ippFindAttribute(p->attrs, "marker-levels", IPP_TAG_INTEGER); + /* marker-levels attribute */ + ipp_attribute_t *types = ippFindAttribute(p->attrs, "marker-types", IPP_TAG_KEYWORD); + /* marker-types attribute */ + ipp_attribute_t *supply = ippFindAttribute(p->attrs, "printer-supply", IPP_TAG_STRING); + /* printer-supply attribute */ + + if (supply != NULL) + { + ippDeleteAttribute(p->attrs, supply); + supply = NULL; + } + + if (!colors || !levels || !types) + return; + + count = ippGetCount(colors); + if (count != ippGetCount(levels) || count != ippGetCount(types)) + return; + for (i = 0; i < count; i ++) { - if ((ptr = strchr(value, ',')) != NULL) - *ptr++ = '\0'; + color = ippGetString(colors, i, NULL); + level = ippGetInteger(levels, i); + type = ippGetString(types, i, NULL); + + for (psptr = pstype; *type && psptr < (pstype + sizeof(pstype) - 1); type ++) + if (*type == '-') + { + type ++; + *psptr++ = (char)toupper(*type & 255); + } + else + *psptr++ = *type; + *psptr = '\0'; - attr->values[i].string.text = _cupsStrAlloc(value); + snprintf(buffer, sizeof(buffer), "index=%d;class=%s;type=%s;unit=percent;maxcapacity=100;level=%d;colorantname=%s;", i + 1, strncmp(pstype, "waste", 5) ? "supplyThatIsConsumed" : "receptacleThatIsFilled", pstype, level, color); - if (ptr) - value = ptr; + if (!i) + supply = ippAddOctetString(p->attrs, IPP_TAG_PRINTER, "printer-supply", buffer, (int)strlen(buffer)); + else + ippSetOctetString(p->attrs, &supply, i, buffer, (int)strlen(buffer)); } } } @@ -2132,26 +2250,14 @@ cupsdSetPrinterAttr( void cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ { - int i, /* Looping var */ - length; /* Length of browse attributes */ + int i; /* Looping var */ char resource[HTTP_MAX_URI]; /* Resource portion of URI */ - int num_air; /* Number of auth-info-required values */ - const char * const *air; /* auth-info-required values */ cupsd_location_t *auth; /* Pointer to authentication element */ const char *auth_supported; /* Authentication supported */ ipp_t *oldattrs; /* Old printer attributes */ ipp_attribute_t *attr; /* Attribute data */ - cups_option_t *option; /* Current printer option */ - char *filter; /* Current filter */ - static const char * const air_none[] = - { /* No authentication */ - "none" - }; - static const char * const air_userpass[] = - { /* Basic/Digest authentication */ - "username", - "password" - }; + char *name, /* Current user/group name */ + *filter; /* Current filter */ DEBUG_printf(("cupsdSetPrinterAttrs: entering name = %s, type = %x\n", p->name, @@ -2164,6 +2270,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ if (!CommonData) cupsdCreateCommonData(); + _cupsRWLockWrite(&p->lock); + /* * Clear out old filters, if any... */ @@ -2175,20 +2283,6 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ */ auth_supported = "requesting-user-name"; - num_air = 1; - air = air_none; - - if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none")) - { - num_air = p->num_auth_info_required; - air = p->auth_info_required; - } - else if ((p->type & CUPS_PRINTER_AUTHENTICATED) && - (p->type & CUPS_PRINTER_DISCOVERED)) - { - num_air = 2; - air = air_userpass; - } if (p->type & CUPS_PRINTER_CLASS) snprintf(resource, sizeof(resource), "/classes/%s", p->name); @@ -2205,27 +2299,22 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT) - auth_type = DefaultAuthType; + auth_type = cupsdDefaultAuthType(); - if (auth_type == CUPSD_AUTH_BASIC || auth_type == CUPSD_AUTH_BASICDIGEST) + if (auth_type == CUPSD_AUTH_BASIC) auth_supported = "basic"; - else if (auth_type == CUPSD_AUTH_DIGEST) - auth_supported = "digest"; #ifdef HAVE_GSSAPI else if (auth_type == CUPSD_AUTH_NEGOTIATE) auth_supported = "negotiate"; #endif /* HAVE_GSSAPI */ - if (!(p->type & CUPS_PRINTER_DISCOVERED)) - { - if (auth_type != CUPSD_AUTH_NONE) - p->type |= CUPS_PRINTER_AUTHENTICATED; - else - p->type &= ~CUPS_PRINTER_AUTHENTICATED; - } + if (auth_type != CUPSD_AUTH_NONE) + p->type |= CUPS_PRINTER_AUTHENTICATED; + else + p->type &= (cups_ptype_t)~CUPS_PRINTER_AUTHENTICATED; } - else if (!(p->type & CUPS_PRINTER_DISCOVERED)) - p->type &= ~CUPS_PRINTER_AUTHENTICATED; + else + p->type &= (cups_ptype_t)~CUPS_PRINTER_AUTHENTICATED; /* * Create the required IPP attributes for a printer... @@ -2238,23 +2327,37 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ "uri-authentication-supported", NULL, auth_supported); ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "uri-security-supported", NULL, "none"); + if (p->printer_id) + ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-id", p->printer_id); ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL, p->name); ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location", NULL, p->location ? p->location : ""); + if (p->geo_location) + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-geo-location", NULL, p->geo_location); + else + ippAddOutOfBand(p->attrs, IPP_TAG_PRINTER, IPP_TAG_UNKNOWN, "printer-geo-location"); ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", NULL, p->info ? p->info : ""); + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-organization", NULL, p->organization ? p->organization : ""); + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-organizational-unit", NULL, p->organizational_unit ? p->organizational_unit : ""); + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uuid", NULL, p->uuid); - if (p->num_users) + if (cupsArrayCount(p->users) > 0) { if (p->deny_users) - ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, - "requesting-user-name-denied", p->num_users, NULL, - p->users); + attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, + "requesting-user-name-denied", + cupsArrayCount(p->users), NULL, NULL); else - ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, - "requesting-user-name-allowed", p->num_users, NULL, - p->users); + attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, + "requesting-user-name-allowed", + cupsArrayCount(p->users), NULL, NULL); + + for (i = 0, name = (char *)cupsArrayFirst(p->users); + name; + i ++, name = (char *)cupsArrayNext(p->users)) + attr->values[i].string.text = _cupsStrAlloc(name); } ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, @@ -2263,10 +2366,12 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ "job-k-limit", p->k_limit); ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-page-limit", p->page_limit); - ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "auth-info-required", num_air, NULL, air); + if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none")) + ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "auth-info-required", p->num_auth_info_required, NULL, + p->auth_info_required); - if (cupsArrayCount(Banners) > 0 && !(p->type & CUPS_PRINTER_DISCOVERED)) + if (cupsArrayCount(Banners) > 0) { /* * Setup the job-sheets-default attribute... @@ -2287,110 +2392,99 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ p->raw = 0; p->remote = 0; - if (p->type & CUPS_PRINTER_DISCOVERED) + /* + * Assign additional attributes depending on whether this is a printer + * or class... + */ + + if (p->type & CUPS_PRINTER_CLASS) { + p->raw = 1; + p->type &= (cups_ptype_t)~CUPS_PRINTER_OPTIONS; + /* - * Tell the client this is a remote printer of some type... + * Add class-specific attributes... */ - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, - "printer-uri-supported", NULL, p->uri); + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, + "printer-make-and-model", NULL, "Local Printer Class"); + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, + "file:///dev/null"); - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info", - NULL, p->uri); + if (p->num_printers > 0) + { + /* + * Add a list of member names; URIs are added in copy_printer_attrs... + */ - if (p->make_model) - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "printer-make-and-model", NULL, p->make_model); + attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, + "member-names", p->num_printers, NULL, NULL); + p->type |= CUPS_PRINTER_OPTIONS; - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, - p->uri); + for (i = 0; i < p->num_printers; i ++) + { + if (attr != NULL) + attr->values[i].string.text = _cupsStrAlloc(p->printers[i]->name); - p->raw = 1; - p->remote = 1; + p->type &= (cups_ptype_t)~CUPS_PRINTER_OPTIONS | p->printers[i]->type; + } + } } else { /* - * Assign additional attributes depending on whether this is a printer - * or class... + * Add printer-specific attributes... */ - if (p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) - { - p->raw = 1; - p->type &= ~CUPS_PRINTER_OPTIONS; - - /* - * Add class-specific attributes... - */ - - if ((p->type & CUPS_PRINTER_IMPLICIT) && p->num_printers > 0 && - p->printers[0]->make_model) - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "printer-make-and-model", NULL, p->printers[0]->make_model); - else - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "printer-make-and-model", NULL, "Local Printer Class"); + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, + p->sanitized_device_uri); - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, - "file:///dev/null"); + /* + * Assign additional attributes from the PPD file (if any)... + */ - if (p->num_printers > 0) - { - /* - * Add a list of member names; URIs are added in copy_printer_attrs... - */ + load_ppd(p); - attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, - "member-names", p->num_printers, NULL, NULL); - p->type |= CUPS_PRINTER_OPTIONS; + /* + * Add filters for printer... + */ - for (i = 0; i < p->num_printers; i ++) - { - if (attr != NULL) - attr->values[i].string.text = _cupsStrRetain(p->printers[i]->name); + cupsdSetPrinterReasons(p, "-cups-missing-filter-warning," + "cups-insecure-filter-warning"); - p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type; - } - } + if (p->pc && p->pc->filters) + { + for (filter = (char *)cupsArrayFirst(p->pc->filters); + filter; + filter = (char *)cupsArrayNext(p->pc->filters)) + add_printer_filter(p, p->filetype, filter); } - else + else if (!(p->type & CUPS_PRINTER_REMOTE)) { /* - * Add printer-specific attributes... + * Add a filter from application/vnd.cups-raw to printer/name to + * handle "raw" printing by users. */ - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, - p->sanitized_device_uri); + add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -"); /* - * Assign additional attributes from the PPD file (if any)... + * Add a PostScript filter, since this is still possibly PS printer. */ - load_ppd(p); - - /* - * Add filters for printer... - */ + add_printer_filter(p, p->filetype, + "application/vnd.cups-postscript 0 -"); + } - cupsdSetPrinterReasons(p, "-cups-missing-filter-warning," - "cups-insecure-filter-warning"); + if (p->pc && p->pc->prefilters) + { + if (!p->prefiltertype) + p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name); - for (filter = (char *)cupsArrayFirst(p->filters); + for (filter = (char *)cupsArrayFirst(p->pc->prefilters); filter; - filter = (char *)cupsArrayNext(p->filters)) - add_printer_filter(p, p->filetype, filter); - - if (p->pre_filters) - { - p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name); - - for (filter = (char *)cupsArrayFirst(p->pre_filters); - filter; - filter = (char *)cupsArrayNext(p->pre_filters)) - add_printer_filter(p, p->prefiltertype, filter); - } + filter = (char *)cupsArrayNext(p->pc->prefilters)) + add_printer_filter(p, p->prefiltertype, filter); } } @@ -2412,7 +2506,7 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ { for (i = 0; i < oldattr->num_values; i ++) attr->values[i].string.text = - _cupsStrRetain(oldattr->values[i].string.text); + _cupsStrAlloc(oldattr->values[i].string.text); } } @@ -2466,7 +2560,7 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ { for (i = 0; i < oldattr->num_values; i ++) attr->values[i].string.text = - _cupsStrRetain(oldattr->values[i].string.text); + _cupsStrAlloc(oldattr->values[i].string.text); } } @@ -2479,7 +2573,7 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ { for (i = 0; i < oldattr->num_values; i ++) attr->values[i].string.text = - _cupsStrRetain(oldattr->values[i].string.text); + _cupsStrAlloc(oldattr->values[i].string.text); } } @@ -2490,98 +2584,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ * Force sharing off for remote queues... */ - if (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) + if (p->type & CUPS_PRINTER_REMOTE) p->shared = 0; - else - { - /* - * Copy the printer options into a browse attributes string we can re-use. - */ - - const char *valptr; /* Pointer into value */ - char *attrptr; /* Pointer into attribute string */ - - - /* - * Free the old browse attributes as needed... - */ - - if (p->browse_attrs) - free(p->browse_attrs); - - /* - * Compute the length of all attributes + job-sheets, lease-duration, - * and BrowseLocalOptions. - */ - - for (length = 1, i = p->num_options, option = p->options; - i > 0; - i --, option ++) - { - length += strlen(option->name) + 2; - - if (option->value) - { - for (valptr = option->value; *valptr; valptr ++) - if (strchr(" \"\'\\", *valptr)) - length += 2; - else - length ++; - } - } - - length += 13 + strlen(p->job_sheets[0]) + strlen(p->job_sheets[1]); - length += 32; - if (BrowseLocalOptions) - length += 12 + strlen(BrowseLocalOptions); - - /* - * Allocate the new string... - */ - - if ((p->browse_attrs = calloc(1, length)) == NULL) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate %d bytes for browse data!", - length); - else - { - /* - * Got the allocated string, now copy the options and attributes over... - */ - - sprintf(p->browse_attrs, "job-sheets=%s,%s lease-duration=%d", - p->job_sheets[0], p->job_sheets[1], BrowseTimeout); - attrptr = p->browse_attrs + strlen(p->browse_attrs); - - if (BrowseLocalOptions) - { - sprintf(attrptr, " ipp-options=%s", BrowseLocalOptions); - attrptr += strlen(attrptr); - } - - for (i = p->num_options, option = p->options; - i > 0; - i --, option ++) - { - *attrptr++ = ' '; - strcpy(attrptr, option->name); - attrptr += strlen(attrptr); - - if (option->value) - { - *attrptr++ = '='; - - for (valptr = option->value; *valptr; valptr ++) - { - if (strchr(" \"\'\\", *valptr)) - *attrptr++ = '\\'; - - *attrptr++ = *valptr; - } - } - } - } - } /* * Populate the document-format-supported attribute... @@ -2598,14 +2602,7 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ add_printer_defaults(p); -#ifdef __sgi - /* - * Write the IRIX printer config and status files... - */ - - write_irix_config(p); - write_irix_state(p); -#endif /* __sgi */ + _cupsRWUnlock(&p->lock); /* * Let the browse protocols reflect the change @@ -2621,8 +2618,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ int /* O - 1 if something changed, 0 otherwise */ cupsdSetPrinterReasons( - cupsd_printer_t *p, /* I - Printer */ - const char *s) /* I - Reasons strings */ + cupsd_printer_t *p, /* I - Printer */ + const char *s) /* I - Reasons strings */ { int i, /* Looping var */ changed = 0; /* Did something change? */ @@ -2656,10 +2653,7 @@ cupsdSetPrinterReasons( p->num_reasons = 0; changed = 1; - cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); - - if (PrintcapFormat == PRINTCAP_PLIST) - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); + dirty_printer(p); } if (!strcmp(s, "none")) @@ -2705,19 +2699,17 @@ cupsdSetPrinterReasons( _cupsStrFree(p->reasons[i]); if (i < p->num_reasons) - memmove(p->reasons + i, p->reasons + i + 1, - (p->num_reasons - i) * sizeof(char *)); + memmove(p->reasons + i, p->reasons + i + 1, (size_t)(p->num_reasons - i) * sizeof(char *)); if (!strcmp(reason, "paused") && p->state == IPP_PRINTER_STOPPED) cupsdSetPrinterState(p, IPP_PRINTER_IDLE, 1); + if (!strcmp(reason, "cups-waiting-for-job-completed") && p->job) + p->job->completed = 0; + if (strcmp(reason, "connecting-to-device")) - { - cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); + dirty_printer(p); - if (PrintcapFormat == PRINTCAP_PLIST) - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); - } break; } } @@ -2748,13 +2740,11 @@ cupsdSetPrinterReasons( if (!strcmp(reason, "paused") && p->state != IPP_PRINTER_STOPPED) cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 1); - if (strcmp(reason, "connecting-to-device")) - { - cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); + if (!strcmp(reason, "cups-waiting-for-job-completed") && p->job) + p->job->completed = 1; - if (PrintcapFormat == PRINTCAP_PLIST) - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); - } + if (strcmp(reason, "connecting-to-device")) + dirty_printer(p); } } } @@ -2773,6 +2763,7 @@ cupsdSetPrinterState( ipp_pstate_t s, /* I - New state */ int update) /* I - Update printers.conf? */ { + cupsd_job_t *job; /* Current job */ ipp_pstate_t old_state; /* Old printer state */ static const char * const printer_states[] = { /* State strings */ @@ -2782,20 +2773,10 @@ cupsdSetPrinterState( }; - /* - * Can't set status of remote printers... - */ - - if (p->type & CUPS_PRINTER_DISCOVERED) - return; - /* * Set the new state... */ - if (PrintcapFormat == PRINTCAP_PLIST) - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); - old_state = p->state; p->state = s; @@ -2805,19 +2786,13 @@ cupsdSetPrinterState( CUPSD_EVENT_PRINTER_STATE, p, NULL, "%s \"%s\" state changed to %s.", (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer", - p->name, printer_states[p->state]); + p->name, printer_states[p->state - IPP_PRINTER_IDLE]); /* * Let the browse code know this needs to be updated... */ - BrowseNext = p; - p->state_time = time(NULL); - p->browse_time = 0; - -#ifdef __sgi - write_irix_state(p); -#endif /* __sgi */ + p->state_time = time(NULL); } /* @@ -2829,6 +2804,17 @@ cupsdSetPrinterState( else cupsdSetPrinterReasons(p, "-paused"); + if (old_state != s) + { + for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); + job; + job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) + if (job->reasons && job->state_value == IPP_JOB_PENDING && + !_cups_strcasecmp(job->dest, p->name)) + ippSetString(job->attrs, &job->reasons, 0, + s == IPP_PRINTER_STOPPED ? "printer-stopped" : "none"); + } + /* * Clear the message for the queue when going to processing... */ @@ -2836,12 +2822,6 @@ cupsdSetPrinterState( if (s == IPP_PRINTER_PROCESSING) p->state_message[0] = '\0'; - /* - * Update the printer history... - */ - - cupsdAddPrinterHistory(p); - /* * Let the browse protocols reflect the change... */ @@ -2856,12 +2836,7 @@ cupsdSetPrinterState( if (update && (old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED)) - { - if (p->type & CUPS_PRINTER_CLASS) - cupsdMarkDirty(CUPSD_DIRTY_CLASSES); - else - cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); - } + dirty_printer(p); } @@ -3022,22 +2997,6 @@ cupsdUpdatePrinters(void) p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) { - /* - * Remove remote printers if we are no longer browsing... - */ - - if (!Browsing && - (p->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_DISCOVERED))) - { - if (p->type & CUPS_PRINTER_IMPLICIT) - cupsArrayRemove(ImplicitPrinters, p); - - cupsArraySave(Printers); - cupsdDeletePrinter(p, 0); - cupsArrayRestore(Printers); - continue; - } - /* * Update the operation policy pointer... */ @@ -3046,11 +3005,10 @@ cupsdUpdatePrinters(void) p->op_policy_ptr = DefaultPolicyPtr; /* - * Update printer attributes as needed... + * Update printer attributes... */ - if (!(p->type & CUPS_PRINTER_DISCOVERED)) - cupsdSetPrinterAttrs(p); + cupsdSetPrinterAttrs(p); } } @@ -3143,8 +3101,7 @@ cupsdValidateDest( *printer = p; if (dtype) - *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT | - CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED); + *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE); return (p->name); } @@ -3153,12 +3110,12 @@ cupsdValidateDest( * Change localhost to the server name... */ - if (!strcasecmp(hostname, "localhost")) + if (!_cups_strcasecmp(hostname, "localhost")) strlcpy(hostname, ServerName, sizeof(hostname)); strlcpy(localname, hostname, sizeof(localname)); - if (!strcasecmp(hostname, ServerName)) + if (!_cups_strcasecmp(hostname, ServerName)) { /* * Localize the hostname... @@ -3175,7 +3132,7 @@ cupsdValidateDest( while (lptr != NULL) { - if (!strcasecmp(lptr, sptr)) + if (!_cups_strcasecmp(lptr, sptr)) { *lptr = '\0'; break; @@ -3195,15 +3152,14 @@ cupsdValidateDest( for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) - if (!strcasecmp(p->hostname, localname) && - !strcasecmp(p->name, rptr)) + if (!_cups_strcasecmp(p->hostname, localname) && + !_cups_strcasecmp(p->name, rptr)) { if (printer) *printer = p; if (dtype) - *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT | - CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED); + *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE); return (p->name); } @@ -3225,16 +3181,6 @@ cupsdWritePrintcap(void) cupsd_printer_t *p; /* Current printer */ -#ifdef __sgi - /* - * Update the IRIX printer state for the default printer; if - * no printers remain, then the default printer file will be - * removed... - */ - - write_irix_state(DefaultPrinter); -#endif /* __sgi */ - /* * See if we have a printcap file; if not, don't bother writing it. */ @@ -3428,14 +3374,18 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */ cupsArrayAdd(CommonDefaults, _cupsStrAlloc("copies-default")); cupsArrayAdd(CommonDefaults, _cupsStrAlloc("document-format-default")); cupsArrayAdd(CommonDefaults, _cupsStrAlloc("finishings-default")); + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-account-id-default")); + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-accounting-user-id-default")); + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-cancel-after-default")); cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-hold-until-default")); cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-priority-default")); cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-sheets-default")); - cupsArrayAdd(CommonDefaults, _cupsStrAlloc("media-default")); + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("media-col-default")); + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("notify-lease-duration-default")); + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("notify-events-default")); cupsArrayAdd(CommonDefaults, _cupsStrAlloc("number-up-default")); - cupsArrayAdd(CommonDefaults, - _cupsStrAlloc("orientation-requested-default")); - cupsArrayAdd(CommonDefaults, _cupsStrAlloc("sides-default")); + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("orientation-requested-default")); + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("print-quality-default")); } /* @@ -3477,6 +3427,10 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, "document-format-default", NULL, "application/octet-stream"); + if (!cupsGetOption("job-cancel-after", p->num_options, p->options)) + ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "job-cancel-after-default", MaxJobTime); + if (!cupsGetOption("job-hold-until", p->num_options, p->options)) ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "job-hold-until-default", NULL, "no-hold"); @@ -3489,10 +3443,6 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "number-up-default", 1); - if (!cupsGetOption("orientation-requested", p->num_options, p->options)) - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, - "orientation-requested-default", NULL, NULL); - if (!cupsGetOption("notify-lease-duration", p->num_options, p->options)) ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "notify-lease-duration-default", DefaultLeaseDuration); @@ -3500,7 +3450,15 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */ if (!cupsGetOption("notify-events", p->num_options, p->options)) ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "notify-events-default", NULL, "job-completed"); -} + + if (!cupsGetOption("orientation-requested", p->num_options, p->options)) + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, + "orientation-requested-default", NULL, NULL); + + if (!cupsGetOption("print-quality", p->num_options, p->options)) + ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, + "print-quality-default", IPP_QUALITY_NORMAL); +} /* @@ -3515,108 +3473,96 @@ add_printer_filter( { char super[MIME_MAX_SUPER], /* Super-type for filter */ type[MIME_MAX_TYPE], /* Type for filter */ + dsuper[MIME_MAX_SUPER], /* Destination super-type for filter */ + dtype[MIME_MAX_TYPE], /* Destination type for filter */ + dest[MIME_MAX_SUPER + MIME_MAX_TYPE + 2], + /* Destination super/type */ program[1024]; /* Program/filter name */ int cost; /* Cost of filter */ - mime_type_t *temptype; /* MIME type looping var */ - char filename[1024], /* Full filter filename */ - *dirsep; /* Pointer to directory separator */ - struct stat fileinfo; /* File information */ + size_t maxsize = 0; /* Maximum supported file size */ + mime_type_t *temptype, /* MIME type looping var */ + *desttype; /* Destination MIME type */ + mime_filter_t *filterptr; /* MIME filter */ + char filename[1024]; /* Full filter filename */ + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "add_printer_filter(p=%p(%s), filtertype=%p(%s/%s), " + "filter=\"%s\")", p, p->name, filtertype, filtertype->super, + filtertype->type, filter); + /* - * Parse the filter string; it should be in the following format: + * Parse the filter string; it should be in one of the following formats: * - * super/type cost program + * source/type cost program + * source/type cost maxsize(nnnn) program + * source/type dest/type cost program + * source/type dest/type cost maxsize(nnnn) program */ - if (sscanf(filter, "%15[^/]/%31s%d%*[ \t]%1023[^\n]", super, type, &cost, - program) != 4) + if (sscanf(filter, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]", + super, type, dsuper, dtype, &cost, program) == 6) { - cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!", - p->name, filter); - return; - } + snprintf(dest, sizeof(dest), "%s/%s/%s", p->name, dsuper, dtype); - /* - * See if the filter program exists; if not, stop the printer and flag - * the error! - */ + if ((desttype = mimeType(MimeDatabase, "printer", dest)) == NULL) + { + desttype = mimeAddType(MimeDatabase, "printer", dest); + if (!p->dest_types) + p->dest_types = cupsArrayNew(NULL, NULL); - if (strcmp(program, "-")) + cupsArrayAdd(p->dest_types, desttype); + } + + } + else { - if (program[0] == '/') - strlcpy(filename, program, sizeof(filename)); + if (sscanf(filter, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, &cost, + program) == 4) + { + desttype = filtertype; + } else - snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program); - - if (stat(filename, &fileinfo)) { - memset(&fileinfo, 0, sizeof(fileinfo)); - - snprintf(p->state_message, sizeof(p->state_message), - "Filter \"%s\" for printer \"%s\" not available: %s", - filename, p->name, strerror(errno)); - cupsdSetPrinterReasons(p, "+cups-missing-filter-warning"); - - cupsdLogMessage(CUPSD_LOG_ERROR, "%s", p->state_message); + cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!", + p->name, filter); + return; } + } - /* - * When running as root, do additional security checks... - */ - - if (!RunUser) - { - /* - * Only use filters that are owned by root and do not have group or world - * write permissions. - */ + if (!strncmp(program, "maxsize(", 8)) + { + char *ptr; /* Pointer into maxsize(nnnn) program */ - if (fileinfo.st_uid || - (fileinfo.st_mode & (S_ISUID | S_IWGRP | S_IWOTH)) != 0) - { - if (fileinfo.st_uid) - snprintf(p->state_message, sizeof(p->state_message), - "Filter \"%s\" for printer \"%s\" not owned by root", - filename, p->name); - else - snprintf(p->state_message, sizeof(p->state_message), - "Filter \"%s\" for printer \"%s\" has insecure permissions " - "(0%o)", filename, p->name, fileinfo.st_mode); + maxsize = (size_t)strtoll(program + 8, &ptr, 10); - cupsdSetPrinterReasons(p, "+cups-insecure-filter-warning"); + if (*ptr != ')') + { + cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!", + p->name, filter); + return; + } - cupsdLogMessage(CUPSD_LOG_ERROR, "%s", p->state_message); - } - else if (fileinfo.st_mode) - { - /* - * Similarly, check that the parent directory is also owned by root and - * does not have world write permissions. - */ + ptr ++; + while (_cups_isspace(*ptr)) + ptr ++; - if ((dirsep = strrchr(filename, '/')) != NULL) - *dirsep = '\0'; + _cups_strcpy(program, ptr); + } - if (!stat(filename, &fileinfo) && - (fileinfo.st_uid || - (fileinfo.st_mode & (S_ISUID | S_IWGRP | S_IWOTH)) != 0)) - { - if (fileinfo.st_uid) - snprintf(p->state_message, sizeof(p->state_message), - "Filter directory \"%s\" for printer \"%s\" not owned by " - "root", filename, p->name); - else - snprintf(p->state_message, sizeof(p->state_message), - "Filter directory \"%s\" for printer \"%s\" has insecure " - "permissions (0%o)", filename, p->name, fileinfo.st_mode); + /* + * Check permissions on the filter and its containing directory... + */ - cupsdSetPrinterReasons(p, "+cups-insecure-filter-warning"); + if (strcmp(program, "-")) + { + if (program[0] == '/') + strlcpy(filename, program, sizeof(filename)); + else + snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program); - cupsdLogMessage(CUPSD_LOG_ERROR, "%s", p->state_message); - } - } - } + _cupsFileCheck(filename, _CUPS_FILE_CHECK_PROGRAM, !RunUser, + cupsdLogFCMessage, p); } /* @@ -3626,16 +3572,42 @@ add_printer_filter( for (temptype = mimeFirstType(MimeDatabase); temptype; temptype = mimeNextType(MimeDatabase)) - if (((super[0] == '*' && strcasecmp(temptype->super, "printer")) || - !strcasecmp(temptype->super, super)) && - (type[0] == '*' || !strcasecmp(temptype->type, type))) + if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) || + !_cups_strcasecmp(temptype->super, super)) && + (type[0] == '*' || !_cups_strcasecmp(temptype->type, type))) { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "add_printer_filter: %s: adding filter %s/%s %s/%s %d %s", - p->name, temptype->super, temptype->type, - filtertype->super, filtertype->type, - cost, program); - mimeAddFilter(MimeDatabase, temptype, filtertype, cost, program); + if (desttype != filtertype) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "add_printer_filter: %s: adding filter %s/%s %s/%s %d " + "%s", p->name, temptype->super, temptype->type, + desttype->super, desttype->type, + cost, program); + filterptr = mimeAddFilter(MimeDatabase, temptype, desttype, cost, + program); + + if (!mimeFilterLookup(MimeDatabase, desttype, filtertype)) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "add_printer_filter: %s: adding filter %s/%s %s/%s " + "0 -", p->name, desttype->super, desttype->type, + filtertype->super, filtertype->type); + mimeAddFilter(MimeDatabase, desttype, filtertype, 0, "-"); + } + } + else + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "add_printer_filter: %s: adding filter %s/%s %s/%s %d " + "%s", p->name, temptype->super, temptype->type, + filtertype->super, filtertype->type, + cost, program); + filterptr = mimeAddFilter(MimeDatabase, temptype, filtertype, cost, + program); + } + + if (filterptr) + filterptr->maxsize = maxsize; } } @@ -3685,6 +3657,9 @@ add_printer_formats(cupsd_printer_t *p) /* I - Printer */ type; type = mimeNextType(MimeDatabase)) { + if (!_cups_strcasecmp(type->super, "printer")) + continue; + snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type); if ((filters = mimeFilter(MimeDatabase, type, p->filetype, NULL)) != NULL) @@ -3732,68 +3707,62 @@ add_printer_formats(cupsd_printer_t *p) /* I - Printer */ attr->values[i].string.text = _cupsStrAlloc(mimetype); } -#ifdef HAVE_DNSSD +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) { char pdl[1024]; /* Buffer to build pdl list */ mime_filter_t *filter; /* MIME filter looping var */ - pdl[0] = '\0'; - - if (mimeType(MimeDatabase, "application", "pdf")) - strlcat(pdl, "application/pdf,", sizeof(pdl)); - - if (mimeType(MimeDatabase, "application", "postscript")) - strlcat(pdl, "application/postscript,", sizeof(pdl)); - - if (mimeType(MimeDatabase, "application", "vnd.cups-raster")) - strlcat(pdl, "application/vnd.cups-raster,", sizeof(pdl)); - /* - * Determine if this is a Tioga PrintJobMgr based queue... + * We only support raw printing if this is not a Tioga PrintJobMgr based + * queue and if application/octet-stream is a known type... */ for (filter = (mime_filter_t *)cupsArrayFirst(MimeDatabase->filters); filter; filter = (mime_filter_t *)cupsArrayNext(MimeDatabase->filters)) { - if (filter->dst == p->filetype && filter->filter && - strstr(filter->filter, "PrintJobMgr")) + if (filter->dst == p->filetype && strstr(filter->filter, "PrintJobMgr")) break; } - /* - * We only support raw printing if this is not a Tioga PrintJobMgr based - * queue and if application/octet-stream is a known conversion... - */ + pdl[0] = '\0'; if (!filter && mimeType(MimeDatabase, "application", "octet-stream")) strlcat(pdl, "application/octet-stream,", sizeof(pdl)); - if (mimeType(MimeDatabase, "image", "png")) - strlcat(pdl, "image/png,", sizeof(pdl)); + /* + * Then list a bunch of formats that are supported by the printer... + */ + + for (type = (mime_type_t *)cupsArrayFirst(p->filetypes); + type; + type = (mime_type_t *)cupsArrayNext(p->filetypes)) + { + if (!_cups_strcasecmp(type->super, "application")) + { + if (!_cups_strcasecmp(type->type, "pdf")) + strlcat(pdl, "application/pdf,", sizeof(pdl)); + else if (!_cups_strcasecmp(type->type, "postscript")) + strlcat(pdl, "application/postscript,", sizeof(pdl)); + } + else if (!_cups_strcasecmp(type->super, "image")) + { + if (!_cups_strcasecmp(type->type, "jpeg")) + strlcat(pdl, "image/jpeg,", sizeof(pdl)); + else if (!_cups_strcasecmp(type->type, "png")) + strlcat(pdl, "image/png,", sizeof(pdl)); + else if (!_cups_strcasecmp(type->type, "pwg-raster")) + strlcat(pdl, "image/pwg-raster,", sizeof(pdl)); + } + } if (pdl[0]) pdl[strlen(pdl) - 1] = '\0'; /* Remove trailing comma */ cupsdSetString(&p->pdl, pdl); } -#endif /* HAVE_DNSSD */ -} - - -/* - * 'add_string_array()' - Add a string to an array of CUPS strings. - */ - -static void -add_string_array(cups_array_t **a, /* I - Array */ - const char *s) /* I - String */ -{ - if (!*a) - *a = cupsArrayNew(NULL, NULL); - - cupsArrayAdd(*a, _cupsStrAlloc(s)); +#endif /* HAVE_DNSSD || HAVE_AVAHI */ } @@ -3806,7 +3775,9 @@ compare_printers(void *first, /* I - First printer */ void *second, /* I - Second printer */ void *data) /* I - App data (not used) */ { - return (strcasecmp(((cupsd_printer_t *)first)->name, + (void)data; + + return (_cups_strcasecmp(((cupsd_printer_t *)first)->name, ((cupsd_printer_t *)second)->name)); } @@ -3820,6 +3791,7 @@ delete_printer_filters( cupsd_printer_t *p) /* I - Printer to remove from */ { mime_filter_t *filter; /* MIME filter looping var */ + mime_type_t *type; /* Destination types for filters */ /* @@ -3837,7 +3809,8 @@ delete_printer_filters( for (filter = mimeFirstFilter(MimeDatabase); filter; filter = mimeNextFilter(MimeDatabase)) - if (filter->dst == p->filetype || filter->dst == p->prefiltertype) + if (filter->dst == p->filetype || filter->dst == p->prefiltertype || + cupsArrayFind(p->dest_types, filter->dst)) { /* * Delete the current filter... @@ -3846,28 +3819,34 @@ delete_printer_filters( mimeDeleteFilter(MimeDatabase, filter); } + for (type = (mime_type_t *)cupsArrayFirst(p->dest_types); + type; + type = (mime_type_t *)cupsArrayNext(p->dest_types)) + mimeDeleteType(MimeDatabase, type); + + cupsArrayDelete(p->dest_types); + p->dest_types = NULL; + cupsdSetPrinterReasons(p, "-cups-insecure-filter-warning" ",cups-missing-filter-warning"); } /* - * 'delete_string_array()' - Delete an array of CUPS strings. + * 'dirty_printer()' - Mark config and state files dirty for the specified + * printer. */ static void -delete_string_array(cups_array_t **a) /* I - Array */ +dirty_printer(cupsd_printer_t *p) /* I - Printer */ { - char *ptr; /* Current string */ - - - for (ptr = (char *)cupsArrayFirst(*a); - ptr; - ptr = (char *)cupsArrayNext(*a)) - _cupsStrFree(ptr); + if (p->type & CUPS_PRINTER_CLASS) + cupsdMarkDirty(CUPSD_DIRTY_CLASSES); + else + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); - cupsArrayDelete(*a); - *a = NULL; + if (PrintcapFormat == PRINTCAP_PLIST) + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); } @@ -3878,27 +3857,45 @@ delete_string_array(cups_array_t **a) /* I - Array */ static void load_ppd(cupsd_printer_t *p) /* I - Printer */ { - int i; /* Looping var */ - cups_file_t *cache; /* Cache file */ + int i, j, k; /* Looping vars */ char cache_name[1024]; /* Cache filename */ struct stat cache_info; /* Cache file info */ ppd_file_t *ppd; /* PPD file */ char ppd_name[1024]; /* PPD filename */ struct stat ppd_info; /* PPD file info */ + char strings_name[1024]; /* Strings filename */ int num_media; /* Number of media options */ - char custom_in[256], /* Custom size name in inches */ - custom_mm[256]; /* Custom size name in millimeters */ - ppd_size_t *size; /* Current size */ - ppd_option_t *output_bin, /* OutputBin options */ - *duplex; /* Duplex options */ + ppd_size_t *size; /* Current PPD size */ + ppd_option_t *duplex, /* Duplex option */ + *output_bin, /* OutputBin option */ + *output_mode, /* OutputMode option */ + *resolution; /* (Set|JCL|)Resolution option */ + ppd_choice_t *choice, /* Current PPD choice */ + *input_slot, /* Current input slot */ + *media_type; /* Current media type */ ppd_attr_t *ppd_attr; /* PPD attribute */ - _cups_pwg_media_t *pwgmedia; /* Matching PWG size name */ + int xdpi, /* Horizontal resolution */ + ydpi; /* Vertical resolution */ + const char *resptr; /* Pointer into resolution keyword */ + pwg_size_t *pwgsize; /* Current PWG size */ + pwg_map_t *pwgsource, /* Current PWG source */ + *pwgtype; /* Current PWG type */ ipp_attribute_t *attr; /* Attribute data */ - ipp_t *media_col_default, /* media-col-default collection value */ - *media_size; /* media-size collection value */ - ipp_value_t *val; /* Attribute value */ - int num_finishings; /* Number of finishings */ - int finishings[5]; /* finishings-supported values */ + _ipp_value_t *val; /* Attribute value */ + int num_finishings, /* Number of finishings */ + finishings[100]; /* finishings-supported values */ + int num_qualities, /* Number of print-quality values */ + qualities[3]; /* print-quality values */ + int num_margins, /* Number of media-*-margin-supported values */ + margins[16]; /* media-*-margin-supported values */ + const char *filter, /* Current filter */ + *mandatory; /* Current mandatory attribute */ + static const char * const pwg_raster_document_types[] = + { + "black_1", + "sgray_8", + "srgb_8" + }; static const char * const sides[3] = /* sides-supported values */ { "one-sided", @@ -3917,7 +3914,7 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ * Check to see if the cache is up-to-date... */ - snprintf(cache_name, sizeof(cache_name), "%s/%s.ipp", CacheDir, p->name); + snprintf(cache_name, sizeof(cache_name), "%s/%s.data", CacheDir, p->name); if (stat(cache_name, &cache_info)) cache_info.st_mtime = 0; @@ -3925,26 +3922,27 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ if (stat(ppd_name, &ppd_info)) ppd_info.st_mtime = 1; + snprintf(strings_name, sizeof(strings_name), "%s/%s.strings", CacheDir, p->name); + ippDelete(p->ppd_attrs); - p->ppd_attrs = ippNew(); + p->ppd_attrs = NULL; - if (cache_info.st_mtime >= ppd_info.st_mtime && - (cache = cupsFileOpen(cache_name, "r")) != NULL) - { - /* - * Load cached information and return... - */ + _ppdCacheDestroy(p->pc); + p->pc = NULL; + if (cache_info.st_mtime >= ppd_info.st_mtime) + { cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", cache_name); - if (ippReadIO(cache, (ipp_iocb_t)cupsFileRead, 1, NULL, - p->ppd_attrs) == IPP_DATA) + if ((p->pc = _ppdCacheCreateWithFile(cache_name, &p->ppd_attrs)) != NULL && + p->ppd_attrs) { - cupsFileClose(cache); + /* + * Loaded successfully! + */ + return; } - - cupsFileClose(cache); } /* @@ -3955,21 +3953,28 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", ppd_name); - delete_string_array(&(p->filters)); - delete_string_array(&(p->pre_filters)); + cupsdClearString(&(p->make_model)); - p->type &= ~CUPS_PRINTER_OPTIONS; + p->type &= (cups_ptype_t)~CUPS_PRINTER_OPTIONS; p->type |= CUPS_PRINTER_BW; finishings[0] = IPP_FINISHINGS_NONE; num_finishings = 1; - if ((ppd = ppdOpenFile(ppd_name)) != NULL) + p->ppd_attrs = ippNew(); + + if ((ppd = _ppdOpenFile(ppd_name, _PPD_LOCALIZATION_NONE)) != NULL) { /* * Add make/model and other various attributes... */ + p->pc = _ppdCacheCreateWithPPD(ppd); + + if (!p->pc) + cupsdLogMessage(CUPSD_LOG_WARN, "Unable to create cache of \"%s\": %s", + ppd_name, cupsLastErrorString()); + ppdMarkDefaults(ppd); if (ppd->color_device) @@ -3979,14 +3984,91 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ if (!ppd->manual_copies) p->type |= CUPS_PRINTER_COPIES; if ((ppd_attr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL) - if (ppd_attr->value && !strcasecmp(ppd_attr->value, "true")) + if (ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true")) p->type |= CUPS_PRINTER_FAX; - ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "color-supported", - ppd->color_device); + ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "color-supported", (char)ppd->color_device); + + if (p->pc && p->pc->charge_info_uri) + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_URI, + "printer-charge-info-uri", NULL, p->pc->charge_info_uri); + + if (p->pc && p->pc->account_id) + ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "job-account-id-supported", + 1); + + if (p->pc && p->pc->accounting_user_id) + ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, + "job-accounting-user-id-supported", 1); + + if (p->pc && p->pc->password) + { + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "job-password-encryption-supported", NULL, "none"); + ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "job-password-supported", (int)strlen(p->pc->password)); + } + if (ppd->throughput) + { ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "pages-per-minute", ppd->throughput); + if (ppd->color_device) + ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "pages-per-minute-color", ppd->throughput); + } + else + { + /* + * When there is no speed information, just say "1 page per minute". + */ + + ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "pages-per-minute", 1); + if (ppd->color_device) + ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "pages-per-minute-color", 1); + } + + if ((ppd_attr = ppdFindAttr(ppd, "1284DeviceId", NULL)) != NULL) + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-device-id", NULL, ppd_attr->value); + + num_qualities = 0; + + if ((output_mode = ppdFindOption(ppd, "OutputMode")) != NULL) + { + if (ppdFindChoice(output_mode, "draft") || + ppdFindChoice(output_mode, "fast")) + qualities[num_qualities ++] = IPP_QUALITY_DRAFT; + + qualities[num_qualities ++] = IPP_QUALITY_NORMAL; + + if (ppdFindChoice(output_mode, "best") || + ppdFindChoice(output_mode, "high")) + qualities[num_qualities ++] = IPP_QUALITY_HIGH; + } + else if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL) + { + do + { + if (strstr(ppd_attr->spec, "draft") || + strstr(ppd_attr->spec, "Draft")) + { + qualities[num_qualities ++] = IPP_QUALITY_DRAFT; + break; + } + } + while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset", + NULL)) != NULL); + + qualities[num_qualities ++] = IPP_QUALITY_NORMAL; + qualities[num_qualities ++] = IPP_QUALITY_HIGH; + } + else + qualities[num_qualities ++] = IPP_QUALITY_NORMAL; + + ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, + "print-quality-supported", num_qualities, qualities); if (ppd->nickname) { @@ -4013,270 +4095,699 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-make-and-model", NULL, p->make_model); + if (p->pc && p->pc->strings) + _cupsMessageSave(strings_name, _CUPS_MESSAGE_STRINGS, p->pc->strings); + + if (!access(strings_name, R_OK)) + cupsdSetString(&p->strings, strings_name); + else + cupsdClearString(&p->strings); + /* * Add media options from the PPD file... */ - if (ppd->num_sizes == 0) + if (ppd->num_sizes == 0 || !p->pc) { - if (!ppdFindAttr(ppd, "APScannerOnly", NULL)) + if (!ppdFindAttr(ppd, "APScannerOnly", NULL) && !ppdFindAttr(ppd, "cups3D", NULL)) cupsdLogMessage(CUPSD_LOG_CRIT, "The PPD file for printer %s contains no media " - "options and is therefore invalid!", p->name); + "options and is therefore invalid.", p->name); + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "media-default", NULL, "unknown"); ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-supported", NULL, "unknown"); } else { - num_media = ppd->num_sizes; - if (ppd->variable_sizes) - num_media ++; + /* + * media-default + */ - attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "media-supported", num_media, NULL, NULL); - if (attr != NULL) + if ((size = ppdPageSize(ppd, NULL)) != NULL) + pwgsize = _ppdCacheGetSize(p->pc, size->name); + else + pwgsize = NULL; + + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "media-default", NULL, + pwgsize ? pwgsize->map.pwg : "unknown"); + + /* + * media-col-default + */ + + if (pwgsize) { - val = attr->values; + ipp_t *col; /* Collection value */ - for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++) - { - if (strcasecmp(size->name, "Custom")) - { - if ((pwgmedia = _cupsPWGMediaBySize(size->width, - size->length)) != NULL) - { - val->string.text = _cupsStrAlloc(pwgmedia->pwg); - } - else - { - snprintf(custom_in, sizeof(custom_in), "adobe_%s_%gx%gin", - size->name, size->width / 72.0, size->length / 72.0); - snprintf(custom_mm, sizeof(custom_mm), "adobe_%s_%gx%gmm", - size->name, size->width * 25.4 / 72.0, - size->length * 25.4 / 72.0); - if (strlen(custom_in) < strlen(custom_mm)) - val->string.text = _cupsStrAlloc(custom_in); - else - val->string.text = _cupsStrAlloc(custom_mm); - } + input_slot = ppdFindMarkedChoice(ppd, "InputSlot"); + media_type = ppdFindMarkedChoice(ppd, "MediaType"); + col = new_media_col(pwgsize, + input_slot ? _ppdCacheGetSource(p->pc, input_slot->choice) : NULL, + media_type ? _ppdCacheGetType(p->pc, media_type->choice) : NULL); - if (size->marked) - { - /* - * Add media-default... - */ + ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-default", col); + ippDelete(col); + } - ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "media-default", NULL, val->string.text); + /* + * media-supported + */ - /* - * Add media-col-default... - */ - - media_size = ippNew(); - ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "x-dimension", (int)(size->width * 2540.0 / 72.0)); - ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "y-dimension", (int)(size->length * 2540.0 / 72.0)); - - media_col_default = ippNew(); - ippAddString(media_col_default, IPP_TAG_PRINTER, - IPP_TAG_KEYWORD | IPP_TAG_COPY, "media-color", NULL, - "white"); - ippAddString(media_col_default, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "media-key", NULL,val->string.text); - ippAddCollection(media_col_default, IPP_TAG_PRINTER, "media-size", - media_size); - ippAddString(media_col_default, IPP_TAG_PRINTER, - IPP_TAG_KEYWORD | IPP_TAG_COPY, "media-type", NULL, - "stationary"); - - ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, - "media-col-default", media_col_default); - } + num_media = p->pc->num_sizes; + if (p->pc->custom_min_keyword) + num_media += 2; - val ++; - } - } + if ((attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "media-supported", num_media, NULL, + NULL)) != NULL) + { + val = attr->values; + + for (i = p->pc->num_sizes, pwgsize = p->pc->sizes; + i > 0; + i --, pwgsize ++, val ++) + val->string.text = _cupsStrAlloc(pwgsize->map.pwg); - if (ppd->variable_sizes) + if (p->pc->custom_min_keyword) { - snprintf(custom_in, sizeof(custom_in), "custom_min_%gx%gin", - ppd->custom_min[0] / 72.0, ppd->custom_min[1] / 72.0); - snprintf(custom_mm, sizeof(custom_mm), "custom_min_%gx%gmm", - ppd->custom_min[0] * 25.4 / 72.0, - ppd->custom_min[1] * 25.4 / 72.0); - if (strlen(custom_in) < strlen(custom_mm)) - val->string.text = _cupsStrAlloc(custom_in); - else - val->string.text = _cupsStrAlloc(custom_mm); + val->string.text = _cupsStrAlloc(p->pc->custom_min_keyword); val ++; - - snprintf(custom_in, sizeof(custom_in), "custom_max_%gx%gin", - ppd->custom_max[0] / 72.0, ppd->custom_max[1] / 72.0); - snprintf(custom_mm, sizeof(custom_mm), "custom_max_%gx%gmm", - ppd->custom_max[0] * 25.4 / 72.0, - ppd->custom_max[1] * 25.4 / 72.0); - if (strlen(custom_in) < strlen(custom_mm)) - val->string.text = _cupsStrAlloc(custom_in); - else - val->string.text = _cupsStrAlloc(custom_mm); - } + val->string.text = _cupsStrAlloc(p->pc->custom_max_keyword); + } } - } - /* - * Output bin... - */ + /* + * media-size-supported + */ - if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL) - { - attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "output-bin-supported", output_bin->num_choices, - NULL, NULL); + num_media = p->pc->num_sizes; + if (p->pc->custom_min_keyword) + num_media ++; - if (attr != NULL) + if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER, + "media-size-supported", num_media, + NULL)) != NULL) { - for (i = 0, val = attr->values; - i < output_bin->num_choices; - i ++, val ++) - val->string.text = _cupsStrAlloc(output_bin->choices[i].choice); - } + val = attr->values; - ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "output-bin-default", NULL, output_bin->defchoice); - } + for (i = p->pc->num_sizes, pwgsize = p->pc->sizes; + i > 0; + i --, pwgsize ++, val ++) + { + val->collection = ippNew(); + ippAddInteger(val->collection, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "x-dimension", pwgsize->width); + ippAddInteger(val->collection, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "y-dimension", pwgsize->length); + } - /* - * Duplexing, etc... - */ + if (p->pc->custom_min_keyword) + { + val->collection = ippNew(); + ippAddRange(val->collection, IPP_TAG_PRINTER, "x-dimension", + p->pc->custom_min_width, p->pc->custom_max_width); + ippAddRange(val->collection, IPP_TAG_PRINTER, "y-dimension", + p->pc->custom_min_length, p->pc->custom_max_length); + } + } - if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL) - if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL) - if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL) - if ((duplex = ppdFindOption(ppd, "KD03Duplex")) == NULL) - duplex = ppdFindOption(ppd, "JCLDuplex"); + /* + * media-source-supported + */ - if (duplex && duplex->num_choices > 1 && - !ppdInstallableConflict(ppd, duplex->keyword, "DuplexTumble")) - { - p->type |= CUPS_PRINTER_DUPLEX; + if (p->pc->num_sources > 0 && + (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "media-source-supported", p->pc->num_sources, + NULL, NULL)) != NULL) + { + for (i = p->pc->num_sources, pwgsource = p->pc->sources, + val = attr->values; + i > 0; + i --, pwgsource ++, val ++) + val->string.text = _cupsStrAlloc(pwgsource->pwg); + } - ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "sides-supported", 3, NULL, sides); + /* + * media-type-supported + */ - if (!strcasecmp(duplex->defchoice, "DuplexTumble")) - ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "sides-default", NULL, "two-sided-short-edge"); - else if (!strcasecmp(duplex->defchoice, "DuplexNoTumble")) - ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "sides-default", NULL, "two-sided-long-edge"); - else - ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "sides-default", NULL, "one-sided"); - } + if (p->pc->num_types > 0 && + (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "media-type-supported", p->pc->num_types, + NULL, NULL)) != NULL) + { + for (i = p->pc->num_types, pwgtype = p->pc->types, + val = attr->values; + i > 0; + i --, pwgtype ++, val ++) + val->string.text = _cupsStrAlloc(pwgtype->pwg); + } - if (ppdFindOption(ppd, "Collate") != NULL) - p->type |= CUPS_PRINTER_COLLATE; + /* + * media-*-margin-supported + */ - if (ppdFindOption(ppd, "StapleLocation") != NULL) - { - p->type |= CUPS_PRINTER_STAPLE; - finishings[num_finishings++] = IPP_FINISHINGS_STAPLE; + for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0; + i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0])); + i --, pwgsize ++) + { + for (j = 0; j < num_margins; j ++) + if (pwgsize->bottom == margins[j]) + break; + + if (j >= num_margins) + { + margins[num_margins] = pwgsize->bottom; + num_margins ++; + } + } + + if (num_margins > 0) + ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "media-bottom-margin-supported", num_margins, margins); + else + ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "media-bottom-margin-supported", 0); + + for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0; + i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0])); + i --, pwgsize ++) + { + for (j = 0; j < num_margins; j ++) + if (pwgsize->left == margins[j]) + break; + + if (j >= num_margins) + { + margins[num_margins] = pwgsize->left; + num_margins ++; + } + } + + if (num_margins > 0) + ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "media-left-margin-supported", num_margins, margins); + else + ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "media-left-margin-supported", 0); + + for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0; + i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0])); + i --, pwgsize ++) + { + for (j = 0; j < num_margins; j ++) + if (pwgsize->right == margins[j]) + break; + + if (j >= num_margins) + { + margins[num_margins] = pwgsize->right; + num_margins ++; + } + } + + if (num_margins > 0) + ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "media-right-margin-supported", num_margins, margins); + else + ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "media-right-margin-supported", 0); + + for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0; + i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0])); + i --, pwgsize ++) + { + for (j = 0; j < num_margins; j ++) + if (pwgsize->top == margins[j]) + break; + + if (j >= num_margins) + { + margins[num_margins] = pwgsize->top; + num_margins ++; + } + } + + if (num_margins > 0) + ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "media-top-margin-supported", num_margins, margins); + else + ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "media-top-margin-supported", 0); + + /* + * media-col-database + */ + + num_media = p->pc->num_sizes; + if (p->pc->num_sources) + { + if (p->pc->num_types > 0) + num_media += p->pc->num_sizes * p->pc->num_sources * + p->pc->num_types; + else + num_media += p->pc->num_sizes * p->pc->num_sources; + } + else if (p->pc->num_types) + num_media += p->pc->num_sizes * p->pc->num_types; + + if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER, + "media-col-database", num_media, + NULL)) != NULL) + { + for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, val = attr->values; + i > 0; + i --, pwgsize ++) + { + /* + * Start by adding the page size without source or type... + */ + + ppdMarkOption(ppd, "PageSize", pwgsize->map.ppd); + + val->collection = new_media_col(pwgsize, NULL, NULL); + val ++; + + /* + * Then add the specific, supported combinations of size, source, and + * type... + */ + + if (p->pc->num_sources > 0) + { + for (j = p->pc->num_sources, pwgsource = p->pc->sources; + j > 0; + j --, pwgsource ++) + { + ppdMarkOption(ppd, "InputSlot", pwgsource->ppd); + + if (p->pc->num_types > 0) + { + for (k = p->pc->num_types, pwgtype = p->pc->types; + k > 0; + k --, pwgtype ++) + { + if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd)) + { + val->collection = new_media_col(pwgsize, pwgsource->pwg, + pwgtype->pwg); + val ++; + } + } + } + else if (!ppdConflicts(ppd)) + { + val->collection = new_media_col(pwgsize, pwgsource->pwg, NULL); + val ++; + } + } + } + else if (p->pc->num_types > 0) + { + for (j = p->pc->num_types, pwgtype = p->pc->types; + j > 0; + j --, pwgtype ++) + { + if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd)) + { + val->collection = new_media_col(pwgsize, NULL, pwgtype->pwg); + val ++; + } + } + } + } + + /* + * Update the number of media-col-database values... + */ + + attr->num_values = val - attr->values; + } } - if (ppdFindOption(ppd, "BindEdge") != NULL) + /* + * Output bin... + */ + + if (p->pc && p->pc->num_bins > 0) { - p->type |= CUPS_PRINTER_BIND; - finishings[num_finishings++] = IPP_FINISHINGS_BIND; - } + attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "output-bin-supported", p->pc->num_bins, + NULL, NULL); - for (i = 0; i < ppd->num_sizes; i ++) - if (ppd->sizes[i].length > 1728) - p->type |= CUPS_PRINTER_LARGE; - else if (ppd->sizes[i].length > 1008) - p->type |= CUPS_PRINTER_MEDIUM; + if (attr != NULL) + { + for (i = 0, val = attr->values; + i < p->pc->num_bins; + i ++, val ++) + val->string.text = _cupsStrAlloc(p->pc->bins[i].pwg); + } + + if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL) + { + for (i = 0; i < p->pc->num_bins; i ++) + if (!strcmp(p->pc->bins[i].ppd, output_bin->defchoice)) + break; + + if (i >= p->pc->num_bins) + i = 0; + + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "output-bin-default", NULL, p->pc->bins[i].pwg); + } else - p->type |= CUPS_PRINTER_SMALL; + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "output-bin-default", NULL, p->pc->bins[0].pwg); + } + else if (((ppd_attr = ppdFindAttr(ppd, "DefaultOutputOrder", + NULL)) != NULL && + !_cups_strcasecmp(ppd_attr->value, "Reverse")) || + (!ppd_attr && ppd->manufacturer && /* "Compatibility heuristic" */ + (!_cups_strcasecmp(ppd->manufacturer, "epson") || + !_cups_strcasecmp(ppd->manufacturer, "lexmark")))) + { + /* + * Report that this printer has a single output bin that leaves pages face + * up. + */ - if ((ppd_attr = ppdFindAttr(ppd, "APICADriver", NULL)) != NULL && - ppd_attr->value && !strcasecmp(ppd_attr->value, "true")) + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "output-bin-supported", NULL, "face-up"); + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "output-bin-default", NULL, "face-up"); + } + else { - if ((ppd_attr = ppdFindAttr(ppd, "APScannerOnly", NULL)) != NULL && - ppd_attr->value && !strcasecmp(ppd_attr->value, "true")) - p->type |= CUPS_PRINTER_SCANNER; - else - p->type |= CUPS_PRINTER_MFP; + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "output-bin-supported", NULL, "face-down"); + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "output-bin-default", NULL, "face-down"); } /* - * Add a filter from application/vnd.cups-raw to printer/name to - * handle "raw" printing by users. + * print-color-mode... */ - add_string_array(&(p->filters), "application/vnd.cups-raw 0 -"); + if (ppd->color_device) + { + static const char * const color_modes[] = + { + "monochrome", + "color" + }; + + ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "print-color-mode-supported", 2, NULL, color_modes); + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "print-color-mode-default", NULL, "color"); + ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "pwg-raster-document-type-supported", 3, NULL, pwg_raster_document_types); + } + else + { + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "print-color-mode-supported", NULL, "monochrome"); + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "print-color-mode-default", NULL, "monochrome"); + ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "pwg-raster-document-type-supported", 2, NULL, pwg_raster_document_types); + } /* - * Add any pre-filters in the PPD file... + * Mandatory job attributes, if any... */ - if ((ppd_attr = ppdFindAttr(ppd, "cupsPreFilter", NULL)) != NULL) + if (p->pc && cupsArrayCount(p->pc->mandatory) > 0) { - for (; ppd_attr; ppd_attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL)) - if (ppd_attr->value) - add_string_array(&(p->pre_filters), ppd_attr->value); + int count = cupsArrayCount(p->pc->mandatory); + /* Number of mandatory attributes */ + + attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "printer-mandatory-job-attributes", count, NULL, + NULL); + + for (val = attr->values, + mandatory = (char *)cupsArrayFirst(p->pc->mandatory); + mandatory; + val ++, mandatory = (char *)cupsArrayNext(p->pc->mandatory)) + val->string.text = _cupsStrAlloc(mandatory); } /* - * Add any filters in the PPD file... + * Printer resolutions... */ - DEBUG_printf(("ppd->num_filters = %d\n", ppd->num_filters)); - for (i = 0; i < ppd->num_filters; i ++) + if ((resolution = ppdFindOption(ppd, "Resolution")) == NULL) + if ((resolution = ppdFindOption(ppd, "JCLResolution")) == NULL) + if ((resolution = ppdFindOption(ppd, "SetResolution")) == NULL) + resolution = ppdFindOption(ppd, "CNRes_PGP"); + + if (resolution) { - DEBUG_printf(("ppd->filters[%d] = \"%s\"\n", i, ppd->filters[i])); - add_string_array(&(p->filters), ppd->filters[i]); + /* + * Report all supported resolutions... + */ - if (!strncasecmp(ppd->filters[i], "application/vnd.cups-command", 28) && - isspace(ppd->filters[i][28] & 255)) - p->type |= CUPS_PRINTER_COMMANDS; - } + attr = ippAddResolutions(p->ppd_attrs, IPP_TAG_PRINTER, "printer-resolution-supported", resolution->num_choices, IPP_RES_PER_INCH, NULL, NULL); - if (ppd->num_filters == 0) + for (i = 0, choice = resolution->choices; + i < resolution->num_choices; + i ++, choice ++) + { + xdpi = ydpi = (int)strtol(choice->choice, (char **)&resptr, 10); + if (resptr > choice->choice && xdpi > 0 && *resptr == 'x') + ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10); + + if (xdpi <= 0 || ydpi <= 0) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "Bad resolution \"%s\" for printer %s.", + choice->choice, p->name); + xdpi = ydpi = 300; + } + + attr->values[i].resolution.xres = xdpi; + attr->values[i].resolution.yres = ydpi; + attr->values[i].resolution.units = IPP_RES_PER_INCH; + + if (choice->marked) + ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, "printer-resolution-default", IPP_RES_PER_INCH, xdpi, ydpi); + + if (i == 0) + ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", IPP_RES_PER_INCH, xdpi, ydpi); + } + } + else if ((ppd_attr = ppdFindAttr(ppd, "DefaultResolution", NULL)) != NULL && + ppd_attr->value) { /* - * If there are no filters, add PostScript printing filters. + * Just the DefaultResolution to report... */ - add_string_array(&(p->filters), - "application/vnd.cups-command 0 commandtops"); - add_string_array(&(p->filters), - "application/vnd.cups-postscript 0 -"); + xdpi = ydpi = (int)strtol(ppd_attr->value, (char **)&resptr, 10); + if (resptr > ppd_attr->value && xdpi > 0) + { + if (*resptr == 'x') + ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10); + else + ydpi = xdpi; + } - p->type |= CUPS_PRINTER_COMMANDS; + if (xdpi <= 0 || ydpi <= 0) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "Bad default resolution \"%s\" for printer %s.", + ppd_attr->value, p->name); + xdpi = ydpi = 300; + } + + ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, + "printer-resolution-default", IPP_RES_PER_INCH, + xdpi, ydpi); + ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, + "printer-resolution-supported", IPP_RES_PER_INCH, + xdpi, ydpi); + ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", IPP_RES_PER_INCH, xdpi, ydpi); } - else if (!(p->type & CUPS_PRINTER_COMMANDS)) + else { /* - * See if this is a PostScript device without a command filter... + * No resolutions in PPD - make one up... */ - for (i = 0; i < ppd->num_filters; i ++) - if (!strncasecmp(ppd->filters[i], - "application/vnd.cups-postscript", 31) && - isspace(ppd->filters[i][31] & 255)) - break; + ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, + "printer-resolution-default", IPP_RES_PER_INCH, + 300, 300); + ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, + "printer-resolution-supported", IPP_RES_PER_INCH, + 300, 300); + ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", IPP_RES_PER_INCH, 300, 300); + } + + /* + * Duplexing, etc... + */ + + ppdMarkDefaults(ppd); + + if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL) + if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL) + if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL) + if ((duplex = ppdFindOption(ppd, "KD03Duplex")) == NULL) + duplex = ppdFindOption(ppd, "JCLDuplex"); + + if (duplex && duplex->num_choices > 1 && + !ppdInstallableConflict(ppd, duplex->keyword, "DuplexTumble")) + { + p->type |= CUPS_PRINTER_DUPLEX; + + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "pwg-raster-document-sheet-back", NULL, "normal"); + + ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "sides-supported", 3, NULL, sides); - if (i < ppd->num_filters) + if (!_cups_strcasecmp(duplex->defchoice, "DuplexTumble")) + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "sides-default", NULL, "two-sided-short-edge"); + else if (!_cups_strcasecmp(duplex->defchoice, "DuplexNoTumble")) + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "sides-default", NULL, "two-sided-long-edge"); + else + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "sides-default", NULL, "one-sided"); + } + else + { + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "sides-supported", NULL, "one-sided"); + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "sides-default", NULL, "one-sided"); + } + + if (ppdFindOption(ppd, "Collate") != NULL) + p->type |= CUPS_PRINTER_COLLATE; + + if (p->pc && p->pc->finishings) + { + _pwg_finishings_t *fin; /* Current finishing value */ + + for (fin = (_pwg_finishings_t *)cupsArrayFirst(p->pc->finishings); fin; fin = (_pwg_finishings_t *)cupsArrayNext(p->pc->finishings)) { - /* - * Add the generic PostScript command filter... - */ + if (num_finishings < (int)(sizeof(finishings) / sizeof(finishings[0]))) + finishings[num_finishings++] = fin->value; + + switch (fin->value) + { + case IPP_FINISHINGS_BIND : + case IPP_FINISHINGS_BIND_LEFT : + case IPP_FINISHINGS_BIND_TOP : + case IPP_FINISHINGS_BIND_RIGHT : + case IPP_FINISHINGS_BIND_BOTTOM : + case IPP_FINISHINGS_EDGE_STITCH : + case IPP_FINISHINGS_EDGE_STITCH_LEFT : + case IPP_FINISHINGS_EDGE_STITCH_TOP : + case IPP_FINISHINGS_EDGE_STITCH_RIGHT : + case IPP_FINISHINGS_EDGE_STITCH_BOTTOM : + p->type |= CUPS_PRINTER_BIND; + break; + + case IPP_FINISHINGS_COVER : + p->type |= CUPS_PRINTER_COVER; + break; + + case IPP_FINISHINGS_PUNCH : + case IPP_FINISHINGS_PUNCH_TOP_LEFT : + case IPP_FINISHINGS_PUNCH_BOTTOM_LEFT : + case IPP_FINISHINGS_PUNCH_TOP_RIGHT : + case IPP_FINISHINGS_PUNCH_BOTTOM_RIGHT : + case IPP_FINISHINGS_PUNCH_DUAL_LEFT : + case IPP_FINISHINGS_PUNCH_DUAL_TOP : + case IPP_FINISHINGS_PUNCH_DUAL_RIGHT : + case IPP_FINISHINGS_PUNCH_DUAL_BOTTOM : + case IPP_FINISHINGS_PUNCH_TRIPLE_LEFT : + case IPP_FINISHINGS_PUNCH_TRIPLE_TOP : + case IPP_FINISHINGS_PUNCH_TRIPLE_RIGHT : + case IPP_FINISHINGS_PUNCH_TRIPLE_BOTTOM : + case IPP_FINISHINGS_PUNCH_QUAD_LEFT : + case IPP_FINISHINGS_PUNCH_QUAD_TOP : + case IPP_FINISHINGS_PUNCH_QUAD_RIGHT : + case IPP_FINISHINGS_PUNCH_QUAD_BOTTOM : + p->type |= CUPS_PRINTER_PUNCH; + break; + + case IPP_FINISHINGS_STAPLE : + case IPP_FINISHINGS_STAPLE_TOP_LEFT : + case IPP_FINISHINGS_STAPLE_BOTTOM_LEFT : + case IPP_FINISHINGS_STAPLE_TOP_RIGHT : + case IPP_FINISHINGS_STAPLE_BOTTOM_RIGHT : + case IPP_FINISHINGS_STAPLE_DUAL_LEFT : + case IPP_FINISHINGS_STAPLE_DUAL_TOP : + case IPP_FINISHINGS_STAPLE_DUAL_RIGHT : + case IPP_FINISHINGS_STAPLE_DUAL_BOTTOM : + case IPP_FINISHINGS_STAPLE_TRIPLE_LEFT : + case IPP_FINISHINGS_STAPLE_TRIPLE_TOP : + case IPP_FINISHINGS_STAPLE_TRIPLE_RIGHT : + case IPP_FINISHINGS_STAPLE_TRIPLE_BOTTOM : + p->type |= CUPS_PRINTER_STAPLE; + break; + + default : + break; + } + } + } - add_string_array(&(p->filters), - "application/vnd.cups-command 0 commandtops"); - p->type |= CUPS_PRINTER_COMMANDS; + if (p->pc && p->pc->templates) + { + const char *template; /* Finishing template */ + ipp_attribute_t *fin_col_db; /* finishings-col-database attribute */ + ipp_t *fin_col; /* finishings-col value */ + + fin_col_db = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER, "finishings-col-database", cupsArrayCount(p->pc->templates), NULL); + for (i = 0, template = (const char *)cupsArrayFirst(p->pc->templates); template; i ++, template = (const char *)cupsArrayNext(p->pc->templates)) + { + fin_col = ippNew(); + ippAddString(fin_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "finishing-template", NULL, template); + ippSetCollection(p->ppd_attrs, &fin_col_db, i, fin_col); + ippDelete(fin_col); + } + } + + for (i = 0; i < ppd->num_sizes; i ++) + if (ppd->sizes[i].length > 1728) + p->type |= CUPS_PRINTER_LARGE; + else if (ppd->sizes[i].length > 1008) + p->type |= CUPS_PRINTER_MEDIUM; + else + p->type |= CUPS_PRINTER_SMALL; + + if ((ppd_attr = ppdFindAttr(ppd, "APICADriver", NULL)) != NULL && + ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true")) + { + if ((ppd_attr = ppdFindAttr(ppd, "APScannerOnly", NULL)) != NULL && + ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true")) + p->type |= CUPS_PRINTER_SCANNER; + else + p->type |= CUPS_PRINTER_MFP; + } + + /* + * Scan the filters in the PPD file... + */ + + if (p->pc) + { + for (filter = (const char *)cupsArrayFirst(p->pc->filters); + filter; + filter = (const char *)cupsArrayNext(p->pc->filters)) + { + if (!_cups_strncasecmp(filter, "application/vnd.cups-command", 28) && + _cups_isspace(filter[28])) + { + p->type |= CUPS_PRINTER_COMMANDS; + break; + } } } @@ -4287,13 +4798,11 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ *end; /* End of name */ int count; /* Number of commands */ - - if ((ppd_attr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL && - ppd_attr->value && ppd_attr->value[0]) + if ((ppd_attr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL) { for (count = 0, start = ppd_attr->value; *start; count ++) { - while (isspace(*start & 255)) + while (_cups_isspace(*start)) start ++; if (!*start) @@ -4309,7 +4818,8 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ if (count > 0) { /* - * Make a copy of the commands string and count how many ... + * Make a copy of the commands string and count how many commands there + * are... */ attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, @@ -4399,13 +4909,134 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ attr->values[i].string.text = _cupsStrAlloc("bcp"); } -#ifdef HAVE_DNSSD - cupsdSetString(&p->product, ppd->product); -#endif /* HAVE_DNSSD */ - if (ppdFindAttr(ppd, "APRemoteQueueID", NULL)) p->type |= CUPS_PRINTER_REMOTE; +#ifdef HAVE_APPLICATIONSERVICES_H + /* + * Convert the file referenced in APPrinterIconPath to a 128x128 PNG + * and save it as cacheDir/printername.png + */ + + if ((ppd_attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL && + ppd_attr->value && + !_cupsFileCheck(ppd_attr->value, _CUPS_FILE_CHECK_FILE, !RunUser, + cupsdLogFCMessage, p)) + { + CGImageRef imageRef = NULL;/* Current icon image */ + CGImageRef biggestIconRef = NULL; + /* Biggest icon image */ + CGImageRef closestTo128IconRef = NULL; + /* Icon image closest to and >= 128 */ + CGImageSourceRef sourceRef; /* The file's image source */ + char outPath[HTTP_MAX_URI]; + /* The path to the PNG file */ + CFURLRef outUrl; /* The URL made from the outPath */ + CFURLRef icnsFileUrl; /* The URL of the original ICNS icon file */ + CGImageDestinationRef destRef; /* The image destination to write */ + size_t bytesPerRow; /* The bytes per row used for resizing */ + CGContextRef context; /* The CG context used for resizing */ + + snprintf(outPath, sizeof(outPath), "%s/%s.png", CacheDir, p->name); + outUrl = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *)outPath, (CFIndex)strlen(outPath), FALSE); + icnsFileUrl = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *)ppd_attr->value, (CFIndex)strlen(ppd_attr->value), FALSE); + if (outUrl && icnsFileUrl) + { + sourceRef = CGImageSourceCreateWithURL(icnsFileUrl, NULL); + if (sourceRef) + { + for (i = 0; i < (int)CGImageSourceGetCount(sourceRef); i ++) + { + imageRef = CGImageSourceCreateImageAtIndex(sourceRef, (size_t)i, NULL); + if (!imageRef) + continue; + + if (CGImageGetWidth(imageRef) == CGImageGetHeight(imageRef)) + { + /* + * Loop through remembering the icon closest to 128 but >= 128 + * and then remember the largest icon. + */ + + if (CGImageGetWidth(imageRef) >= 128 && + (!closestTo128IconRef || + CGImageGetWidth(imageRef) < + CGImageGetWidth(closestTo128IconRef))) + { + CGImageRelease(closestTo128IconRef); + CGImageRetain(imageRef); + closestTo128IconRef = imageRef; + } + + if (!biggestIconRef || + CGImageGetWidth(imageRef) > CGImageGetWidth(biggestIconRef)) + { + CGImageRelease(biggestIconRef); + CGImageRetain(imageRef); + biggestIconRef = imageRef; + } + } + + CGImageRelease(imageRef); + } + + if (biggestIconRef) + { + /* + * If biggestIconRef is NULL, we found no icons. Otherwise we first + * want the closest to 128, but if none are larger than 128, we want + * the largest icon available. + */ + + imageRef = closestTo128IconRef ? closestTo128IconRef : + biggestIconRef; + CGImageRetain(imageRef); + CGImageRelease(biggestIconRef); + if (closestTo128IconRef) + CGImageRelease(closestTo128IconRef); + destRef = CGImageDestinationCreateWithURL(outUrl, kUTTypePNG, 1, + NULL); + if (destRef) + { + if (CGImageGetWidth(imageRef) != 128) + { + bytesPerRow = CGImageGetBytesPerRow(imageRef) / + CGImageGetWidth(imageRef) * 128; + context = CGBitmapContextCreate(NULL, 128, 128, + CGImageGetBitsPerComponent(imageRef), + bytesPerRow, + CGImageGetColorSpace(imageRef), + kCGImageAlphaPremultipliedFirst); + if (context) + { + CGContextDrawImage(context, CGRectMake(0, 0, 128, 128), + imageRef); + CGImageRelease(imageRef); + imageRef = CGBitmapContextCreateImage(context); + CGContextRelease(context); + } + } + + CGImageDestinationAddImage(destRef, imageRef, NULL); + CGImageDestinationFinalize(destRef); + CFRelease(destRef); + } + + CGImageRelease(imageRef); + } + + CFRelease(sourceRef); + } + } + + if (outUrl) + CFRelease(outUrl); + + if (icnsFileUrl) + CFRelease(icnsFileUrl); + } +#endif /* HAVE_APPLICATIONSERVICES_H */ + /* * Close the PPD and set the type... */ @@ -4420,63 +5051,26 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ pstatus = ppdLastError(&pline); - cupsdLogMessage(CUPSD_LOG_ERROR, "PPD file for %s cannot be loaded!", - p->name); + cupsdLogMessage(CUPSD_LOG_ERROR, "PPD file for %s cannot be loaded.", p->name); if (pstatus <= PPD_ALLOC_ERROR) - cupsdLogMessage(CUPSD_LOG_ERROR, "%s", strerror(errno)); + cupsdLogMessage(CUPSD_LOG_ERROR, "%s: %s", ppd_name, strerror(errno)); else - cupsdLogMessage(CUPSD_LOG_ERROR, "%s on line %d.", - ppdErrorString(pstatus), pline); + cupsdLogMessage(CUPSD_LOG_ERROR, "%s on line %d of %s.", ppdErrorString(pstatus), pline, ppd_name); cupsdLogMessage(CUPSD_LOG_INFO, "Hint: Run \"cupstestppd %s\" and fix any errors.", ppd_name); - - /* - * Add a filter from application/vnd.cups-raw to printer/name to - * handle "raw" printing by users. - */ - - add_string_array(&(p->filters), "application/vnd.cups-raw 0 -"); - - /* - * Add a PostScript filter, since this is still possibly PS printer. - */ - - add_string_array(&(p->filters), "application/vnd.cups-postscript 0 -"); } else { - /* - * If we have an interface script, add a filter entry for it... - */ - - char interface[1024]; /* Interface script */ - - - snprintf(interface, sizeof(interface), "%s/interfaces/%s", ServerRoot, - p->name); - if (!access(interface, X_OK)) - { - /* - * Yes, we have a System V style interface script; use it! - */ - - ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "printer-make-and-model", NULL, - "Local System V Printer"); - - snprintf(interface, sizeof(interface), "*/* 0 %s/interfaces/%s", - ServerRoot, p->name); - add_string_array(&(p->filters), interface); - } - else if (!strncmp(p->device_uri, "ipp://", 6) && - (strstr(p->device_uri, "/printers/") != NULL || - strstr(p->device_uri, "/classes/") != NULL || - (strstr(p->device_uri, "._ipp.") != NULL && - !strcmp(p->device_uri + strlen(p->device_uri) - 5, - "/cups")))) + if (((!strncmp(p->device_uri, "ipp://", 6) || + !strncmp(p->device_uri, "ipps://", 7)) && + (strstr(p->device_uri, "/printers/") != NULL || + strstr(p->device_uri, "/classes/") != NULL)) || + ((strstr(p->device_uri, "._ipp.") != NULL || + strstr(p->device_uri, "._ipps.") != NULL) && + !strcmp(p->device_uri + strlen(p->device_uri) - 5, "/cups"))) { /* * Tell the client this is really a hard-wired remote printer. @@ -4484,14 +5078,6 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ p->type |= CUPS_PRINTER_REMOTE; - /* - * Point the printer-uri-supported attribute to the - * remote printer... - */ - - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, - "printer-uri-supported", NULL, p->device_uri); - /* * Then set the make-and-model accordingly... */ @@ -4525,7 +5111,7 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "finishings-default", IPP_FINISHINGS_NONE); - if (ppd && (cache = cupsFileOpen(cache_name, "w")) != NULL) + if (ppd && p->pc) { /* * Save cached PPD attributes to disk... @@ -4533,283 +5119,62 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Saving %s...", cache_name); - p->ppd_attrs->state = IPP_IDLE; - - if (ippWriteIO(cache, (ipp_iocb_t)cupsFileWrite, 1, NULL, - p->ppd_attrs) != IPP_DATA) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to save PPD cache file \"%s\" - %s", cache_name, - strerror(errno)); - unlink(cache_name); - } - - cupsFileClose(cache); + _ppdCacheWriteFile(p->pc, cache_name, p->ppd_attrs); } - else if (cache_info.st_mtime) + else { /* - * Remove cache file... + * Remove cache files... */ - unlink(cache_name); - } -} - - -#ifdef __sgi -/* - * 'write_irix_config()' - Update the config files used by the IRIX - * desktop tools. - */ - -static void -write_irix_config(cupsd_printer_t *p) /* I - Printer to update */ -{ - char filename[1024]; /* Interface script filename */ - cups_file_t *fp; /* Interface script file */ - ipp_attribute_t *attr; /* Attribute data */ - - - /* - * Add dummy interface and GUI scripts to fool SGI's "challenged" printing - * tools. First the interface script that tells the tools what kind of - * printer we have... - */ - - snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name); - - if (p->type & CUPS_PRINTER_CLASS) - unlink(filename); - else if ((fp = cupsFileOpen(filename, "w")) != NULL) - { - cupsFilePuts(fp, "#!/bin/sh\n"); - - if ((attr = ippFindAttribute(p->attrs, "printer-make-and-model", - IPP_TAG_TEXT)) != NULL) - cupsFilePrintf(fp, "NAME=\"%s\"\n", attr->values[0].string.text); - else if (p->type & CUPS_PRINTER_CLASS) - cupsFilePuts(fp, "NAME=\"Printer Class\"\n"); - else - cupsFilePuts(fp, "NAME=\"Remote Destination\"\n"); - - if (p->type & CUPS_PRINTER_COLOR) - cupsFilePuts(fp, "TYPE=ColorPostScript\n"); - else - cupsFilePuts(fp, "TYPE=MonoPostScript\n"); - - cupsFilePrintf(fp, "HOSTNAME=%s\n", ServerName); - cupsFilePrintf(fp, "HOSTPRINTER=%s\n", p->name); - - cupsFileClose(fp); - - chmod(filename, 0755); - chown(filename, User, Group); - } - - /* - * Then the member file that tells which device file the queue is connected - * to... Networked printers use "/dev/null" in this file, so that's what - * we use (the actual device URI can confuse some apps...) - */ - - snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name); - - if (p->type & CUPS_PRINTER_CLASS) - unlink(filename); - else if ((fp = cupsFileOpen(filename, "w")) != NULL) - { - cupsFilePuts(fp, "/dev/null\n"); - - cupsFileClose(fp); - - chmod(filename, 0644); - chown(filename, User, Group); - } - - /* - * The gui_interface file is a script or program that launches a GUI - * option panel for the printer, using options specified on the - * command-line in the third argument. The option panel must send - * any printing options to stdout on a single line when the user - * accepts them, or nothing if the user cancels the dialog. - * - * The default options panel program is /usr/bin/glpoptions, from - * the ESP Print Pro software. You can select another using the - * PrintcapGUI option. - */ - - snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui", p->name); - - if (p->type & CUPS_PRINTER_CLASS) - unlink(filename); - else if ((fp = cupsFileOpen(filename, "w")) != NULL) - { - cupsFilePuts(fp, "#!/bin/sh\n"); - cupsFilePrintf(fp, "%s -d %s -o \"$3\"\n", PrintcapGUI, p->name); - - cupsFileClose(fp); - - chmod(filename, 0755); - chown(filename, User, Group); - } - - /* - * The POD config file is needed by the printstatus command to show - * the printer location and device. - */ - - snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name); - - if (p->type & CUPS_PRINTER_CLASS) - unlink(filename); - else if ((fp = cupsFileOpen(filename, "w")) != NULL) - { - cupsFilePrintf(fp, "Printer Class | %s\n", - (p->type & CUPS_PRINTER_COLOR) ? "ColorPostScript" : "MonoPostScript"); - cupsFilePrintf(fp, "Printer Model | %s\n", p->make_model ? p->make_model : ""); - cupsFilePrintf(fp, "Location Code | %s\n", p->location ? p->location : ""); - cupsFilePrintf(fp, "Physical Location | %s\n", p->info ? p->info : ""); - cupsFilePrintf(fp, "Port Path | %s\n", p->device_uri); - cupsFilePrintf(fp, "Config Path | /var/spool/lp/pod/%s.config\n", p->name); - cupsFilePrintf(fp, "Active Status Path | /var/spool/lp/pod/%s.status\n", p->name); - cupsFilePuts(fp, "Status Update Wait | 10 seconds\n"); - - cupsFileClose(fp); - - chmod(filename, 0664); - chown(filename, User, Group); + if (cache_info.st_mtime) + unlink(cache_name); } } /* - * 'write_irix_state()' - Update the status files used by IRIX printing - * desktop tools. + * 'new_media_col()' - Create a media-col collection value. */ -static void -write_irix_state(cupsd_printer_t *p) /* I - Printer to update */ +static ipp_t * /* O - Collection value */ +new_media_col(pwg_size_t *size, /* I - media-size/margin values */ + const char *source, /* I - media-source value */ + const char *type) /* I - media-type value */ { - char filename[1024]; /* Interface script filename */ - cups_file_t *fp; /* Interface script file */ - int tag; /* Status tag value */ - - - if (p) - { - /* - * The POD status file is needed for the printstatus window to - * provide the current status of the printer. - */ - - snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name); - - if (p->type & CUPS_PRINTER_CLASS) - unlink(filename); - else if ((fp = cupsFileOpen(filename, "w")) != NULL) - { - cupsFilePrintf(fp, "Operational Status | %s\n", - (p->state == IPP_PRINTER_IDLE) ? "Idle" : - (p->state == IPP_PRINTER_PROCESSING) ? "Busy" : - "Faulted"); - cupsFilePrintf(fp, "Information | 01 00 00 | %s\n", CUPS_SVERSION); - cupsFilePrintf(fp, "Information | 02 00 00 | Device URI: %s\n", - p->device_uri); - cupsFilePrintf(fp, "Information | 03 00 00 | %s jobs\n", - p->accepting ? "Accepting" : "Not accepting"); - cupsFilePrintf(fp, "Information | 04 00 00 | %s\n", p->state_message); - - cupsFileClose(fp); - - chmod(filename, 0664); - chown(filename, User, Group); - } - - /* - * The activeicons file is needed to provide desktop icons for printers: - * - * [ quoted from /usr/lib/print/tagit ] - * - * --- Type of printer tags (base values) - * - * Dumb=66048 # 0x10200 - * DumbColor=66080 # 0x10220 - * Raster=66112 # 0x10240 - * ColorRaster=66144 # 0x10260 - * Plotter=66176 # 0x10280 - * PostScript=66208 # 0x102A0 - * ColorPostScript=66240 # 0x102C0 - * MonoPostScript=66272 # 0x102E0 - * - * --- Printer state modifiers for local printers - * - * Idle=0 # 0x0 - * Busy=1 # 0x1 - * Faulted=2 # 0x2 - * Unknown=3 # 0x3 (Faulted due to unknown reason) - * - * --- Printer state modifiers for network printers - * - * NetIdle=8 # 0x8 - * NetBusy=9 # 0x9 - * NetFaulted=10 # 0xA - * NetUnknown=11 # 0xB (Faulted due to unknown reason) - */ - - snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name); - - if (p->type & CUPS_PRINTER_CLASS) - unlink(filename); - else if ((fp = cupsFileOpen(filename, "w")) != NULL) - { - if (p->type & CUPS_PRINTER_COLOR) - tag = 66240; - else - tag = 66272; - - if (p->type & CUPS_PRINTER_REMOTE) - tag |= 8; - - if (p->state == IPP_PRINTER_PROCESSING) - tag |= 1; - - else if (p->state == IPP_PRINTER_STOPPED) - tag |= 2; - - cupsFilePuts(fp, "#!/bin/sh\n"); - cupsFilePrintf(fp, "#Tag %d\n", tag); - - cupsFileClose(fp); - - chmod(filename, 0755); - chown(filename, User, Group); - } - } - - /* - * The default file is needed by the printers window to show - * the default printer. - */ - - snprintf(filename, sizeof(filename), "/var/spool/lp/default"); - - if (DefaultPrinter != NULL) - { - if ((fp = cupsFileOpen(filename, "w")) != NULL) - { - cupsFilePrintf(fp, "%s\n", DefaultPrinter->name); - - cupsFileClose(fp); - - chmod(filename, 0644); - chown(filename, User, Group); - } - } - else - unlink(filename); + ipp_t *media_col, /* Collection value */ + *media_size; /* media-size value */ + + + media_col = ippNew(); + + media_size = ippNew(); + ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "x-dimension", size->width); + ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "y-dimension", size->length); + ippAddCollection(media_col, IPP_TAG_PRINTER, "media-size", media_size); + ippDelete(media_size); + + ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "media-bottom-margin", size->bottom); + ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "media-left-margin", size->left); + ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "media-right-margin", size->right); + ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "media-top-margin", size->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); + + return (media_col); } -#endif /* __sgi */ /* @@ -4831,7 +5196,7 @@ write_xml_string(cups_file_t *fp, /* I - File to write to */ if (*s == '&') { if (s > start) - cupsFileWrite(fp, start, s - start); + cupsFileWrite(fp, start, (size_t)(s - start)); cupsFilePuts(fp, "&"); start = s + 1; @@ -4839,7 +5204,7 @@ write_xml_string(cups_file_t *fp, /* I - File to write to */ else if (*s == '<') { if (s > start) - cupsFileWrite(fp, start, s - start); + cupsFileWrite(fp, start, (size_t)(s - start)); cupsFilePuts(fp, "<"); start = s + 1; @@ -4849,8 +5214,3 @@ write_xml_string(cups_file_t *fp, /* I - File to write to */ if (s > start) cupsFilePuts(fp, start); } - - -/* - * End of "$Id: printers.c 7968 2008-09-19 23:03:01Z mike $". - */