X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=scheduler%2Fprinters.c;h=86b3e5939cb06e2aca715aa83d6467099759605f;hb=a990ad13c72db45073b5d73f4dba0d99074062e3;hp=a2e71fb931bc698d363f0065f5a17464c5d7db4b;hpb=20fbc9034781e607f8063453c8a52ec73fc5c293;p=thirdparty%2Fcups.git diff --git a/scheduler/printers.c b/scheduler/printers.c index a2e71fb93..86b3e5939 100644 --- a/scheduler/printers.c +++ b/scheduler/printers.c @@ -1,54 +1,16 @@ /* - * "$Id: printers.c 6970 2007-09-17 23:58:28Z mike $" + * "$Id$" * - * Printer routines for the Common UNIX Printing System (CUPS). + * Printer routines for the CUPS scheduler. * - * Copyright 2007-2008 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * Copyright 2007-2015 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. - * 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. - * 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... - * 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... - * cupsdSanitizeURI() - Sanitize a device URI... - * 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. - * compare_printers() - Compare two printers. - * delete_printer_filters() - Delete all MIME filters for a printer. - * 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. + * 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/". */ /* @@ -57,6 +19,23 @@ #include "cupsd.h" #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__ */ /* @@ -69,10 +48,11 @@ static void add_printer_filter(cupsd_printer_t *p, mime_type_t *type, static void add_printer_formats(cupsd_printer_t *p); static int compare_printers(void *first, void *second, void *data); static void delete_printer_filters(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 void dirty_printer(cupsd_printer_t *p); +static void load_ppd(cupsd_printer_t *p); +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); /* @@ -83,6 +63,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 */ /* @@ -106,14 +88,19 @@ cupsdAddPrinter(const char *name) /* I - Name of printer */ cupsdSetString(&p->info, name); cupsdSetString(&p->hostname, ServerName); - cupsdSetStringf(&p->uri, "ipp://%s:%d/printers/%s", ServerName, LocalPort, name); - cupsdSetStringf(&p->device_uri, "file:/dev/null"); + 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"); @@ -123,9 +110,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... */ @@ -133,11 +117,10 @@ cupsdAddPrinter(const char *name) /* I - Name of printer */ if (!Printers) Printers = cupsArrayNew(compare_printers, NULL); + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAddPrinter: Adding %s to Printers", p->name); cupsArrayAdd(Printers, p); - if (!ImplicitPrinters) - ImplicitPrinters = cupsArrayNew(compare_printers, NULL); - /* * Return the new printer... */ @@ -146,104 +129,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); -#ifdef __APPLE__ - if (p->recoverable) - ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "com.apple.print.recoverable-message", NULL, p->recoverable); -#endif /* __APPLE__ */ - if (p->num_reasons == 0) - ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "printer-state-reasons", NULL, - p->state == IPP_PRINTER_STOPPED ? "paused" : "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. */ @@ -259,6 +144,14 @@ cupsdCreateCommonData(void) char filename[1024], /* Filename */ *notifier; /* Current notifier */ cupsd_policy_t *p; /* Current policy */ + int k_supported; /* Maximum file size supported */ +#ifdef HAVE_STATVFS + struct statvfs spoolinfo; /* FS info for spool directory */ + double spoolsize; /* FS size */ +#elif defined(HAVE_STATFS) + struct statfs spoolinfo; /* FS info for spool directory */ + double spoolsize; /* FS size */ +#endif /* HAVE_STATVFS */ static const int nups[] = /* number-up-supported values */ { 1, 2, 4, 6, 9, 16 }; static const int orients[4] =/* orientation-requested-supported values */ @@ -279,53 +172,66 @@ 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", - "1.1" + "1.1", + "2.0", + "2.1" }; 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_JOB_ATTRIBUTES, - 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, - 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 */ { @@ -339,17 +245,21 @@ cupsdCreateCommonData(void) ,"gzip" #endif /* HAVE_LIBZ */ }; + static const char * const media_col_supported[] = + { /* media-col-supported values */ + "media-bottom-margin", + "media-left-margin", + "media-right-margin", + "media-size", + "media-source", + "media-top-margin", + "media-type" + }; static const char * const multiple_document_handling[] = { /* multiple-document-handling-supported values */ "separate-documents-uncollated-copies", "separate-documents-collated-copies" }; - static const char * const errors[] = /* printer-error-policy-supported values */ - { - "abort-job", - "retry-job", - "stop-printer" - }; static const char * const notify_attrs[] = { /* notify-attributes-supported values */ "printer-state-change-time", @@ -380,6 +290,78 @@ cupsdCreateCommonData(void) "server-started", "server-stopped" }; + static const char * const job_creation[] = + { /* job-creation-attributes-supported */ + "copies", + "finishings", + "ipp-attribute-fidelity", + "job-hold-until", + "job-name", + "job-priority", + "job-sheets", + "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 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-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) @@ -387,22 +369,50 @@ 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... */ /* charset-configured */ - ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET, - "charset-configured", NULL, DefaultCharset); + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY, + "charset-configured", NULL, "utf-8"); /* charset-supported */ - ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET, + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY, "charset-supported", sizeof(charsets) / sizeof(charsets[0]), NULL, charsets); /* compression-supported */ - ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, "compression-supported", sizeof(compressions) / sizeof(compressions[0]), NULL, compressions); @@ -411,27 +421,57 @@ cupsdCreateCommonData(void) ippAddRange(CommonData, IPP_TAG_PRINTER, "copies-supported", 1, MaxCopies); /* cups-version */ - ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_TEXT, "cups-version", - NULL, CUPS_SVERSION + 6); + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_TEXT | IPP_TAG_COPY, + "cups-version", NULL, CUPS_SVERSION + 6); - /* generated-natural-language-supported */ + /* generated-natural-language-supported (no IPP_TAG_COPY) */ 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, + 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, + 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); + /* job-settable-attributes-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, + "job-settable-attributes-supported", + sizeof(job_settable) / sizeof(job_settable[0]), + NULL, job_settable); + /* job-sheets-supported */ if (cupsArrayCount(Banners) > 0) { @@ -440,10 +480,12 @@ cupsdCreateCommonData(void) */ if (Classification && !ClassifyOverride) - attr = ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME, + attr = ippAddString(CommonData, IPP_TAG_PRINTER, + IPP_TAG_NAME | IPP_TAG_COPY, "job-sheets-supported", NULL, Classification); else - attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME, + attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, + IPP_TAG_NAME | IPP_TAG_COPY, "job-sheets-supported", cupsArrayCount(Banners) + 1, NULL, NULL); @@ -461,15 +503,34 @@ cupsdCreateCommonData(void) for (i = 1, banner = (cupsd_banner_t *)cupsArrayFirst(Banners); banner; i ++, banner = (cupsd_banner_t *)cupsArrayNext(Banners)) - attr->values[i].string.text = _cupsStrAlloc(banner->name); + attr->values[i].string.text = banner->name; } } else - ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME, + 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", + sizeof(media_col_supported) / + sizeof(media_col_supported[0]), NULL, + media_col_supported); + /* multiple-document-handling-supported */ - ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, "multiple-document-handling-supported", sizeof(multiple_document_handling) / sizeof(multiple_document_handling[0]), NULL, @@ -481,14 +542,17 @@ cupsdCreateCommonData(void) /* multiple-operation-time-out */ ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "multiple-operation-time-out", 60); + "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 */ + /* natural-language-configured (no IPP_TAG_COPY) */ ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE, "natural-language-configured", NULL, DefaultLanguage); /* notify-attributes-supported */ - ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, "notify-attributes-supported", (int)(sizeof(notify_attrs) / sizeof(notify_attrs[0])), NULL, notify_attrs); @@ -503,13 +567,13 @@ cupsdCreateCommonData(void) "notify-max-events-supported", MaxEvents); /* notify-events-supported */ - ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, "notify-events-supported", (int)(sizeof(notify_events) / sizeof(notify_events[0])), NULL, notify_events); /* notify-pull-method-supported */ - ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, "notify-pull-method-supported", NULL, "ippget"); /* notify-schemes-supported */ @@ -545,8 +609,7 @@ cupsdCreateCommonData(void) /* 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, @@ -555,26 +618,46 @@ cupsdCreateCommonData(void) /* page-ranges-supported */ ippAddBoolean(CommonData, IPP_TAG_PRINTER, "page-ranges-supported", 1); - /* pdf-override-supported */ - ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "pdl-override-supported", NULL, "not-attempted"); + /* 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, "attempted"); - /* printer-error-policy-supported */ - ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME, - "printer-error-policy-supported", - sizeof(errors) / sizeof(errors[0]), NULL, errors); + /* 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, + attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY, "printer-op-policy-supported", cupsArrayCount(Policies), NULL, NULL); for (i = 0, p = (cupsd_policy_t *)cupsArrayFirst(Policies); p; i ++, p = (cupsd_policy_t *)cupsArrayNext(Policies)) - attr->values[i].string.text = _cupsStrAlloc(p->name); + attr->values[i].string.text = p->name; + /* printer-settable-attributes-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, + "printer-settable-attributes-supported", + sizeof(printer_settable) / sizeof(printer_settable[0]), + NULL, printer_settable); + + /* 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); } @@ -591,8 +674,10 @@ cupsdDeleteAllPrinters(void) for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) - if (!(p->type & CUPS_PRINTER_CLASS)) - cupsdDeletePrinter(p, 0); + { + p->op_policy_ptr = DefaultPolicyPtr; + cupsdDeletePrinter(p, 0); + } } @@ -600,15 +685,13 @@ cupsdDeleteAllPrinters(void) * 'cupsdDeletePrinter()' - Delete a printer from the system. */ -void +int /* O - 1 if classes affected, 0 otherwise */ cupsdDeletePrinter( cupsd_printer_t *p, /* I - Printer to delete */ int update) /* I - Update printers.conf? */ { - int i; /* Looping var */ -#ifdef __sgi - char filename[1024]; /* Interface script filename */ -#endif /* __sgi */ + int i, /* Looping var */ + changed = 0; /* Class changed? */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDeletePrinter(p=%p(%s), update=%d)", @@ -624,94 +707,41 @@ cupsdDeletePrinter( * Stop printing on this printer... */ - cupsdStopPrinter(p, update); + cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update); - /* - * If this printer is the next for browsing, point to the next one... - */ + p->state = IPP_PRINTER_STOPPED; /* Force for browsed printers */ - if (p == BrowseNext) - { - cupsArrayFind(Printers, p); - BrowseNext = (cupsd_printer_t *)cupsArrayNext(Printers); - } + if (p->job) + cupsdSetJobState(p->job, IPP_JOB_PENDING, CUPSD_JOB_FORCE, + update ? "Job stopped due to printer being deleted." : + "Job stopped."); /* * Remove the printer from the list... */ + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdDeletePrinter: Removing %s from Printers", p->name); cupsArrayRemove(Printers, p); - if (p->type & CUPS_PRINTER_IMPLICIT) - cupsArrayRemove(ImplicitPrinters, p); - - /* - * Remove the dummy interface/icon/option files under IRIX... - */ - -#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); - - snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name); - unlink(filename); - - snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name); - unlink(filename); - - snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name); - unlink(filename); - - snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name); - unlink(filename); -#endif /* __sgi */ - /* * If p is the default printer, assign a different one... */ if (p == DefaultPrinter) - { DefaultPrinter = NULL; - if (UseNetworkDefault) - { - /* - * Find the first network default printer and use it... - */ - - cupsd_printer_t *dp; /* New default printer */ - - - 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; - } - } - } - /* * Remove this printer from any classes... */ - if (!(p->type & CUPS_PRINTER_IMPLICIT)) - { - cupsdDeletePrinterFromClasses(p); + changed = cupsdDeletePrinterFromClasses(p); - /* - * Deregister from any browse protocols... - */ + /* + * Deregister from any browse protocols... + */ - cupsdDeregisterPrinter(p, 1); - } + cupsdDeregisterPrinter(p, 1); /* * Free all memory used by the printer... @@ -720,36 +750,31 @@ 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 ++) - free(p->reasons[i]); + _cupsStrFree(p->reasons[i]); ippDelete(p->attrs); - - delete_printer_filters(p); + ippDelete(p->ppd_attrs); mimeDeleteType(MimeDatabase, p->filetype); mimeDeleteType(MimeDatabase, p->prefiltertype); - 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]); cupsdClearString(&p->job_sheets[1]); cupsdClearString(&p->device_uri); + cupsdClearString(&p->sanitized_device_uri); cupsdClearString(&p->port_monitor); cupsdClearString(&p->op_policy); cupsdClearString(&p->error_policy); @@ -757,20 +782,13 @@ cupsdDeletePrinter( 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); - -#ifdef __APPLE__ - cupsdClearString(&p->recoverable); -#endif /* __APPLE__ */ - cupsFreeOptions(p->num_options, p->options); free(p); @@ -780,6 +798,8 @@ cupsdDeletePrinter( */ cupsArrayRestore(Printers); + + return (changed); } @@ -815,30 +835,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. */ @@ -846,9 +842,10 @@ cupsdFreePrinterUsers( void cupsdLoadAllPrinters(void) { + int i; /* Looping var */ cups_file_t *fp; /* printers.conf file */ int linenum; /* Current line number */ - char line[1024], /* Line from file */ + char line[4096], /* Line from file */ *value, /* Pointer to value */ *valueptr; /* Pointer into value */ cupsd_printer_t *p; /* Current printer */ @@ -859,13 +856,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... @@ -880,8 +872,8 @@ cupsdLoadAllPrinters(void) * Decode the directive... */ - if (!strcasecmp(line, " or @@ -903,17 +895,14 @@ cupsdLoadAllPrinters(void) * Set the default printer as needed... */ - if (!strcasecmp(line, "")) + else if (!_cups_strcasecmp(line, "") || !_cups_strcasecmp(line, "")) { if (p != NULL) { @@ -922,9 +911,8 @@ cupsdLoadAllPrinters(void) */ cupsdSetPrinterAttrs(p); - cupsdAddPrinterHistory(p); - if (p->device_uri && strncmp(p->device_uri, "file:", 5) && + if (strncmp(p->device_uri, "file:", 5) && p->state != IPP_PRINTER_STOPPED) { /* @@ -952,47 +940,68 @@ cupsdLoadAllPrinters(void) p = NULL; } else - { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); - break; - } } else if (!p) { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); - break; } - else if (!strcasecmp(line, "AuthInfoRequired")) + 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, "Location")) + else if (!_cups_strcasecmp(line, "MakeModel")) + { + if (value) + cupsdSetString(&p->make_model, value); + } + 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) - cupsdSetString(&p->device_uri, value); + cupsdSetDeviceURI(p, value); else - { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); - break; - } } - else if (!strcasecmp(line, "Option") && value) + else if (!_cups_strcasecmp(line, "Option") && value) { /* * Option name value @@ -1011,37 +1020,66 @@ 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); else if (value) cupsdClearString(&p->port_monitor); else - { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); - break; + } + else if (!_cups_strcasecmp(line, "Reason")) + { + if (value && + strcmp(value, "connecting-to-device") && + strcmp(value, "cups-insecure-filter-warning") && + strcmp(value, "cups-missing-filter-warning")) + { + for (i = 0 ; i < p->num_reasons; i ++) + if (!strcmp(value, p->reasons[i])) + break; + + if (i >= p->num_reasons && + p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0]))) + { + p->reasons[p->num_reasons] = _cupsStrAlloc(value); + p->num_reasons ++; + } } + else + 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; + + for (i = 0 ; i < p->num_reasons; i ++) + if (!strcmp("paused", p->reasons[i])) + break; + + if (i >= p->num_reasons && + p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0]))) + { + p->reasons[p->num_reasons] = _cupsStrAlloc("paused"); + p->num_reasons ++; + } + } else - { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); - break; - } } - else if (!strcasecmp(line, "StateMessage")) + else if (!_cups_strcasecmp(line, "StateMessage")) { /* * Set the initial queue state message... @@ -1050,7 +1088,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... @@ -1059,53 +1097,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); - break; - } } - else if (!strcasecmp(line, "Shared")) + else if (!_cups_strcasecmp(line, "Type")) + { + if (value) + p->type = (cups_ptype_t)atoi(value); + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of printers.conf.", linenum); + } + 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); - break; - } } - else if (!strcasecmp(line, "JobSheets")) + else if (!_cups_strcasecmp(line, "JobSheets")) { /* * Set the initial job sheets... @@ -1128,80 +1177,62 @@ cupsdLoadAllPrinters(void) for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++); if (*valueptr) - *valueptr++ = '\0'; + *valueptr = '\0'; cupsdSetString(&p->job_sheets[1], value); } } else - { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); - break; - } } - 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); - break; - } } - 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); - break; - } } - else if (!strcasecmp(line, "QuotaPeriod")) + else if (!_cups_strcasecmp(line, "QuotaPeriod")) { if (value) p->quota_period = atoi(value); else - { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); - break; - } } - else if (!strcasecmp(line, "PageLimit")) + else if (!_cups_strcasecmp(line, "PageLimit")) { if (value) p->page_limit = atoi(value); else - { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); - break; - } } - else if (!strcasecmp(line, "KLimit")) + else if (!_cups_strcasecmp(line, "KLimit")) { if (value) p->k_limit = atoi(value); else - { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); - break; - } } - else if (!strcasecmp(line, "OpPolicy")) + else if (!_cups_strcasecmp(line, "OpPolicy")) { if (value) { @@ -1219,24 +1250,25 @@ cupsdLoadAllPrinters(void) value, linenum); } else - { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum); - break; - } } - else if (!strcasecmp(line, "ErrorPolicy")) + else if (!_cups_strcasecmp(line, "ErrorPolicy")) { if (value) - cupsdSetString(&p->error_policy, value); - else { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of printers.conf.", linenum); - break; + 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); } - else if (!strcasecmp(line, "Attribute") && value) + else if (!_cups_strcasecmp(line, "Attribute") && value) { for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++); @@ -1247,21 +1279,27 @@ cupsdLoadAllPrinters(void) { for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0'); - cupsdSetPrinterAttr(p, value, valueptr); + if (!p->attrs) + cupsdSetPrinterAttrs(p); - if (!strncmp(value, "marker-", 7)) - p->marker_time = time(NULL); + if (!strcmp(value, "marker-change-time")) + p->marker_time = atoi(valueptr); + else + 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); } } @@ -1282,11 +1320,10 @@ cupsdRenamePrinter( * Remove the printer from the array(s) first... */ + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdRenamePrinter: Removing %s from Printers", p->name); cupsArrayRemove(Printers, p); - if (p->type & CUPS_PRINTER_IMPLICIT) - cupsArrayRemove(ImplicitPrinters, p); - /* * Rename the printer type... */ @@ -1294,8 +1331,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... @@ -1313,10 +1353,9 @@ cupsdRenamePrinter( * Add the printer back to the printer array(s)... */ + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdRenamePrinter: Adding %s to Printers", p->name); cupsArrayAdd(Printers, p); - - if (p->type & CUPS_PRINTER_IMPLICIT) - cupsArrayAdd(ImplicitPrinters, p); } @@ -1330,13 +1369,15 @@ cupsdSaveAllPrinters(void) { int i; /* Looping var */ cups_file_t *fp; /* printers.conf file */ - char temp[1024]; /* Temporary string */ - char backup[1024]; /* printers.conf.O file */ + char filename[1024], /* printers.conf filename */ + temp[1024], /* Temporary string */ + value[2048], /* Value string */ + *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 */ cups_option_t *option; /* Current option */ - const char *ptr; /* Pointer into info/location */ ipp_attribute_t *marker; /* Current marker attribute */ @@ -1344,35 +1385,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 = 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)); + if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm & 0600)) == NULL) 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... @@ -1384,6 +1402,7 @@ cupsdSaveAllPrinters(void) cupsFilePuts(fp, "# Printer configuration file for " CUPS_SVERSION "\n"); cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp); + cupsFilePuts(fp, "# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING\n"); /* * Write each local printer known to the system... @@ -1394,12 +1413,10 @@ cupsdSaveAllPrinters(void) printer = (cupsd_printer_t *)cupsArrayNext(Printers)) { /* - * Skip remote destinations and printer classes... + * Skip printer classes... */ - if ((printer->type & CUPS_PRINTER_DISCOVERED) || - (printer->type & CUPS_PRINTER_CLASS) || - (printer->type & CUPS_PRINTER_IMPLICIT)) + if (printer->type & CUPS_PRINTER_CLASS) continue; /* @@ -1411,64 +1428,77 @@ cupsdSaveAllPrinters(void) else cupsFilePrintf(fp, "\n", printer->name); - if (printer->num_auth_info_required > 0) - { - cupsFilePrintf(fp, "AuthInfoRequired %s", printer->auth_info_required[0]); - for (i = 1; i < printer->num_auth_info_required; i ++) - cupsFilePrintf(fp, ",%s", printer->auth_info_required[i]); - cupsFilePutChar(fp, '\n'); - } + cupsFilePrintf(fp, "UUID %s\n", printer->uuid); - if (printer->info) + if (printer->num_auth_info_required > 0) { - if ((ptr = strchr(printer->info, '#')) != NULL) + switch (printer->num_auth_info_required) { - /* - * Need to quote the first # in the info string... - */ - - cupsFilePuts(fp, "Info "); - cupsFileWrite(fp, printer->info, ptr - printer->info); - cupsFilePutChar(fp, '\\'); - cupsFilePuts(fp, ptr); - cupsFilePutChar(fp, '\n'); + case 1 : + strlcpy(value, printer->auth_info_required[0], sizeof(value)); + break; + + case 2 : + snprintf(value, sizeof(value), "%s,%s", + printer->auth_info_required[0], + printer->auth_info_required[1]); + break; + + case 3 : + default : + snprintf(value, sizeof(value), "%s,%s,%s", + printer->auth_info_required[0], + printer->auth_info_required[1], + printer->auth_info_required[2]); + break; } - else - cupsFilePrintf(fp, "Info %s\n", printer->info); + + cupsFilePutConf(fp, "AuthInfoRequired", value); } + if (printer->info) + cupsFilePutConf(fp, "Info", printer->info); + if (printer->location) - { - if ((ptr = strchr(printer->info, '#')) != NULL) - { - /* - * Need to quote the first # in the location string... - */ + cupsFilePutConf(fp, "Location", printer->location); - cupsFilePuts(fp, "Location "); - cupsFileWrite(fp, printer->location, ptr - printer->location); - cupsFilePutChar(fp, '\\'); - cupsFilePuts(fp, ptr); - cupsFilePutChar(fp, '\n'); - } - else - cupsFilePrintf(fp, "Location %s\n", printer->location); - } - if (printer->device_uri) - cupsFilePrintf(fp, "DeviceURI %s\n", printer->device_uri); + 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) - cupsFilePrintf(fp, "PortMonitor %s\n", printer->port_monitor); + cupsFilePutConf(fp, "PortMonitor", printer->port_monitor); if (printer->state == IPP_PRINTER_STOPPED) { cupsFilePuts(fp, "State Stopped\n"); - cupsFilePrintf(fp, "StateMessage %s\n", 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") && + strcmp(printer->reasons[i], "cups-insecure-filter-warning") && + strcmp(printer->reasons[i], "cups-missing-filter-warning")) + cupsFilePutConf(fp, "Reason", printer->reasons[i]); + + cupsFilePrintf(fp, "Type %d\n", printer->type); if (printer->accepting) cupsFilePuts(fp, "Accepting Yes\n"); @@ -1480,35 +1510,50 @@ cupsdSaveAllPrinters(void) else cupsFilePuts(fp, "Shared No\n"); - cupsFilePrintf(fp, "JobSheets %s %s\n", printer->job_sheets[0], - printer->job_sheets[1]); + snprintf(value, sizeof(value), "%s %s", printer->job_sheets[0], + printer->job_sheets[1]); + cupsFilePutConf(fp, "JobSheets", value); cupsFilePrintf(fp, "QuotaPeriod %d\n", printer->quota_period); cupsFilePrintf(fp, "PageLimit %d\n", printer->page_limit); cupsFilePrintf(fp, "KLimit %d\n", printer->k_limit); - for (i = 0; i < printer->num_users; i ++) - cupsFilePrintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow", - 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) - cupsFilePrintf(fp, "OpPolicy %s\n", printer->op_policy); + cupsFilePutConf(fp, "OpPolicy", printer->op_policy); if (printer->error_policy) - cupsFilePrintf(fp, "ErrorPolicy %s\n", printer->error_policy); + cupsFilePutConf(fp, "ErrorPolicy", printer->error_policy); for (i = printer->num_options, option = printer->options; i > 0; i --, option ++) - cupsFilePrintf(fp, "Option %s %s\n", option->name, option->value); + { + snprintf(value, sizeof(value), "%s %s", option->name, option->value); + cupsFilePutConf(fp, "Option", value); + } if ((marker = ippFindAttribute(printer->attrs, "marker-colors", IPP_TAG_NAME)) != NULL) { - cupsFilePrintf(fp, "Attribute %s %s", marker->name, - marker->values[0].string.text); - for (i = 1; i < marker->num_values; i ++) - cupsFilePrintf(fp, ",%s", marker->values[i].string.text); - cupsFilePuts(fp, "\n"); + snprintf(value, sizeof(value), "%s ", marker->name); + + for (i = 0, ptr = value + strlen(value); + i < marker->num_values && ptr < (value + sizeof(value) - 1); + i ++) + { + if (i) + *ptr++ = ','; + + strlcpy(ptr, marker->values[i].string.text, (size_t)(value + sizeof(value) - ptr)); + ptr += strlen(ptr); + } + + *ptr = '\0'; + cupsFilePutConf(fp, "Attribute", value); } if ((marker = ippFindAttribute(printer->attrs, "marker-levels", @@ -1521,38 +1566,86 @@ cupsdSaveAllPrinters(void) cupsFilePuts(fp, "\n"); } - if ((marker = ippFindAttribute(printer->attrs, "marker-names", - IPP_TAG_NAME)) != NULL) + if ((marker = ippFindAttribute(printer->attrs, "marker-low-levels", + IPP_TAG_INTEGER)) != NULL) { - cupsFilePrintf(fp, "Attribute %s %s", marker->name, - marker->values[0].string.text); + cupsFilePrintf(fp, "Attribute %s %d", marker->name, + marker->values[0].integer); for (i = 1; i < marker->num_values; i ++) - cupsFilePrintf(fp, ",%s", marker->values[i].string.text); + cupsFilePrintf(fp, ",%d", marker->values[i].integer); cupsFilePuts(fp, "\n"); } - if ((marker = ippFindAttribute(printer->attrs, "marker-types", - IPP_TAG_KEYWORD)) != NULL) + if ((marker = ippFindAttribute(printer->attrs, "marker-high-levels", + IPP_TAG_INTEGER)) != NULL) { - cupsFilePrintf(fp, "Attribute %s %s", marker->name, - marker->values[0].string.text); + cupsFilePrintf(fp, "Attribute %s %d", marker->name, + marker->values[0].integer); for (i = 1; i < marker->num_values; i ++) - cupsFilePrintf(fp, ",%s", marker->values[i].string.text); + cupsFilePrintf(fp, ",%d", marker->values[i].integer); cupsFilePuts(fp, "\n"); } - cupsFilePuts(fp, "\n"); + if ((marker = ippFindAttribute(printer->attrs, "marker-message", + IPP_TAG_TEXT)) != NULL) + { + snprintf(value, sizeof(value), "%s %s", marker->name, + marker->values[0].string.text); + + cupsFilePutConf(fp, "Attribute", value); + } + + if ((marker = ippFindAttribute(printer->attrs, "marker-names", + IPP_TAG_NAME)) != NULL) + { + snprintf(value, sizeof(value), "%s ", marker->name); + + for (i = 0, ptr = value + strlen(value); + i < marker->num_values && ptr < (value + sizeof(value) - 1); + i ++) + { + if (i) + *ptr++ = ','; + + strlcpy(ptr, marker->values[i].string.text, (size_t)(value + sizeof(value) - ptr)); + ptr += strlen(ptr); + } + + *ptr = '\0'; + cupsFilePutConf(fp, "Attribute", value); + } + + if ((marker = ippFindAttribute(printer->attrs, "marker-types", + IPP_TAG_KEYWORD)) != NULL) + { + snprintf(value, sizeof(value), "%s ", marker->name); + + for (i = 0, ptr = value + strlen(value); + i < marker->num_values && ptr < (value + sizeof(value) - 1); + i ++) + { + if (i) + *ptr++ = ','; + + strlcpy(ptr, marker->values[i].string.text, (size_t)(value + sizeof(value) - ptr)); + ptr += strlen(ptr); + } + + *ptr = '\0'; + cupsFilePutConf(fp, "Attribute", value); + } -#ifdef __sgi - /* - * Make IRIX desktop & printer status happy - */ + if (printer->marker_time) + cupsFilePrintf(fp, "Attribute marker-change-time %ld\n", + (long)printer->marker_time); - write_irix_state(printer); -#endif /* __sgi */ + if (printer == DefaultPrinter) + cupsFilePuts(fp, "\n"); + else + cupsFilePuts(fp, "\n"); } - cupsFileClose(fp); + cupsdCloseCreatedConfFile(fp, filename); } @@ -1606,6 +1699,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)) { @@ -1642,7 +1745,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); } @@ -1654,16 +1757,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")) @@ -1684,6 +1777,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")) @@ -1709,6 +1812,74 @@ cupsdSetAuthInfoRequired( } +/* + * 'cupsdSetDeviceURI()' - Set the device URI for a printer. + */ + +void +cupsdSetDeviceURI(cupsd_printer_t *p, /* I - Printer */ + const char *uri) /* I - Device URI */ +{ + char buffer[1024], /* URI buffer */ + *start, /* Start of data after scheme */ + *slash, /* First slash after scheme:// */ + *ptr; /* Pointer into user@host:port part */ + + + /* + * Set the full device URI.. + */ + + cupsdSetString(&(p->device_uri), uri); + + /* + * Copy the device URI to a temporary buffer so we can sanitize any auth + * info in it... + */ + + strlcpy(buffer, uri, sizeof(buffer)); + + /* + * Find the end of the scheme:// part... + */ + + if ((ptr = strchr(buffer, ':')) != NULL) + { + for (start = ptr + 1; *start; start ++) + if (*start != '/') + break; + + /* + * Find the next slash (/) in the URI... + */ + + if ((slash = strchr(start, '/')) == NULL) + slash = start + strlen(start); /* No slash, point to the end */ + + /* + * Check for an @ sign before the slash... + */ + + if ((ptr = strchr(start, '@')) != NULL && ptr < slash) + { + /* + * Found an @ sign and it is before the resource part, so we have + * an authentication string. Copy the remaining URI over the + * authentication string... + */ + + _cups_strcpy(start, ptr + 1); + } + } + + /* + * Save the sanitized URI... + */ + + cupsdSetString(&(p->sanitized_device_uri), buffer); +} + + /* * 'cupsdSetPrinterAttr()' - Set a printer attribute. */ @@ -1717,28 +1888,65 @@ 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 */ + /* + * Don't allow empty values... + */ + + if (!*value && strcmp(name, "marker-message")) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Ignoring empty \"%s\" attribute", name); + 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... */ - if (!strcmp(name, "marker-levels")) + if (!strcmp(name, "marker-levels") || !strcmp(name, "marker-low-levels") || + !strcmp(name, "marker-high-levels")) { /* * Integer values... @@ -1759,21 +1967,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 @@ -1784,6 +1993,8 @@ cupsdSetPrinterAttr( if (!strcmp(name, "marker-types")) value_tag = IPP_TAG_KEYWORD; + else if (!strcmp(name, "marker-message")) + value_tag = IPP_TAG_TEXT; else value_tag = IPP_TAG_NAME; @@ -1795,33 +2006,127 @@ cupsdSetPrinterAttr( } if (attr) + { + for (i = 0; i < attr->num_values; i ++) + _cupsStrFree(attr->values[i].string.text); + attr->num_values = count; + } else attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, value_tag, name, count, NULL, NULL); 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, quote = '\0', ptr = temp; i < count; i ++) { - if ((ptr = strchr(value, ',')) != NULL) - *ptr++ = '\0'; + 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; - _cupsStrFree(attr->values[i].string.text); - attr->values[i].string.text = _cupsStrAlloc(value); + if (ptr == start) + start ++; + else + _cups_strcpy(ptr, ptr + 1); + } + else if (*ptr == ',') + { + *ptr++ = '\0'; + break; + } + } - if (ptr) - value = ptr; + attr->values[i].string.text = _cupsStrAlloc(start); } } - cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); + 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 ++) + { + 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'; + + 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 (!i) + supply = ippAddOctetString(p->attrs, IPP_TAG_PRINTER, "printer-supply", buffer, (int)strlen(buffer)); + else + ippSetOctetString(p->attrs, &supply, i, buffer, (int)strlen(buffer)); + } + } } @@ -1832,57 +2137,14 @@ cupsdSetPrinterAttr( void cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ { - int i, /* Looping var */ - length; /* Length of browse attributes */ - char uri[HTTP_MAX_URI]; /* URI for printer */ + int i; /* Looping var */ char resource[HTTP_MAX_URI]; /* Resource portion of URI */ - char filename[1024]; /* Name of PPD file */ - int num_air; /* Number of auth-info-required values */ - const char * const *air; /* auth-info-required values */ - int num_media; /* Number of media options */ cupsd_location_t *auth; /* Pointer to authentication element */ const char *auth_supported; /* Authentication supported */ - ppd_file_t *ppd; /* PPD file data */ - ppd_option_t *input_slot, /* InputSlot options */ - *media_type, /* MediaType options */ - *page_size, /* PageSize options */ - *output_bin, /* OutputBin options */ - *media_quality, /* EFMediaQualityMode options */ - *duplex; /* Duplex options */ - ppd_attr_t *ppdattr; /* PPD attribute */ + ipp_t *oldattrs; /* Old printer attributes */ ipp_attribute_t *attr; /* Attribute data */ - ipp_value_t *val; /* Attribute value */ - int num_finishings; /* Number of finishings */ - int finishings[5]; /* finishings-supported values */ - cups_option_t *option; /* Current printer option */ - static const char * const sides[3] = /* sides-supported values */ - { - "one-sided", - "two-sided-long-edge", - "two-sided-short-edge" - }; - static const char * const air_userpass[] = - { /* Basic/Digest authentication */ - "username", - "password" - }; -#ifdef HAVE_GSSAPI - static const char * const air_negotiate[] = - { /* Kerberos authentication */ - "negotiate" - }; -#endif /* HAVE_GSSAPI */ - static const char * const air_none[] = - { /* No authentication */ - "none" - }; - static const char * const standard_commands[] = - { /* Standard CUPS commands */ - "AutoConfigure", - "Clean", - "PrintSelfTestPage", - "ReportLevels" - }; + char *name, /* Current user/group name */ + *filter; /* Current filter */ DEBUG_printf(("cupsdSetPrinterAttrs: entering name = %s, type = %x\n", p->name, @@ -1906,74 +2168,44 @@ 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; + if (p->type & CUPS_PRINTER_CLASS) + snprintf(resource, sizeof(resource), "/classes/%s", p->name); + else + snprintf(resource, sizeof(resource), "/printers/%s", p->name); - if (!strcmp(air[0], "username")) - auth_supported = "basic"; - else - auth_supported = "negotiate"; - } - else if (!(p->type & CUPS_PRINTER_DISCOVERED)) + if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL || + auth->type == CUPSD_AUTH_NONE) + auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB); + + if (auth) { - if (p->type & CUPS_PRINTER_CLASS) - snprintf(resource, sizeof(resource), "/classes/%s", p->name); - else - snprintf(resource, sizeof(resource), "/printers/%s", p->name); + int auth_type; /* Authentication type */ - if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL || - auth->type == CUPSD_AUTH_NONE) - auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB); - if (auth) - { - if (auth->type == CUPSD_AUTH_BASIC || auth->type == CUPSD_AUTH_BASICDIGEST) - { - auth_supported = "basic"; - num_air = 2; - air = air_userpass; - } - else if (auth->type == CUPSD_AUTH_DIGEST) - { - auth_supported = "digest"; - num_air = 2; - air = air_userpass; - } + if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT) + auth_type = cupsdDefaultAuthType(); + + if (auth_type == CUPSD_AUTH_BASIC) + auth_supported = "basic"; #ifdef HAVE_GSSAPI - else if (auth->type == CUPSD_AUTH_NEGOTIATE) - { - auth_supported = "negotiate"; - num_air = 1; - air = air_negotiate; - } + else if (auth_type == CUPSD_AUTH_NEGOTIATE) + auth_supported = "negotiate"; #endif /* HAVE_GSSAPI */ - 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_PRINTER_AUTHENTICATED; - } - else if (p->type & CUPS_PRINTER_AUTHENTICATED) - { - num_air = 2; - air = air_userpass; + p->type &= (cups_ptype_t)~CUPS_PRINTER_AUTHENTICATED; } + else + p->type &= (cups_ptype_t)~CUPS_PRINTER_AUTHENTICATED; /* * Create the required IPP attributes for a printer... */ - if (p->attrs) - ippDelete(p->attrs); - + oldattrs = p->attrs; p->attrs = ippNew(); ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, @@ -1984,21 +2216,31 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ 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_URI, "printer-more-info", - NULL, p->uri); + 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, @@ -2007,10 +2249,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... @@ -2031,2156 +2275,2801 @@ 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"); + + 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... */ - p->type &= ~CUPS_PRINTER_OPTIONS; - - if (p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) - { - p->raw = 1; - - /* - * 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, - "file:///dev/null"); - - if (p->num_printers > 0) - { - /* - * Add a list of member URIs and names... - */ + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, + p->sanitized_device_uri); - attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, - "member-uris", p->num_printers, NULL, NULL); - p->type |= CUPS_PRINTER_OPTIONS; + /* + * Assign additional attributes from the PPD file (if any)... + */ - for (i = 0; i < p->num_printers; i ++) - { - if (attr != NULL) - attr->values[i].string.text = _cupsStrAlloc(p->printers[i]->uri); + load_ppd(p); - p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type; - } + /* + * Add filters for printer... + */ - attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, - "member-names", p->num_printers, NULL, NULL); + cupsdSetPrinterReasons(p, "-cups-missing-filter-warning," + "cups-insecure-filter-warning"); - if (attr != NULL) - { - for (i = 0; i < p->num_printers; i ++) - attr->values[i].string.text = _cupsStrAlloc(p->printers[i]->name); - } - } + 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... Start by sanitizing the device - * URI so it doesn't have a username or password in it... - */ + char interface[1024]; /* Interface script */ - if (!p->device_uri) - strcpy(uri, "file:/dev/null"); - else if (strstr(p->device_uri, "://") != NULL) + + snprintf(interface, sizeof(interface), "%s/interfaces/%s", ServerRoot, + p->name); + if (!access(interface, X_OK)) { /* - * http://..., ipp://..., etc. + * Yes, we have a System V style interface script; use it! */ - cupsdSanitizeURI(p->device_uri, uri, sizeof(uri)); + snprintf(interface, sizeof(interface), "*/* 0 %s/interfaces/%s", + ServerRoot, p->name); + add_printer_filter(p, p->filetype, interface); } else { /* - * file:..., serial:..., etc. + * Add a filter from application/vnd.cups-raw to printer/name to + * handle "raw" printing by users. + */ + + add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -"); + + /* + * Add a PostScript filter, since this is still possibly PS printer. */ - strlcpy(uri, p->device_uri, sizeof(uri)); + add_printer_filter(p, p->filetype, + "application/vnd.cups-postscript 0 -"); } + } - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, - uri); + if (p->pc && p->pc->prefilters) + { + if (!p->prefiltertype) + p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name); - /* - * Assign additional attributes from the PPD file (if any)... - */ + for (filter = (char *)cupsArrayFirst(p->pc->prefilters); + filter; + filter = (char *)cupsArrayNext(p->pc->prefilters)) + add_printer_filter(p, p->prefiltertype, filter); + } + } - p->type |= CUPS_PRINTER_BW; - finishings[0] = IPP_FINISHINGS_NONE; - num_finishings = 1; + /* + * Copy marker attributes as needed... + */ - snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, - p->name); + if (oldattrs) + { + ipp_attribute_t *oldattr; /* Old attribute */ - if ((ppd = ppdOpenFile(filename)) != NULL) - { - /* - * Add make/model and other various attributes... - */ - if (ppd->color_device) - p->type |= CUPS_PRINTER_COLOR; - if (ppd->variable_sizes) - p->type |= CUPS_PRINTER_VARIABLE; - if (!ppd->manual_copies) - p->type |= CUPS_PRINTER_COPIES; - if ((ppdattr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL) - if (ppdattr->value && !strcasecmp(ppdattr->value, "true")) - p->type |= CUPS_PRINTER_FAX; - - ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "color-supported", - ppd->color_device); - if (ppd->throughput) - ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "pages-per-minute", ppd->throughput); - - if (ppd->nickname) - { - /* - * The NickName can be localized in the character set specified - * by the LanugageEncoding attribute. However, ppdOpen2() has - * already converted the ppd->nickname member to UTF-8 for us - * (the original attribute value is available separately) - */ + if ((oldattr = ippFindAttribute(oldattrs, "marker-colors", + IPP_TAG_NAME)) != NULL) + { + if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, + "marker-colors", oldattr->num_values, NULL, + NULL)) != NULL) + { + for (i = 0; i < oldattr->num_values; i ++) + attr->values[i].string.text = + _cupsStrAlloc(oldattr->values[i].string.text); + } + } - cupsdSetString(&p->make_model, ppd->nickname); - } - else if (ppd->modelname) - { - /* - * Model name can only contain specific characters... - */ + if ((oldattr = ippFindAttribute(oldattrs, "marker-levels", + IPP_TAG_INTEGER)) != NULL) + { + if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "marker-levels", oldattr->num_values, + NULL)) != NULL) + { + for (i = 0; i < oldattr->num_values; i ++) + attr->values[i].integer = oldattr->values[i].integer; + } + } - cupsdSetString(&p->make_model, ppd->modelname); - } - else - cupsdSetString(&p->make_model, "Bad PPD File"); + if ((oldattr = ippFindAttribute(oldattrs, "marker-message", + IPP_TAG_TEXT)) != NULL) + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "marker-message", + NULL, oldattr->values[0].string.text); - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "printer-make-and-model", NULL, p->make_model); + if ((oldattr = ippFindAttribute(oldattrs, "marker-low-levels", + IPP_TAG_INTEGER)) != NULL) + { + if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "marker-low-levels", oldattr->num_values, + NULL)) != NULL) + { + for (i = 0; i < oldattr->num_values; i ++) + attr->values[i].integer = oldattr->values[i].integer; + } + } - /* - * Add media options from the PPD file... - */ + if ((oldattr = ippFindAttribute(oldattrs, "marker-high-levels", + IPP_TAG_INTEGER)) != NULL) + { + if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "marker-high-levels", oldattr->num_values, + NULL)) != NULL) + { + for (i = 0; i < oldattr->num_values; i ++) + attr->values[i].integer = oldattr->values[i].integer; + } + } - if ((input_slot = ppdFindOption(ppd, "InputSlot")) != NULL) - num_media = input_slot->num_choices; - else - num_media = 0; + if ((oldattr = ippFindAttribute(oldattrs, "marker-names", + IPP_TAG_NAME)) != NULL) + { + if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, + "marker-names", oldattr->num_values, NULL, + NULL)) != NULL) + { + for (i = 0; i < oldattr->num_values; i ++) + attr->values[i].string.text = + _cupsStrAlloc(oldattr->values[i].string.text); + } + } - if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL) - num_media += media_type->num_choices; + if ((oldattr = ippFindAttribute(oldattrs, "marker-types", + IPP_TAG_KEYWORD)) != NULL) + { + if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "marker-types", oldattr->num_values, NULL, + NULL)) != NULL) + { + for (i = 0; i < oldattr->num_values; i ++) + attr->values[i].string.text = + _cupsStrAlloc(oldattr->values[i].string.text); + } + } - if ((page_size = ppdFindOption(ppd, "PageSize")) != NULL) - num_media += page_size->num_choices; + ippDelete(oldattrs); + } - if ((media_quality = ppdFindOption(ppd, "EFMediaQualityMode")) != NULL) - num_media += media_quality->num_choices; + /* + * Force sharing off for remote queues... + */ - if (num_media == 0) - { - cupsdLogMessage(CUPSD_LOG_CRIT, - "The PPD file for printer %s contains no media " - "options and is therefore invalid!", p->name); - } - else - { - attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "media-supported", num_media, NULL, NULL); - if (attr != NULL) - { - val = attr->values; + if (p->type & CUPS_PRINTER_REMOTE) + p->shared = 0; - if (input_slot != NULL) - for (i = 0; i < input_slot->num_choices; i ++, val ++) - val->string.text = _cupsStrAlloc(input_slot->choices[i].choice); + /* + * Populate the document-format-supported attribute... + */ - if (media_type != NULL) - for (i = 0; i < media_type->num_choices; i ++, val ++) - val->string.text = _cupsStrAlloc(media_type->choices[i].choice); + add_printer_formats(p); - if (media_quality != NULL) - for (i = 0; i < media_quality->num_choices; i ++, val ++) - val->string.text = _cupsStrAlloc(media_quality->choices[i].choice); + DEBUG_printf(("cupsdSetPrinterAttrs: leaving name = %s, type = %x\n", p->name, + p->type)); - if (page_size != NULL) - { - for (i = 0; i < page_size->num_choices; i ++, val ++) - val->string.text = _cupsStrAlloc(page_size->choices[i].choice); + /* + * Add name-default attributes... + */ - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "media-default", NULL, page_size->defchoice); - } - else if (input_slot != NULL) - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "media-default", NULL, input_slot->defchoice); - else if (media_type != NULL) - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "media-default", NULL, media_type->defchoice); - else if (media_quality != NULL) - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "media-default", NULL, media_quality->defchoice); - else - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "media-default", NULL, "none"); - } - } + add_printer_defaults(p); - /* - * Output bin... - */ + /* + * Let the browse protocols reflect the change + */ - if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL) - { - attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "output-bin-supported", output_bin->num_choices, - NULL, NULL); + cupsdRegisterPrinter(p); +} - if (attr != NULL) - { - for (i = 0, val = attr->values; - i < output_bin->num_choices; - i ++, val ++) - val->string.text = _cupsStrAlloc(output_bin->choices[i].choice); - } - } - /* - * Duplexing, etc... - */ +/* + * 'cupsdSetPrinterReasons()' - Set/update the reasons strings. + */ - 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"); +int /* O - 1 if something changed, 0 otherwise */ +cupsdSetPrinterReasons( + cupsd_printer_t *p, /* I - Printer */ + const char *s) /* I - Reasons strings */ +{ + int i, /* Looping var */ + changed = 0; /* Did something change? */ + const char *sptr; /* Pointer into reasons */ + char reason[255], /* Reason string */ + *rptr; /* Pointer into reason */ - if (duplex && duplex->num_choices > 1) - { - p->type |= CUPS_PRINTER_DUPLEX; - ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "sides-supported", 3, NULL, sides); + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdSetPrinterReasons(p=%p(%s),s=\"%s\"", p, p->name, s); - if (!strcasecmp(duplex->defchoice, "DuplexTumble")) - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "sides-default", NULL, "two-sided-short-edge"); - else if (!strcasecmp(duplex->defchoice, "DuplexNoTumble")) - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "sides-default", NULL, "two-sided-long-edge"); - else - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "sides-default", NULL, "one-sided"); - } + if (s[0] == '-' || s[0] == '+') + { + /* + * Add/remove reasons... + */ - if (ppdFindOption(ppd, "Collate") != NULL) - p->type |= CUPS_PRINTER_COLLATE; + sptr = s + 1; + } + else + { + /* + * Replace reasons... + */ - if (ppdFindOption(ppd, "StapleLocation") != NULL) - { - p->type |= CUPS_PRINTER_STAPLE; - finishings[num_finishings++] = IPP_FINISHINGS_STAPLE; - } + sptr = s; - if (ppdFindOption(ppd, "BindEdge") != NULL) - { - p->type |= CUPS_PRINTER_BIND; - finishings[num_finishings++] = IPP_FINISHINGS_BIND; - } + for (i = 0; i < p->num_reasons; i ++) + _cupsStrFree(p->reasons[i]); - 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; + p->num_reasons = 0; + changed = 1; - /* - * Add a filter from application/vnd.cups-raw to printer/name to - * handle "raw" printing by users. - */ + dirty_printer(p); + } - add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -"); + if (!strcmp(s, "none")) + return (changed); - /* - * Add any pre-filters in the PPD file... - */ + /* + * Loop through all of the reasons... + */ - if ((ppdattr = ppdFindAttr(ppd, "cupsPreFilter", NULL)) != NULL) - { - p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name); + while (*sptr) + { + /* + * Skip leading whitespace and commas... + */ - for (; ppdattr; ppdattr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL)) - if (ppdattr->value) - add_printer_filter(p, p->prefiltertype, ppdattr->value); - } + while (isspace(*sptr & 255) || *sptr == ',') + sptr ++; - /* - * Add any filters in the PPD file... - */ + for (rptr = reason; *sptr && !isspace(*sptr & 255) && *sptr != ','; sptr ++) + if (rptr < (reason + sizeof(reason) - 1)) + *rptr++ = *sptr; - DEBUG_printf(("ppd->num_filters = %d\n", ppd->num_filters)); - for (i = 0; i < ppd->num_filters; i ++) - { - DEBUG_printf(("ppd->filters[%d] = \"%s\"\n", i, ppd->filters[i])); - add_printer_filter(p, p->filetype, ppd->filters[i]); - } + if (rptr == reason) + break; - if (ppd->num_filters == 0) - { - /* - * If there are no filters, add PostScript printing filters. - */ + *rptr = '\0'; - add_printer_filter(p, p->filetype, - "application/vnd.cups-command 0 commandtops"); - add_printer_filter(p, p->filetype, - "application/vnd.cups-postscript 0 -"); + if (s[0] == '-') + { + /* + * Remove reason... + */ - p->type |= CUPS_PRINTER_COMMANDS; - } - else if (!(p->type & CUPS_PRINTER_COMMANDS)) + for (i = 0; i < p->num_reasons; i ++) + if (!strcmp(reason, p->reasons[i])) { /* - * See if this is a PostScript device without a command filter... + * Found a match, so remove it... */ - for (i = 0; i < ppd->num_filters; i ++) - if (!strncasecmp(ppd->filters[i], - "application/vnd.cups-postscript", 31)) - break; - - if (i < ppd->num_filters) - { - /* - * Add the generic PostScript command filter... - */ + p->num_reasons --; + changed = 1; + _cupsStrFree(p->reasons[i]); - add_printer_filter(p, p->filetype, - "application/vnd.cups-command 0 commandtops"); - p->type |= CUPS_PRINTER_COMMANDS; - } - } + if (i < p->num_reasons) + memmove(p->reasons + i, p->reasons + i + 1, (size_t)(p->num_reasons - i) * sizeof(char *)); - if (p->type & CUPS_PRINTER_COMMANDS) - { - char *commands, /* Copy of commands */ - *start, /* Start of name */ - *end; /* End of name */ - int count; /* Number of commands */ + 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 ((ppdattr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL && - ppdattr->value && ppdattr->value[0]) - { - for (count = 0, start = ppdattr->value; *start; count ++) - { - while (isspace(*start & 255)) - start ++; + if (strcmp(reason, "connecting-to-device")) + dirty_printer(p); - if (!*start) - break; + break; + } + } + else if (p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0]))) + { + /* + * Add reason... + */ - while (*start && !isspace(*start & 255)) - start ++; - } - } - else - count = 0; + for (i = 0; i < p->num_reasons; i ++) + if (!strcmp(reason, p->reasons[i])) + break; - if (count > 0) - { - /* - * Make a copy of the commands string and count how many ... - */ + if (i >= p->num_reasons) + { + if (i >= (int)(sizeof(p->reasons) / sizeof(p->reasons[0]))) + { + cupsdLogMessage(CUPSD_LOG_ALERT, + "Too many printer-state-reasons values for %s (%d)", + p->name, i + 1); + return (changed); + } - attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "printer-commands", count, NULL, NULL); + p->reasons[i] = _cupsStrAlloc(reason); + p->num_reasons ++; + changed = 1; - commands = strdup(ppdattr->value); + if (!strcmp(reason, "paused") && p->state != IPP_PRINTER_STOPPED) + cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 1); - for (count = 0, start = commands; *start; count ++) - { - while (isspace(*start & 255)) - start ++; + if (!strcmp(reason, "cups-waiting-for-job-completed") && p->job) + p->job->completed = 1; - if (!*start) - break; + if (strcmp(reason, "connecting-to-device")) + dirty_printer(p); + } + } + } - end = start; - while (*end && !isspace(*end & 255)) - end ++; + return (changed); +} - if (*end) - *end++ = '\0'; - attr->values[count].string.text = _cupsStrAlloc(start); - - start = end; - } +/* + * 'cupsdSetPrinterState()' - Update the current state of a printer. + */ - free(commands); - } - else - { - /* - * Add the standard list of commands... - */ +void +cupsdSetPrinterState( + cupsd_printer_t *p, /* I - Printer to change */ + 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 */ + "idle", + "processing", + "stopped" + }; - ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "printer-commands", - (int)(sizeof(standard_commands) / - sizeof(standard_commands[0])), NULL, - standard_commands); - } - } - else - { - /* - * No commands supported... - */ - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "printer-commands", NULL, "none"); - } + /* + * Set the new state... + */ - /* - * Show current and available port monitors for this printer... - */ + old_state = p->state; + p->state = s; - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor", - NULL, p->port_monitor ? p->port_monitor : "none"); + if (old_state != s) + { + cupsdAddEvent(s == IPP_PRINTER_STOPPED ? CUPSD_EVENT_PRINTER_STOPPED : + 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 - IPP_PRINTER_IDLE]); - for (i = 1, ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL); - ppdattr; - i ++, ppdattr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL)); + /* + * Let the browse code know this needs to be updated... + */ - if (ppd->protocols) - { - if (strstr(ppd->protocols, "TBCP")) - i ++; - else if (strstr(ppd->protocols, "BCP")) - i ++; - } + p->state_time = time(NULL); + } - attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, - "port-monitor-supported", i, NULL, NULL); + /* + * Set/clear the paused reason as needed... + */ - attr->values[0].string.text = _cupsStrAlloc("none"); + if (s == IPP_PRINTER_STOPPED) + cupsdSetPrinterReasons(p, "+paused"); + else + cupsdSetPrinterReasons(p, "-paused"); - for (i = 1, ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL); - ppdattr; - i ++, ppdattr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL)) - attr->values[i].string.text = _cupsStrAlloc(ppdattr->value); + 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"); + } - if (ppd->protocols) - { - if (strstr(ppd->protocols, "TBCP")) - attr->values[i].string.text = _cupsStrAlloc("tbcp"); - else if (strstr(ppd->protocols, "BCP")) - attr->values[i].string.text = _cupsStrAlloc("bcp"); - } + /* + * Clear the message for the queue when going to processing... + */ -#ifdef HAVE_DNSSD - cupsdSetString(&p->product, ppd->product); -#endif /* HAVE_DNSSD */ + if (s == IPP_PRINTER_PROCESSING) + p->state_message[0] = '\0'; - if (ppdFindAttr(ppd, "APRemoteQueueID", NULL)) - p->type |= CUPS_PRINTER_REMOTE; + /* + * Let the browse protocols reflect the change... + */ - /* - * Close the PPD and set the type... - */ + if (update) + cupsdRegisterPrinter(p); - ppdClose(ppd); - } - else if (!access(filename, 0)) - { - int pline; /* PPD line number */ - ppd_status_t pstatus; /* PPD load status */ + /* + * Save the printer configuration if a printer goes from idle or processing + * to stopped (or visa-versa)... + */ + if (update && + (old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED)) + dirty_printer(p); +} - pstatus = ppdLastError(&pline); - cupsdLogMessage(CUPSD_LOG_ERROR, "PPD file for %s cannot be loaded!", - p->name); +/* + * 'cupsdStopPrinter()' - Stop a printer from printing any jobs... + */ - if (pstatus <= PPD_ALLOC_ERROR) - cupsdLogMessage(CUPSD_LOG_ERROR, "%s", strerror(errno)); - else - cupsdLogMessage(CUPSD_LOG_ERROR, "%s on line %d.", - ppdErrorString(pstatus), pline); +void +cupsdStopPrinter(cupsd_printer_t *p, /* I - Printer to stop */ + int update)/* I - Update printers.conf? */ +{ + /* + * Set the printer state... + */ - cupsdLogMessage(CUPSD_LOG_INFO, - "Hint: Run \"cupstestppd %s\" and fix any errors.", - filename); + cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update); - /* - * Add a filter from application/vnd.cups-raw to printer/name to - * handle "raw" printing by users. - */ + /* + * See if we have a job printing on this printer... + */ - add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -"); + if (p->job && p->job->state_value == IPP_JOB_PROCESSING) + cupsdSetJobState(p->job, IPP_JOB_PENDING, CUPSD_JOB_DEFAULT, + "Job stopped due to printer being paused."); +} - /* - * Add a PostScript filter, since this is still possibly PS printer. - */ - add_printer_filter(p, p->filetype, - "application/vnd.cups-postscript 0 -"); - } - else - { - /* - * If we have an interface script, add a filter entry for it... - */ +/* + * 'cupsdUpdatePrinterPPD()' - Update keywords in a printer's PPD file. + */ - snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot, - p->name); - if (!access(filename, X_OK)) - { - /* - * Yes, we have a System V style interface script; use it! - */ +int /* O - 1 if successful, 0 otherwise */ +cupsdUpdatePrinterPPD( + cupsd_printer_t *p, /* I - Printer */ + int num_keywords, /* I - Number of keywords */ + cups_option_t *keywords) /* I - Keywords */ +{ + int i; /* Looping var */ + cups_file_t *src, /* Original file */ + *dst; /* New file */ + char srcfile[1024], /* Original filename */ + dstfile[1024], /* New filename */ + line[1024], /* Line from file */ + keystring[41]; /* Keyword from line */ + cups_option_t *keyword; /* Current keyword */ - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "printer-make-and-model", NULL, - "Local System V Printer"); - snprintf(filename, sizeof(filename), "*/* 0 %s/interfaces/%s", - ServerRoot, p->name); - add_printer_filter(p, p->filetype, filename); - } - else if (p->device_uri && - !strncmp(p->device_uri, "ipp://", 6) && - (strstr(p->device_uri, "/printers/") != NULL || - strstr(p->device_uri, "/classes/") != NULL)) - { - /* - * Tell the client this is really a hard-wired remote printer. - */ + cupsdLogMessage(CUPSD_LOG_INFO, "Updating keywords in PPD file for %s...", + p->name); - p->type |= CUPS_PRINTER_REMOTE; + /* + * Get the old and new PPD filenames... + */ - /* - * Point the printer-uri-supported attribute to the - * remote printer... - */ + snprintf(srcfile, sizeof(srcfile), "%s/ppd/%s.ppd.O", ServerRoot, p->name); + snprintf(dstfile, sizeof(srcfile), "%s/ppd/%s.ppd", ServerRoot, p->name); - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, - "printer-uri-supported", NULL, p->device_uri); + /* + * Rename the old file and open the old and new... + */ - /* - * Then set the make-and-model accordingly... - */ + if (rename(dstfile, srcfile)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to backup PPD file for %s: %s", + p->name, strerror(errno)); + return (0); + } - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "printer-make-and-model", NULL, "Remote Printer"); + if ((src = cupsFileOpen(srcfile, "r")) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open PPD file \"%s\": %s", + srcfile, strerror(errno)); + rename(srcfile, dstfile); + return (0); + } - /* - * Print all files directly... - */ + if ((dst = cupsFileOpen(dstfile, "w")) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create PPD file \"%s\": %s", + dstfile, strerror(errno)); + cupsFileClose(src); + rename(srcfile, dstfile); + return (0); + } - p->raw = 1; - p->remote = 1; - } - else - { - /* - * Otherwise we have neither - treat this as a "dumb" printer - * with no PPD file... - */ + /* + * Copy the first line and then write out all of the keywords... + */ - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "printer-make-and-model", NULL, "Local Raw Printer"); + if (!cupsFileGets(src, line, sizeof(line))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to read PPD file \"%s\": %s", + srcfile, strerror(errno)); + cupsFileClose(src); + cupsFileClose(dst); + rename(srcfile, dstfile); + return (0); + } - p->raw = 1; - } - } + cupsFilePrintf(dst, "%s\n", line); - ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, - "finishings-supported", num_finishings, finishings); - ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, - "finishings-default", IPP_FINISHINGS_NONE); - } + for (i = num_keywords, keyword = keywords; i > 0; i --, keyword ++) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, "*%s: %s", keyword->name, keyword->value); + cupsFilePrintf(dst, "*%s: %s\n", keyword->name, keyword->value); } /* - * Force sharing off for remote queues... + * Then copy the rest of the PPD file, dropping any keywords we changed. */ - if (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) - p->shared = 0; - else + while (cupsFileGets(src, line, sizeof(line))) { /* - * Copy the printer options into a browse attributes string we can re-use. + * Skip keywords we've already set... */ - const char *valptr; /* Pointer into value */ - char *attrptr; /* Pointer into attribute string */ - + if (sscanf(line, "*%40[^:]:", keystring) == 1 && + cupsGetOption(keystring, num_keywords, keywords)) + continue; /* - * Free the old browse attributes as needed... + * Otherwise write the line... */ - if (p->browse_attrs) - free(p->browse_attrs); - - /* - * Compute the length of all attributes + job-sheets, lease-duration, - * and BrowseLocalOptions. - */ + cupsFilePrintf(dst, "%s\n", line); + } - for (length = 1, i = p->num_options, option = p->options; - i > 0; - i --, option ++) - { - length += strlen(option->name) + 2; + /* + * Close files and return... + */ - if (option->value) - { - for (valptr = option->value; *valptr; valptr ++) - if (strchr(" \"\'\\", *valptr)) - length += 2; - else - length ++; - } - } + cupsFileClose(src); + cupsFileClose(dst); - length += 13 + strlen(p->job_sheets[0]) + strlen(p->job_sheets[1]); - length += 32; - if (BrowseLocalOptions) - length += 12 + strlen(BrowseLocalOptions); + return (1); +} - if (p->num_auth_info_required > 0) - { - length += 18; /* auth-info-required */ - for (i = 0; i < p->num_auth_info_required; i ++) - length += strlen(p->auth_info_required[i]) + 1; - } +/* + * 'cupsdUpdatePrinters()' - Update printers after a partial reload. + */ - /* - * Allocate the new string... - */ +void +cupsdUpdatePrinters(void) +{ + cupsd_printer_t *p; /* Current printer */ - 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); + /* + * Loop through the printers and recreate the printer attributes + * for any local printers since the policy and/or access control + * stuff may have changed. Also, if browsing is disabled, remove + * any remote printers... + */ - if (BrowseLocalOptions) - { - sprintf(attrptr, " ipp-options=%s", BrowseLocalOptions); - attrptr += strlen(attrptr); - } + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + { + /* + * Update the operation policy pointer... + */ - for (i = p->num_options, option = p->options; - i > 0; - i --, option ++) - { - *attrptr++ = ' '; - strcpy(attrptr, option->name); - attrptr += strlen(attrptr); + if ((p->op_policy_ptr = cupsdFindPolicy(p->op_policy)) == NULL) + p->op_policy_ptr = DefaultPolicyPtr; - if (option->value) - { - *attrptr++ = '='; + /* + * Update printer attributes... + */ - for (valptr = option->value; *valptr; valptr ++) - { - if (strchr(" \"\'\\", *valptr)) - *attrptr++ = '\\'; + cupsdSetPrinterAttrs(p); + } +} - *attrptr++ = *valptr; - } - } - } - if (p->num_auth_info_required > 0) - { - strcpy(attrptr, "auth-info-required"); - attrptr += 18; +/* + * 'cupsdValidateDest()' - Validate a printer/class destination. + */ - for (i = 0; i < p->num_auth_info_required; i ++) - { - *attrptr++ = i ? ',' : '='; - strcpy(attrptr, p->auth_info_required[i]); - attrptr += strlen(attrptr); - } - } - else - *attrptr = '\0'; - } - } - - /* - * Populate the document-format-supported attribute... - */ +const char * /* O - Printer or class name */ +cupsdValidateDest( + const char *uri, /* I - Printer URI */ + cups_ptype_t *dtype, /* O - Type (printer or class) */ + cupsd_printer_t **printer) /* O - Printer pointer */ +{ + cupsd_printer_t *p; /* Current printer */ + char localname[1024],/* Localized hostname */ + *lptr, /* Pointer into localized hostname */ + *sptr, /* Pointer into server name */ + *rptr, /* Pointer into resource */ + scheme[32], /* Scheme portion of URI */ + username[64], /* Username portion of URI */ + hostname[HTTP_MAX_HOST], + /* Host portion of URI */ + resource[HTTP_MAX_URI]; + /* Resource portion of URI */ + int port; /* Port portion of URI */ - add_printer_formats(p); - DEBUG_printf(("cupsdSetPrinterAttrs: leaving name = %s, type = %x\n", p->name, - p->type)); + DEBUG_printf(("cupsdValidateDest(uri=\"%s\", dtype=%p, printer=%p)\n", uri, + dtype, printer)); /* - * Add name-default attributes... + * Initialize return values... */ - add_printer_defaults(p); + if (printer) + *printer = NULL; + + if (dtype) + *dtype = (cups_ptype_t)0; -#ifdef __sgi /* - * Write the IRIX printer config and status files... + * Pull the hostname and resource from the URI... */ - write_irix_config(p); - write_irix_state(p); -#endif /* __sgi */ + httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), + username, sizeof(username), hostname, sizeof(hostname), + &port, resource, sizeof(resource)); /* - * Let the browse protocols reflect the change + * See if the resource is a class or printer... */ - cupsdRegisterPrinter(p); -} - - -/* - * 'cupsdSetPrinterReasons()' - Set/update the reasons strings. - */ - -void -cupsdSetPrinterReasons( - cupsd_printer_t *p, /* I - Printer */ - const char *s) /* I - Reasons strings */ -{ - int i; /* Looping var */ - const char *sptr; /* Pointer into reasons */ - char reason[255], /* Reason string */ - *rptr; /* Pointer into reason */ - + if (!strncmp(resource, "/classes/", 9)) + { + /* + * Class... + */ - if (s[0] == '-' || s[0] == '+') + rptr = resource + 9; + } + else if (!strncmp(resource, "/printers/", 10)) { /* - * Add/remove reasons... + * Printer... */ - sptr = s + 1; + rptr = resource + 10; } else { /* - * Replace reasons... + * Bad resource name... */ - sptr = s; + return (NULL); + } - for (i = 0; i < p->num_reasons; i ++) - free(p->reasons[i]); + /* + * See if the printer or class name exists... + */ - p->num_reasons = 0; - } + p = cupsdFindDest(rptr); - if (!strcmp(s, "none")) - return; + if (p == NULL && strchr(rptr, '@') == NULL) + return (NULL); + else if (p != NULL) + { + if (printer) + *printer = p; + + if (dtype) + *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE); + + return (p->name); + } /* - * Loop through all of the reasons... + * Change localhost to the server name... */ - while (*sptr) + if (!_cups_strcasecmp(hostname, "localhost")) + strlcpy(hostname, ServerName, sizeof(hostname)); + + strlcpy(localname, hostname, sizeof(localname)); + + if (!_cups_strcasecmp(hostname, ServerName)) { /* - * Skip leading whitespace and commas... + * Localize the hostname... */ - while (isspace(*sptr & 255) || *sptr == ',') - sptr ++; - - for (rptr = reason; *sptr && !isspace(*sptr & 255) && *sptr != ','; sptr ++) - if (rptr < (reason + sizeof(reason) - 1)) - *rptr++ = *sptr; - - if (rptr == reason) - break; - - *rptr = '\0'; + lptr = strchr(localname, '.'); + sptr = strchr(ServerName, '.'); - if (s[0] == '-') + if (sptr != NULL && lptr != NULL) { /* - * Remove reason... + * Strip the common domain name components... */ - for (i = 0; i < p->num_reasons; i ++) - if (!strcasecmp(reason, p->reasons[i])) + while (lptr != NULL) + { + if (!_cups_strcasecmp(lptr, sptr)) { - /* - * Found a match, so remove it... - */ - - p->num_reasons --; - free(p->reasons[i]); + *lptr = '\0'; + break; + } + else + lptr = strchr(lptr + 1, '.'); + } + } + } - if (i < p->num_reasons) - memmove(p->reasons + i, p->reasons + i + 1, - (p->num_reasons - i) * sizeof(char *)); + DEBUG_printf(("localized hostname is \"%s\"...\n", localname)); - i --; + /* + * Find a matching printer or class... + */ - if (!strcmp(reason, "paused") && p->state == IPP_PRINTER_STOPPED) - cupsdSetPrinterState(p, IPP_PRINTER_IDLE, 1); - } - } - else if (p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0]))) + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + if (!_cups_strcasecmp(p->hostname, localname) && + !_cups_strcasecmp(p->name, rptr)) { - /* - * Add reason... - */ - - for (i = 0; i < p->num_reasons; i ++) - if (!strcasecmp(reason, p->reasons[i])) - break; + if (printer) + *printer = p; - if (i >= p->num_reasons) - { - p->reasons[i] = strdup(reason); - p->num_reasons ++; + if (dtype) + *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE); - if (!strcmp(reason, "paused") && p->state != IPP_PRINTER_STOPPED) - cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 1); - } + return (p->name); } - } + + return (NULL); } /* - * 'cupsdSetPrinterState()' - Update the current state of a printer. + * 'cupsdWritePrintcap()' - Write a pseudo-printcap file for older applications + * that need it... */ void -cupsdSetPrinterState( - cupsd_printer_t *p, /* I - Printer to change */ - ipp_pstate_t s, /* I - New state */ - int update) /* I - Update printers.conf? */ +cupsdWritePrintcap(void) { - ipp_pstate_t old_state; /* Old printer state */ + int i; /* Looping var */ + cups_file_t *fp; /* Printcap file */ + cupsd_printer_t *p; /* Current printer */ /* - * Can't set status of remote printers... + * See if we have a printcap file; if not, don't bother writing it. */ - if (p->type & CUPS_PRINTER_DISCOVERED) + if (!Printcap || !*Printcap) return; + cupsdLogMessage(CUPSD_LOG_INFO, "Generating printcap %s...", Printcap); + /* - * Set the new state... + * Open the printcap file... */ - old_state = p->state; - p->state = s; + if ((fp = cupsFileOpen(Printcap, "w")) == NULL) + return; - if (old_state != s) + /* + * Put a comment header at the top so that users will know where the + * data has come from... + */ + + if (PrintcapFormat != PRINTCAP_PLIST) + cupsFilePrintf(fp, "# This file was automatically generated by cupsd(8) " + "from the\n" + "# %s/printers.conf file. All changes to this file\n" + "# will be lost.\n", ServerRoot); + + /* + * Write a new printcap with the current list of printers. + */ + + switch (PrintcapFormat) { - cupsdAddEvent(s == IPP_PRINTER_STOPPED ? CUPSD_EVENT_PRINTER_STOPPED : - CUPSD_EVENT_PRINTER_STATE, p, NULL, - "%s \"%s\" state changed.", - (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer", - p->name); + case PRINTCAP_BSD : + /* + * Each printer is put in the file as: + * + * Printer1: + * Printer2: + * Printer3: + * ... + * PrinterN: + */ - /* - * Let the browse code know this needs to be updated... - */ + if (DefaultPrinter) + cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", DefaultPrinter->name, + DefaultPrinter->info, ServerName, + DefaultPrinter->name); + + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + if (p != DefaultPrinter) + cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", p->name, p->info, + ServerName, p->name); + break; - BrowseNext = p; - p->state_time = time(NULL); - p->browse_time = 0; + case PRINTCAP_PLIST : + /* + * Each printer is written as a dictionary in a plist file. + * Currently the printer-name, printer-info, printer-is-accepting-jobs, + * printer-location, printer-make-and-model, printer-state, + * printer-state-reasons, printer-type, and (sanitized) device-uri. + */ -#ifdef __sgi - write_irix_state(p); -#endif /* __sgi */ - } + cupsFilePuts(fp, "\n" + "\n" + "\n" + "\n"); - cupsdAddPrinterHistory(p); + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + { + cupsFilePuts(fp, "\t\n" + "\t\tprinter-name\n" + "\t\t"); + write_xml_string(fp, p->name); + cupsFilePuts(fp, "\n" + "\t\tprinter-info\n" + "\t\t"); + write_xml_string(fp, p->info); + cupsFilePrintf(fp, "\n" + "\t\tprinter-is-accepting-jobs\n" + "\t\t<%s/>\n" + "\t\tprinter-location\n" + "\t\t", p->accepting ? "true" : "false"); + write_xml_string(fp, p->location); + cupsFilePuts(fp, "\n" + "\t\tprinter-make-and-model\n" + "\t\t"); + write_xml_string(fp, p->make_model); + cupsFilePrintf(fp, "\n" + "\t\tprinter-state\n" + "\t\t%d\n" + "\t\tprinter-state-reasons\n" + "\t\t\n", p->state); + for (i = 0; i < p->num_reasons; i ++) + { + cupsFilePuts(fp, "\t\t\t"); + write_xml_string(fp, p->reasons[i]); + cupsFilePuts(fp, "\n"); + } + cupsFilePrintf(fp, "\t\t\n" + "\t\tprinter-type\n" + "\t\t%d\n" + "\t\tdevice-uri\n" + "\t\t", p->type); + write_xml_string(fp, p->sanitized_device_uri); + cupsFilePuts(fp, "\n" + "\t\n"); + } + cupsFilePuts(fp, "\n" + "\n"); + break; - /* - * Let the browse protocols reflect the change... - */ + case PRINTCAP_SOLARIS : + /* + * Each printer is put in the file as: + * + * _all:all=Printer1,Printer2,Printer3,...,PrinterN + * _default:use=DefaultPrinter + * Printer1:\ + * :bsdaddr=ServerName,Printer1:\ + * :description=Description: + * Printer2: + * :bsdaddr=ServerName,Printer2:\ + * :description=Description: + * Printer3: + * :bsdaddr=ServerName,Printer3:\ + * :description=Description: + * ... + * PrinterN: + * :bsdaddr=ServerName,PrinterN:\ + * :description=Description: + */ - if (update) - cupsdRegisterPrinter(p); + cupsFilePuts(fp, "_all:all="); + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayCurrent(Printers)) + cupsFilePrintf(fp, "%s%c", p->name, + cupsArrayNext(Printers) ? ',' : '\n'); + + if (DefaultPrinter) + cupsFilePrintf(fp, "_default:use=%s\n", DefaultPrinter->name); + + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + cupsFilePrintf(fp, "%s:\\\n" + "\t:bsdaddr=%s,%s:\\\n" + "\t:description=%s:\n", + p->name, ServerName, p->name, + p->info ? p->info : ""); + break; + } /* - * Save the printer configuration if a printer goes from idle or processing - * to stopped (or visa-versa)... + * Close the file... */ - if ((old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED) && - update) - { - if (p->type & CUPS_PRINTER_CLASS) - cupsdMarkDirty(CUPSD_DIRTY_CLASSES); - else - cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); - } + cupsFileClose(fp); } /* - * 'cupsdStopPrinter()' - Stop a printer from printing any jobs... + * 'add_printer_defaults()' - Add name-default attributes to the printer attributes. */ -void -cupsdStopPrinter(cupsd_printer_t *p, /* I - Printer to stop */ - int update)/* I - Update printers.conf? */ +static void +add_printer_defaults(cupsd_printer_t *p)/* I - Printer */ { - cupsd_job_t *job; /* Active print job */ + int i; /* Looping var */ + int num_options; /* Number of default options */ + cups_option_t *options, /* Default options */ + *option; /* Current option */ + char name[256]; /* name-default */ /* - * Set the printer state... + * Maintain a common array of default attribute names... */ - cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update); + if (!CommonDefaults) + { + CommonDefaults = cupsArrayNew((cups_array_func_t)strcmp, NULL); + + 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-col-default")); + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("number-up-default")); + cupsArrayAdd(CommonDefaults, + _cupsStrAlloc("orientation-requested-default")); + } /* - * See if we have a job printing on this printer... + * Add all of the default options from the .conf files... */ - if (p->job) + for (num_options = 0, options = NULL, i = p->num_options, option = p->options; + i > 0; + i --, option ++) { - /* - * Get pointer to job... - */ + if (strcmp(option->name, "ipp-options") && + strcmp(option->name, "job-sheets") && + strcmp(option->name, "lease-duration")) + { + snprintf(name, sizeof(name), "%s-default", option->name); + num_options = cupsAddOption(name, option->value, num_options, &options); - job = (cupsd_job_t *)p->job; + if (!cupsArrayFind(CommonDefaults, name)) + cupsArrayAdd(CommonDefaults, _cupsStrAlloc(name)); + } + } - /* - * Stop it... - */ + /* + * Convert options to IPP attributes... + */ - cupsdStopJob(job, 0); + cupsEncodeOptions2(p->attrs, num_options, options, IPP_TAG_PRINTER); + cupsFreeOptions(num_options, options); - /* - * Reset the state to pending... - */ + /* + * Add standard -default attributes as needed... + */ - job->state->values[0].integer = IPP_JOB_PENDING; - job->state_value = IPP_JOB_PENDING; - job->dirty = 1; + if (!cupsGetOption("copies", p->num_options, p->options)) + ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default", + 1); - cupsdMarkDirty(CUPSD_DIRTY_JOBS); + if (!cupsGetOption("document-format", p->num_options, p->options)) + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, + "document-format-default", NULL, "application/octet-stream"); - cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, p, job, - "Job stopped due to printer being paused"); - } + 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"); + + if (!cupsGetOption("job-priority", p->num_options, p->options)) + ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "job-priority-default", 50); + + if (!cupsGetOption("number-up", p->num_options, p->options)) + ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "number-up-default", 1); + + if (!cupsGetOption("notify-lease-duration", p->num_options, p->options)) + ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "notify-lease-duration-default", DefaultLeaseDuration); + + 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); } /* - * 'cupsdUpdatePrinterPPD()' - Update keywords in a printer's PPD file. + * 'add_printer_filter()' - Add a MIME filter for a printer. */ -int /* O - 1 if successful, 0 otherwise */ -cupsdUpdatePrinterPPD( - cupsd_printer_t *p, /* I - Printer */ - int num_keywords, /* I - Number of keywords */ - cups_option_t *keywords) /* I - Keywords */ +static void +add_printer_filter( + cupsd_printer_t *p, /* I - Printer to add to */ + mime_type_t *filtertype, /* I - Filter or prefilter MIME type */ + const char *filter) /* I - Filter to add */ { - int i; /* Looping var */ - cups_file_t *src, /* Original file */ - *dst; /* New file */ - char srcfile[1024], /* Original filename */ - dstfile[1024], /* New filename */ - line[1024], /* Line from file */ - keystring[41]; /* Keyword from line */ - cups_option_t *keyword; /* Current keyword */ + 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 */ + 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_INFO, "Updating keywords in PPD file for %s...", - p->name); + 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); /* - * Get the old and new PPD filenames... + * Parse the filter string; it should be in one of the following formats: + * + * source/type cost program + * source/type cost maxsize(nnnn) program + * source/type dest/type cost program + * source/type dest/type cost maxsize(nnnn) program */ - snprintf(srcfile, sizeof(srcfile), "%s/ppd/%s.ppd.O", ServerRoot, p->name); - snprintf(dstfile, sizeof(srcfile), "%s/ppd/%s.ppd", ServerRoot, p->name); + if (sscanf(filter, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]", + super, type, dsuper, dtype, &cost, program) == 6) + { + snprintf(dest, sizeof(dest), "%s/%s/%s", p->name, dsuper, dtype); - /* - * Rename the old file and open the old and new... - */ + if ((desttype = mimeType(MimeDatabase, "printer", dest)) == NULL) + { + desttype = mimeAddType(MimeDatabase, "printer", dest); + if (!p->dest_types) + p->dest_types = cupsArrayNew(NULL, NULL); - if (rename(dstfile, srcfile)) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to backup PPD file for %s: %s", - p->name, strerror(errno)); - return (0); - } + cupsArrayAdd(p->dest_types, desttype); + } - if ((src = cupsFileOpen(srcfile, "r")) == NULL) + } + else { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open PPD file \"%s\": %s", - srcfile, strerror(errno)); - rename(srcfile, dstfile); - return (0); + if (sscanf(filter, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, &cost, + program) == 4) + { + desttype = filtertype; + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!", + p->name, filter); + return; + } } - if ((dst = cupsFileOpen(dstfile, "w")) == NULL) + if (!strncmp(program, "maxsize(", 8)) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create PPD file \"%s\": %s", - dstfile, strerror(errno)); - cupsFileClose(src); - rename(srcfile, dstfile); - return (0); - } + char *ptr; /* Pointer into maxsize(nnnn) program */ - /* - * Copy the first line and then write out all of the keywords... - */ + maxsize = (size_t)strtoll(program + 8, &ptr, 10); - if (!cupsFileGets(src, line, sizeof(line))) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to read PPD file \"%s\": %s", - srcfile, strerror(errno)); - cupsFileClose(src); - cupsFileClose(dst); - rename(srcfile, dstfile); - return (0); - } + if (*ptr != ')') + { + cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!", + p->name, filter); + return; + } - cupsFilePrintf(dst, "%s\n", line); + ptr ++; + while (_cups_isspace(*ptr)) + ptr ++; - for (i = num_keywords, keyword = keywords; i > 0; i --, keyword ++) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, "*%s: %s", keyword->name, keyword->value); - cupsFilePrintf(dst, "*%s: %s\n", keyword->name, keyword->value); + _cups_strcpy(program, ptr); } /* - * Then copy the rest of the PPD file, dropping any keywords we changed. + * Check permissions on the filter and its containing directory... */ - while (cupsFileGets(src, line, sizeof(line))) + if (strcmp(program, "-")) { - /* - * Skip keywords we've already set... - */ - - if (sscanf(line, "*%40[^:]:", keystring) == 1 && - cupsGetOption(keystring, num_keywords, keywords)) - continue; - - /* - * Otherwise write the line... - */ + if (program[0] == '/') + strlcpy(filename, program, sizeof(filename)); + else + snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program); - cupsFilePrintf(dst, "%s\n", line); + _cupsFileCheck(filename, _CUPS_FILE_CHECK_PROGRAM, !RunUser, + cupsdLogFCMessage, p); } /* - * Close files and return... + * Add the filter to the MIME database, supporting wildcards as needed... */ - cupsFileClose(src); - cupsFileClose(dst); + for (temptype = mimeFirstType(MimeDatabase); + temptype; + temptype = mimeNextType(MimeDatabase)) + if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) || + !_cups_strcasecmp(temptype->super, super)) && + (type[0] == '*' || !_cups_strcasecmp(temptype->type, type))) + { + 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); + } - return (1); + if (filterptr) + filterptr->maxsize = maxsize; + } } /* - * 'cupsdUpdatePrinters()' - Update printers after a partial reload. + * 'add_printer_formats()' - Add document-format-supported values for a printer. */ -void -cupsdUpdatePrinters(void) +static void +add_printer_formats(cupsd_printer_t *p) /* I - Printer */ { - cupsd_printer_t *p; /* Current printer */ + int i; /* Looping var */ + mime_type_t *type; /* Current MIME type */ + cups_array_t *filters; /* Filters */ + ipp_attribute_t *attr; /* document-format-supported attribute */ + char mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2]; + /* MIME type name */ /* - * Loop through the printers and recreate the printer attributes - * for any local printers since the policy and/or access control - * stuff may have changed. Also, if browsing is disabled, remove - * any remote printers... + * Raw (and remote) queues advertise all of the supported MIME + * types... */ - for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); - p; - p = (cupsd_printer_t *)cupsArrayNext(Printers)) + cupsArrayDelete(p->filetypes); + p->filetypes = NULL; + + if (p->raw) { - /* - * Remove remote printers if we are no longer browsing... - */ + ippAddStrings(p->attrs, IPP_TAG_PRINTER, + (ipp_tag_t)(IPP_TAG_MIMETYPE | IPP_TAG_COPY), + "document-format-supported", NumMimeTypes, NULL, MimeTypes); + return; + } - if (!Browsing && - (p->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_DISCOVERED))) - { - if (p->type & CUPS_PRINTER_IMPLICIT) - cupsArrayRemove(ImplicitPrinters, p); + /* + * Otherwise, loop through the supported MIME types and see if there + * are filters for them... + */ - cupsArraySave(Printers); - cupsdDeletePrinter(p, 0); - cupsArrayRestore(Printers); - continue; - } + cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer_formats: %d types, %d filters", + mimeNumTypes(MimeDatabase), mimeNumFilters(MimeDatabase)); - /* - * Update the operation policy pointer... - */ + p->filetypes = cupsArrayNew(NULL, NULL); - if ((p->op_policy_ptr = cupsdFindPolicy(p->op_policy)) == NULL) - p->op_policy_ptr = DefaultPolicyPtr; + for (type = mimeFirstType(MimeDatabase); + type; + type = mimeNextType(MimeDatabase)) + { + if (!_cups_strcasecmp(type->super, "printer")) + continue; - /* - * Update printer attributes as needed... - */ + snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type); - if (!(p->type & CUPS_PRINTER_DISCOVERED)) - cupsdSetPrinterAttrs(p); - } -} + if ((filters = mimeFilter(MimeDatabase, type, p->filetype, NULL)) != NULL) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "add_printer_formats: %s: %s needs %d filters", + p->name, mimetype, cupsArrayCount(filters)); - -/* - * 'cupsdValidateDest()' - Validate a printer/class destination. - */ - -const char * /* O - Printer or class name */ -cupsdValidateDest( - const char *uri, /* I - Printer URI */ - cups_ptype_t *dtype, /* O - Type (printer or class) */ - cupsd_printer_t **printer) /* O - Printer pointer */ -{ - cupsd_printer_t *p; /* Current printer */ - char localname[1024],/* Localized hostname */ - *lptr, /* Pointer into localized hostname */ - *sptr, /* Pointer into server name */ - *rptr, /* Pointer into resource */ - scheme[32], /* Scheme portion of URI */ - username[64], /* Username portion of URI */ - hostname[HTTP_MAX_HOST], - /* Host portion of URI */ - resource[HTTP_MAX_URI]; - /* Resource portion of URI */ - int port; /* Port portion of URI */ - - - DEBUG_printf(("cupsdValidateDest(uri=\"%s\", dtype=%p, printer=%p)\n", uri, - dtype, printer)); - - /* - * Initialize return values... - */ - - if (printer) - *printer = NULL; - - if (dtype) - *dtype = (cups_ptype_t)0; + cupsArrayDelete(filters); + cupsArrayAdd(p->filetypes, type); + } + else + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "add_printer_formats: %s: %s not supported", + p->name, mimetype); + } /* - * Pull the hostname and resource from the URI... + * Add the file formats that can be filtered... */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), - username, sizeof(username), hostname, sizeof(hostname), - &port, resource, sizeof(resource)); + if ((type = mimeType(MimeDatabase, "application", "octet-stream")) == NULL || + !cupsArrayFind(p->filetypes, type)) + i = 1; + else + i = 0; - /* - * See if the resource is a class or printer... - */ + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "add_printer_formats: %s: %d supported types", + p->name, cupsArrayCount(p->filetypes) + i); - if (!strncmp(resource, "/classes/", 9)) - { - /* - * Class... - */ + attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, + "document-format-supported", + cupsArrayCount(p->filetypes) + i, NULL, NULL); - rptr = resource + 9; - } - else if (!strncmp(resource, "/printers/", 10)) - { - /* - * Printer... - */ + if (i) + attr->values[0].string.text = _cupsStrAlloc("application/octet-stream"); - rptr = resource + 10; - } - else + for (type = (mime_type_t *)cupsArrayFirst(p->filetypes); + type; + i ++, type = (mime_type_t *)cupsArrayNext(p->filetypes)) { - /* - * Bad resource name... - */ + snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type); - return (NULL); + attr->values[i].string.text = _cupsStrAlloc(mimetype); } - /* - * See if the printer or class name exists... - */ - - p = cupsdFindDest(rptr); - - if (p == NULL && strchr(rptr, '@') == NULL) - return (NULL); - else if (p != NULL) +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) { - if (printer) - *printer = p; + char pdl[1024]; /* Buffer to build pdl list */ + mime_filter_t *filter; /* MIME filter looping var */ - if (dtype) - *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT | - CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED); - return (p->name); - } + /* + * We only support raw printing if this is not a Tioga PrintJobMgr based + * queue and if application/octet-stream is a known type... + */ - /* - * Change localhost to the server name... - */ + for (filter = (mime_filter_t *)cupsArrayFirst(MimeDatabase->filters); + filter; + filter = (mime_filter_t *)cupsArrayNext(MimeDatabase->filters)) + { + if (filter->dst == p->filetype && strstr(filter->filter, "PrintJobMgr")) + break; + } - if (!strcasecmp(hostname, "localhost")) - strlcpy(hostname, ServerName, sizeof(hostname)); + pdl[0] = '\0'; - strlcpy(localname, hostname, sizeof(localname)); + if (!filter && mimeType(MimeDatabase, "application", "octet-stream")) + strlcat(pdl, "application/octet-stream,", sizeof(pdl)); - if (!strcasecmp(hostname, ServerName)) - { /* - * Localize the hostname... + * Then list a bunch of formats that are supported by the printer... */ - lptr = strchr(localname, '.'); - sptr = strchr(ServerName, '.'); - - if (sptr != NULL && lptr != NULL) + for (type = (mime_type_t *)cupsArrayFirst(p->filetypes); + type; + type = (mime_type_t *)cupsArrayNext(p->filetypes)) { - /* - * Strip the common domain name components... - */ - - while (lptr != NULL) + if (!_cups_strcasecmp(type->super, "application")) { - if (!strcasecmp(lptr, sptr)) - { - *lptr = '\0'; - break; - } - else - lptr = strchr(lptr + 1, '.'); + 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)); } } - } - - DEBUG_printf(("localized hostname is \"%s\"...\n", localname)); - - /* - * Find a matching printer or class... - */ - - for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); - p; - p = (cupsd_printer_t *)cupsArrayNext(Printers)) - if (!strcasecmp(p->hostname, localname) && - !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); - return (p->name); - } + if (pdl[0]) + pdl[strlen(pdl) - 1] = '\0'; /* Remove trailing comma */ - return (NULL); + cupsdSetString(&p->pdl, pdl); + } +#endif /* HAVE_DNSSD || HAVE_AVAHI */ } /* - * 'cupsdWritePrintcap()' - Write a pseudo-printcap file for older applications - * that need it... + * 'compare_printers()' - Compare two printers. */ -void -cupsdWritePrintcap(void) +static int /* O - Result of comparison */ +compare_printers(void *first, /* I - First printer */ + void *second, /* I - Second printer */ + void *data) /* I - App data (not used) */ { - cups_file_t *fp; /* printcap file */ - cupsd_printer_t *p; /* Current printer */ + (void)data; + return (_cups_strcasecmp(((cupsd_printer_t *)first)->name, + ((cupsd_printer_t *)second)->name)); +} -#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 */ +/* + * 'delete_printer_filters()' - Delete all MIME filters for a printer. + */ - /* - * See if we have a printcap file; if not, don't bother writing it. - */ +static void +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 */ - if (!Printcap || !*Printcap) - return; /* - * Open the printcap file... + * Range check input... */ - if ((fp = cupsFileOpen(Printcap, "w")) == NULL) + if (p == NULL) return; /* - * Put a comment header at the top so that users will know where the - * data has come from... + * Remove all filters from the MIME database that have a destination + * type == printer... */ - cupsFilePuts(fp, - "# This file was automatically generated by cupsd(8) from the\n"); - cupsFilePrintf(fp, "# %s/printers.conf file. All changes to this file\n", - ServerRoot); - cupsFilePuts(fp, "# will be lost.\n"); + for (filter = mimeFirstFilter(MimeDatabase); + filter; + filter = mimeNextFilter(MimeDatabase)) + if (filter->dst == p->filetype || filter->dst == p->prefiltertype || + cupsArrayFind(p->dest_types, filter->dst)) + { + /* + * Delete the current filter... + */ - if (Printers) - { - /* - * Write a new printcap with the current list of printers. - */ + mimeDeleteFilter(MimeDatabase, filter); + } - switch (PrintcapFormat) - { - case PRINTCAP_BSD: - /* - * Each printer is put in the file as: - * - * Printer1: - * Printer2: - * Printer3: - * ... - * PrinterN: - */ + for (type = (mime_type_t *)cupsArrayFirst(p->dest_types); + type; + type = (mime_type_t *)cupsArrayNext(p->dest_types)) + mimeDeleteType(MimeDatabase, type); - if (DefaultPrinter) - cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", DefaultPrinter->name, - DefaultPrinter->info, ServerName, - DefaultPrinter->name); + cupsArrayDelete(p->dest_types); + p->dest_types = NULL; - for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); - p; - p = (cupsd_printer_t *)cupsArrayNext(Printers)) - if (p != DefaultPrinter) - cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", p->name, p->info, - ServerName, p->name); - break; + cupsdSetPrinterReasons(p, "-cups-insecure-filter-warning" + ",cups-missing-filter-warning"); +} - case PRINTCAP_SOLARIS: - /* - * Each printer is put in the file as: - * - * _all:all=Printer1,Printer2,Printer3,...,PrinterN - * _default:use=DefaultPrinter - * Printer1:\ - * :bsdaddr=ServerName,Printer1:\ - * :description=Description: - * Printer2: - * :bsdaddr=ServerName,Printer2:\ - * :description=Description: - * Printer3: - * :bsdaddr=ServerName,Printer3:\ - * :description=Description: - * ... - * PrinterN: - * :bsdaddr=ServerName,PrinterN:\ - * :description=Description: - */ - cupsFilePuts(fp, "_all:all="); - for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); - p; - p = (cupsd_printer_t *)cupsArrayCurrent(Printers)) - cupsFilePrintf(fp, "%s%c", p->name, - cupsArrayNext(Printers) ? ',' : '\n'); - - if (DefaultPrinter) - cupsFilePrintf(fp, "_default:use=%s\n", DefaultPrinter->name); - - for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); - p; - p = (cupsd_printer_t *)cupsArrayNext(Printers)) - cupsFilePrintf(fp, "%s:\\\n" - "\t:bsdaddr=%s,%s:\\\n" - "\t:description=%s:\n", - p->name, ServerName, p->name, - p->info ? p->info : ""); - break; - } - } +/* + * 'dirty_printer()' - Mark config and state files dirty for the specified + * printer. + */ - /* - * Close the file... - */ +static void +dirty_printer(cupsd_printer_t *p) /* I - Printer */ +{ + if (p->type & CUPS_PRINTER_CLASS) + cupsdMarkDirty(CUPSD_DIRTY_CLASSES); + else + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); - cupsFileClose(fp); + if (PrintcapFormat == PRINTCAP_PLIST) + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); } /* - * 'cupsdSanitizeURI()' - Sanitize a device URI... + * 'load_ppd()' - Load a cached PPD file, updating the cache as needed. */ -char * /* O - New device URI */ -cupsdSanitizeURI(const char *uri, /* I - Original device URI */ - char *buffer, /* O - New device URI */ - int buflen) /* I - Size of new device URI buffer */ +static void +load_ppd(cupsd_printer_t *p) /* I - Printer */ { - char *start, /* Start of data after scheme */ - *slash, /* First slash after scheme:// */ - *ptr; /* Pointer into user@host:port part */ + 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 */ + int num_media; /* Number of media 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 */ + 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_value_t *val; /* Attribute value */ + int num_finishings, /* Number of finishings */ + finishings[5]; /* 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 sides[3] = /* sides-supported values */ + { + "one-sided", + "two-sided-long-edge", + "two-sided-short-edge" + }; + static const char * const standard_commands[] = + { /* Standard CUPS commands */ + "AutoConfigure", + "Clean", + "PrintSelfTestPage" + }; /* - * Range check input... + * Check to see if the cache is up-to-date... */ - if (!uri || !buffer || buflen < 2) - return (NULL); - - /* - * Copy the device URI to the new buffer... - */ + snprintf(cache_name, sizeof(cache_name), "%s/%s.data", CacheDir, p->name); + if (stat(cache_name, &cache_info)) + cache_info.st_mtime = 0; - strlcpy(buffer, uri, buflen); + snprintf(ppd_name, sizeof(ppd_name), "%s/ppd/%s.ppd", ServerRoot, p->name); + if (stat(ppd_name, &ppd_info)) + ppd_info.st_mtime = 1; - /* - * Find the end of the scheme:// part... - */ + ippDelete(p->ppd_attrs); + p->ppd_attrs = NULL; - if ((ptr = strchr(buffer, ':')) == NULL) - return (buffer); /* No scheme: part... */ + _ppdCacheDestroy(p->pc); + p->pc = NULL; - for (start = ptr + 1; *start; start ++) - if (*start != '/') - break; + if (cache_info.st_mtime >= ppd_info.st_mtime) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", cache_name); - /* - * Find the next slash (/) in the URI... - */ + if ((p->pc = _ppdCacheCreateWithFile(cache_name, &p->ppd_attrs)) != NULL && + p->ppd_attrs) + { + /* + * Loaded successfully! + */ - if ((slash = strchr(start, '/')) == NULL) - slash = start + strlen(start); /* No slash, point to the end */ + return; + } + } /* - * Check for an @ sign before the slash... + * Reload PPD attributes from disk... */ - if ((ptr = strchr(start, '@')) != NULL && ptr < slash) + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", ppd_name); + + cupsdClearString(&(p->make_model)); + + p->type &= (cups_ptype_t)~CUPS_PRINTER_OPTIONS; + p->type |= CUPS_PRINTER_BW; + + finishings[0] = IPP_FINISHINGS_NONE; + num_finishings = 1; + + p->ppd_attrs = ippNew(); + + if ((ppd = _ppdOpenFile(ppd_name, _PPD_LOCALIZATION_NONE)) != NULL) { /* - * Found an @ sign and it is before the resource part, so we have - * an authentication string. Copy the remaining URI over the - * authentication string... + * Add make/model and other various attributes... */ - _cups_strcpy(start, ptr + 1); - } + p->pc = _ppdCacheCreateWithPPD(ppd); - /* - * Return the new device URI... - */ + if (!p->pc) + cupsdLogMessage(CUPSD_LOG_WARN, "Unable to create cache of \"%s\": %s", + ppd_name, cupsLastErrorString()); - return (buffer); -} + ppdMarkDefaults(ppd); + if (ppd->color_device) + p->type |= CUPS_PRINTER_COLOR; + if (ppd->variable_sizes) + p->type |= CUPS_PRINTER_VARIABLE; + if (!ppd->manual_copies) + p->type |= CUPS_PRINTER_COPIES; + if ((ppd_attr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL) + if (ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true")) + p->type |= CUPS_PRINTER_FAX; -/* - * 'add_printer_defaults()' - Add name-default attributes to the printer attributes. - */ + ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "color-supported", (char)ppd->color_device); -static void -add_printer_defaults(cupsd_printer_t *p)/* I - Printer */ -{ - int i; /* Looping var */ - int num_options; /* Number of default options */ - cups_option_t *options, /* Default options */ - *option; /* Current option */ - char name[256]; /* name-default */ + 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); - /* - * Maintain a common array of default attribute names... - */ + if (p->pc && p->pc->accounting_user_id) + ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, + "job-accounting-user-id-supported", 1); - if (!CommonDefaults) - { - CommonDefaults = cupsArrayNew((cups_array_func_t)strcmp, NULL); + 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)); + } - cupsArrayAdd(CommonDefaults, _cupsStrAlloc("copies-default")); - cupsArrayAdd(CommonDefaults, _cupsStrAlloc("document-format-default")); - cupsArrayAdd(CommonDefaults, _cupsStrAlloc("finishings-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("number-up-default")); - cupsArrayAdd(CommonDefaults, - _cupsStrAlloc("orientation-requested-default")); - cupsArrayAdd(CommonDefaults, _cupsStrAlloc("sides-default")); - } + 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". + */ - /* - * Add all of the default options from the .conf files... - */ + 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); + } - for (num_options = 0, i = p->num_options, option = p->options; - i > 0; - i --, option ++) - { - if (strcmp(option->name, "ipp-options") && - strcmp(option->name, "job-sheets") && - strcmp(option->name, "lease-duration")) + 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) { - snprintf(name, sizeof(name), "%s-default", option->name); - num_options = cupsAddOption(name, option->value, num_options, &options); + if (ppdFindChoice(output_mode, "draft") || + ppdFindChoice(output_mode, "fast")) + qualities[num_qualities ++] = IPP_QUALITY_DRAFT; - if (!cupsArrayFind(CommonDefaults, name)) - cupsArrayAdd(CommonDefaults, _cupsStrAlloc(name)); + 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); - /* - * Convert options to IPP attributes... - */ + qualities[num_qualities ++] = IPP_QUALITY_NORMAL; + qualities[num_qualities ++] = IPP_QUALITY_HIGH; + } + else + qualities[num_qualities ++] = IPP_QUALITY_NORMAL; - cupsEncodeOptions2(p->attrs, num_options, options, IPP_TAG_PRINTER); - cupsFreeOptions(num_options, options); + ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, + "print-quality-supported", num_qualities, qualities); - /* - * Add standard -default attributes as needed... - */ + if (ppd->nickname) + { + /* + * The NickName can be localized in the character set specified + * by the LanugageEncoding attribute. However, ppdOpen2() has + * already converted the ppd->nickname member to UTF-8 for us + * (the original attribute value is available separately) + */ - if (!cupsGetOption("copies", p->num_options, p->options)) - ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default", - 1); + cupsdSetString(&p->make_model, ppd->nickname); + } + else if (ppd->modelname) + { + /* + * Model name can only contain specific characters... + */ - if (!cupsGetOption("document-format", p->num_options, p->options)) - ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, - "document-format-default", NULL, "application/octet-stream"); + cupsdSetString(&p->make_model, ppd->modelname); + } + else + cupsdSetString(&p->make_model, "Bad PPD File"); - 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"); + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, + "printer-make-and-model", NULL, p->make_model); - if (!cupsGetOption("job-priority", p->num_options, p->options)) - ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "job-priority-default", 50); + /* + * Add media options from the PPD file... + */ - if (!cupsGetOption("number-up", p->num_options, p->options)) - ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "number-up-default", 1); + if (ppd->num_sizes == 0 || !p->pc) + { + if (!ppdFindAttr(ppd, "APScannerOnly", NULL)) + cupsdLogMessage(CUPSD_LOG_CRIT, + "The PPD file for printer %s contains no media " + "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 + { + /* + * media-default + */ - if (!cupsGetOption("orientation-requested", p->num_options, p->options)) - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, - "orientation-requested-default", NULL, NULL); + if ((size = ppdPageSize(ppd, NULL)) != NULL) + pwgsize = _ppdCacheGetSize(p->pc, size->name); + else + pwgsize = 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); + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "media-default", NULL, + pwgsize ? pwgsize->map.pwg : "unknown"); - if (!cupsGetOption("notify-events", p->num_options, p->options)) - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "notify-events-default", NULL, "job-completed"); -} + /* + * media-col-default + */ + + if (pwgsize) + { + ipp_t *col; /* Collection value */ + + 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); + + ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-default", + col); + ippDelete(col); + } + /* + * media-supported + */ -/* - * 'add_printer_filter()' - Add a MIME filter for a printer. - */ + num_media = p->pc->num_sizes; + if (p->pc->custom_min_keyword) + num_media += 2; -static void -add_printer_filter( - cupsd_printer_t *p, /* I - Printer to add to */ - mime_type_t *filtertype, /* I - Filter or prefilter MIME type */ - const char *filter) /* I - Filter to add */ -{ - char super[MIME_MAX_SUPER], /* Super-type for filter */ - type[MIME_MAX_TYPE], /* Type for filter */ - program[1024]; /* Program/filter name */ - int cost; /* Cost of filter */ - mime_type_t *temptype; /* MIME type looping var */ - char filename[1024]; /* Full filter filename */ + 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); - /* - * Parse the filter string; it should be in the following format: - * - * super/type cost program - */ + if (p->pc->custom_min_keyword) + { + val->string.text = _cupsStrAlloc(p->pc->custom_min_keyword); + val ++; + val->string.text = _cupsStrAlloc(p->pc->custom_max_keyword); + } + } - if (sscanf(filter, "%15[^/]/%31s%d%1023s", super, type, &cost, program) != 4) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!", - p->name, filter); - return; - } + /* + * media-size-supported + */ - /* - * See if the filter program exists; if not, stop the printer and flag - * the error! - */ + num_media = p->pc->num_sizes; + if (p->pc->custom_min_keyword) + num_media ++; - if (strcmp(program, "-")) - { - if (program[0] == '/') - strlcpy(filename, program, sizeof(filename)); - else - snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program); + if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER, + "media-size-supported", num_media, + NULL)) != NULL) + { + val = attr->values; - if (access(filename, X_OK)) - { - snprintf(p->state_message, sizeof(p->state_message), - "Filter \"%s\" for printer \"%s\" not available: %s", - program, p->name, strerror(errno)); - cupsdSetPrinterReasons(p, "+cups-missing-filter-error"); - cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 0); + 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); + } + + 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); + } + } + + /* + * media-source-supported + */ + + 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); + } + + /* + * media-type-supported + */ + + 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); + } + + /* + * media-*-margin-supported + */ + + 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... + */ - cupsdLogMessage(CUPSD_LOG_ERROR, "%s", p->state_message); + 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; + } } - } - /* - * Mark the CUPS_PRINTER_COMMANDS bit if we have a filter for - * application/vnd.cups-command... - */ + /* + * Output bin... + */ + + if (p->pc && p->pc->num_bins > 0) + { + attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "output-bin-supported", p->pc->num_bins, + NULL, NULL); - if (!strcasecmp(super, "application") && - !strcasecmp(type, "vnd.cups-command")) - p->type |= CUPS_PRINTER_COMMANDS; + 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); + } - /* - * Add the filter to the MIME database, supporting wildcards as needed... - */ + 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; - 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 (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 + 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")))) { - 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); + /* + * Report that this printer has a single output bin that leaves pages face + * up. + */ + + 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 + { + 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"); } -} + /* + * print-color-mode... + */ -/* - * 'add_printer_formats()' - Add document-format-supported values for a printer. - */ + 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"); + } + 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"); + } -static void -add_printer_formats(cupsd_printer_t *p) /* I - Printer */ -{ - int i; /* Looping var */ - mime_type_t *type; /* Current MIME type */ - cups_array_t *filters; /* Filters */ - ipp_attribute_t *attr; /* document-format-supported attribute */ - char mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2]; - /* MIME type name */ + /* + * Mandatory job attributes, if any... + */ + if (p->pc && cupsArrayCount(p->pc->mandatory) > 0) + { + 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); + } - /* - * Raw (and remote) queues advertise all of the supported MIME - * types... - */ + /* + * Printer resolutions... + */ - cupsArrayDelete(p->filetypes); - p->filetypes = NULL; + if ((resolution = ppdFindOption(ppd, "Resolution")) == NULL) + if ((resolution = ppdFindOption(ppd, "JCLResolution")) == NULL) + if ((resolution = ppdFindOption(ppd, "SetResolution")) == NULL) + resolution = ppdFindOption(ppd, "CNRes_PGP"); - if (p->raw) - { - ippAddStrings(p->attrs, IPP_TAG_PRINTER, - (ipp_tag_t)(IPP_TAG_MIMETYPE | IPP_TAG_COPY), - "document-format-supported", NumMimeTypes, NULL, MimeTypes); - return; - } + if (resolution) + { + /* + * Report all supported resolutions... + */ - /* - * Otherwise, loop through the supported MIME types and see if there - * are filters for them... - */ + attr = ippAddResolutions(p->ppd_attrs, IPP_TAG_PRINTER, + "printer-resolution-supported", + resolution->num_choices, IPP_RES_PER_INCH, + NULL, NULL); - cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer_formats: %d types, %d filters", - mimeNumTypes(MimeDatabase), mimeNumFilters(MimeDatabase)); + 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); - p->filetypes = cupsArrayNew(NULL, NULL); + if (xdpi <= 0 || ydpi <= 0) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "Bad resolution \"%s\" for printer %s.", + choice->choice, p->name); + xdpi = ydpi = 300; + } - for (type = mimeFirstType(MimeDatabase); - type; - type = mimeNextType(MimeDatabase)) - { - snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type); + 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); + } + } + else if ((ppd_attr = ppdFindAttr(ppd, "DefaultResolution", NULL)) != NULL && + ppd_attr->value) + { + /* + * Just the DefaultResolution to report... + */ + + 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; + } - if ((filters = mimeFilter(MimeDatabase, type, p->filetype, NULL)) != NULL) - { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "add_printer_formats: %s: %s needs %d filters", - p->name, mimetype, cupsArrayCount(filters)); + if (xdpi <= 0 || ydpi <= 0) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "Bad default resolution \"%s\" for printer %s.", + ppd_attr->value, p->name); + xdpi = ydpi = 300; + } - cupsArrayDelete(filters); - cupsArrayAdd(p->filetypes, type); + 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); } else - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "add_printer_formats: %s: %s not supported", - p->name, mimetype); - } - - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "add_printer_formats: %s: %d supported types", - p->name, cupsArrayCount(p->filetypes) + 1); + { + /* + * No resolutions in PPD - make one up... + */ - /* - * Add the file formats that can be filtered... - */ + 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); + } - if ((type = mimeType(MimeDatabase, "application", "octet-stream")) == NULL || - !cupsArrayFind(p->filetypes, type)) - i = 1; - else - i = 0; + /* + * Duplexing, etc... + */ - attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, - "document-format-supported", - cupsArrayCount(p->filetypes) + 1, NULL, NULL); + ppdMarkDefaults(ppd); - if (i) - attr->values[0].string.text = _cupsStrAlloc("application/octet-stream"); + 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"); - for (type = (mime_type_t *)cupsArrayFirst(p->filetypes); - type; - i ++, type = (mime_type_t *)cupsArrayNext(p->filetypes)) - { - snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type); + if (duplex && duplex->num_choices > 1 && + !ppdInstallableConflict(ppd, duplex->keyword, "DuplexTumble")) + { + p->type |= CUPS_PRINTER_DUPLEX; - attr->values[i].string.text = _cupsStrAlloc(mimetype); - } + ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "sides-supported", 3, NULL, sides); -#ifdef HAVE_DNSSD - { - char pdl[1024]; /* Buffer to build pdl list */ - mime_filter_t *filter; /* MIME filter looping var */ + 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; - pdl[0] = '\0'; + if (ppdFindOption(ppd, "StapleLocation") != NULL) + { + p->type |= CUPS_PRINTER_STAPLE; + finishings[num_finishings++] = IPP_FINISHINGS_STAPLE; + } - if (mimeType(MimeDatabase, "application", "pdf")) - strlcat(pdl, "application/pdf,", sizeof(pdl)); + if (ppdFindOption(ppd, "BindEdge") != NULL) + { + p->type |= CUPS_PRINTER_BIND; + finishings[num_finishings++] = IPP_FINISHINGS_BIND; + } - if (mimeType(MimeDatabase, "application", "postscript")) - strlcat(pdl, "application/postscript,", sizeof(pdl)); + 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 (mimeType(MimeDatabase, "application", "vnd.cups-raster")) - strlcat(pdl, "application/vnd.cups-raster,", sizeof(pdl)); + 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; + } /* - * Determine if this is a Tioga PrintJobMgr based queue... + * Scan the filters in the PPD file... */ - for (filter = (mime_filter_t *)cupsArrayFirst(MimeDatabase->filters); - filter; - filter = (mime_filter_t *)cupsArrayNext(MimeDatabase->filters)) + if (p->pc) { - if (filter->dst == p->filetype && filter->filter && - strstr(filter->filter, "PrintJobMgr")) - break; + 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; + } + } } - /* - * We only support raw printing if this is not a Tioga PrintJobMgr based - * queue and if application/octet-stream is a known conversion... - */ - - if (!filter && mimeType(MimeDatabase, "application", "octet-stream")) - strlcat(pdl, "application/octet-stream,", sizeof(pdl)); + if (p->type & CUPS_PRINTER_COMMANDS) + { + char *commands, /* Copy of commands */ + *start, /* Start of name */ + *end; /* End of name */ + int count; /* Number of commands */ - if (mimeType(MimeDatabase, "image", "png")) - strlcat(pdl, "image/png,", sizeof(pdl)); + if ((ppd_attr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL) + { + for (count = 0, start = ppd_attr->value; *start; count ++) + { + while (_cups_isspace(*start)) + start ++; - if (pdl[0]) - pdl[strlen(pdl) - 1] = '\0'; /* Remove trailing comma */ + if (!*start) + break; - cupsdSetString(&p->pdl, pdl); - } -#endif /* HAVE_DNSSD */ -} + while (*start && !isspace(*start & 255)) + start ++; + } + } + else + count = 0; + if (count > 0) + { + /* + * Make a copy of the commands string and count how many commands there + * are... + */ -/* - * 'compare_printers()' - Compare two printers. - */ + attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "printer-commands", count, NULL, NULL); -static int /* O - Result of comparison */ -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, - ((cupsd_printer_t *)second)->name)); -} + commands = strdup(ppd_attr->value); + for (count = 0, start = commands; *start; count ++) + { + while (isspace(*start & 255)) + start ++; -/* - * 'delete_printer_filters()' - Delete all MIME filters for a printer. - */ + if (!*start) + break; -static void -delete_printer_filters( - cupsd_printer_t *p) /* I - Printer to remove from */ -{ - mime_filter_t *filter; /* MIME filter looping var */ + end = start; + while (*end && !isspace(*end & 255)) + end ++; + if (*end) + *end++ = '\0'; - /* - * Range check input... - */ + attr->values[count].string.text = _cupsStrAlloc(start); - if (p == NULL) - return; + start = end; + } - /* - * Remove all filters from the MIME database that have a destination - * type == printer... - */ + free(commands); + } + else + { + /* + * Add the standard list of commands... + */ - for (filter = mimeFirstFilter(MimeDatabase); - filter; - filter = mimeNextFilter(MimeDatabase)) - if (filter->dst == p->filetype) + ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "printer-commands", + (int)(sizeof(standard_commands) / + sizeof(standard_commands[0])), NULL, + standard_commands); + } + } + else { /* - * Delete the current filter... + * No commands supported... */ - mimeDeleteFilter(MimeDatabase, filter); + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "printer-commands", NULL, "none"); } -} + /* + * Show current and available port monitors for this printer... + */ -#ifdef __sgi -/* - * 'write_irix_config()' - Update the config files used by the IRIX - * desktop tools. - */ + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor", + NULL, p->port_monitor ? p->port_monitor : "none"); -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 */ + for (i = 1, ppd_attr = ppdFindAttr(ppd, "cupsPortMonitor", NULL); + ppd_attr; + i ++, ppd_attr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL)); + if (ppd->protocols) + { + if (strstr(ppd->protocols, "TBCP")) + i ++; + else if (strstr(ppd->protocols, "BCP")) + i ++; + } - /* - * 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... - */ + attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, + "port-monitor-supported", i, NULL, NULL); - snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name); + attr->values[0].string.text = _cupsStrAlloc("none"); - if (p->type & CUPS_PRINTER_CLASS) - unlink(filename); - else if ((fp = cupsFileOpen(filename, "w")) != NULL) - { - cupsFilePuts(fp, "#!/bin/sh\n"); + for (i = 1, ppd_attr = ppdFindAttr(ppd, "cupsPortMonitor", NULL); + ppd_attr; + i ++, ppd_attr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL)) + attr->values[i].string.text = _cupsStrAlloc(ppd_attr->value); - 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 (ppd->protocols) + { + if (strstr(ppd->protocols, "TBCP")) + attr->values[i].string.text = _cupsStrAlloc("tbcp"); + else if (strstr(ppd->protocols, "BCP")) + attr->values[i].string.text = _cupsStrAlloc("bcp"); + } - if (p->type & CUPS_PRINTER_COLOR) - cupsFilePuts(fp, "TYPE=ColorPostScript\n"); - else - cupsFilePuts(fp, "TYPE=MonoPostScript\n"); + if (ppdFindAttr(ppd, "APRemoteQueueID", NULL)) + p->type |= CUPS_PRINTER_REMOTE; - cupsFilePrintf(fp, "HOSTNAME=%s\n", ServerName); - cupsFilePrintf(fp, "HOSTPRINTER=%s\n", p->name); +#ifdef HAVE_APPLICATIONSERVICES_H + /* + * Convert the file referenced in APPrinterIconPath to a 128x128 PNG + * and save it as cacheDir/printername.png + */ - cupsFileClose(fp); + 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; + } + } - chmod(filename, 0755); - chown(filename, User, Group); - } + CGImageRelease(imageRef); + } - /* - * 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...) - */ + 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); + } - snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name); + CGImageRelease(imageRef); + } - if (p->type & CUPS_PRINTER_CLASS) - unlink(filename); - else if ((fp = cupsFileOpen(filename, "w")) != NULL) - { - cupsFilePuts(fp, "/dev/null\n"); + CFRelease(sourceRef); + } + } - cupsFileClose(fp); + if (outUrl) + CFRelease(outUrl); - chmod(filename, 0644); - chown(filename, User, Group); + if (icnsFileUrl) + CFRelease(icnsFileUrl); + } +#endif /* HAVE_APPLICATIONSERVICES_H */ + + /* + * Close the PPD and set the type... + */ + + ppdClose(ppd); } + else if (!access(ppd_name, 0)) + { + int pline; /* PPD line number */ + ppd_status_t pstatus; /* PPD load status */ - /* - * 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); + pstatus = ppdLastError(&pline); - 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); + cupsdLogMessage(CUPSD_LOG_ERROR, "PPD file for %s cannot be loaded.", p->name); - cupsFileClose(fp); + if (pstatus <= PPD_ALLOC_ERROR) + cupsdLogMessage(CUPSD_LOG_ERROR, "%s: %s", ppd_name, strerror(errno)); + else + cupsdLogMessage(CUPSD_LOG_ERROR, "%s on line %d of %s.", ppdErrorString(pstatus), pline, ppd_name); - chmod(filename, 0755); - chown(filename, User, Group); + cupsdLogMessage(CUPSD_LOG_INFO, + "Hint: Run \"cupstestppd %s\" and fix any errors.", + ppd_name); } + else + { + /* + * If we have an interface script, add a filter entry for it... + */ - /* - * The POD config file is needed by the printstatus command to show - * the printer location and device. - */ + char interface[1024]; /* Interface script */ - 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 ? 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); - } -} + 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"); + } + else 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. + */ -/* - * 'write_irix_state()' - Update the status files used by IRIX printing - * desktop tools. - */ + p->type |= CUPS_PRINTER_REMOTE; -static void -write_irix_state(cupsd_printer_t *p) /* I - Printer to update */ -{ - char filename[1024]; /* Interface script filename */ - cups_file_t *fp; /* Interface script file */ - int tag; /* Status tag value */ + /* + * Point the printer-uri-supported attribute to the + * remote printer... + */ + if (strchr(p->device_uri, '?')) + { + /* + * Strip trailing "?options" from URI... + */ - if (p) - { - /* - * The POD status file is needed for the printstatus window to - * provide the current status of the printer. - */ + char resource[HTTP_MAX_URI], /* New URI */ + *ptr; /* Pointer into URI */ + + strlcpy(resource, p->device_uri, sizeof(resource)); + if ((ptr = strchr(resource, '?')) != NULL) + *ptr = '\0'; + + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, + "printer-uri-supported", NULL, resource); + } + else + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, + "printer-uri-supported", NULL, p->device_uri); + + /* + * Then set the make-and-model accordingly... + */ - snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name); + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, + "printer-make-and-model", NULL, "Remote Printer"); - if (p->type & CUPS_PRINTER_CLASS) - unlink(filename); - else if ((fp = cupsFileOpen(filename, "w")) != NULL) + /* + * Print all files directly... + */ + + p->raw = 1; + p->remote = 1; + } + else { - 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 ? 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); + /* + * Otherwise we have neither - treat this as a "dumb" printer + * with no PPD file... + */ + + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, + "printer-make-and-model", NULL, "Local Raw Printer"); + + p->raw = 1; } + } + + ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, + "finishings-supported", num_finishings, finishings); + ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, + "finishings-default", IPP_FINISHINGS_NONE); + if (ppd && p->pc) + { /* - * 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) + * Save cached PPD attributes to disk... */ - snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name); + cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Saving %s...", cache_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; + _ppdCacheWriteFile(p->pc, cache_name, p->ppd_attrs); + } + else + { + /* + * Remove cache files... + */ - if (p->type & CUPS_PRINTER_REMOTE) - tag |= 8; + if (cache_info.st_mtime) + unlink(cache_name); + } +} - if (p->state == IPP_PRINTER_PROCESSING) - tag |= 1; - else if (p->state == IPP_PRINTER_STOPPED) - tag |= 2; +/* + * 'new_media_col()' - Create a media-col collection value. + */ + +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 */ +{ + 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); +} - cupsFilePuts(fp, "#!/bin/sh\n"); - cupsFilePrintf(fp, "#Tag %d\n", tag); - cupsFileClose(fp); +/* + * 'write_xml_string()' - Write a string with XML escaping. + */ - chmod(filename, 0755); - chown(filename, User, Group); - } - } +static void +write_xml_string(cups_file_t *fp, /* I - File to write to */ + const char *s) /* I - String to write */ +{ + const char *start; /* Start of current sequence */ - /* - * The default file is needed by the printers window to show - * the default printer. - */ - snprintf(filename, sizeof(filename), "/var/spool/lp/default"); + if (!s) + return; - if (DefaultPrinter != NULL) + for (start = s; *s; s ++) { - if ((fp = cupsFileOpen(filename, "w")) != NULL) + if (*s == '&') { - cupsFilePrintf(fp, "%s\n", DefaultPrinter->name); + if (s > start) + cupsFileWrite(fp, start, (size_t)(s - start)); - cupsFileClose(fp); + cupsFilePuts(fp, "&"); + start = s + 1; + } + else if (*s == '<') + { + if (s > start) + cupsFileWrite(fp, start, (size_t)(s - start)); - chmod(filename, 0644); - chown(filename, User, Group); + cupsFilePuts(fp, "<"); + start = s + 1; } } - else - unlink(filename); + + if (s > start) + cupsFilePuts(fp, start); } -#endif /* __sgi */ /* - * End of "$Id: printers.c 6970 2007-09-17 23:58:28Z mike $". + * End of "$Id$". */