X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=scheduler%2Fprinters.c;h=b0298c0ec382991293a4204f32b58202bd9a5bad;hb=4220952d4d4e3b02701326ea2189a71ab3529a5f;hp=6bc26166390ade9decbc2c7115fd12b1f4f0a794;hpb=68b10830fa5eca364644a90bb564821698611ff7;p=thirdparty%2Fcups.git diff --git a/scheduler/printers.c b/scheduler/printers.c index 6bc261663..b0298c0ec 100644 --- a/scheduler/printers.c +++ b/scheduler/printers.c @@ -1,9 +1,9 @@ /* * "$Id: printers.c 7968 2008-09-19 23:03:01Z mike $" * - * Printer routines for the Common UNIX Printing System (CUPS). + * Printer routines for the CUPS scheduler. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -51,6 +51,7 @@ * delete_string_array() - Delete an array of CUPS strings. * load_ppd() - Load a cached PPD file, updating the cache as * needed. + * new_media_col() - Create a media-col collection value. * write_irix_config() - Update the config files used by the IRIX * desktop tools. * write_irix_state() - Update the status files used by IRIX printing @@ -64,7 +65,6 @@ #include "cupsd.h" #include -#include /* @@ -80,6 +80,8 @@ static int compare_printers(void *first, void *second, void *data); static void delete_printer_filters(cupsd_printer_t *p); static void delete_string_array(cups_array_t **a); static void load_ppd(cupsd_printer_t *p); +static ipp_t *new_media_col(_pwg_size_t *size, const char *source, + const char *type); #ifdef __sgi static void write_irix_config(cupsd_printer_t *p); static void write_irix_state(cupsd_printer_t *p); @@ -205,11 +207,6 @@ cupsdAddPrinterHistory( 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, "none"); @@ -312,6 +309,7 @@ cupsdCreateCommonData(void) IPP_GET_PRINTER_ATTRIBUTES, IPP_HOLD_JOB, IPP_RELEASE_JOB, + IPP_RESTART_JOB, IPP_PAUSE_PRINTER, IPP_RESUME_PRINTER, IPP_PURGE_JOBS, @@ -329,6 +327,9 @@ cupsdCreateCommonData(void) IPP_DISABLE_PRINTER, IPP_HOLD_NEW_JOBS, IPP_RELEASE_HELD_NEW_JOBS, + IPP_CANCEL_JOBS, + IPP_CANCEL_MY_JOBS, + IPP_CLOSE_JOB, CUPS_GET_DEFAULT, CUPS_GET_PRINTERS, CUPS_ADD_PRINTER, @@ -361,9 +362,12 @@ cupsdCreateCommonData(void) }; static const char * const media_col_supported[] = { /* media-col-supported values */ - "media-color", - "media-key", + "media-bottom-margin", + "media-left-margin", + "media-right-margin", "media-size", + "media-source", + "media-top-margin", "media-type" }; static const char * const multiple_document_handling[] = @@ -401,15 +405,38 @@ 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-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-quality", @@ -421,6 +448,18 @@ cupsdCreateCommonData(void) "printer-info", "printer-location" }; + static const char * const which_jobs[] = + { /* which-jobs-supported values */ + "completed", + "not-completed", + "aborted", + "all", + "canceled", + "pending", + "pending-held", + "processing", + "processing-stopped" + }; if (CommonData) @@ -435,7 +474,7 @@ cupsdCreateCommonData(void) /* charset-configured */ ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY, - "charset-configured", NULL, DefaultCharset); + "charset-configured", NULL, "utf-8"); /* charset-supported */ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY, @@ -455,8 +494,8 @@ cupsdCreateCommonData(void) ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_TEXT | IPP_TAG_COPY, "cups-version", NULL, CUPS_SVERSION + 6); - /* generated-natural-language-supported */ - ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE | IPP_TAG_COPY, + /* generated-natural-language-supported (no IPP_TAG_COPY) */ + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE, "generated-natural-language-supported", NULL, DefaultLanguage); /* ipp-versions-supported */ @@ -464,11 +503,24 @@ cupsdCreateCommonData(void) "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-creation-attributes-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, + "job-creation-attributes-supported", + sizeof(job_creation) / sizeof(job_creation[0]), + NULL, job_creation); + /* job-hold-until-supported */ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-hold-until-supported", sizeof(holds) / sizeof(holds[0]), NULL, holds); + /* job-ids-supported */ + ippAddBoolean(CommonData, IPP_TAG_PRINTER, "job-ids-supported", 1); + /* job-priority-supported */ ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-priority-supported", 100); @@ -539,8 +591,8 @@ cupsdCreateCommonData(void) ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "multiple-operation-time-out", MultipleOperationTimeout); - /* natural-language-configured */ - ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE | IPP_TAG_COPY, + /* natural-language-configured (no IPP_TAG_COPY) */ + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE, "natural-language-configured", NULL, DefaultLanguage); /* notify-attributes-supported */ @@ -633,6 +685,11 @@ cupsdCreateCommonData(void) /* server-is-sharing-printers */ ippAddBoolean(CommonData, IPP_TAG_PRINTER, "server-is-sharing-printers", BrowseLocalProtocols != 0 && Browsing); + + /* which-jobs-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, + "which-jobs-supported", + sizeof(which_jobs) / sizeof(which_jobs[0]), NULL, which_jobs); } @@ -649,7 +706,10 @@ cupsdDeleteAllPrinters(void) for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) + { + p->op_policy_ptr = DefaultPolicyPtr; cupsdDeletePrinter(p, 0); + } } @@ -657,12 +717,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 */ + int i, /* Looping var */ + changed = 0; /* Class changed? */ #ifdef __sgi char filename[1024]; /* Interface script filename */ #endif /* __sgi */ @@ -773,7 +834,7 @@ cupsdDeletePrinter( if (!(p->type & CUPS_PRINTER_IMPLICIT)) { - cupsdDeletePrinterFromClasses(p); + changed = cupsdDeletePrinterFromClasses(p); /* * Deregister from any browse protocols... @@ -841,10 +902,6 @@ cupsdDeletePrinter( if (p->browse_attrs) free(p->browse_attrs); -#ifdef __APPLE__ - cupsdClearString(&p->recoverable); -#endif /* __APPLE__ */ - cupsFreeOptions(p->num_options, p->options); free(p); @@ -854,6 +911,8 @@ cupsdDeletePrinter( */ cupsArrayRestore(Printers); + + return (changed); } @@ -1094,7 +1153,6 @@ cupsdLoadAllPrinters(void) else if (!strcasecmp(line, "Reason")) { if (value && - strcmp(value, "com.apple.print.recoverable-warning") && strcmp(value, "connecting-to-device") && strcmp(value, "cups-insecure-filter-warning") && strcmp(value, "cups-missing-filter-warning")) @@ -1518,6 +1576,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... @@ -1598,8 +1657,7 @@ cupsdSaveAllPrinters(void) cupsFilePrintf(fp, "StateTime %d\n", (int)printer->state_time); for (i = 0; i < printer->num_reasons; i ++) - if (strcmp(printer->reasons[i], "com.apple.print.recoverable-warning") && - strcmp(printer->reasons[i], "connecting-to-device") && + 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]); @@ -2625,8 +2683,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ int /* O - 1 if something changed, 0 otherwise */ cupsdSetPrinterReasons( - cupsd_printer_t *p, /* I - Printer */ - const char *s) /* I - Reasons strings */ + cupsd_printer_t *p, /* I - Printer */ + const char *s) /* I - Reasons strings */ { int i, /* Looping var */ changed = 0; /* Did something change? */ @@ -2778,6 +2836,12 @@ cupsdSetPrinterState( int update) /* I - Update printers.conf? */ { ipp_pstate_t old_state; /* Old printer state */ + static const char * const printer_states[] = + { /* State strings */ + "idle", + "processing", + "stopped" + }; /* @@ -2801,9 +2865,9 @@ cupsdSetPrinterState( { cupsdAddEvent(s == IPP_PRINTER_STOPPED ? CUPSD_EVENT_PRINTER_STOPPED : CUPSD_EVENT_PRINTER_STATE, p, NULL, - "%s \"%s\" state changed.", + "%s \"%s\" state changed to %s.", (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer", - p->name); + p->name, printer_states[p->state]); /* * Let the browse code know this needs to be updated... @@ -3429,11 +3493,10 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */ cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-hold-until-default")); cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-priority-default")); cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-sheets-default")); - cupsArrayAdd(CommonDefaults, _cupsStrAlloc("media-default")); + cupsArrayAdd(CommonDefaults, _cupsStrAlloc("media-col-default")); cupsArrayAdd(CommonDefaults, _cupsStrAlloc("number-up-default")); cupsArrayAdd(CommonDefaults, _cupsStrAlloc("orientation-requested-default")); - cupsArrayAdd(CommonDefaults, _cupsStrAlloc("sides-default")); } /* @@ -3487,10 +3550,6 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "number-up-default", 1); - if (!cupsGetOption("orientation-requested", p->num_options, p->options)) - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, - "orientation-requested-default", NULL, NULL); - if (!cupsGetOption("notify-lease-duration", p->num_options, p->options)) ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "notify-lease-duration-default", DefaultLeaseDuration); @@ -3498,6 +3557,14 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */ if (!cupsGetOption("notify-events", p->num_options, p->options)) ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "notify-events-default", NULL, "job-completed"); + + if (!cupsGetOption("orientation-requested", p->num_options, p->options)) + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, + "orientation-requested-default", NULL, NULL); + + if (!cupsGetOption("print-quality", p->num_options, p->options)) + ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, + "print-quality-default", IPP_QUALITY_NORMAL); } @@ -3566,11 +3633,12 @@ add_printer_filter( if (!RunUser) { /* - * Only use filters that are owned by root and do not have world write - * permissions. + * Only use filters that are owned by root and do not have group or world + * write permissions. */ - if (fileinfo.st_uid || (fileinfo.st_mode & (S_ISUID | S_IWOTH)) != 0) + if (fileinfo.st_uid || + (fileinfo.st_mode & (S_ISUID | S_IWGRP | S_IWOTH)) != 0) { if (fileinfo.st_uid) snprintf(p->state_message, sizeof(p->state_message), @@ -3597,7 +3665,7 @@ add_printer_filter( if (!stat(filename, &fileinfo) && (fileinfo.st_uid || - (fileinfo.st_mode & (S_ISUID | S_IWOTH)) != 0)) + (fileinfo.st_mode & (S_ISUID | S_IWGRP | S_IWOTH)) != 0)) { if (fileinfo.st_uid) snprintf(p->state_message, sizeof(p->state_message), @@ -3699,10 +3767,6 @@ add_printer_formats(cupsd_printer_t *p) /* I - Printer */ p->name, mimetype); } - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "add_printer_formats: %s: %d supported types", - p->name, cupsArrayCount(p->filetypes) + 1); - /* * Add the file formats that can be filtered... */ @@ -3713,9 +3777,13 @@ add_printer_formats(cupsd_printer_t *p) /* I - Printer */ else i = 0; + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "add_printer_formats: %s: %d supported types", + p->name, cupsArrayCount(p->filetypes) + i); + attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, "document-format-supported", - cupsArrayCount(p->filetypes) + 1, NULL, NULL); + cupsArrayCount(p->filetypes) + i, NULL, NULL); if (i) attr->values[0].string.text = _cupsStrAlloc("application/octet-stream"); @@ -3735,40 +3803,48 @@ add_printer_formats(cupsd_printer_t *p) /* I - Printer */ mime_filter_t *filter; /* MIME filter looping var */ - pdl[0] = '\0'; - - if (mimeType(MimeDatabase, "application", "pdf")) - strlcat(pdl, "application/pdf,", sizeof(pdl)); - - if (mimeType(MimeDatabase, "application", "postscript")) - strlcat(pdl, "application/postscript,", sizeof(pdl)); - - if (mimeType(MimeDatabase, "application", "vnd.cups-raster")) - strlcat(pdl, "application/vnd.cups-raster,", sizeof(pdl)); - /* - * Determine if this is a Tioga PrintJobMgr based queue... + * We only support raw printing if this is not a Tioga PrintJobMgr based + * queue and if application/octet-stream is a known type... */ for (filter = (mime_filter_t *)cupsArrayFirst(MimeDatabase->filters); filter; filter = (mime_filter_t *)cupsArrayNext(MimeDatabase->filters)) { - if (filter->dst == p->filetype && filter->filter && + if (filter->dst == p->filetype && filter->filter && strstr(filter->filter, "PrintJobMgr")) break; } - /* - * We only support raw printing if this is not a Tioga PrintJobMgr based - * queue and if application/octet-stream is a known conversion... - */ + pdl[0] = '\0'; if (!filter && mimeType(MimeDatabase, "application", "octet-stream")) strlcat(pdl, "application/octet-stream,", sizeof(pdl)); - if (mimeType(MimeDatabase, "image", "png")) - strlcat(pdl, "image/png,", sizeof(pdl)); + /* + * Then list a bunch of formats that are supported by the printer... + */ + + for (type = (mime_type_t *)cupsArrayFirst(p->filetypes); + type; + type = (mime_type_t *)cupsArrayNext(p->filetypes)) + { + if (!strcasecmp(type->super, "application")) + { + if (!strcasecmp(type->type, "pdf")) + strlcat(pdl, "application/pdf,", sizeof(pdl)); + else if (!strcasecmp(type->type, "postscript")) + strlcat(pdl, "application/postscript,", sizeof(pdl)); + } + else if (!strcasecmp(type->super, "image")) + { + if (!strcasecmp(type->type, "jpeg")) + strlcat(pdl, "image/jpeg,", sizeof(pdl)); + else if (!strcasecmp(type->type, "png")) + strlcat(pdl, "image/png,", sizeof(pdl)); + } + } if (pdl[0]) pdl[strlen(pdl) - 1] = '\0'; /* Remove trailing comma */ @@ -3834,7 +3910,7 @@ delete_printer_filters( for (filter = mimeFirstFilter(MimeDatabase); filter; filter = mimeNextFilter(MimeDatabase)) - if (filter->dst == p->filetype) + if (filter->dst == p->filetype || filter->dst == p->prefiltertype) { /* * Delete the current filter... @@ -3875,27 +3951,39 @@ delete_string_array(cups_array_t **a) /* I - Array */ static void load_ppd(cupsd_printer_t *p) /* I - Printer */ { - int i; /* Looping var */ - cups_file_t *cache; /* Cache file */ - char cache_name[1024]; /* Cache filename */ - struct stat cache_info; /* Cache file info */ + int i, j, k; /* Looping vars */ + cups_file_t *cache; /* IPP cache file */ + char cache_name[1024]; /* IPP cache filename */ + struct stat cache_info; /* IPP cache file info */ + char pwg_name[1024]; /* PWG cache filename */ + struct stat pwg_info; /* PWG 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 */ - char custom_in[256], /* Custom size name in inches */ - custom_mm[256]; /* Custom size name in millimeters */ - ppd_size_t *size; /* Current size */ - ppd_option_t *output_bin, /* OutputBin options */ - *duplex; /* Duplex options */ + ppd_size_t *size; /* Current PPD size */ + ppd_option_t *duplex, /* Duplex option */ + *output_bin, /* OutputBin option */ + *output_mode, /* OutputMode option */ + *resolution; /* (Set|JCL|)Resolution option */ + ppd_choice_t *choice, /* Current PPD choice */ + *input_slot, /* Current input slot */ + *media_type; /* Current media type */ ppd_attr_t *ppd_attr; /* PPD attribute */ - _cups_pwg_media_t *pwgmedia; /* Matching PWG size name */ + int xdpi, /* Horizontal resolution */ + ydpi; /* Vertical resolution */ + const char *resptr; /* Pointer into resolution keyword */ + _pwg_size_t *pwgsize; /* Current PWG size */ + _pwg_map_t *pwgsource, /* Current PWG source */ + *pwgtype; /* Current PWG type */ ipp_attribute_t *attr; /* Attribute data */ - ipp_t *media_col_default, /* media-col-default collection value */ - *media_size; /* media-size collection value */ ipp_value_t *val; /* Attribute value */ - int num_finishings; /* Number of finishings */ - int finishings[5]; /* finishings-supported values */ + 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 */ static const char * const sides[3] = /* sides-supported values */ { "one-sided", @@ -3914,10 +4002,14 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ * Check to see if the cache is up-to-date... */ - snprintf(cache_name, sizeof(cache_name), "%s/%s.ipp", CacheDir, p->name); + snprintf(cache_name, sizeof(cache_name), "%s/%s.ipp3", CacheDir, p->name); if (stat(cache_name, &cache_info)) cache_info.st_mtime = 0; + snprintf(pwg_name, sizeof(pwg_name), "%s/%s.pwg2", CacheDir, p->name); + if (stat(pwg_name, &pwg_info)) + pwg_info.st_mtime = 0; + snprintf(ppd_name, sizeof(ppd_name), "%s/ppd/%s.ppd", ServerRoot, p->name); if (stat(ppd_name, &ppd_info)) ppd_info.st_mtime = 1; @@ -3925,7 +4017,13 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ ippDelete(p->ppd_attrs); p->ppd_attrs = ippNew(); - if (cache_info.st_mtime >= ppd_info.st_mtime && + _pwgDestroy(p->pwg); + p->pwg = NULL; + + if (pwg_info.st_mtime >= ppd_info.st_mtime) + p->pwg = _pwgCreateWithFile(pwg_name); + + if (cache_info.st_mtime >= ppd_info.st_mtime && p->pwg && (cache = cupsFileOpen(cache_name, "r")) != NULL) { /* @@ -3950,6 +4048,9 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); + _pwgDestroy(p->pwg); + p->pwg = NULL; + cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", ppd_name); delete_string_array(&(p->filters)); @@ -3967,6 +4068,8 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ * Add make/model and other various attributes... */ + p->pwg = _pwgCreateWithPPD(ppd); + ppdMarkDefaults(ppd); if (ppd->color_device) @@ -3982,8 +4085,51 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "color-supported", ppd->color_device); 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); + } + + num_qualities = 0; + + if ((output_mode = ppdFindOption(ppd, "OutputMode")) != NULL) + { + if (ppdFindChoice(output_mode, "draft") || + ppdFindChoice(output_mode, "fast")) + qualities[num_qualities ++] = IPP_QUALITY_DRAFT; + if (ppdFindChoice(output_mode, "normal") || + ppdFindChoice(output_mode, "good")) + qualities[num_qualities ++] = IPP_QUALITY_NORMAL; + if (ppdFindChoice(output_mode, "best") || + ppdFindChoice(output_mode, "high")) + qualities[num_qualities ++] = IPP_QUALITY_HIGH; + } + else if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL) + { + do + { + if (strstr(ppd_attr->spec, "draft") || + strstr(ppd_attr->spec, "Draft")) + { + qualities[num_qualities ++] = IPP_QUALITY_DRAFT; + break; + } + } + while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset", + NULL)) != NULL); + + qualities[num_qualities ++] = IPP_QUALITY_NORMAL; + qualities[num_qualities ++] = IPP_QUALITY_HIGH; + } + + if (num_qualities == 0) + qualities[num_qualities ++] = IPP_QUALITY_NORMAL; + + ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, + "print-quality-supported", num_qualities, qualities); if (ppd->nickname) { @@ -4014,112 +4160,296 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ * Add media options from the PPD file... */ - if (ppd->num_sizes == 0) + if (ppd->num_sizes == 0 || !p->pwg) { 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 { - num_media = ppd->num_sizes; - if (ppd->variable_sizes) - num_media ++; + /* + * media-default + */ - attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "media-supported", num_media, NULL, NULL); - if (attr != NULL) + if ((size = ppdPageSize(ppd, NULL)) != NULL) + pwgsize = _pwgGetSize(p->pwg, size->name); + else + pwgsize = NULL; + + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "media-default", NULL, + pwgsize ? pwgsize->map.pwg : "unknown"); + + /* + * media-col-default + */ + + if (pwgsize) + { + ipp_t *col; /* Collection value */ + + input_slot = ppdFindMarkedChoice(ppd, "InputSlot"); + media_type = ppdFindMarkedChoice(ppd, "MediaType"); + col = new_media_col(pwgsize, + input_slot ? + _pwgGetSource(p->pwg, + input_slot->choice) : + NULL, + media_type ? + _pwgGetType(p->pwg, + media_type->choice) : + NULL); + + ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-default", + col); + ippDelete(col); + } + + /* + * media-supported + */ + + num_media = p->pwg->num_sizes; + if (p->pwg->custom_min_keyword) + num_media += 2; + + if ((attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "media-supported", num_media, NULL, + NULL)) != NULL) { val = attr->values; - for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++) + for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes; + i > 0; + i --, pwgsize ++, val ++) + val->string.text = _cupsStrRetain(pwgsize->map.pwg); + + if (p->pwg->custom_min_keyword) + { + val->string.text = _cupsStrRetain(p->pwg->custom_min_keyword); + val ++; + val->string.text = _cupsStrRetain(p->pwg->custom_max_keyword); + } + } + + /* + * media-source-supported + */ + + if (p->pwg->num_sources > 0 && + (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "media-source-supported", p->pwg->num_sources, + NULL, NULL)) != NULL) + { + for (i = p->pwg->num_sources, pwgsource = p->pwg->sources, + val = attr->values; + i > 0; + i --, pwgsource ++, val ++) + val->string.text = _cupsStrRetain(pwgsource->pwg); + } + + /* + * media-type-supported + */ + + if (p->pwg->num_types > 0 && + (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "media-type-supported", p->pwg->num_types, + NULL, NULL)) != NULL) + { + for (i = p->pwg->num_types, pwgtype = p->pwg->types, + val = attr->values; + i > 0; + i --, pwgtype ++, val ++) + val->string.text = _cupsStrRetain(pwgtype->pwg); + } + + /* + * media-*-margin-supported + */ + + for (i = p->pwg->num_sizes, pwgsize = p->pwg->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->pwg->num_sizes, pwgsize = p->pwg->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->pwg->num_sizes, pwgsize = p->pwg->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->pwg->num_sizes, pwgsize = p->pwg->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->pwg->num_sizes; + if (p->pwg->num_sources) + { + if (p->pwg->num_types > 0) + num_media += p->pwg->num_sizes * p->pwg->num_sources * + p->pwg->num_types; + else + num_media += p->pwg->num_sizes * p->pwg->num_sources; + } + else if (p->pwg->num_types) + num_media += p->pwg->num_sizes * p->pwg->num_types; + + if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER, + "media-col-database", num_media, + NULL)) != NULL) + { + for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes, val = attr->values; + i > 0; + i --, pwgsize ++) { - if (strcasecmp(size->name, "Custom")) + /* + * Start by adding the page size without source or type... + */ + + ppdMarkOption(ppd, "PageSize", pwgsize->map.ppd); + + val->collection = new_media_col(pwgsize, NULL, NULL); + val ++; + + /* + * Then add the specific, supported combinations of size, source, and + * type... + */ + + if (p->pwg->num_sources > 0) { - if ((pwgmedia = _cupsPWGMediaBySize(size->width, - size->length)) != NULL) + for (j = p->pwg->num_sources, pwgsource = p->pwg->sources; + j > 0; + j --, pwgsource ++) { - val->string.text = _cupsStrAlloc(pwgmedia->pwg); - } - else - { - snprintf(custom_in, sizeof(custom_in), "adobe_%s_%gx%gin", - size->name, size->width / 72.0, size->length / 72.0); - snprintf(custom_mm, sizeof(custom_mm), "adobe_%s_%gx%gmm", - size->name, size->width * 25.4 / 72.0, - size->length * 25.4 / 72.0); - if (strlen(custom_in) < strlen(custom_mm)) - val->string.text = _cupsStrAlloc(custom_in); - else - val->string.text = _cupsStrAlloc(custom_mm); - } + ppdMarkOption(ppd, "InputSlot", pwgsource->ppd); - if (size->marked) + if (p->pwg->num_types > 0) + { + for (k = p->pwg->num_types, pwgtype = p->pwg->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->pwg->num_types > 0) + { + for (j = p->pwg->num_types, pwgtype = p->pwg->types; + j > 0; + j --, pwgtype ++) { - /* - * Add media-default... - */ - - ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "media-default", NULL, val->string.text); - - /* - * Add media-col-default... - */ - - media_size = ippNew(); - ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "x-dimension", (int)(size->width * 2540.0 / 72.0)); - ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "y-dimension", (int)(size->length * 2540.0 / 72.0)); - - media_col_default = ippNew(); - ippAddString(media_col_default, IPP_TAG_PRINTER, - IPP_TAG_KEYWORD | IPP_TAG_COPY, "media-color", NULL, - "white"); - ippAddString(media_col_default, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "media-key", NULL,val->string.text); - ippAddCollection(media_col_default, IPP_TAG_PRINTER, "media-size", - media_size); - ippAddString(media_col_default, IPP_TAG_PRINTER, - IPP_TAG_KEYWORD | IPP_TAG_COPY, "media-type", NULL, - "stationary"); - - ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, - "media-col-default", media_col_default); + if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd)) + { + val->collection = new_media_col(pwgsize, NULL, pwgtype->pwg); + val ++; + } } - - val ++; } } - if (ppd->variable_sizes) - { - snprintf(custom_in, sizeof(custom_in), "custom_min_%gx%gin", - ppd->custom_min[0] / 72.0, ppd->custom_min[1] / 72.0); - snprintf(custom_mm, sizeof(custom_mm), "custom_min_%gx%gmm", - ppd->custom_min[0] * 25.4 / 72.0, - ppd->custom_min[1] * 25.4 / 72.0); - if (strlen(custom_in) < strlen(custom_mm)) - val->string.text = _cupsStrAlloc(custom_in); - else - val->string.text = _cupsStrAlloc(custom_mm); - val ++; + /* + * Update the number of media-col-database values... + */ - snprintf(custom_in, sizeof(custom_in), "custom_max_%gx%gin", - ppd->custom_max[0] / 72.0, ppd->custom_max[1] / 72.0); - snprintf(custom_mm, sizeof(custom_mm), "custom_max_%gx%gmm", - ppd->custom_max[0] * 25.4 / 72.0, - ppd->custom_max[1] * 25.4 / 72.0); - if (strlen(custom_in) < strlen(custom_mm)) - val->string.text = _cupsStrAlloc(custom_in); - else - val->string.text = _cupsStrAlloc(custom_mm); - } + attr->num_values = val - attr->values; } } @@ -4127,22 +4457,149 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ * Output bin... */ - if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL) + if (p->pwg && p->pwg->num_bins > 0) { attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "output-bin-supported", output_bin->num_choices, + "output-bin-supported", p->pwg->num_bins, NULL, NULL); if (attr != NULL) { for (i = 0, val = attr->values; - i < output_bin->num_choices; + i < p->pwg->num_bins; i ++, val ++) - val->string.text = _cupsStrAlloc(output_bin->choices[i].choice); + val->string.text = _cupsStrAlloc(p->pwg->bins[i].pwg); } + if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL) + { + for (i = 0; i < p->pwg->num_bins; i ++) + if (!strcmp(p->pwg->bins[i].ppd, output_bin->defchoice)) + break; + + if (i >= p->pwg->num_bins) + i = 0; + + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "output-bin-default", NULL, p->pwg->bins[i].pwg); + } + else + ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "output-bin-default", NULL, p->pwg->bins[0].pwg); + } + else if (((ppd_attr = ppdFindAttr(ppd, "DefaultOutputOrder", + NULL)) != NULL && + !strcasecmp(ppd_attr->value, "Reverse")) || + (!ppd_attr && ppd->manufacturer && /* EPSON "compatibility heuristic" */ + !strcasecmp(ppd->manufacturer, "epson"))) + { + /* + * 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-default", NULL, output_bin->defchoice); + "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"); + } + + /* + * Printer resolutions... + */ + + if ((resolution = ppdFindOption(ppd, "Resolution")) == NULL) + if ((resolution = ppdFindOption(ppd, "JCLResolution")) == NULL) + if ((resolution = ppdFindOption(ppd, "SetResolution")) == NULL) + resolution = ppdFindOption(ppd, "CNRes_PGP"); + + if (resolution) + { + /* + * Report all supported resolutions... + */ + + attr = ippAddResolutions(p->ppd_attrs, IPP_TAG_PRINTER, + "printer-resolution-supported", + resolution->num_choices, IPP_RES_PER_INCH, + NULL, NULL); + + for (i = 0, choice = resolution->choices; + i < resolution->num_choices; + i ++, choice ++) + { + xdpi = ydpi = (int)strtol(choice->choice, (char **)&resptr, 10); + if (resptr > choice->choice && xdpi > 0 && *resptr == 'x') + ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10); + + if (xdpi <= 0 || ydpi <= 0) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "Bad resolution \"%s\" for printer %s.", + choice->choice, p->name); + xdpi = ydpi = 72; + } + + 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 (xdpi <= 0 || ydpi <= 0) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "Bad default resolution \"%s\" for printer %s.", + ppd_attr->value, p->name); + xdpi = ydpi = 72; + } + + 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 + { + /* + * No resolutions in PPD - make one up... + */ + + ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, + "printer-resolution-default", IPP_RES_PER_INCH, + 72, 72); + ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, + "printer-resolution-supported", IPP_RES_PER_INCH, + 72, 72); } /* @@ -4173,6 +4630,13 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ 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; @@ -4522,7 +4986,7 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "finishings-default", IPP_FINISHINGS_NONE); - if (ppd && (cache = cupsFileOpen(cache_name, "w")) != NULL) + if (ppd && (cache = cupsFileOpen(cache_name, "w9")) != NULL) { /* * Save cached PPD attributes to disk... @@ -4542,18 +5006,68 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ } cupsFileClose(cache); + + _pwgWriteFile(p->pwg, pwg_name); } - else if (cache_info.st_mtime) + else { /* - * Remove cache file... + * Remove cache files... */ - unlink(cache_name); + if (cache_info.st_mtime) + unlink(cache_name); + + if (pwg_info.st_mtime) + unlink(pwg_name); } } +/* + * '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); +} + + #ifdef __sgi /* * 'write_irix_config()' - Update the config files used by the IRIX