/*
* "$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-2010 by Apple Inc.
+ * Copyright 2007-2011 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
* Contents:
*
* cupsdAddPrinter() - Add a printer to the system.
- * cupsdAddPrinterHistory() - Add the current printer state to the history.
- * cupsdAddPrinterUser() - Add a user to the ACL.
* cupsdCreateCommonData() - Create the common printer data.
* cupsdDeleteAllPrinters() - Delete all printers from the system.
* cupsdDeletePrinter() - Delete a printer from the system.
* cupsdFindDest() - Find a destination in the list.
* cupsdFindPrinter() - Find a printer in the list.
- * cupsdFreePrinterUsers() - Free allow/deny users.
* cupsdLoadAllPrinters() - Load printers from the printers.conf file.
* cupsdRenamePrinter() - Rename a printer.
* cupsdSaveAllPrinters() - Save all printer definitions to the
* add_printer_filter() - Add a MIME filter for a printer.
* add_printer_formats() - Add document-format-supported values for a
* printer.
- * add_string_array() - Add a string to an array of CUPS strings.
* compare_printers() - Compare two printers.
* delete_printer_filters() - Delete all MIME filters for a printer.
- * delete_string_array() - Delete an array of CUPS strings.
+ * dirty_printer() - Mark config and state files dirty for the
+ * specified printer.
* load_ppd() - Load a cached PPD file, updating the cache as
* needed.
* new_media_col() - Create a media-col collection value.
#include "cupsd.h"
#include <cups/dir.h>
+#ifdef HAVE_APPLICATIONSERVICES_H
+# include <ApplicationServices/ApplicationServices.h>
+#endif /* HAVE_APPLICATIONSERVICES_H */
+#ifdef HAVE_SYS_MOUNT_H
+# include <sys/mount.h>
+#endif /* HAVE_SYS_MOUNT_H */
+#ifdef HAVE_SYS_STATVFS_H
+# include <sys/statvfs.h>
+#elif defined(HAVE_SYS_STATFS_H)
+# include <sys/statfs.h>
+#endif /* HAVE_SYS_STATVFS_H */
+#ifdef HAVE_SYS_VFS_H
+# include <sys/vfs.h>
+#endif /* HAVE_SYS_VFS_H */
/*
static void add_printer_filter(cupsd_printer_t *p, mime_type_t *type,
const char *filter);
static void add_printer_formats(cupsd_printer_t *p);
-static void add_string_array(cups_array_t **a, const char *s);
static int compare_printers(void *first, void *second, void *data);
static void delete_printer_filters(cupsd_printer_t *p);
-static void delete_string_array(cups_array_t **a);
+static void dirty_printer(cupsd_printer_t *p);
static void load_ppd(cupsd_printer_t *p);
static ipp_t *new_media_col(_pwg_size_t *size, const char *source,
const char *type);
cupsdAddPrinter(const char *name) /* I - Name of printer */
{
cupsd_printer_t *p; /* New printer */
+ char uri[1024]; /* Printer URI */
/*
cupsdSetString(&p->info, name);
cupsdSetString(&p->hostname, ServerName);
- cupsdSetStringf(&p->uri, "ipp://%s:%d/printers/%s", ServerName, RemotePort,
- name);
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ ServerName, RemotePort, "/printers/%s", name);
+ cupsdSetString(&p->uri, uri);
cupsdSetDeviceURI(p, "file:///dev/null");
p->state = IPP_PRINTER_STOPPED;
p->op_policy_ptr = DefaultPolicyPtr;
- if (MaxPrinterHistory)
- p->history = calloc(MaxPrinterHistory, sizeof(ipp_t *));
-
/*
* Insert the printer in the printer list alphabetically...
*/
}
-/*
- * 'cupsdAddPrinterHistory()' - Add the current printer state to the history.
- */
-
-void
-cupsdAddPrinterHistory(
- cupsd_printer_t *p) /* I - Printer */
-{
- ipp_t *history; /* History collection */
-
-
- /*
- * Stop early if we aren't keeping history data...
- */
-
- if (MaxPrinterHistory <= 0)
- return;
-
- /*
- * Retire old history data as needed...
- */
-
- p->sequence_number ++;
-
- if (p->num_history >= MaxPrinterHistory)
- {
- p->num_history --;
- ippDelete(p->history[0]);
- memmove(p->history, p->history + 1, p->num_history * sizeof(ipp_t *));
- }
-
- /*
- * Create a collection containing the current printer-state, printer-up-time,
- * printer-state-message, and printer-state-reasons attributes.
- */
-
- history = ippNew();
- ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
- p->state);
- ippAddBoolean(history, IPP_TAG_PRINTER, "printer-is-accepting-jobs",
- p->accepting);
- ippAddBoolean(history, IPP_TAG_PRINTER, "printer-is-shared", p->shared);
- ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-state-message",
- NULL, p->state_message);
- if (p->num_reasons == 0)
- ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "printer-state-reasons", NULL, "none");
- else
- ippAddStrings(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "printer-state-reasons", p->num_reasons, NULL,
- (const char * const *)p->reasons);
- ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
- "printer-state-change-time", p->state_time);
- ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
- "printer-state-sequence-number", p->sequence_number);
-
- p->history[p->num_history] = history;
- p->num_history ++;
-}
-
-
-/*
- * 'cupsdAddPrinterUser()' - Add a user to the ACL.
- */
-
-void
-cupsdAddPrinterUser(
- cupsd_printer_t *p, /* I - Printer */
- const char *username) /* I - User */
-{
- const char **temp; /* Temporary array pointer */
-
-
- if (!p || !username)
- return;
-
- if (p->num_users == 0)
- temp = malloc(sizeof(char **));
- else
- temp = realloc(p->users, sizeof(char **) * (p->num_users + 1));
-
- if (!temp)
- return;
-
- p->users = temp;
- temp += p->num_users;
-
- if ((*temp = strdup(username)) != NULL)
- p->num_users ++;
-}
-
-
/*
* 'cupsdCreateCommonData()' - Create the common printer data.
*/
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 */
"multiple-document-handling",
"number-up",
"output-bin",
+ "output-mode",
"orientation-requested",
"page-ranges",
"print-quality",
"multiple-document-handling",
"number-up",
"output-bin",
+ "output-mode",
"orientation-requested",
"page-ranges",
"print-quality",
"printer-location"
};
static const char * const which_jobs[] =
- { /* which-jobs-supported values */
- "completed",
- "not-completed",
- "aborted",
- "all",
- "canceled",
- "pending",
- "pending-held",
- "processing",
- "processing-stopped"
- };
+ { /* which-jobs-supported values */
+ "completed",
+ "not-completed",
+ "aborted",
+ "all",
+ "canceled",
+ "pending",
+ "pending-held",
+ "processing",
+ "processing-stopped"
+ };
if (CommonData)
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...
/* job-ids-supported */
ippAddBoolean(CommonData, IPP_TAG_PRINTER, "job-ids-supported", 1);
+ /* job-k-octets-supported */
+ ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "job-k-octets-supported", k_supported);
+
/* job-priority-supported */
ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"job-priority-supported", 100);
/* page-ranges-supported */
ippAddBoolean(CommonData, IPP_TAG_PRINTER, "page-ranges-supported", 1);
- /* pdf-override-supported */
+ /* pdl-override-supported */
ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
- "pdl-override-supported", NULL, "not-attempted");
+ "pdl-override-supported", NULL, "attempted");
/* printer-op-policy-supported */
attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update);
+ p->state = IPP_PRINTER_STOPPED; /* Force for browsed printers */
+
if (p->job)
cupsdSetJobState(p->job, IPP_JOB_PENDING, CUPSD_JOB_FORCE,
update ? "Job stopped due to printer being deleted." :
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 ++)
mimeDeleteType(MimeDatabase, p->filetype);
mimeDeleteType(MimeDatabase, p->prefiltertype);
- delete_string_array(&(p->filters));
- delete_string_array(&(p->pre_filters));
-
- cupsdFreePrinterUsers(p);
+ cupsdFreeStrings(&(p->users));
cupsdFreeQuotas(p);
cupsdClearString(&p->uri);
cupsdClearString(&p->alert_description);
#ifdef HAVE_DNSSD
- cupsdClearString(&p->product);
cupsdClearString(&p->pdl);
#endif /* HAVE_DNSSD */
}
-/*
- * '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.
*/
*/
cupsdSetPrinterAttrs(p);
- cupsdAddPrinterHistory(p);
if (strncmp(p->device_uri, "file:", 5) &&
p->state != IPP_PRINTER_STOPPED)
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
- else if (!strcasecmp(line, "Product"))
- {
- if (value)
- {
-#ifdef HAVE_DNSSD
- p->product = _cupsStrAlloc(value);
-#endif /* HAVE_DNSSD */
- }
- else
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Syntax error on line %d of printers.conf.", linenum);
- }
- else if (!strcasecmp(line, "Filter"))
- {
- if (value)
- {
- if (!p->filters)
- p->filters = cupsArrayNew(NULL, NULL);
-
- cupsArrayAdd(p->filters, _cupsStrAlloc(value));
- }
- else
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Syntax error on line %d of printers.conf.", linenum);
- }
- else if (!strcasecmp(line, "PreFilter"))
- {
- if (value)
- {
- if (!p->pre_filters)
- p->pre_filters = cupsArrayNew(NULL, NULL);
-
- cupsArrayAdd(p->pre_filters, _cupsStrAlloc(value));
- }
- else
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Syntax error on line %d of printers.conf.", linenum);
- }
else if (!strcasecmp(line, "Shared"))
{
/*
if (value)
{
p->deny_users = 0;
- cupsdAddPrinterUser(p, value);
+ cupsdAddString(&(p->users), value);
}
else
cupsdLogMessage(CUPSD_LOG_ERROR,
if (value)
{
p->deny_users = 1;
- cupsdAddPrinterUser(p, value);
+ cupsdAddString(&(p->users), value);
}
else
cupsdLogMessage(CUPSD_LOG_ERROR,
char temp[1024], /* Temporary string */
backup[1024], /* printers.conf.O file */
value[2048], /* Value string */
- *ptr; /* Pointer into value */
+ *ptr, /* Pointer into value */
+ *name; /* Current user/group name */
cupsd_printer_t *printer; /* Current printer class */
time_t curtime; /* Current time */
struct tm *curdate; /* Current date */
*/
fchown(cupsFileNumber(fp), getuid(), Group);
- fchmod(cupsFileNumber(fp), 0600);
+ fchmod(cupsFileNumber(fp), ConfigFilePerm & 0600);
/*
* Write a small header to the file...
cupsFilePrintf(fp, "Type %d\n", printer->type);
-#ifdef HAVE_DNSSD
- if (printer->product)
- cupsFilePutConf(fp, "Product", printer->product);
-#endif /* HAVE_DNSSD */
-
- for (ptr = (char *)cupsArrayFirst(printer->filters);
- ptr;
- ptr = (char *)cupsArrayNext(printer->filters))
- cupsFilePutConf(fp, "Filter", ptr);
-
- for (ptr = (char *)cupsArrayFirst(printer->pre_filters);
- ptr;
- ptr = (char *)cupsArrayNext(printer->pre_filters))
- cupsFilePutConf(fp, "PreFilter", ptr);
-
if (printer->accepting)
cupsFilePuts(fp, "Accepting Yes\n");
else
cupsFilePrintf(fp, "PageLimit %d\n", printer->page_limit);
cupsFilePrintf(fp, "KLimit %d\n", printer->k_limit);
- for (i = 0; i < printer->num_users; i ++)
- cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser",
- printer->users[i]);
+ for (name = (char *)cupsArrayFirst(printer->users);
+ name;
+ name = (char *)cupsArrayNext(printer->users))
+ cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser", name);
if (printer->op_policy)
cupsFilePutConf(fp, "OpPolicy", printer->op_policy);
ipp_t *oldattrs; /* Old printer attributes */
ipp_attribute_t *attr; /* Attribute data */
cups_option_t *option; /* Current printer option */
- char *filter; /* Current filter */
+ char *name, /* Current user/group name */
+ *filter; /* Current filter */
static const char * const air_none[] =
{ /* No authentication */
"none"
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
NULL, p->info ? p->info : "");
- 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 = _cupsStrRetain(name);
}
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
* Tell the client this is a remote printer of some type...
*/
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
- "printer-uri-supported", NULL, p->uri);
+ if (strchr(p->uri, '?'))
+ {
+ /*
+ * Strip trailing "?options" from URI...
+ */
+
+ char *ptr; /* Pointer into URI */
+
+ strlcpy(resource, p->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->uri);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info",
NULL, p->uri);
cupsdSetPrinterReasons(p, "-cups-missing-filter-warning,"
"cups-insecure-filter-warning");
- for (filter = (char *)cupsArrayFirst(p->filters);
- filter;
- filter = (char *)cupsArrayNext(p->filters))
- add_printer_filter(p, p->filetype, filter);
+ 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 if (!(p->type & CUPS_PRINTER_REMOTE))
+ {
+ char interface[1024]; /* Interface script */
+
- if (p->pre_filters)
+ 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!
+ */
+
+ snprintf(interface, sizeof(interface), "*/* 0 %s/interfaces/%s",
+ ServerRoot, p->name);
+ add_printer_filter(p, p->filetype, interface);
+ }
+ else
+ {
+ /*
+ * 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.
+ */
+
+ add_printer_filter(p, p->filetype,
+ "application/vnd.cups-postscript 0 -");
+ }
+ }
+
+ if (p->pc && p->pc->prefilters)
{
p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name);
- for (filter = (char *)cupsArrayFirst(p->pre_filters);
+ for (filter = (char *)cupsArrayFirst(p->pc->prefilters);
filter;
- filter = (char *)cupsArrayNext(p->pre_filters))
+ filter = (char *)cupsArrayNext(p->pc->prefilters))
add_printer_filter(p, p->prefiltertype, filter);
}
}
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? */
p->num_reasons = 0;
changed = 1;
- cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
-
- if (PrintcapFormat == PRINTCAP_PLIST)
- cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
+ dirty_printer(p);
}
if (!strcmp(s, "none"))
cupsdSetPrinterState(p, IPP_PRINTER_IDLE, 1);
if (strcmp(reason, "connecting-to-device"))
- {
- cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
-
- if (PrintcapFormat == PRINTCAP_PLIST)
- cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
- }
+ dirty_printer(p);
break;
}
}
cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 1);
if (strcmp(reason, "connecting-to-device"))
- {
- cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
-
- if (PrintcapFormat == PRINTCAP_PLIST)
- cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
- }
+ dirty_printer(p);
}
}
}
* Set the new state...
*/
- if (PrintcapFormat == PRINTCAP_PLIST)
- cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
-
old_state = p->state;
p->state = s;
CUPSD_EVENT_PRINTER_STATE, p, NULL,
"%s \"%s\" state changed to %s.",
(p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
- p->name, printer_states[p->state]);
+ p->name, printer_states[p->state - IPP_PRINTER_IDLE]);
/*
* Let the browse code know this needs to be updated...
if (s == IPP_PRINTER_PROCESSING)
p->state_message[0] = '\0';
- /*
- * Update the printer history...
- */
-
- cupsdAddPrinterHistory(p);
-
/*
* Let the browse protocols reflect the change...
*/
if (update &&
(old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED))
- {
- if (p->type & CUPS_PRINTER_CLASS)
- cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
- else
- cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
- }
+ dirty_printer(p);
}
{
char super[MIME_MAX_SUPER], /* Super-type for filter */
type[MIME_MAX_TYPE], /* Type for filter */
+ dsuper[MIME_MAX_SUPER], /* Destination super-type for filter */
+ dtype[MIME_MAX_TYPE], /* Destination type for filter */
+ dest[MIME_MAX_SUPER + MIME_MAX_TYPE + 2],
+ /* Destination super/type */
program[1024]; /* Program/filter name */
int cost; /* Cost of filter */
- mime_type_t *temptype; /* MIME type looping var */
+ mime_type_t *temptype, /* MIME type looping var */
+ *desttype; /* Destination MIME type */
char filename[1024], /* Full filter filename */
*dirsep; /* Pointer to directory separator */
struct stat fileinfo; /* File information */
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "add_printer_filter(p=%p(%s), filtertype=%p(%s/%s), "
+ "filter=\"%s\")", p, p->name, filtertype, filtertype->super,
+ filtertype->type, filter);
+
/*
- * Parse the filter string; it should be in the following format:
+ * Parse the filter string; it should be in one of the following formats:
*
- * super/type cost program
+ * source/type cost program
+ * source/type dest/type cost program
*/
- if (sscanf(filter, "%15[^/]/%31s%d%*[ \t]%1023[^\n]", super, type, &cost,
- program) != 4)
+ if (sscanf(filter, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
+ super, type, dsuper, dtype, &cost, program) == 6)
{
- cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!",
- p->name, filter);
- return;
+ snprintf(dest, sizeof(dest), "%s/%s/%s", p->name, dsuper, dtype);
+
+ if ((desttype = mimeType(MimeDatabase, "printer", dest)) == NULL)
+ {
+ desttype = mimeAddType(MimeDatabase, "printer", dest);
+ if (!p->dest_types)
+ p->dest_types = cupsArrayNew(NULL, NULL);
+
+ cupsArrayAdd(p->dest_types, desttype);
+ }
+
+ }
+ else
+ {
+ 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;
+ }
}
/*
memset(&fileinfo, 0, sizeof(fileinfo));
snprintf(p->state_message, sizeof(p->state_message),
- "Filter \"%s\" for printer \"%s\" not available: %s",
- filename, p->name, strerror(errno));
+ "Printer driver \"%s\" not available: %s", filename,
+ strerror(errno));
cupsdSetPrinterReasons(p, "+cups-missing-filter-warning");
- cupsdLogMessage(CUPSD_LOG_ERROR, "%s", p->state_message);
+ cupsdLogMessage(CUPSD_LOG_ERROR, "%s: %s", p->name, p->state_message);
}
/*
* When running as root, do additional security checks...
*/
- if (!RunUser)
+ else if (!RunUser)
{
/*
- * Only use filters that are owned by root and do not have group or world
- * write permissions.
+ * Only use filters that are owned by root and do not have world write
+ * permissions.
*/
if (fileinfo.st_uid ||
(fileinfo.st_mode & (S_ISUID | S_IWGRP | S_IWOTH)) != 0)
{
- if (fileinfo.st_uid)
- snprintf(p->state_message, sizeof(p->state_message),
- "Filter \"%s\" for printer \"%s\" not owned by root",
- filename, p->name);
- else
- snprintf(p->state_message, sizeof(p->state_message),
- "Filter \"%s\" for printer \"%s\" has insecure permissions "
- "(0%o)", filename, p->name, fileinfo.st_mode);
+ snprintf(p->state_message, sizeof(p->state_message),
+ "Printer driver \"%s\" has insecure permissions (%d/0%o).",
+ filename, (int)fileinfo.st_uid, fileinfo.st_mode);
cupsdSetPrinterReasons(p, "+cups-insecure-filter-warning");
- cupsdLogMessage(CUPSD_LOG_ERROR, "%s", p->state_message);
+ cupsdLogMessage(CUPSD_LOG_WARN, "%s: %s", p->name, p->state_message);
}
else if (fileinfo.st_mode)
{
if (!stat(filename, &fileinfo) &&
(fileinfo.st_uid ||
- (fileinfo.st_mode & (S_ISUID | S_IWGRP | S_IWOTH)) != 0))
+ (fileinfo.st_mode & (S_ISUID | S_IWOTH)) != 0))
{
- if (fileinfo.st_uid)
- snprintf(p->state_message, sizeof(p->state_message),
- "Filter directory \"%s\" for printer \"%s\" not owned by "
- "root", filename, p->name);
- else
- snprintf(p->state_message, sizeof(p->state_message),
- "Filter directory \"%s\" for printer \"%s\" has insecure "
- "permissions (0%o)", filename, p->name, fileinfo.st_mode);
+ snprintf(p->state_message, sizeof(p->state_message),
+ "Printer driver directory \"%s\" has insecure permissions "
+ "(%d/0%o).", filename, (int)fileinfo.st_uid,
+ fileinfo.st_mode);
cupsdSetPrinterReasons(p, "+cups-insecure-filter-warning");
- cupsdLogMessage(CUPSD_LOG_ERROR, "%s", p->state_message);
+ cupsdLogMessage(CUPSD_LOG_WARN, "%s: %s", p->name, p->state_message);
}
}
}
!strcasecmp(temptype->super, super)) &&
(type[0] == '*' || !strcasecmp(temptype->type, type)))
{
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "add_printer_filter: %s: adding filter %s/%s %s/%s %d %s",
- p->name, temptype->super, temptype->type,
- filtertype->super, filtertype->type,
- cost, program);
- mimeAddFilter(MimeDatabase, temptype, filtertype, cost, program);
+ if (desttype != filtertype)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "add_printer_filter: %s: adding filter %s/%s %s/%s %d "
+ "%s", p->name, temptype->super, temptype->type,
+ desttype->super, desttype->type,
+ cost, program);
+ 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, cost, "-");
+ }
+ }
+ 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);
+ mimeAddFilter(MimeDatabase, temptype, filtertype, cost, program);
+ }
}
}
type;
type = mimeNextType(MimeDatabase))
{
+ if (!strcasecmp(type->super, "printer"))
+ continue;
+
snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
if ((filters = mimeFilter(MimeDatabase, type, p->filetype, NULL)) != NULL)
strlcat(pdl, "image/jpeg,", sizeof(pdl));
else if (!strcasecmp(type->type, "png"))
strlcat(pdl, "image/png,", sizeof(pdl));
+ else if (!strcasecmp(type->type, "pwg-raster"))
+ strlcat(pdl, "image/pwg-raster,", sizeof(pdl));
}
}
}
-/*
- * 'add_string_array()' - Add a string to an array of CUPS strings.
- */
-
-static void
-add_string_array(cups_array_t **a, /* I - Array */
- const char *s) /* I - String */
-{
- if (!*a)
- *a = cupsArrayNew(NULL, NULL);
-
- cupsArrayAdd(*a, _cupsStrAlloc(s));
-}
-
-
/*
* 'compare_printers()' - Compare two printers.
*/
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 */
/*
for (filter = mimeFirstFilter(MimeDatabase);
filter;
filter = mimeNextFilter(MimeDatabase))
- if (filter->dst == p->filetype || filter->dst == p->prefiltertype)
+ if (filter->dst == p->filetype || filter->dst == p->prefiltertype ||
+ cupsArrayFind(p->dest_types, filter->dst))
{
/*
* Delete the current filter...
mimeDeleteFilter(MimeDatabase, filter);
}
+ for (type = (mime_type_t *)cupsArrayFirst(p->dest_types);
+ type;
+ type = (mime_type_t *)cupsArrayNext(p->dest_types))
+ mimeDeleteType(MimeDatabase, type);
+
+ cupsArrayDelete(p->dest_types);
+ p->dest_types = NULL;
+
cupsdSetPrinterReasons(p, "-cups-insecure-filter-warning"
",cups-missing-filter-warning");
}
/*
- * 'delete_string_array()' - Delete an array of CUPS strings.
+ * 'dirty_printer()' - Mark config and state files dirty for the specified
+ * printer.
*/
static void
-delete_string_array(cups_array_t **a) /* I - Array */
+dirty_printer(cupsd_printer_t *p) /* I - Printer */
{
- char *ptr; /* Current string */
-
-
- for (ptr = (char *)cupsArrayFirst(*a);
- ptr;
- ptr = (char *)cupsArrayNext(*a))
- _cupsStrFree(ptr);
+ if (p->type & CUPS_PRINTER_DISCOVERED)
+ cupsdMarkDirty(CUPSD_DIRTY_REMOTE);
+ else if (p->type & CUPS_PRINTER_CLASS)
+ cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
+ else
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
- cupsArrayDelete(*a);
- *a = NULL;
+ if (PrintcapFormat == PRINTCAP_PLIST)
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
}
load_ppd(cupsd_printer_t *p) /* I - Printer */
{
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 */
+ 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 */
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 */
static const char * const sides[3] = /* sides-supported values */
{
"one-sided",
* Check to see if the cache is up-to-date...
*/
- snprintf(cache_name, sizeof(cache_name), "%s/%s.ipp2", CacheDir, p->name);
+ snprintf(cache_name, sizeof(cache_name), "%s/%s.data", CacheDir, p->name);
if (stat(cache_name, &cache_info))
cache_info.st_mtime = 0;
- snprintf(pwg_name, sizeof(pwg_name), "%s/%s.pwg", 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;
ippDelete(p->ppd_attrs);
p->ppd_attrs = ippNew();
- _pwgDestroy(p->pwg);
- p->pwg = NULL;
+ _ppdCacheDestroy(p->pc);
+ p->pc = 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)
+ if (cache_info.st_mtime >= ppd_info.st_mtime)
{
- /*
- * Load cached information and return...
- */
-
cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", cache_name);
- if (ippReadIO(cache, (ipp_iocb_t)cupsFileRead, 1, NULL,
- p->ppd_attrs) == IPP_DATA)
+ if ((p->pc = _ppdCacheCreateWithFile(cache_name, &p->ppd_attrs)) != NULL &&
+ p->ppd_attrs)
{
- cupsFileClose(cache);
+ /*
+ * Loaded successfully!
+ */
+
return;
}
-
- cupsFileClose(cache);
}
/*
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));
- delete_string_array(&(p->pre_filters));
-
p->type &= ~CUPS_PRINTER_OPTIONS;
p->type |= CUPS_PRINTER_BW;
* Add make/model and other various attributes...
*/
- p->pwg = _pwgCreateWithPPD(ppd);
+ p->pc = _ppdCacheCreateWithPPD(ppd);
ppdMarkDefaults(ppd);
ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"pages-per-minute-color", ppd->throughput);
}
+ else
+ {
+ /*
+ * When there is no speed information, just say "1 page per minute".
+ */
+
+ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "pages-per-minute", 1);
+ if (ppd->color_device)
+ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "pages-per-minute-color", 1);
+ }
num_qualities = 0;
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;
+
+ qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
+
if (ppdFindChoice(output_mode, "best") ||
ppdFindChoice(output_mode, "high"))
qualities[num_qualities ++] = IPP_QUALITY_HIGH;
qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
qualities[num_qualities ++] = IPP_QUALITY_HIGH;
}
-
- if (num_qualities == 0)
+ else
qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
* Add media options from the PPD file...
*/
- if (ppd->num_sizes == 0 || !p->pwg)
+ if (ppd->num_sizes == 0 || !p->pc)
{
if (!ppdFindAttr(ppd, "APScannerOnly", NULL))
cupsdLogMessage(CUPSD_LOG_CRIT,
*/
if ((size = ppdPageSize(ppd, NULL)) != NULL)
- pwgsize = _pwgGetSize(p->pwg, size->name);
+ pwgsize = _ppdCacheGetSize(p->pc, size->name);
else
pwgsize = NULL;
media_type = ppdFindMarkedChoice(ppd, "MediaType");
col = new_media_col(pwgsize,
input_slot ?
- _pwgGetSource(p->pwg,
- input_slot->choice) :
+ _ppdCacheGetSource(p->pc,
+ input_slot->choice) :
NULL,
media_type ?
- _pwgGetType(p->pwg,
- media_type->choice) :
+ _ppdCacheGetType(p->pc,
+ media_type->choice) :
NULL);
ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-default",
* media-supported
*/
- num_media = p->pwg->num_sizes;
- if (p->pwg->custom_min_keyword)
+ num_media = p->pc->num_sizes;
+ if (p->pc->custom_min_keyword)
num_media += 2;
if ((attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
{
val = attr->values;
- for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes;
+ for (i = p->pc->num_sizes, pwgsize = p->pc->sizes;
i > 0;
i --, pwgsize ++, val ++)
val->string.text = _cupsStrRetain(pwgsize->map.pwg);
- if (p->pwg->custom_min_keyword)
+ if (p->pc->custom_min_keyword)
{
- val->string.text = _cupsStrRetain(p->pwg->custom_min_keyword);
+ val->string.text = _cupsStrRetain(p->pc->custom_min_keyword);
val ++;
- val->string.text = _cupsStrRetain(p->pwg->custom_max_keyword);
+ val->string.text = _cupsStrRetain(p->pc->custom_max_keyword);
}
}
* media-source-supported
*/
- if (p->pwg->num_sources > 0 &&
+ if (p->pc->num_sources > 0 &&
(attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "media-source-supported", p->pwg->num_sources,
+ "media-source-supported", p->pc->num_sources,
NULL, NULL)) != NULL)
{
- for (i = p->pwg->num_sources, pwgsource = p->pwg->sources,
+ for (i = p->pc->num_sources, pwgsource = p->pc->sources,
val = attr->values;
i > 0;
i --, pwgsource ++, val ++)
* media-type-supported
*/
- if (p->pwg->num_types > 0 &&
+ if (p->pc->num_types > 0 &&
(attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "media-type-supported", p->pwg->num_types,
+ "media-type-supported", p->pc->num_types,
NULL, NULL)) != NULL)
{
- for (i = p->pwg->num_types, pwgtype = p->pwg->types,
+ for (i = p->pc->num_types, pwgtype = p->pc->types,
val = attr->values;
i > 0;
i --, pwgtype ++, val ++)
* media-*-margin-supported
*/
- for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes, num_margins = 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 ++)
{
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;
+ 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 ++)
{
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;
+ 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 ++)
{
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;
+ 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 ++)
{
* media-col-database
*/
- num_media = p->pwg->num_sizes;
- if (p->pwg->num_sources)
+ num_media = p->pc->num_sizes;
+ if (p->pc->num_sources)
{
- if (p->pwg->num_types > 0)
- num_media += p->pwg->num_sizes * p->pwg->num_sources *
- p->pwg->num_types;
+ if (p->pc->num_types > 0)
+ num_media += p->pc->num_sizes * p->pc->num_sources *
+ p->pc->num_types;
else
- num_media += p->pwg->num_sizes * p->pwg->num_sources;
+ num_media += p->pc->num_sizes * p->pc->num_sources;
}
- else if (p->pwg->num_types)
- num_media += p->pwg->num_sizes * p->pwg->num_types;
+ 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->pwg->num_sizes, pwgsize = p->pwg->sizes, val = attr->values;
+ for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, val = attr->values;
i > 0;
i --, pwgsize ++)
{
* type...
*/
- if (p->pwg->num_sources > 0)
+ if (p->pc->num_sources > 0)
{
- for (j = p->pwg->num_sources, pwgsource = p->pwg->sources;
+ for (j = p->pc->num_sources, pwgsource = p->pc->sources;
j > 0;
j --, pwgsource ++)
{
ppdMarkOption(ppd, "InputSlot", pwgsource->ppd);
- if (p->pwg->num_types > 0)
+ if (p->pc->num_types > 0)
{
- for (k = p->pwg->num_types, pwgtype = p->pwg->types;
+ for (k = p->pc->num_types, pwgtype = p->pc->types;
k > 0;
k --, pwgtype ++)
{
}
}
}
- else if (p->pwg->num_types > 0)
+ else if (p->pc->num_types > 0)
{
- for (j = p->pwg->num_types, pwgtype = p->pwg->types;
+ for (j = p->pc->num_types, pwgtype = p->pc->types;
j > 0;
j --, pwgtype ++)
{
* Output bin...
*/
- if (p->pwg && p->pwg->num_bins > 0)
+ if (p->pc && p->pc->num_bins > 0)
{
attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "output-bin-supported", p->pwg->num_bins,
+ "output-bin-supported", p->pc->num_bins,
NULL, NULL);
if (attr != NULL)
{
for (i = 0, val = attr->values;
- i < p->pwg->num_bins;
+ i < p->pc->num_bins;
i ++, val ++)
- val->string.text = _cupsStrAlloc(p->pwg->bins[i].pwg);
+ val->string.text = _cupsStrAlloc(p->pc->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))
+ for (i = 0; i < p->pc->num_bins; i ++)
+ if (!strcmp(p->pc->bins[i].ppd, output_bin->defchoice))
break;
- if (i >= p->pwg->num_bins)
+ if (i >= p->pc->num_bins)
i = 0;
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "output-bin-default", NULL, p->pwg->bins[i].pwg);
+ "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->pwg->bins[0].pwg);
+ "output-bin-default", NULL, p->pc->bins[0].pwg);
}
- else if ((ppd_attr = ppdFindAttr(ppd, "DefaultOutputOrder",
+ else if (((ppd_attr = ppdFindAttr(ppd, "DefaultOutputOrder",
NULL)) != NULL &&
- !strcasecmp(ppd_attr->value, "Reverse"))
+ !strcasecmp(ppd_attr->value, "Reverse")) ||
+ (!ppd_attr && ppd->manufacturer && /* "Compatibility heuristic" */
+ (!strcasecmp(ppd->manufacturer, "epson") ||
+ !strcasecmp(ppd->manufacturer, "lexmark"))))
{
+ /*
+ * 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-down");
}
+ /*
+ * output-mode and print-color-mode...
+ */
+
+ if (ppd->color_device)
+ {
+ static const char * const output_modes[] =
+ {
+ "monochrome",
+ "color"
+ };
+
+ ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "output-mode-supported", 2, NULL, output_modes);
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "output-mode-default", NULL, "color");
+
+ ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "print-color-mode-supported", 2, NULL, output_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,
+ "output-mode-supported", NULL, "monochrome");
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "output-mode-default", NULL, "monochrome");
+
+ 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");
+ }
+
/*
* Printer resolutions...
*/
cupsdLogMessage(CUPSD_LOG_WARN,
"Bad resolution \"%s\" for printer %s.",
choice->choice, p->name);
- xdpi = ydpi = 72;
+ xdpi = ydpi = 300;
}
attr->values[i].resolution.xres = xdpi;
cupsdLogMessage(CUPSD_LOG_WARN,
"Bad default resolution \"%s\" for printer %s.",
ppd_attr->value, p->name);
- xdpi = ydpi = 72;
+ xdpi = ydpi = 300;
}
ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
"printer-resolution-default", IPP_RES_PER_INCH,
- 72, 72);
+ 300, 300);
ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
"printer-resolution-supported", IPP_RES_PER_INCH,
- 72, 72);
+ 300, 300);
}
/*
* Duplexing, etc...
*/
+ ppdMarkDefaults(ppd);
+
if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL)
if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL)
if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL)
}
/*
- * Add a filter from application/vnd.cups-raw to printer/name to
- * handle "raw" printing by users.
- */
-
- add_string_array(&(p->filters), "application/vnd.cups-raw 0 -");
-
- /*
- * Add any pre-filters in the PPD file...
- */
-
- if ((ppd_attr = ppdFindAttr(ppd, "cupsPreFilter", NULL)) != NULL)
- {
- for (; ppd_attr; ppd_attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL))
- if (ppd_attr->value)
- add_string_array(&(p->pre_filters), ppd_attr->value);
- }
-
- /*
- * Add any filters in the PPD file...
+ * Scan the filters in the PPD file...
*/
- 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_string_array(&(p->filters), ppd->filters[i]);
-
- if (!strncasecmp(ppd->filters[i], "application/vnd.cups-command", 28) &&
- isspace(ppd->filters[i][28] & 255))
- p->type |= CUPS_PRINTER_COMMANDS;
- }
-
- if (ppd->num_filters == 0)
- {
- /*
- * If there are no filters, add PostScript printing filters.
- */
-
- add_string_array(&(p->filters),
- "application/vnd.cups-command 0 commandtops");
- add_string_array(&(p->filters),
- "application/vnd.cups-postscript 0 -");
-
- p->type |= CUPS_PRINTER_COMMANDS;
- }
- else if (!(p->type & CUPS_PRINTER_COMMANDS))
+ if (p->pc)
{
- /*
- * See if this is a PostScript device without a command filter...
- */
-
- for (i = 0; i < ppd->num_filters; i ++)
- if (!strncasecmp(ppd->filters[i],
- "application/vnd.cups-postscript", 31) &&
- isspace(ppd->filters[i][31] & 255))
- break;
-
- if (i < ppd->num_filters)
+ for (filter = (const char *)cupsArrayFirst(p->pc->filters);
+ filter;
+ filter = (const char *)cupsArrayNext(p->pc->filters))
{
- /*
- * Add the generic PostScript command filter...
- */
-
- add_string_array(&(p->filters),
- "application/vnd.cups-command 0 commandtops");
- p->type |= CUPS_PRINTER_COMMANDS;
+ if (!strncasecmp(filter, "application/vnd.cups-command", 28) &&
+ _cups_isspace(filter[28]))
+ {
+ p->type |= CUPS_PRINTER_COMMANDS;
+ break;
+ }
}
}
*end; /* End of name */
int count; /* Number of commands */
-
- if ((ppd_attr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL &&
- ppd_attr->value && ppd_attr->value[0])
+ if ((ppd_attr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL)
{
for (count = 0, start = ppd_attr->value; *start; count ++)
{
- while (isspace(*start & 255))
+ while (_cups_isspace(*start))
start ++;
if (!*start)
if (count > 0)
{
/*
- * Make a copy of the commands string and count how many ...
+ * Make a copy of the commands string and count how many commands there
+ * are...
*/
attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
attr->values[i].string.text = _cupsStrAlloc("bcp");
}
-#ifdef HAVE_DNSSD
- cupsdSetString(&p->product, ppd->product);
-#endif /* HAVE_DNSSD */
-
if (ppdFindAttr(ppd, "APRemoteQueueID", NULL))
p->type |= CUPS_PRINTER_REMOTE;
+#ifdef HAVE_APPLICATIONSERVICES_H
+ /*
+ * Convert the file referenced in APPrinterIconPath to a 128x128 PNG
+ * and save it as cacheDir/printername.png
+ */
+
+ if ((ppd_attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL &&
+ ppd_attr->value)
+ {
+ 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,
+ strlen(outPath),
+ FALSE);
+ icnsFileUrl = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
+ (UInt8 *)ppd_attr->value,
+ strlen(ppd_attr->value),
+ FALSE);
+ if (outUrl && icnsFileUrl)
+ {
+ sourceRef = CGImageSourceCreateWithURL(icnsFileUrl, NULL);
+ if (sourceRef)
+ {
+ for (i = 0; i < CGImageSourceGetCount(sourceRef); i ++)
+ {
+ imageRef = CGImageSourceCreateImageAtIndex(sourceRef, i, NULL);
+ if (!imageRef)
+ continue;
+
+ if (CGImageGetWidth(imageRef) == CGImageGetHeight(imageRef))
+ {
+ /*
+ * Loop through remembering the icon closest to 128 but >= 128
+ * and then remember the largest icon.
+ */
+
+ if (CGImageGetWidth(imageRef) >= 128 &&
+ (!closestTo128IconRef ||
+ CGImageGetWidth(imageRef) <
+ CGImageGetWidth(closestTo128IconRef)))
+ {
+ CGImageRelease(closestTo128IconRef);
+ CGImageRetain(imageRef);
+ closestTo128IconRef = imageRef;
+ }
+
+ if (!biggestIconRef ||
+ CGImageGetWidth(imageRef) > CGImageGetWidth(biggestIconRef))
+ {
+ CGImageRelease(biggestIconRef);
+ CGImageRetain(imageRef);
+ biggestIconRef = imageRef;
+ }
+ }
+
+ CGImageRelease(imageRef);
+ }
+
+ if (biggestIconRef)
+ {
+ /*
+ * If biggestIconRef is NULL, we found no icons. Otherwise we first
+ * want the closest to 128, but if none are larger than 128, we want
+ * the largest icon available.
+ */
+
+ imageRef = closestTo128IconRef ? closestTo128IconRef :
+ biggestIconRef;
+ CGImageRetain(imageRef);
+ CGImageRelease(biggestIconRef);
+ if (closestTo128IconRef)
+ CGImageRelease(closestTo128IconRef);
+ destRef = CGImageDestinationCreateWithURL(outUrl, kUTTypePNG, 1,
+ NULL);
+ if (destRef)
+ {
+ if (CGImageGetWidth(imageRef) != 128)
+ {
+ bytesPerRow = CGImageGetBytesPerRow(imageRef) /
+ CGImageGetWidth(imageRef) * 128;
+ context = CGBitmapContextCreate(NULL, 128, 128,
+ CGImageGetBitsPerComponent(imageRef),
+ bytesPerRow,
+ CGImageGetColorSpace(imageRef),
+ kCGImageAlphaPremultipliedFirst);
+ if (context)
+ {
+ CGContextDrawImage(context, CGRectMake(0, 0, 128, 128),
+ imageRef);
+ CGImageRelease(imageRef);
+ imageRef = CGBitmapContextCreateImage(context);
+ CGContextRelease(context);
+ }
+ }
+
+ CGImageDestinationAddImage(destRef, imageRef, NULL);
+ CGImageDestinationFinalize(destRef);
+ CFRelease(destRef);
+ }
+
+ CGImageRelease(imageRef);
+ }
+
+ CFRelease(sourceRef);
+ }
+ }
+
+ if (outUrl)
+ CFRelease(outUrl);
+
+ if (icnsFileUrl)
+ CFRelease(icnsFileUrl);
+ }
+#endif /* HAVE_APPLICATIONSERVICES_H */
+
/*
* Close the PPD and set the type...
*/
cupsdLogMessage(CUPSD_LOG_INFO,
"Hint: Run \"cupstestppd %s\" and fix any errors.",
ppd_name);
-
- /*
- * Add a filter from application/vnd.cups-raw to printer/name to
- * handle "raw" printing by users.
- */
-
- add_string_array(&(p->filters), "application/vnd.cups-raw 0 -");
-
- /*
- * Add a PostScript filter, since this is still possibly PS printer.
- */
-
- add_string_array(&(p->filters), "application/vnd.cups-postscript 0 -");
}
else
{
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
"printer-make-and-model", NULL,
"Local System V Printer");
-
- snprintf(interface, sizeof(interface), "*/* 0 %s/interfaces/%s",
- ServerRoot, p->name);
- add_string_array(&(p->filters), interface);
}
else if (!strncmp(p->device_uri, "ipp://", 6) &&
(strstr(p->device_uri, "/printers/") != NULL ||
* remote printer...
*/
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
- "printer-uri-supported", NULL, p->device_uri);
+ 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...
ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
"finishings-default", IPP_FINISHINGS_NONE);
- if (ppd && (cache = cupsFileOpen(cache_name, "w9")) != NULL)
+ if (ppd && p->pc)
{
/*
* Save cached PPD attributes to disk...
cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Saving %s...", cache_name);
- p->ppd_attrs->state = IPP_IDLE;
-
- if (ippWriteIO(cache, (ipp_iocb_t)cupsFileWrite, 1, NULL,
- p->ppd_attrs) != IPP_DATA)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to save PPD cache file \"%s\" - %s", cache_name,
- strerror(errno));
- unlink(cache_name);
- }
-
- cupsFileClose(cache);
-
- _pwgWriteFile(p->pwg, pwg_name);
+ _ppdCacheWriteFile(p->pc, cache_name, p->ppd_attrs);
}
else
{
if (cache_info.st_mtime)
unlink(cache_name);
-
- if (pwg_info.st_mtime)
- unlink(pwg_name);
}
}