/*
* Printer routines for the CUPS scheduler.
*
- * Copyright 2007-2016 by Apple Inc.
- * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ * Copyright © 2007-2018 by Apple Inc.
+ * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
*
- * 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/".
+ * Licensed under Apache License v2.0. See the file "LICENSE" for more
+ * information.
*/
/*
struct statfs spoolinfo; /* FS info for spool directory */
double spoolsize; /* FS size */
#endif /* HAVE_STATVFS */
- static const int nups[] = /* number-up-supported values */
+ static const char * const page_delivery[] =
+ { /* page-delivery-supported values */
+ "reverse-order",
+ "same-order"
+ };
+ static const char * const print_scaling[] =
+ { /* print-scaling-supported values */
+ "auto",
+ "auto-fit",
+ "fill",
+ "fit",
+ "none"
+ };
+ static const int number_up[] = /* number-up-supported values */
{ 1, 2, 4, 6, 9, 16 };
+ static const char * const number_up_layout[] =
+ { /* number-up-layout-supported values */
+ "btlr",
+ "btrl",
+ "lrbt",
+ "lrtb",
+ "rlbt",
+ "rltb",
+ "tblr",
+ "tbrl"
+ };
static const int orients[4] =/* orientation-requested-supported values */
{
IPP_PORTRAIT,
{ /* job-creation-attributes-supported */
"copies",
"finishings",
+ "finishings-col",
"ipp-attribute-fidelity",
"job-hold-until",
"job-name",
"media-col",
"multiple-document-handling",
"number-up",
- "output-bin",
+ "number-up-layout",
"orientation-requested",
+ "output-bin",
+ "page-delivery",
"page-ranges",
"print-color-mode",
"print-quality",
+ "print-scaling",
"printer-resolution",
"sides"
};
/* number-up-supported */
ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
- "number-up-supported", sizeof(nups) / sizeof(nups[0]), nups);
+ "number-up-supported", sizeof(number_up) / sizeof(number_up[0]), number_up);
+
+ /* number-up-layout-supported */
+ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "number-up-layout-supported", sizeof(number_up_layout) / sizeof(number_up_layout[0]), NULL, number_up_layout);
/* operations-supported */
ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
"orientation-requested-supported", 4, orients);
+ /* page-delivery-supported */
+ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "page-delivery-supported", sizeof(page_delivery) / sizeof(page_delivery[0]), NULL, page_delivery);
+
/* page-ranges-supported */
ippAddBoolean(CommonData, IPP_TAG_PRINTER, "page-ranges-supported", 1);
ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
"pdl-override-supported", NULL, "attempted");
+ /* print-scaling-supported */
+ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-scaling-supported", sizeof(print_scaling) / sizeof(print_scaling[0]), NULL, print_scaling);
+
/* printer-get-attributes-supported */
ippAddString(CommonData, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "printer-get-attributes-supported", NULL, "document-format");
* Remove any old PPD or script files...
*/
- snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot, p->name);
- unlink(filename);
- snprintf(filename, sizeof(filename), "%s/interfaces/%s.O", ServerRoot, p->name);
- unlink(filename);
-
snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, p->name);
unlink(filename);
snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd.O", ServerRoot, p->name);
cupsdClearString(&p->port_monitor);
cupsdClearString(&p->op_policy);
cupsdClearString(&p->error_policy);
+ cupsdClearString(&p->strings);
cupsdClearString(&p->alert);
cupsdClearString(&p->alert_description);
}
+/*
+ * 'cupsdDeleteTemporaryPrinters()' - Delete unneeded temporary printers.
+ */
+
+void
+cupsdDeleteTemporaryPrinters(int force) /* I - Force deletion instead of auto? */
+{
+ cupsd_printer_t *p; /* Current printer */
+ time_t unused_time; /* Last time for printer state change */
+
+
+ /*
+ * Allow temporary printers to stick around for 60 seconds after the last job
+ * completes.
+ */
+
+ unused_time = time(NULL) - 60;
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ {
+ if (p->temporary && (force || p->state_time < unused_time))
+ cupsdDeletePrinter(p, 0);
+ }
+}
+
+
/*
* 'cupsdFindDest()' - Find a destination in the list.
*/
* Decode the directive...
*/
- if (!_cups_strcasecmp(line, "<Printer") ||
- !_cups_strcasecmp(line, "<DefaultPrinter"))
+ if (!_cups_strcasecmp(line, "NextPrinterId"))
+ {
+ if (value && (i = atoi(value)) > 0)
+ NextPrinterId = i;
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "<Printer") || !_cups_strcasecmp(line, "<DefaultPrinter"))
{
/*
* <Printer name> or <DefaultPrinter name>
* Close out the current printer...
*/
+ if (!p->printer_id)
+ {
+ p->printer_id = NextPrinterId ++;
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+ }
+
cupsdSetPrinterAttrs(p);
- if (strncmp(p->device_uri, "file:", 5) &&
- p->state != IPP_PRINTER_STOPPED)
+ if (strncmp(p->device_uri, "file:", 5) && p->state != IPP_PRINTER_STOPPED)
{
/*
* See if the backend exists...
*/
- snprintf(line, sizeof(line), "%s/backend/%s", ServerBin,
- p->device_uri);
+ snprintf(line, sizeof(line), "%s/backend/%s", ServerBin, p->device_uri);
if ((valueptr = strchr(line + strlen(ServerBin), ':')) != NULL)
*valueptr = '\0'; /* Chop everything but URI scheme */
*/
p->state = IPP_PRINTER_STOPPED;
- snprintf(p->state_message, sizeof(p->state_message),
- "Backend %s does not exist!", line);
+ snprintf(p->state_message, sizeof(p->state_message), "Backend %s does not exist!", line);
}
}
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
+ else if (!_cups_strcasecmp(line, "PrinterId"))
+ {
+ if (value && (i = atoi(value)) > 0)
+ p->printer_id = i;
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad PrinterId on line %d of printers.conf.", linenum);
+ }
else if (!_cups_strcasecmp(line, "UUID"))
{
if (value && !strncmp(value, "urn:uuid:", 9))
cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
cupsFilePuts(fp, "# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING\n");
+ cupsFilePrintf(fp, "NextPrinterId %d\n", NextPrinterId);
+
/*
* Write each local printer known to the system...
*/
else
cupsFilePrintf(fp, "<Printer %s>\n", printer->name);
+ if (printer->printer_id)
+ cupsFilePrintf(fp, "PrinterId %d\n", printer->printer_id);
+
cupsFilePrintf(fp, "UUID %s\n", printer->uuid);
if (printer->num_auth_info_required > 0)
"uri-authentication-supported", NULL, auth_supported);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"uri-security-supported", NULL, "none");
+ if (p->printer_id)
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-id", p->printer_id);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL,
p->name);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
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-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("notify-lease-duration-default"));
+ cupsArrayAdd(CommonDefaults, _cupsStrAlloc("notify-events-default"));
cupsArrayAdd(CommonDefaults, _cupsStrAlloc("number-up-default"));
- cupsArrayAdd(CommonDefaults,
- _cupsStrAlloc("orientation-requested-default"));
+ cupsArrayAdd(CommonDefaults, _cupsStrAlloc("orientation-requested-default"));
+ cupsArrayAdd(CommonDefaults, _cupsStrAlloc("print-quality-default"));
}
/*
ppd_file_t *ppd; /* PPD file */
char ppd_name[1024]; /* PPD filename */
struct stat ppd_info; /* PPD file info */
+ char strings_name[1024]; /* Strings filename */
int num_media; /* Number of media options */
ppd_size_t *size; /* Current PPD size */
ppd_option_t *duplex, /* Duplex option */
ipp_attribute_t *attr; /* Attribute data */
_ipp_value_t *val; /* Attribute value */
int num_finishings, /* Number of finishings */
- finishings[5]; /* finishings-supported values */
+ finishings[100]; /* finishings-supported values */
int num_qualities, /* Number of print-quality values */
qualities[3]; /* print-quality values */
int num_margins, /* Number of media-*-margin-supported values */
margins[16]; /* media-*-margin-supported values */
const char *filter, /* Current filter */
*mandatory; /* Current mandatory attribute */
+ static const char * const pwg_raster_document_types[] =
+ {
+ "black_1",
+ "sgray_8",
+ "srgb_8"
+ };
static const char * const sides[3] = /* sides-supported values */
{
"one-sided",
if (stat(ppd_name, &ppd_info))
ppd_info.st_mtime = 1;
+ snprintf(strings_name, sizeof(strings_name), "%s/%s.strings", CacheDir, p->name);
+
ippDelete(p->ppd_attrs);
p->ppd_attrs = NULL;
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
"printer-make-and-model", NULL, p->make_model);
+ if (p->pc && p->pc->strings)
+ _cupsMessageSave(strings_name, _CUPS_MESSAGE_STRINGS, p->pc->strings);
+
+ if (!access(strings_name, R_OK))
+ cupsdSetString(&p->strings, strings_name);
+ else
+ cupsdClearString(&p->strings);
+
/*
* Add media options from the PPD file...
*/
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);
+ 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);
}
"print-color-mode-supported", 2, NULL, color_modes);
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"print-color-mode-default", NULL, "color");
+ ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "pwg-raster-document-type-supported", 3, NULL, pwg_raster_document_types);
}
else
{
"print-color-mode-supported", NULL, "monochrome");
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"print-color-mode-default", NULL, "monochrome");
+ ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "pwg-raster-document-type-supported", 2, NULL, pwg_raster_document_types);
}
/*
* Report all supported resolutions...
*/
- attr = ippAddResolutions(p->ppd_attrs, IPP_TAG_PRINTER,
- "printer-resolution-supported",
- resolution->num_choices, IPP_RES_PER_INCH,
- NULL, NULL);
+ 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;
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);
+ ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, "printer-resolution-default", IPP_RES_PER_INCH, xdpi, ydpi);
+
+ if (i == 0)
+ ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", IPP_RES_PER_INCH, xdpi, ydpi);
}
}
else if ((ppd_attr = ppdFindAttr(ppd, "DefaultResolution", NULL)) != NULL &&
ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
"printer-resolution-supported", IPP_RES_PER_INCH,
xdpi, ydpi);
+ ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", IPP_RES_PER_INCH, xdpi, ydpi);
}
else
{
ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
"printer-resolution-supported", IPP_RES_PER_INCH,
300, 300);
+ ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", IPP_RES_PER_INCH, 300, 300);
}
/*
{
p->type |= CUPS_PRINTER_DUPLEX;
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "pwg-raster-document-sheet-back", NULL, "normal");
+
ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"sides-supported", 3, NULL, sides);
if (ppdFindOption(ppd, "Collate") != NULL)
p->type |= CUPS_PRINTER_COLLATE;
- if (ppdFindOption(ppd, "StapleLocation") != NULL)
+ if (p->pc && p->pc->finishings)
{
- p->type |= CUPS_PRINTER_STAPLE;
- finishings[num_finishings++] = IPP_FINISHINGS_STAPLE;
+ _pwg_finishings_t *fin; /* Current finishing value */
+
+ for (fin = (_pwg_finishings_t *)cupsArrayFirst(p->pc->finishings); fin; fin = (_pwg_finishings_t *)cupsArrayNext(p->pc->finishings))
+ {
+ if (num_finishings < (int)(sizeof(finishings) / sizeof(finishings[0])))
+ finishings[num_finishings++] = fin->value;
+
+ switch (fin->value)
+ {
+ case IPP_FINISHINGS_BIND :
+ case IPP_FINISHINGS_BIND_LEFT :
+ case IPP_FINISHINGS_BIND_TOP :
+ case IPP_FINISHINGS_BIND_RIGHT :
+ case IPP_FINISHINGS_BIND_BOTTOM :
+ case IPP_FINISHINGS_EDGE_STITCH :
+ case IPP_FINISHINGS_EDGE_STITCH_LEFT :
+ case IPP_FINISHINGS_EDGE_STITCH_TOP :
+ case IPP_FINISHINGS_EDGE_STITCH_RIGHT :
+ case IPP_FINISHINGS_EDGE_STITCH_BOTTOM :
+ p->type |= CUPS_PRINTER_BIND;
+ break;
+
+ case IPP_FINISHINGS_COVER :
+ p->type |= CUPS_PRINTER_COVER;
+ break;
+
+ case IPP_FINISHINGS_PUNCH :
+ case IPP_FINISHINGS_PUNCH_TOP_LEFT :
+ case IPP_FINISHINGS_PUNCH_BOTTOM_LEFT :
+ case IPP_FINISHINGS_PUNCH_TOP_RIGHT :
+ case IPP_FINISHINGS_PUNCH_BOTTOM_RIGHT :
+ case IPP_FINISHINGS_PUNCH_DUAL_LEFT :
+ case IPP_FINISHINGS_PUNCH_DUAL_TOP :
+ case IPP_FINISHINGS_PUNCH_DUAL_RIGHT :
+ case IPP_FINISHINGS_PUNCH_DUAL_BOTTOM :
+ case IPP_FINISHINGS_PUNCH_TRIPLE_LEFT :
+ case IPP_FINISHINGS_PUNCH_TRIPLE_TOP :
+ case IPP_FINISHINGS_PUNCH_TRIPLE_RIGHT :
+ case IPP_FINISHINGS_PUNCH_TRIPLE_BOTTOM :
+ case IPP_FINISHINGS_PUNCH_QUAD_LEFT :
+ case IPP_FINISHINGS_PUNCH_QUAD_TOP :
+ case IPP_FINISHINGS_PUNCH_QUAD_RIGHT :
+ case IPP_FINISHINGS_PUNCH_QUAD_BOTTOM :
+ p->type |= CUPS_PRINTER_PUNCH;
+ break;
+
+ case IPP_FINISHINGS_STAPLE :
+ case IPP_FINISHINGS_STAPLE_TOP_LEFT :
+ case IPP_FINISHINGS_STAPLE_BOTTOM_LEFT :
+ case IPP_FINISHINGS_STAPLE_TOP_RIGHT :
+ case IPP_FINISHINGS_STAPLE_BOTTOM_RIGHT :
+ case IPP_FINISHINGS_STAPLE_DUAL_LEFT :
+ case IPP_FINISHINGS_STAPLE_DUAL_TOP :
+ case IPP_FINISHINGS_STAPLE_DUAL_RIGHT :
+ case IPP_FINISHINGS_STAPLE_DUAL_BOTTOM :
+ case IPP_FINISHINGS_STAPLE_TRIPLE_LEFT :
+ case IPP_FINISHINGS_STAPLE_TRIPLE_TOP :
+ case IPP_FINISHINGS_STAPLE_TRIPLE_RIGHT :
+ case IPP_FINISHINGS_STAPLE_TRIPLE_BOTTOM :
+ p->type |= CUPS_PRINTER_STAPLE;
+ break;
+
+ default :
+ break;
+ }
+ }
}
- if (ppdFindOption(ppd, "BindEdge") != NULL)
+ if (p->pc && p->pc->templates)
{
- p->type |= CUPS_PRINTER_BIND;
- finishings[num_finishings++] = IPP_FINISHINGS_BIND;
+ const char *template; /* Finishing template */
+ ipp_attribute_t *fin_col_db; /* finishings-col-database attribute */
+ ipp_t *fin_col; /* finishings-col value */
+
+ fin_col_db = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER, "finishings-col-database", cupsArrayCount(p->pc->templates), NULL);
+ for (i = 0, template = (const char *)cupsArrayFirst(p->pc->templates); template; i ++, template = (const char *)cupsArrayNext(p->pc->templates))
+ {
+ fin_col = ippNew();
+ ippAddString(fin_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "finishing-template", NULL, template);
+ ippSetCollection(p->ppd_attrs, &fin_col_db, i, fin_col);
+ ippDelete(fin_col);
+ }
}
for (i = 0; i < ppd->num_sizes; i ++)
"printer-commands", NULL, "none");
}
- /*
- * 3D printer support...
- */
-
- if (ppdFindAttr(ppd, "cups3D", NULL))
- p->type |= CUPS_PRINTER_3D;
-
/*
* Show current and available port monitors for this printer...
*/
p->type |= CUPS_PRINTER_REMOTE;
- /*
- * Point the printer-uri-supported attribute to the
- * remote printer...
- */
-
- if (strchr(p->device_uri, '?'))
- {
- /*
- * Strip trailing "?options" from URI...
- */
-
- 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...
*/