/*
* "$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.
* write_irix_config() - Update the config files used by the IRIX
* desktop tools.
* write_irix_state() - Update the status files used by IRIX printing
#include "cupsd.h"
#include <cups/dir.h>
-#include <cups/pwgmedia.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);
#ifdef __sgi
static void write_irix_config(cupsd_printer_t *p);
static void write_irix_state(cupsd_printer_t *p);
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 */
IPP_GET_PRINTER_ATTRIBUTES,
IPP_HOLD_JOB,
IPP_RELEASE_JOB,
+ IPP_RESTART_JOB,
IPP_PAUSE_PRINTER,
IPP_RESUME_PRINTER,
IPP_PURGE_JOBS,
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,
};
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[] =
"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",
+ "output-mode",
+ "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",
+ "output-mode",
"orientation-requested",
"page-ranges",
"print-quality",
"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)
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...
"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-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,
/* 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);
}
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 */
+
+
+ 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->pre_filters)
+ 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);
}
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"));
}
/*
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);
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);
}
{
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)
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);
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));
+ else if (!strcasecmp(type->type, "pwg-raster"))
+ strlcat(pdl, "image/pwg-raster,", sizeof(pdl));
+ }
+ }
if (pdl[0])
pdl[strlen(pdl) - 1] = '\0'; /* Remove trailing comma */
}
-/*
- * '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);
}
static void
load_ppd(cupsd_printer_t *p) /* I - Printer */
{
- int i; /* Looping var */
- cups_file_t *cache; /* Cache file */
+ int i, j, k; /* Looping vars */
char cache_name[1024]; /* Cache filename */
struct stat cache_info; /* Cache file info */
ppd_file_t *ppd; /* PPD file */
char ppd_name[1024]; /* PPD filename */
struct stat ppd_info; /* PPD file info */
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_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 */
+ ppd_choice_t *choice, /* Current PPD choice */
+ *input_slot, /* Current input slot */
+ *media_type; /* Current media type */
ppd_attr_t *ppd_attr; /* PPD attribute */
int xdpi, /* Horizontal resolution */
ydpi; /* Vertical resolution */
const char *resptr; /* Pointer into resolution keyword */
- _cups_pwg_media_t *pwgmedia; /* Matching PWG size name */
+ _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 */
+ 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.ipp", CacheDir, p->name);
+ snprintf(cache_name, sizeof(cache_name), "%s/%s.data", CacheDir, p->name);
if (stat(cache_name, &cache_info))
cache_info.st_mtime = 0;
ippDelete(p->ppd_attrs);
p->ppd_attrs = ippNew();
- if (cache_info.st_mtime >= ppd_info.st_mtime &&
- (cache = cupsFileOpen(cache_name, "r")) != NULL)
- {
- /*
- * Load cached information and return...
- */
+ _ppdCacheDestroy(p->pc);
+ p->pc = NULL;
+ if (cache_info.st_mtime >= ppd_info.st_mtime)
+ {
cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", cache_name);
- if (ippReadIO(cache, (ipp_iocb_t)cupsFileRead, 1, NULL,
- p->ppd_attrs) == IPP_DATA)
+ if ((p->pc = _ppdCacheCreateWithFile(cache_name, &p->ppd_attrs)) != NULL &&
+ p->ppd_attrs)
{
- cupsFileClose(cache);
+ /*
+ * Loaded successfully!
+ */
+
return;
}
-
- cupsFileClose(cache);
}
/*
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->pc = _ppdCacheCreateWithPPD(ppd);
+
ppdMarkDefaults(ppd);
if (ppd->color_device)
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);
+ }
+ 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 ((output_mode = ppdFindOption(ppd, "OutputMode")) != NULL)
+ {
+ if (ppdFindChoice(output_mode, "draft") ||
+ ppdFindChoice(output_mode, "fast"))
+ qualities[num_qualities ++] = IPP_QUALITY_DRAFT;
+
+ qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
+
+ if (ppdFindChoice(output_mode, "best") ||
+ ppdFindChoice(output_mode, "high"))
+ qualities[num_qualities ++] = IPP_QUALITY_HIGH;
+ }
+ else if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL)
+ {
+ do
+ {
+ if (strstr(ppd_attr->spec, "draft") ||
+ strstr(ppd_attr->spec, "Draft"))
+ {
+ qualities[num_qualities ++] = IPP_QUALITY_DRAFT;
+ break;
+ }
+ }
+ while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset",
+ NULL)) != NULL);
+
+ qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
+ qualities[num_qualities ++] = IPP_QUALITY_HIGH;
+ }
+ else
+ qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
+
+ ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "print-quality-supported", num_qualities, qualities);
if (ppd->nickname)
{
* Add media options from the PPD file...
*/
- if (ppd->num_sizes == 0)
+ if (ppd->num_sizes == 0 || !p->pc)
{
if (!ppdFindAttr(ppd, "APScannerOnly", NULL))
cupsdLogMessage(CUPSD_LOG_CRIT,
"The PPD file for printer %s contains no media "
"options and is therefore invalid!", p->name);
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "media-default", NULL, "unknown");
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"media-supported", NULL, "unknown");
}
else
{
- num_media = ppd->num_sizes;
- if (ppd->variable_sizes)
- num_media ++;
+ /*
+ * media-default
+ */
- attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "media-supported", num_media, NULL, NULL);
- if (attr != NULL)
+ if ((size = ppdPageSize(ppd, NULL)) != NULL)
+ pwgsize = _ppdCacheGetSize(p->pc, size->name);
+ else
+ pwgsize = NULL;
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "media-default", NULL,
+ pwgsize ? pwgsize->map.pwg : "unknown");
+
+ /*
+ * media-col-default
+ */
+
+ if (pwgsize)
+ {
+ ipp_t *col; /* Collection value */
+
+ input_slot = ppdFindMarkedChoice(ppd, "InputSlot");
+ media_type = ppdFindMarkedChoice(ppd, "MediaType");
+ col = new_media_col(pwgsize,
+ input_slot ?
+ _ppdCacheGetSource(p->pc,
+ input_slot->choice) :
+ NULL,
+ media_type ?
+ _ppdCacheGetType(p->pc,
+ media_type->choice) :
+ NULL);
+
+ ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-default",
+ col);
+ ippDelete(col);
+ }
+
+ /*
+ * media-supported
+ */
+
+ 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,
+ "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->pc->num_sizes, pwgsize = p->pc->sizes;
+ i > 0;
+ i --, pwgsize ++, val ++)
+ val->string.text = _cupsStrRetain(pwgsize->map.pwg);
+
+ if (p->pc->custom_min_keyword)
{
- if (strcasecmp(size->name, "Custom"))
- {
- if ((pwgmedia = _cupsPWGMediaBySize(size->width,
- size->length)) != NULL)
- {
- val->string.text = _cupsStrAlloc(pwgmedia->pwg);
- }
- else
- {
- snprintf(custom_in, sizeof(custom_in), "adobe_%s_%gx%gin",
- size->name, size->width / 72.0, size->length / 72.0);
- snprintf(custom_mm, sizeof(custom_mm), "adobe_%s_%gx%gmm",
- size->name, size->width * 25.4 / 72.0,
- size->length * 25.4 / 72.0);
- if (strlen(custom_in) < strlen(custom_mm))
- val->string.text = _cupsStrAlloc(custom_in);
- else
- val->string.text = _cupsStrAlloc(custom_mm);
- }
+ val->string.text = _cupsStrRetain(p->pc->custom_min_keyword);
+ val ++;
+ val->string.text = _cupsStrRetain(p->pc->custom_max_keyword);
+ }
+ }
- if (size->marked)
- {
- /*
- * Add media-default...
- */
+ /*
+ * media-source-supported
+ */
- ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "media-default", NULL, val->string.text);
+ if (p->pc->num_sources > 0 &&
+ (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "media-source-supported", p->pc->num_sources,
+ NULL, NULL)) != NULL)
+ {
+ for (i = p->pc->num_sources, pwgsource = p->pc->sources,
+ val = attr->values;
+ i > 0;
+ i --, pwgsource ++, val ++)
+ val->string.text = _cupsStrRetain(pwgsource->pwg);
+ }
- /*
- * 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);
- }
+ /*
+ * media-type-supported
+ */
- val ++;
- }
+ if (p->pc->num_types > 0 &&
+ (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "media-type-supported", p->pc->num_types,
+ NULL, NULL)) != NULL)
+ {
+ for (i = p->pc->num_types, pwgtype = p->pc->types,
+ val = attr->values;
+ i > 0;
+ i --, pwgtype ++, val ++)
+ val->string.text = _cupsStrRetain(pwgtype->pwg);
+ }
+
+ /*
+ * media-*-margin-supported
+ */
+
+ for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
+ i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
+ i --, pwgsize ++)
+ {
+ for (j = 0; j < num_margins; j ++)
+ if (pwgsize->bottom == margins[j])
+ break;
+
+ if (j >= num_margins)
+ {
+ margins[num_margins] = pwgsize->bottom;
+ num_margins ++;
}
+ }
- if (ppd->variable_sizes)
+ if (num_margins > 0)
+ ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-bottom-margin-supported", num_margins, margins);
+ else
+ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-bottom-margin-supported", 0);
+
+ for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
+ i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
+ i --, pwgsize ++)
+ {
+ for (j = 0; j < num_margins; j ++)
+ if (pwgsize->left == margins[j])
+ break;
+
+ if (j >= num_margins)
{
- 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);
+ margins[num_margins] = pwgsize->left;
+ num_margins ++;
+ }
+ }
+
+ if (num_margins > 0)
+ ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-left-margin-supported", num_margins, margins);
+ else
+ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-left-margin-supported", 0);
+
+ for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
+ i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
+ i --, pwgsize ++)
+ {
+ for (j = 0; j < num_margins; j ++)
+ if (pwgsize->right == margins[j])
+ break;
+
+ if (j >= num_margins)
+ {
+ margins[num_margins] = pwgsize->right;
+ num_margins ++;
+ }
+ }
+
+ if (num_margins > 0)
+ ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-right-margin-supported", num_margins, margins);
+ else
+ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-right-margin-supported", 0);
+
+ for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
+ i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
+ i --, pwgsize ++)
+ {
+ for (j = 0; j < num_margins; j ++)
+ if (pwgsize->top == margins[j])
+ break;
+
+ if (j >= num_margins)
+ {
+ margins[num_margins] = pwgsize->top;
+ num_margins ++;
+ }
+ }
+
+ if (num_margins > 0)
+ ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-top-margin-supported", num_margins, margins);
+ else
+ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-top-margin-supported", 0);
+
+ /*
+ * media-col-database
+ */
+
+ num_media = p->pc->num_sizes;
+ if (p->pc->num_sources)
+ {
+ if (p->pc->num_types > 0)
+ num_media += p->pc->num_sizes * p->pc->num_sources *
+ p->pc->num_types;
+ else
+ num_media += p->pc->num_sizes * p->pc->num_sources;
+ }
+ else if (p->pc->num_types)
+ num_media += p->pc->num_sizes * p->pc->num_types;
+
+ if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER,
+ "media-col-database", num_media,
+ NULL)) != NULL)
+ {
+ for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, val = attr->values;
+ i > 0;
+ i --, pwgsize ++)
+ {
+ /*
+ * Start by adding the page size without source or type...
+ */
+
+ ppdMarkOption(ppd, "PageSize", pwgsize->map.ppd);
+
+ val->collection = new_media_col(pwgsize, NULL, NULL);
val ++;
- 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);
+ /*
+ * Then add the specific, supported combinations of size, source, and
+ * type...
+ */
+
+ if (p->pc->num_sources > 0)
+ {
+ for (j = p->pc->num_sources, pwgsource = p->pc->sources;
+ j > 0;
+ j --, pwgsource ++)
+ {
+ ppdMarkOption(ppd, "InputSlot", pwgsource->ppd);
+
+ if (p->pc->num_types > 0)
+ {
+ for (k = p->pc->num_types, pwgtype = p->pc->types;
+ k > 0;
+ k --, pwgtype ++)
+ {
+ if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd))
+ {
+ val->collection = new_media_col(pwgsize, pwgsource->pwg,
+ pwgtype->pwg);
+ val ++;
+ }
+ }
+ }
+ else if (!ppdConflicts(ppd))
+ {
+ val->collection = new_media_col(pwgsize, pwgsource->pwg, NULL);
+ val ++;
+ }
+ }
+ }
+ else if (p->pc->num_types > 0)
+ {
+ for (j = p->pc->num_types, pwgtype = p->pc->types;
+ j > 0;
+ j --, pwgtype ++)
+ {
+ if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd))
+ {
+ val->collection = new_media_col(pwgsize, NULL, pwgtype->pwg);
+ val ++;
+ }
+ }
+ }
}
+
+ /*
+ * Update the number of media-col-database values...
+ */
+
+ attr->num_values = val - attr->values;
}
}
* Output bin...
*/
- if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
+ if (p->pc && p->pc->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->pc->num_bins,
NULL, NULL);
if (attr != NULL)
{
for (i = 0, val = attr->values;
- i < output_bin->num_choices;
+ i < p->pc->num_bins;
i ++, val ++)
- val->string.text = _cupsStrAlloc(output_bin->choices[i].choice);
+ val->string.text = _cupsStrAlloc(p->pc->bins[i].pwg);
}
+ if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
+ {
+ for (i = 0; i < p->pc->num_bins; i ++)
+ if (!strcmp(p->pc->bins[i].ppd, output_bin->defchoice))
+ break;
+
+ if (i >= p->pc->num_bins)
+ i = 0;
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "output-bin-default", NULL, p->pc->bins[i].pwg);
+ }
+ else
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "output-bin-default", NULL, p->pc->bins[0].pwg);
+ }
+ else if (((ppd_attr = ppdFindAttr(ppd, "DefaultOutputOrder",
+ NULL)) != NULL &&
+ !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-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");
+ }
+
+ /*
+ * 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");
}
/*
i < resolution->num_choices;
i ++, choice ++)
{
- xdpi = (int)strtol(choice->choice, (char **)&resptr, 10);
- if (resptr > choice->choice && xdpi > 0)
- {
- if (*resptr == 'x')
- ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10);
- else
- ydpi = xdpi;
- }
+ 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;
+ xdpi = ydpi = 300;
}
attr->values[i].resolution.xres = xdpi;
- attr->values[i].resolution.yres = xdpi;
+ attr->values[i].resolution.yres = ydpi;
attr->values[i].resolution.units = IPP_RES_PER_INCH;
if (choice->marked)
* Just the DefaultResolution to report...
*/
- xdpi = (int)strtol(ppd_attr->value, (char **)&resptr, 10);
+ xdpi = ydpi = (int)strtol(ppd_attr->value, (char **)&resptr, 10);
if (resptr > ppd_attr->value && xdpi > 0)
{
if (*resptr == 'x')
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)
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;
}
/*
- * 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 ++)
+ if (p->pc)
{
- 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))
- {
- /*
- * 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, "w")) != 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);
+ _ppdCacheWriteFile(p->pc, cache_name, p->ppd_attrs);
}
- else if (cache_info.st_mtime)
+ else
{
/*
- * Remove cache file...
+ * Remove cache files...
*/
- unlink(cache_name);
+ if (cache_info.st_mtime)
+ unlink(cache_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