#include "cupsd.h"
#include <cups/dir.h>
#ifdef HAVE_APPLICATIONSERVICES_H
# include <ApplicationServices/ApplicationServices.h>
#endif
#ifdef HAVE_SYS_MOUNT_H
# include <sys/mount.h>
#endif
#ifdef HAVE_SYS_STATFS_H
# include <sys/statfs.h>
#endif
#ifdef HAVE_SYS_STATVFS_H
# include <sys/statvfs.h>
#endif
#ifdef HAVE_SYS_VFS_H
# include <sys/vfs.h>
#endif
static void add_printer_defaults(cupsd_printer_t *p);
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 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);
#endif
static void write_xml_string(cups_file_t *fp, const char *s);
cupsd_printer_t *
cupsdAddPrinter(const char *name)
{
cupsd_printer_t *p;
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddPrinter(\"%s\")", name);
if ((p = calloc(1, sizeof(cupsd_printer_t))) == NULL)
{
cupsdLogMessage(CUPSD_LOG_CRIT, "Unable to allocate memory for printer - %s",
strerror(errno));
return (NULL);
}
cupsdSetString(&p->name, name);
cupsdSetString(&p->info, name);
cupsdSetString(&p->hostname, ServerName);
cupsdSetStringf(&p->uri, "ipp://%s:%d/printers/%s", ServerName, RemotePort,
name);
cupsdSetDeviceURI(p, "file:///dev/null");
p->state = IPP_PRINTER_STOPPED;
p->state_time = time(NULL);
p->accepting = 0;
p->shared = DefaultShared;
p->filetype = mimeAddType(MimeDatabase, "printer", name);
cupsdSetString(&p->job_sheets[0], "none");
cupsdSetString(&p->job_sheets[1], "none");
cupsdSetString(&p->error_policy, ErrorPolicy);
cupsdSetString(&p->op_policy, DefaultPolicy);
p->op_policy_ptr = DefaultPolicyPtr;
if (MaxPrinterHistory)
p->history = calloc(MaxPrinterHistory, sizeof(ipp_t *));
if (!Printers)
Printers = cupsArrayNew(compare_printers, NULL);
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdAddPrinter: Adding %s to Printers", p->name);
cupsArrayAdd(Printers, p);
if (!ImplicitPrinters)
ImplicitPrinters = cupsArrayNew(compare_printers, NULL);
return (p);
}
void
cupsdAddPrinterHistory(
cupsd_printer_t *p)
{
ipp_t *history;
if (MaxPrinterHistory <= 0)
return;
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 *));
}
history = ippNew();
ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
p->state);
ippAddBoolean(history, IPP_TAG_PRINTER, "printer-is-accepting-jobs",
p->accepting);
ippAddBoolean(history, IPP_TAG_PRINTER, "printer-is-shared", p->shared);
ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-state-message",
NULL, p->state_message);
#ifdef __APPLE__
if (p->recoverable)
ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT,
"com.apple.print.recoverable-message", NULL, p->recoverable);
#endif
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 ++;
}
void
cupsdAddPrinterUser(
cupsd_printer_t *p,
const char *username)
{
const char **temp;
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 ++;
}
void
cupsdCreateCommonData(void)
{
int i;
ipp_attribute_t *attr;
cups_dir_t *dir;
cups_dentry_t *dent;
cups_array_t *notifiers;
char filename[1024],
*notifier;
cupsd_policy_t *p;
int k_supported;
#ifdef HAVE_STATFS
struct statfs spoolinfo;
double spoolsize;
#elif defined(HAVE_STATVFS)
struct statvfs spoolinfo;
double spoolsize;
#endif
static const int nups[] =
{ 1, 2, 4, 6, 9, 16 };
static const int orients[4] =
{
IPP_PORTRAIT,
IPP_LANDSCAPE,
IPP_REVERSE_LANDSCAPE,
IPP_REVERSE_PORTRAIT
};
static const char * const holds[] =
{
"no-hold",
"indefinite",
"day-time",
"evening",
"night",
"second-shift",
"third-shift",
"weekend"
};
static const char * const versions[] =
{
"1.0",
"1.1",
"2.0",
"2.1"
};
static const int ops[] =
{
IPP_PRINT_JOB,
IPP_VALIDATE_JOB,
IPP_CREATE_JOB,
IPP_SEND_DOCUMENT,
IPP_CANCEL_JOB,
IPP_GET_JOB_ATTRIBUTES,
IPP_GET_JOBS,
IPP_GET_PRINTER_ATTRIBUTES,
IPP_HOLD_JOB,
IPP_RELEASE_JOB,
IPP_PAUSE_PRINTER,
IPP_RESUME_PRINTER,
IPP_PURGE_JOBS,
IPP_SET_PRINTER_ATTRIBUTES,
IPP_SET_JOB_ATTRIBUTES,
IPP_GET_PRINTER_SUPPORTED_VALUES,
IPP_CREATE_PRINTER_SUBSCRIPTION,
IPP_CREATE_JOB_SUBSCRIPTION,
IPP_GET_SUBSCRIPTION_ATTRIBUTES,
IPP_GET_SUBSCRIPTIONS,
IPP_RENEW_SUBSCRIPTION,
IPP_CANCEL_SUBSCRIPTION,
IPP_GET_NOTIFICATIONS,
IPP_ENABLE_PRINTER,
IPP_DISABLE_PRINTER,
IPP_HOLD_NEW_JOBS,
IPP_RELEASE_HELD_NEW_JOBS,
CUPS_GET_DEFAULT,
CUPS_GET_PRINTERS,
CUPS_ADD_PRINTER,
CUPS_DELETE_PRINTER,
CUPS_GET_CLASSES,
CUPS_ADD_CLASS,
CUPS_DELETE_CLASS,
CUPS_ACCEPT_JOBS,
CUPS_REJECT_JOBS,
CUPS_SET_DEFAULT,
CUPS_GET_DEVICES,
CUPS_GET_PPDS,
CUPS_MOVE_JOB,
CUPS_AUTHENTICATE_JOB,
CUPS_GET_PPD,
CUPS_GET_DOCUMENT,
IPP_RESTART_JOB
};
static const char * const charsets[] =
{
"us-ascii",
"utf-8"
};
static const char * const compressions[] =
{
"none"
#ifdef HAVE_LIBZ
,"gzip"
#endif
};
static const char * const media_col_supported[] =
{
"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[] =
{
"separate-documents-uncollated-copies",
"separate-documents-collated-copies"
};
static const char * const notify_attrs[] =
{
"printer-state-change-time",
"notify-lease-expiration-time",
"notify-subscriber-user-name"
};
static const char * const notify_events[] =
{
"job-completed",
"job-config-changed",
"job-created",
"job-progress",
"job-state-changed",
"job-stopped",
"printer-added",
"printer-changed",
"printer-config-changed",
"printer-deleted",
"printer-finishings-changed",
"printer-media-changed",
"printer-modified",
"printer-restarted",
"printer-shutdown",
"printer-state-changed",
"printer-stopped",
"server-audit",
"server-restarted",
"server-started",
"server-stopped"
};
static const char * const job_creation[] =
{
"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[] =
{
"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-resolution",
"sides"
};
static const char * const pdf_versions[] =
{
"adobe-1.2",
"adobe-1.3",
"adobe-1.4",
"adobe-1.5",
"adobe-1.6",
"adobe-1.7",
"iso-19005-1_2005",
"iso-32000-1_2008",
"pwg-5102.3"
};
static const char * const printer_settable[] =
{
"printer-info",
"printer-location"
};
if (CommonData)
ippDelete(CommonData);
CommonData = ippNew();
#ifdef 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;
#elif defined(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;
#else
k_supported = INT_MAX;
#endif
ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY,
"charset-configured", NULL, "utf-8");
ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY,
"charset-supported", sizeof(charsets) / sizeof(charsets[0]),
NULL, charsets);
ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
"compression-supported",
sizeof(compressions) / sizeof(compressions[0]),
NULL, compressions);
ippAddRange(CommonData, IPP_TAG_PRINTER, "copies-supported", 1, MaxCopies);
ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_TEXT | IPP_TAG_COPY,
"cups-version", NULL, CUPS_SVERSION + 6);
ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
"generated-natural-language-supported", NULL, DefaultLanguage);
ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
"ipp-versions-supported", sizeof(versions) / sizeof(versions[0]),
NULL, versions);
ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"ippget-event-life", 15);
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);
ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
"job-hold-until-supported", sizeof(holds) / sizeof(holds[0]),
NULL, holds);
ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"job-priority-supported", 100);
ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
"job-settable-attributes-supported",
sizeof(job_settable) / sizeof(job_settable[0]),
NULL, job_settable);
if (cupsArrayCount(Banners) > 0)
{
if (Classification && !ClassifyOverride)
attr = ippAddString(CommonData, IPP_TAG_PRINTER,
IPP_TAG_NAME | IPP_TAG_COPY,
"job-sheets-supported", NULL, Classification);
else
attr = ippAddStrings(CommonData, IPP_TAG_PRINTER,
IPP_TAG_NAME | IPP_TAG_COPY,
"job-sheets-supported", cupsArrayCount(Banners) + 1,
NULL, NULL);
if (attr == NULL)
cupsdLogMessage(CUPSD_LOG_EMERG,
"Unable to allocate memory for "
"job-sheets-supported attribute: %s!", strerror(errno));
else if (!Classification || ClassifyOverride)
{
cupsd_banner_t *banner;
attr->values[0].string.text = _cupsStrAlloc("none");
for (i = 1, banner = (cupsd_banner_t *)cupsArrayFirst(Banners);
banner;
i ++, banner = (cupsd_banner_t *)cupsArrayNext(Banners))
attr->values[i].string.text = banner->name;
}
}
else
ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
"job-sheets-supported", NULL, "none");
ippAddRange(CommonData, IPP_TAG_PRINTER, "jpeg-k-octets-supported", 0,
k_supported);
ippAddRange(CommonData, IPP_TAG_PRINTER, "jpeg-x-dimension-supported", 0,
65535);
ippAddRange(CommonData, IPP_TAG_PRINTER, "jpeg-y-dimension-supported", 1,
65535);
ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
"media-col-supported",
sizeof(media_col_supported) /
sizeof(media_col_supported[0]), NULL,
media_col_supported);
ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
"multiple-document-handling-supported",
sizeof(multiple_document_handling) /
sizeof(multiple_document_handling[0]), NULL,
multiple_document_handling);
ippAddBoolean(CommonData, IPP_TAG_PRINTER,
"multiple-document-jobs-supported", 1);
ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"multiple-operation-time-out", MultipleOperationTimeout);
ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
"natural-language-configured", NULL, DefaultLanguage);
ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
"notify-attributes-supported",
(int)(sizeof(notify_attrs) / sizeof(notify_attrs[0])),
NULL, notify_attrs);
ippAddRange(CommonData, IPP_TAG_PRINTER,
"notify-lease-duration-supported", 0,
MaxLeaseDuration ? MaxLeaseDuration : 2147483647);
ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"notify-max-events-supported", MaxEvents);
ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
"notify-events-supported",
(int)(sizeof(notify_events) / sizeof(notify_events[0])),
NULL, notify_events);
ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
"notify-pull-method-supported", NULL, "ippget");
snprintf(filename, sizeof(filename), "%s/notifier", ServerBin);
if ((dir = cupsDirOpen(filename)) != NULL)
{
notifiers = cupsArrayNew((cups_array_func_t)strcmp, NULL);
while ((dent = cupsDirRead(dir)) != NULL)
if (S_ISREG(dent->fileinfo.st_mode) &&
(dent->fileinfo.st_mode & S_IXOTH) != 0)
cupsArrayAdd(notifiers, _cupsStrAlloc(dent->filename));
if (cupsArrayCount(notifiers) > 0)
{
attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"notify-schemes-supported",
cupsArrayCount(notifiers), NULL, NULL);
for (i = 0, notifier = (char *)cupsArrayFirst(notifiers);
notifier;
i ++, notifier = (char *)cupsArrayNext(notifiers))
attr->values[i].string.text = notifier;
}
cupsArrayDelete(notifiers);
cupsDirClose(dir);
}
ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"number-up-supported", sizeof(nups) / sizeof(nups[0]), nups);
ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
"operations-supported",
sizeof(ops) / sizeof(ops[0]) + JobFiles - 1, ops);
ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
"orientation-requested-supported", 4, orients);
ippAddBoolean(CommonData, IPP_TAG_PRINTER, "page-ranges-supported", 1);
ippAddRange(CommonData, IPP_TAG_PRINTER, "pdf-k-octets-supported", 0,
k_supported);
ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
"pdf-versions-supported",
sizeof(pdf_versions) / sizeof(pdf_versions[0]), NULL,
pdf_versions);
ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
"pdl-override-supported", NULL, "attempted");
attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
"printer-op-policy-supported", cupsArrayCount(Policies),
NULL, NULL);
for (i = 0, p = (cupsd_policy_t *)cupsArrayFirst(Policies);
p;
i ++, p = (cupsd_policy_t *)cupsArrayNext(Policies))
attr->values[i].string.text = p->name;
ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
"printer-settable-attributes-supported",
sizeof(printer_settable) / sizeof(printer_settable[0]),
NULL, printer_settable);
ippAddBoolean(CommonData, IPP_TAG_PRINTER, "server-is-sharing-printers",
BrowseLocalProtocols != 0 && Browsing);
}
void
cupsdDeleteAllPrinters(void)
{
cupsd_printer_t *p;
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
p;
p = (cupsd_printer_t *)cupsArrayNext(Printers))
{
p->op_policy_ptr = DefaultPolicyPtr;
cupsdDeletePrinter(p, 0);
}
}
int
cupsdDeletePrinter(
cupsd_printer_t *p,
int update)
{
int i,
changed = 0;
#ifdef __sgi
char filename[1024];
#endif
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDeletePrinter(p=%p(%s), update=%d)",
p, p->name, update);
cupsArraySave(Printers);
cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update);
if (p->job)
cupsdSetJobState(p->job, IPP_JOB_PENDING, CUPSD_JOB_FORCE,
update ? "Job stopped due to printer being deleted." :
"Job stopped.");
if (p == BrowseNext)
{
cupsArrayFind(Printers, p);
BrowseNext = (cupsd_printer_t *)cupsArrayNext(Printers);
}
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdDeletePrinter: Removing %s from Printers", p->name);
cupsArrayRemove(Printers, p);
if (p->type & CUPS_PRINTER_IMPLICIT)
{
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdDeletePrinter: Removing %s from ImplicitPrinters",
p->name);
cupsArrayRemove(ImplicitPrinters, p);
}
#ifdef __sgi
snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
unlink(filename);
snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui",
p->name);
unlink(filename);
snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
unlink(filename);
snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
unlink(filename);
snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
unlink(filename);
snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
unlink(filename);
#endif
if (p == DefaultPrinter)
{
DefaultPrinter = NULL;
if (UseNetworkDefault)
{
cupsd_printer_t *dp;
for (dp = (cupsd_printer_t *)cupsArrayFirst(Printers);
dp;
dp = (cupsd_printer_t *)cupsArrayNext(Printers))
if (dp != p && (dp->type & CUPS_PRINTER_DEFAULT))
{
DefaultPrinter = dp;
break;
}
}
}
if (!(p->type & CUPS_PRINTER_IMPLICIT))
{
changed = cupsdDeletePrinterFromClasses(p);
cupsdDeregisterPrinter(p, 1);
}
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 ++)
_cupsStrFree(p->reasons[i]);
ippDelete(p->attrs);
ippDelete(p->ppd_attrs);
mimeDeleteType(MimeDatabase, p->filetype);
mimeDeleteType(MimeDatabase, p->prefiltertype);
delete_string_array(&(p->filters));
delete_string_array(&(p->pre_filters));
cupsdFreePrinterUsers(p);
cupsdFreeQuotas(p);
cupsdClearString(&p->uri);
cupsdClearString(&p->hostname);
cupsdClearString(&p->name);
cupsdClearString(&p->location);
cupsdClearString(&p->make_model);
cupsdClearString(&p->info);
cupsdClearString(&p->job_sheets[0]);
cupsdClearString(&p->job_sheets[1]);
cupsdClearString(&p->device_uri);
cupsdClearString(&p->sanitized_device_uri);
cupsdClearString(&p->port_monitor);
cupsdClearString(&p->op_policy);
cupsdClearString(&p->error_policy);
cupsdClearString(&p->alert);
cupsdClearString(&p->alert_description);
#ifdef HAVE_DNSSD
cupsdClearString(&p->product);
cupsdClearString(&p->pdl);
#endif
cupsArrayDelete(p->filetypes);
if (p->browse_attrs)
free(p->browse_attrs);
#ifdef __APPLE__
cupsdClearString(&p->recoverable);
#endif
cupsFreeOptions(p->num_options, p->options);
free(p);
cupsArrayRestore(Printers);
return (changed);
}
cupsd_printer_t *
cupsdFindDest(const char *name)
{
cupsd_printer_t key;
key.name = (char *)name;
return ((cupsd_printer_t *)cupsArrayFind(Printers, &key));
}
cupsd_printer_t *
cupsdFindPrinter(const char *name)
{
cupsd_printer_t *p;
if ((p = cupsdFindDest(name)) != NULL && (p->type & CUPS_PRINTER_CLASS))
return (NULL);
else
return (p);
}
void
cupsdFreePrinterUsers(
cupsd_printer_t *p)
{
int i;
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;
}
void
cupsdLoadAllPrinters(void)
{
int i;
cups_file_t *fp;
int linenum;
char line[4096],
*value,
*valueptr;
cupsd_printer_t *p;
snprintf(line, sizeof(line), "%s/printers.conf", ServerRoot);
if ((fp = cupsFileOpen(line, "r")) == NULL)
{
if (errno != ENOENT)
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open %s - %s", line,
strerror(errno));
return;
}
linenum = 0;
p = NULL;
while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
{
if (!strcasecmp(line, "<Printer") ||
!strcasecmp(line, "<DefaultPrinter"))
{
if (p == NULL && value)
{
cupsdLogMessage(CUPSD_LOG_DEBUG, "Loading printer %s...", value);
p = cupsdAddPrinter(value);
p->accepting = 1;
p->state = IPP_PRINTER_IDLE;
if (!strcasecmp(line, "<DefaultPrinter"))
DefaultPrinter = p;
}
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
else if (!strcasecmp(line, "</Printer>"))
{
if (p != NULL)
{
cupsdSetPrinterAttrs(p);
cupsdAddPrinterHistory(p);
if (strncmp(p->device_uri, "file:", 5) &&
p->state != IPP_PRINTER_STOPPED)
{
snprintf(line, sizeof(line), "%s/backend/%s", ServerBin,
p->device_uri);
if ((valueptr = strchr(line + strlen(ServerBin), ':')) != NULL)
*valueptr = '\0';
if (access(line, 0))
{
p->state = IPP_PRINTER_STOPPED;
snprintf(p->state_message, sizeof(p->state_message),
"Backend %s does not exist!", line);
}
}
p = NULL;
}
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
else if (!p)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
else if (!strcasecmp(line, "AuthInfoRequired"))
{
if (!cupsdSetAuthInfoRequired(p, value, NULL))
cupsdLogMessage(CUPSD_LOG_ERROR,
"Bad AuthInfoRequired on line %d of printers.conf.",
linenum);
}
else if (!strcasecmp(line, "Info"))
{
if (value)
cupsdSetString(&p->info, value);
}
else if (!strcasecmp(line, "MakeModel"))
{
if (value)
cupsdSetString(&p->make_model, value);
}
else if (!strcasecmp(line, "Location"))
{
if (value)
cupsdSetString(&p->location, value);
}
else if (!strcasecmp(line, "DeviceURI"))
{
if (value)
cupsdSetDeviceURI(p, value);
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
else if (!strcasecmp(line, "Option") && value)
{
for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
if (!*valueptr)
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
else
{
for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
p->num_options = cupsAddOption(value, valueptr, p->num_options,
&(p->options));
}
}
else if (!strcasecmp(line, "PortMonitor"))
{
if (value && strcmp(value, "none"))
cupsdSetString(&p->port_monitor, value);
else if (value)
cupsdClearString(&p->port_monitor);
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
else if (!strcasecmp(line, "Reason"))
{
if (value &&
strcmp(value, "com.apple.print.recoverable-warning") &&
strcmp(value, "connecting-to-device") &&
strcmp(value, "cups-insecure-filter-warning") &&
strcmp(value, "cups-missing-filter-warning"))
{
for (i = 0 ; i < p->num_reasons; i ++)
if (!strcmp(value, p->reasons[i]))
break;
if (i >= p->num_reasons &&
p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
{
p->reasons[p->num_reasons] = _cupsStrAlloc(value);
p->num_reasons ++;
}
}
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
else if (!strcasecmp(line, "State"))
{
if (value && !strcasecmp(value, "idle"))
p->state = IPP_PRINTER_IDLE;
else if (value && !strcasecmp(value, "stopped"))
{
p->state = IPP_PRINTER_STOPPED;
for (i = 0 ; i < p->num_reasons; i ++)
if (!strcmp("paused", p->reasons[i]))
break;
if (i >= p->num_reasons &&
p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
{
p->reasons[p->num_reasons] = _cupsStrAlloc("paused");
p->num_reasons ++;
}
}
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
else if (!strcasecmp(line, "StateMessage"))
{
if (value)
strlcpy(p->state_message, value, sizeof(p->state_message));
}
else if (!strcasecmp(line, "StateTime"))
{
if (value)
p->state_time = atoi(value);
}
else if (!strcasecmp(line, "Accepting"))
{
if (value &&
(!strcasecmp(value, "yes") ||
!strcasecmp(value, "on") ||
!strcasecmp(value, "true")))
p->accepting = 1;
else if (value &&
(!strcasecmp(value, "no") ||
!strcasecmp(value, "off") ||
!strcasecmp(value, "false")))
p->accepting = 0;
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
else if (!strcasecmp(line, "Type"))
{
if (value)
p->type = atoi(value);
else
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
}
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 &&
(!strcasecmp(value, "yes") ||
!strcasecmp(value, "on") ||
!strcasecmp(value, "true")))
p->shared = 1;
else if (value &&
(!strcasecmp(value, "no") ||
!strcasecmp(value, "off") ||
!strcasecmp(value, "false")))
p->shared = 0;
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
else if (!strcasecmp(line, "JobSheets"))
{
if (value)
{
for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
if (*valueptr)
*valueptr++ = '\0';
cupsdSetString(&p->job_sheets[0], value);
while (isspace(*valueptr & 255))
valueptr ++;
if (*valueptr)
{
for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++);
if (*valueptr)
*valueptr = '\0';
cupsdSetString(&p->job_sheets[1], value);
}
}
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
else if (!strcasecmp(line, "AllowUser"))
{
if (value)
{
p->deny_users = 0;
cupsdAddPrinterUser(p, value);
}
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
else if (!strcasecmp(line, "DenyUser"))
{
if (value)
{
p->deny_users = 1;
cupsdAddPrinterUser(p, value);
}
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
else if (!strcasecmp(line, "QuotaPeriod"))
{
if (value)
p->quota_period = atoi(value);
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
else if (!strcasecmp(line, "PageLimit"))
{
if (value)
p->page_limit = atoi(value);
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
else if (!strcasecmp(line, "KLimit"))
{
if (value)
p->k_limit = atoi(value);
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
else if (!strcasecmp(line, "OpPolicy"))
{
if (value)
{
cupsd_policy_t *pol;
if ((pol = cupsdFindPolicy(value)) != NULL)
{
cupsdSetString(&p->op_policy, value);
p->op_policy_ptr = pol;
}
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Bad policy \"%s\" on line %d of printers.conf",
value, linenum);
}
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
else if (!strcasecmp(line, "ErrorPolicy"))
{
if (value)
cupsdSetString(&p->error_policy, value);
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
}
else if (!strcasecmp(line, "Attribute") && value)
{
for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
if (!*valueptr)
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of printers.conf.", linenum);
else
{
for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
if (!p->attrs)
cupsdSetPrinterAttrs(p);
if (!strcmp(value, "marker-change-time"))
p->marker_time = atoi(valueptr);
else
cupsdSetPrinterAttr(p, value, valueptr);
}
}
else
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unknown configuration directive %s on line %d of printers.conf.",
line, linenum);
}
}
cupsFileClose(fp);
}
void
cupsdRenamePrinter(
cupsd_printer_t *p,
const char *name)
{
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdRenamePrinter: Removing %s from Printers", p->name);
cupsArrayRemove(Printers, p);
if (p->type & CUPS_PRINTER_IMPLICIT)
{
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdRenamePrinter: Removing %s from ImplicitPrinters",
p->name);
cupsArrayRemove(ImplicitPrinters, p);
}
mimeDeleteType(MimeDatabase, p->filetype);
p->filetype = mimeAddType(MimeDatabase, "printer", name);
mimeDeleteType(MimeDatabase, p->prefiltertype);
p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", name);
cupsdSetString(&p->name, name);
cupsdSetPrinterAttrs(p);
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdRenamePrinter: Adding %s to Printers", p->name);
cupsArrayAdd(Printers, p);
if (p->type & CUPS_PRINTER_IMPLICIT)
{
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdRenamePrinter: Adding %s to ImplicitPrinters",
p->name);
cupsArrayAdd(ImplicitPrinters, p);
}
}
void
cupsdSaveAllPrinters(void)
{
int i;
cups_file_t *fp;
char temp[1024],
backup[1024],
value[2048],
*ptr;
cupsd_printer_t *printer;
time_t curtime;
struct tm *curdate;
cups_option_t *option;
ipp_attribute_t *marker;
snprintf(temp, sizeof(temp), "%s/printers.conf", ServerRoot);
snprintf(backup, sizeof(backup), "%s/printers.conf.O", ServerRoot);
if (rename(temp, backup))
{
if (errno != ENOENT)
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to backup printers.conf - %s", strerror(errno));
}
if ((fp = cupsFileOpen(temp, "w")) == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to save printers.conf - %s", strerror(errno));
if (rename(backup, temp))
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to restore printers.conf - %s", strerror(errno));
return;
}
else
cupsdLogMessage(CUPSD_LOG_INFO, "Saving printers.conf...");
fchown(cupsFileNumber(fp), getuid(), Group);
fchmod(cupsFileNumber(fp), 0600);
curtime = time(NULL);
curdate = localtime(&curtime);
strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
cupsFilePuts(fp, "# Printer configuration file for " CUPS_SVERSION "\n");
cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
cupsFilePuts(fp, "# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING\n");
for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
printer;
printer = (cupsd_printer_t *)cupsArrayNext(Printers))
{
if ((printer->type & CUPS_PRINTER_DISCOVERED) ||
(printer->type & CUPS_PRINTER_CLASS) ||
(printer->type & CUPS_PRINTER_IMPLICIT))
continue;
if (printer == DefaultPrinter)
cupsFilePrintf(fp, "<DefaultPrinter %s>\n", printer->name);
else
cupsFilePrintf(fp, "<Printer %s>\n", printer->name);
if (printer->num_auth_info_required > 0)
{
switch (printer->num_auth_info_required)
{
case 1 :
strlcpy(value, printer->auth_info_required[0], sizeof(value));
break;
case 2 :
snprintf(value, sizeof(value), "%s,%s",
printer->auth_info_required[0],
printer->auth_info_required[1]);
break;
case 3 :
default :
snprintf(value, sizeof(value), "%s,%s,%s",
printer->auth_info_required[0],
printer->auth_info_required[1],
printer->auth_info_required[2]);
break;
}
cupsFilePutConf(fp, "AuthInfoRequired", value);
}
if (printer->info)
cupsFilePutConf(fp, "Info", printer->info);
if (printer->location)
cupsFilePutConf(fp, "Location", printer->location);
if (printer->make_model)
cupsFilePutConf(fp, "MakeModel", printer->make_model);
cupsFilePutConf(fp, "DeviceURI", printer->device_uri);
if (printer->port_monitor)
cupsFilePutConf(fp, "PortMonitor", printer->port_monitor);
if (printer->state == IPP_PRINTER_STOPPED)
{
cupsFilePuts(fp, "State Stopped\n");
if (printer->state_message)
cupsFilePutConf(fp, "StateMessage", printer->state_message);
}
else
cupsFilePuts(fp, "State Idle\n");
cupsFilePrintf(fp, "StateTime %d\n", (int)printer->state_time);
for (i = 0; i < printer->num_reasons; i ++)
if (strcmp(printer->reasons[i], "com.apple.print.recoverable-warning") &&
strcmp(printer->reasons[i], "connecting-to-device") &&
strcmp(printer->reasons[i], "cups-insecure-filter-warning") &&
strcmp(printer->reasons[i], "cups-missing-filter-warning"))
cupsFilePutConf(fp, "Reason", printer->reasons[i]);
cupsFilePrintf(fp, "Type %d\n", printer->type);
#ifdef HAVE_DNSSD
if (printer->product)
cupsFilePutConf(fp, "Product", printer->product);
#endif
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
cupsFilePuts(fp, "Accepting No\n");
if (printer->shared)
cupsFilePuts(fp, "Shared Yes\n");
else
cupsFilePuts(fp, "Shared No\n");
snprintf(value, sizeof(value), "%s %s", printer->job_sheets[0],
printer->job_sheets[1]);
cupsFilePutConf(fp, "JobSheets", value);
cupsFilePrintf(fp, "QuotaPeriod %d\n", printer->quota_period);
cupsFilePrintf(fp, "PageLimit %d\n", printer->page_limit);
cupsFilePrintf(fp, "KLimit %d\n", printer->k_limit);
for (i = 0; i < printer->num_users; i ++)
cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser",
printer->users[i]);
if (printer->op_policy)
cupsFilePutConf(fp, "OpPolicy", printer->op_policy);
if (printer->error_policy)
cupsFilePutConf(fp, "ErrorPolicy", printer->error_policy);
for (i = printer->num_options, option = printer->options;
i > 0;
i --, option ++)
{
snprintf(value, sizeof(value), "%s %s", option->name, option->value);
cupsFilePutConf(fp, "Option", value);
}
if ((marker = ippFindAttribute(printer->attrs, "marker-colors",
IPP_TAG_NAME)) != NULL)
{
snprintf(value, sizeof(value), "%s ", marker->name);
for (i = 0, ptr = value + strlen(value);
i < marker->num_values && ptr < (value + sizeof(value) - 1);
i ++)
{
if (i)
*ptr++ = ',';
strlcpy(ptr, marker->values[i].string.text,
value + sizeof(value) - ptr);
ptr += strlen(ptr);
}
*ptr = '\0';
cupsFilePutConf(fp, "Attribute", value);
}
if ((marker = ippFindAttribute(printer->attrs, "marker-levels",
IPP_TAG_INTEGER)) != NULL)
{
cupsFilePrintf(fp, "Attribute %s %d", marker->name,
marker->values[0].integer);
for (i = 1; i < marker->num_values; i ++)
cupsFilePrintf(fp, ",%d", marker->values[i].integer);
cupsFilePuts(fp, "\n");
}
if ((marker = ippFindAttribute(printer->attrs, "marker-low-levels",
IPP_TAG_INTEGER)) != NULL)
{
cupsFilePrintf(fp, "Attribute %s %d", marker->name,
marker->values[0].integer);
for (i = 1; i < marker->num_values; i ++)
cupsFilePrintf(fp, ",%d", marker->values[i].integer);
cupsFilePuts(fp, "\n");
}
if ((marker = ippFindAttribute(printer->attrs, "marker-high-levels",
IPP_TAG_INTEGER)) != NULL)
{
cupsFilePrintf(fp, "Attribute %s %d", marker->name,
marker->values[0].integer);
for (i = 1; i < marker->num_values; i ++)
cupsFilePrintf(fp, ",%d", marker->values[i].integer);
cupsFilePuts(fp, "\n");
}
if ((marker = ippFindAttribute(printer->attrs, "marker-message",
IPP_TAG_TEXT)) != NULL)
{
snprintf(value, sizeof(value), "%s %s", marker->name,
marker->values[0].string.text);
cupsFilePutConf(fp, "Attribute", value);
}
if ((marker = ippFindAttribute(printer->attrs, "marker-names",
IPP_TAG_NAME)) != NULL)
{
snprintf(value, sizeof(value), "%s ", marker->name);
for (i = 0, ptr = value + strlen(value);
i < marker->num_values && ptr < (value + sizeof(value) - 1);
i ++)
{
if (i)
*ptr++ = ',';
strlcpy(ptr, marker->values[i].string.text,
value + sizeof(value) - ptr);
ptr += strlen(ptr);
}
*ptr = '\0';
cupsFilePutConf(fp, "Attribute", value);
}
if ((marker = ippFindAttribute(printer->attrs, "marker-types",
IPP_TAG_KEYWORD)) != NULL)
{
snprintf(value, sizeof(value), "%s ", marker->name);
for (i = 0, ptr = value + strlen(value);
i < marker->num_values && ptr < (value + sizeof(value) - 1);
i ++)
{
if (i)
*ptr++ = ',';
strlcpy(ptr, marker->values[i].string.text,
value + sizeof(value) - ptr);
ptr += strlen(ptr);
}
*ptr = '\0';
cupsFilePutConf(fp, "Attribute", value);
}
if (printer->marker_time)
cupsFilePrintf(fp, "Attribute marker-change-time %ld\n",
(long)printer->marker_time);
cupsFilePuts(fp, "</Printer>\n");
#ifdef __sgi
write_irix_state(printer);
#endif
}
cupsFileClose(fp);
}
int
cupsdSetAuthInfoRequired(
cupsd_printer_t *p,
const char *values,
ipp_attribute_t *attr)
{
int i;
p->num_auth_info_required = 0;
if (values)
{
const char *end;
while (*values && p->num_auth_info_required < 4)
{
if ((end = strchr(values, ',')) == NULL)
end = values + strlen(values);
if ((end - values) == 4 && !strncmp(values, "none", 4))
{
if (p->num_auth_info_required != 0 || *end)
return (0);
p->auth_info_required[p->num_auth_info_required] = "none";
p->num_auth_info_required ++;
return (1);
}
else if ((end - values) == 9 && !strncmp(values, "negotiate", 9))
{
if (p->num_auth_info_required != 0 || *end)
return (0);
p->auth_info_required[p->num_auth_info_required] = "negotiate";
p->num_auth_info_required ++;
}
else if ((end - values) == 6 && !strncmp(values, "domain", 6))
{
p->auth_info_required[p->num_auth_info_required] = "domain";
p->num_auth_info_required ++;
}
else if ((end - values) == 8 && !strncmp(values, "password", 8))
{
p->auth_info_required[p->num_auth_info_required] = "password";
p->num_auth_info_required ++;
}
else if ((end - values) == 8 && !strncmp(values, "username", 8))
{
p->auth_info_required[p->num_auth_info_required] = "username";
p->num_auth_info_required ++;
}
else
return (0);
values = (*end) ? end + 1 : end;
}
if (p->num_auth_info_required == 0)
{
p->auth_info_required[0] = "none";
p->num_auth_info_required = 1;
}
if (p->num_auth_info_required > 1 ||
strcmp(p->auth_info_required[0], "none"))
p->type |= CUPS_PRINTER_AUTHENTICATED;
else
p->type &= ~CUPS_PRINTER_AUTHENTICATED;
return (1);
}
if (!attr || attr->num_values > 4)
return (0);
if (attr->num_values > 1 ||
strcmp(attr->values[0].string.text, "none"))
p->type |= CUPS_PRINTER_AUTHENTICATED;
else
p->type &= ~CUPS_PRINTER_AUTHENTICATED;
for (i = 0; i < attr->num_values; i ++)
{
if (!strcmp(attr->values[i].string.text, "none"))
{
if (p->num_auth_info_required != 0 || attr->num_values != 1)
return (0);
p->auth_info_required[p->num_auth_info_required] = "none";
p->num_auth_info_required ++;
return (1);
}
else if (!strcmp(attr->values[i].string.text, "negotiate"))
{
if (p->num_auth_info_required != 0 || attr->num_values != 1)
return (0);
p->auth_info_required[p->num_auth_info_required] = "negotiate";
p->num_auth_info_required ++;
return (1);
}
else if (!strcmp(attr->values[i].string.text, "domain"))
{
p->auth_info_required[p->num_auth_info_required] = "domain";
p->num_auth_info_required ++;
}
else if (!strcmp(attr->values[i].string.text, "password"))
{
p->auth_info_required[p->num_auth_info_required] = "password";
p->num_auth_info_required ++;
}
else if (!strcmp(attr->values[i].string.text, "username"))
{
p->auth_info_required[p->num_auth_info_required] = "username";
p->num_auth_info_required ++;
}
else
return (0);
}
return (1);
}
void
cupsdSetDeviceURI(cupsd_printer_t *p,
const char *uri)
{
char buffer[1024],
*start,
*slash,
*ptr;
cupsdSetString(&(p->device_uri), uri);
strlcpy(buffer, uri, sizeof(buffer));
if ((ptr = strchr(buffer, ':')) != NULL)
{
for (start = ptr + 1; *start; start ++)
if (*start != '/')
break;
if ((slash = strchr(start, '/')) == NULL)
slash = start + strlen(start);
if ((ptr = strchr(start, '@')) != NULL && ptr < slash)
{
_cups_strcpy(start, ptr + 1);
}
}
cupsdSetString(&(p->sanitized_device_uri), buffer);
}
void
cupsdSetPrinterAttr(
cupsd_printer_t *p,
const char *name,
char *value)
{
ipp_attribute_t *attr;
int i,
count;
char *ptr;
ipp_tag_t value_tag;
if (!*value && strcmp(name, "marker-message"))
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Ignoring empty \"%s\" attribute", name);
return;
}
for (count = 1, ptr = value;
(ptr = strchr(ptr, ',')) != NULL;
ptr ++, count ++);
if (!strcmp(name, "marker-levels") || !strcmp(name, "marker-low-levels") ||
!strcmp(name, "marker-high-levels"))
{
if ((attr = ippFindAttribute(p->attrs, name, IPP_TAG_INTEGER)) != NULL &&
attr->num_values < count)
{
ippDeleteAttribute(p->attrs, attr);
attr = NULL;
}
if (attr)
attr->num_values = count;
else
attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, name,
count, NULL);
if (!attr)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to allocate memory for printer attribute "
"(%d values)", count);
return;
}
for (i = 0; i < count; i ++)
{
if ((ptr = strchr(value, ',')) != NULL)
*ptr++ = '\0';
attr->values[i].integer = strtol(value, NULL, 10);
if (ptr)
value = ptr;
}
}
else
{
if (!strcmp(name, "marker-types"))
value_tag = IPP_TAG_KEYWORD;
else if (!strcmp(name, "marker-message"))
value_tag = IPP_TAG_TEXT;
else
value_tag = IPP_TAG_NAME;
if ((attr = ippFindAttribute(p->attrs, name, value_tag)) != NULL &&
attr->num_values < count)
{
ippDeleteAttribute(p->attrs, attr);
attr = NULL;
}
if (attr)
{
for (i = 0; i < attr->num_values; i ++)
_cupsStrFree(attr->values[i].string.text);
attr->num_values = count;
}
else
attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, value_tag, name,
count, NULL, NULL);
if (!attr)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to allocate memory for printer attribute "
"(%d values)", count);
return;
}
for (i = 0; i < count; i ++)
{
if ((ptr = strchr(value, ',')) != NULL)
*ptr++ = '\0';
attr->values[i].string.text = _cupsStrAlloc(value);
if (ptr)
value = ptr;
}
}
}
void
cupsdSetPrinterAttrs(cupsd_printer_t *p)
{
int i,
length;
char resource[HTTP_MAX_URI];
int num_air;
const char * const *air;
cupsd_location_t *auth;
const char *auth_supported;
ipp_t *oldattrs;
ipp_attribute_t *attr;
cups_option_t *option;
char *filter;
static const char * const air_none[] =
{
"none"
};
static const char * const air_userpass[] =
{
"username",
"password"
};
DEBUG_printf(("cupsdSetPrinterAttrs: entering name = %s, type = %x\n", p->name,
p->type));
if (!CommonData)
cupsdCreateCommonData();
delete_printer_filters(p);
auth_supported = "requesting-user-name";
num_air = 1;
air = air_none;
if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none"))
{
num_air = p->num_auth_info_required;
air = p->auth_info_required;
}
else if ((p->type & CUPS_PRINTER_AUTHENTICATED) &&
(p->type & CUPS_PRINTER_DISCOVERED))
{
num_air = 2;
air = air_userpass;
}
if (p->type & CUPS_PRINTER_CLASS)
snprintf(resource, sizeof(resource), "/classes/%s", p->name);
else
snprintf(resource, sizeof(resource), "/printers/%s", p->name);
if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
auth->type == CUPSD_AUTH_NONE)
auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
if (auth)
{
int auth_type;
if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT)
auth_type = DefaultAuthType;
if (auth_type == CUPSD_AUTH_BASIC || auth_type == CUPSD_AUTH_BASICDIGEST)
auth_supported = "basic";
else if (auth_type == CUPSD_AUTH_DIGEST)
auth_supported = "digest";
#ifdef HAVE_GSSAPI
else if (auth_type == CUPSD_AUTH_NEGOTIATE)
auth_supported = "negotiate";
#endif
if (!(p->type & CUPS_PRINTER_DISCOVERED))
{
if (auth_type != CUPSD_AUTH_NONE)
p->type |= CUPS_PRINTER_AUTHENTICATED;
else
p->type &= ~CUPS_PRINTER_AUTHENTICATED;
}
}
else if (!(p->type & CUPS_PRINTER_DISCOVERED))
p->type &= ~CUPS_PRINTER_AUTHENTICATED;
oldattrs = p->attrs;
p->attrs = ippNew();
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"uri-authentication-supported", NULL, auth_supported);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"uri-security-supported", NULL, "none");
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL,
p->name);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
NULL, p->location ? p->location : "");
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
NULL, p->info ? p->info : "");
if (p->num_users)
{
if (p->deny_users)
ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
"requesting-user-name-denied", p->num_users, NULL,
p->users);
else
ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
"requesting-user-name-allowed", p->num_users, NULL,
p->users);
}
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"job-quota-period", p->quota_period);
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"job-k-limit", p->k_limit);
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"job-page-limit", p->page_limit);
ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"auth-info-required", num_air, NULL, air);
if (cupsArrayCount(Banners) > 0 && !(p->type & CUPS_PRINTER_DISCOVERED))
{
attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
"job-sheets-default", 2, NULL, NULL);
if (attr != NULL)
{
attr->values[0].string.text = _cupsStrAlloc(Classification ?
Classification : p->job_sheets[0]);
attr->values[1].string.text = _cupsStrAlloc(Classification ?
Classification : p->job_sheets[1]);
}
}
p->raw = 0;
p->remote = 0;
if (p->type & CUPS_PRINTER_DISCOVERED)
{
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);
if (p->make_model)
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
"printer-make-and-model", NULL, p->make_model);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
p->uri);
p->raw = 1;
p->remote = 1;
}
else
{
if (p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
{
p->raw = 1;
p->type &= ~CUPS_PRINTER_OPTIONS;
if ((p->type & CUPS_PRINTER_IMPLICIT) && p->num_printers > 0 &&
p->printers[0]->make_model)
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
"printer-make-and-model", NULL, p->printers[0]->make_model);
else
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
"printer-make-and-model", NULL, "Local Printer Class");
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
"file:///dev/null");
if (p->num_printers > 0)
{
attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
"member-names", p->num_printers, NULL, NULL);
p->type |= CUPS_PRINTER_OPTIONS;
for (i = 0; i < p->num_printers; i ++)
{
if (attr != NULL)
attr->values[i].string.text = _cupsStrRetain(p->printers[i]->name);
p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
}
}
}
else
{
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
p->sanitized_device_uri);
load_ppd(p);
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->pre_filters)
{
p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name);
for (filter = (char *)cupsArrayFirst(p->pre_filters);
filter;
filter = (char *)cupsArrayNext(p->pre_filters))
add_printer_filter(p, p->prefiltertype, filter);
}
}
}
if (oldattrs)
{
ipp_attribute_t *oldattr;
if ((oldattr = ippFindAttribute(oldattrs, "marker-colors",
IPP_TAG_NAME)) != NULL)
{
if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
"marker-colors", oldattr->num_values, NULL,
NULL)) != NULL)
{
for (i = 0; i < oldattr->num_values; i ++)
attr->values[i].string.text =
_cupsStrRetain(oldattr->values[i].string.text);
}
}
if ((oldattr = ippFindAttribute(oldattrs, "marker-levels",
IPP_TAG_INTEGER)) != NULL)
{
if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"marker-levels", oldattr->num_values,
NULL)) != NULL)
{
for (i = 0; i < oldattr->num_values; i ++)
attr->values[i].integer = oldattr->values[i].integer;
}
}
if ((oldattr = ippFindAttribute(oldattrs, "marker-message",
IPP_TAG_TEXT)) != NULL)
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "marker-message",
NULL, oldattr->values[0].string.text);
if ((oldattr = ippFindAttribute(oldattrs, "marker-low-levels",
IPP_TAG_INTEGER)) != NULL)
{
if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"marker-low-levels", oldattr->num_values,
NULL)) != NULL)
{
for (i = 0; i < oldattr->num_values; i ++)
attr->values[i].integer = oldattr->values[i].integer;
}
}
if ((oldattr = ippFindAttribute(oldattrs, "marker-high-levels",
IPP_TAG_INTEGER)) != NULL)
{
if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"marker-high-levels", oldattr->num_values,
NULL)) != NULL)
{
for (i = 0; i < oldattr->num_values; i ++)
attr->values[i].integer = oldattr->values[i].integer;
}
}
if ((oldattr = ippFindAttribute(oldattrs, "marker-names",
IPP_TAG_NAME)) != NULL)
{
if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
"marker-names", oldattr->num_values, NULL,
NULL)) != NULL)
{
for (i = 0; i < oldattr->num_values; i ++)
attr->values[i].string.text =
_cupsStrRetain(oldattr->values[i].string.text);
}
}
if ((oldattr = ippFindAttribute(oldattrs, "marker-types",
IPP_TAG_KEYWORD)) != NULL)
{
if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"marker-types", oldattr->num_values, NULL,
NULL)) != NULL)
{
for (i = 0; i < oldattr->num_values; i ++)
attr->values[i].string.text =
_cupsStrRetain(oldattr->values[i].string.text);
}
}
ippDelete(oldattrs);
}
if (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))
p->shared = 0;
else
{
const char *valptr;
char *attrptr;
if (p->browse_attrs)
free(p->browse_attrs);
for (length = 1, i = p->num_options, option = p->options;
i > 0;
i --, option ++)
{
length += strlen(option->name) + 2;
if (option->value)
{
for (valptr = option->value; *valptr; valptr ++)
if (strchr(" \"\'\\", *valptr))
length += 2;
else
length ++;
}
}
length += 13 + strlen(p->job_sheets[0]) + strlen(p->job_sheets[1]);
length += 32;
if (BrowseLocalOptions)
length += 12 + strlen(BrowseLocalOptions);
if ((p->browse_attrs = calloc(1, length)) == NULL)
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to allocate %d bytes for browse data!",
length);
else
{
sprintf(p->browse_attrs, "job-sheets=%s,%s lease-duration=%d",
p->job_sheets[0], p->job_sheets[1], BrowseTimeout);
attrptr = p->browse_attrs + strlen(p->browse_attrs);
if (BrowseLocalOptions)
{
sprintf(attrptr, " ipp-options=%s", BrowseLocalOptions);
attrptr += strlen(attrptr);
}
for (i = p->num_options, option = p->options;
i > 0;
i --, option ++)
{
*attrptr++ = ' ';
strcpy(attrptr, option->name);
attrptr += strlen(attrptr);
if (option->value)
{
*attrptr++ = '=';
for (valptr = option->value; *valptr; valptr ++)
{
if (strchr(" \"\'\\", *valptr))
*attrptr++ = '\\';
*attrptr++ = *valptr;
}
}
}
}
}
add_printer_formats(p);
DEBUG_printf(("cupsdSetPrinterAttrs: leaving name = %s, type = %x\n", p->name,
p->type));
add_printer_defaults(p);
#ifdef __sgi
write_irix_config(p);
write_irix_state(p);
#endif
cupsdRegisterPrinter(p);
}
int
cupsdSetPrinterReasons(
cupsd_printer_t *p,
const char *s)
{
int i,
changed = 0;
const char *sptr;
char reason[255],
*rptr;
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdSetPrinterReasons(p=%p(%s),s=\"%s\"", p, p->name, s);
if (s[0] == '-' || s[0] == '+')
{
sptr = s + 1;
}
else
{
sptr = s;
for (i = 0; i < p->num_reasons; i ++)
_cupsStrFree(p->reasons[i]);
p->num_reasons = 0;
changed = 1;
cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
if (PrintcapFormat == PRINTCAP_PLIST)
cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
}
if (!strcmp(s, "none"))
return (changed);
while (*sptr)
{
while (isspace(*sptr & 255) || *sptr == ',')
sptr ++;
for (rptr = reason; *sptr && !isspace(*sptr & 255) && *sptr != ','; sptr ++)
if (rptr < (reason + sizeof(reason) - 1))
*rptr++ = *sptr;
if (rptr == reason)
break;
*rptr = '\0';
if (s[0] == '-')
{
for (i = 0; i < p->num_reasons; i ++)
if (!strcmp(reason, p->reasons[i]))
{
p->num_reasons --;
changed = 1;
_cupsStrFree(p->reasons[i]);
if (i < p->num_reasons)
memmove(p->reasons + i, p->reasons + i + 1,
(p->num_reasons - i) * sizeof(char *));
if (!strcmp(reason, "paused") && p->state == IPP_PRINTER_STOPPED)
cupsdSetPrinterState(p, IPP_PRINTER_IDLE, 1);
if (strcmp(reason, "connecting-to-device"))
{
cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
if (PrintcapFormat == PRINTCAP_PLIST)
cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
}
break;
}
}
else if (p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
{
for (i = 0; i < p->num_reasons; i ++)
if (!strcmp(reason, p->reasons[i]))
break;
if (i >= p->num_reasons)
{
if (i >= (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
{
cupsdLogMessage(CUPSD_LOG_ALERT,
"Too many printer-state-reasons values for %s (%d)",
p->name, i + 1);
return (changed);
}
p->reasons[i] = _cupsStrAlloc(reason);
p->num_reasons ++;
changed = 1;
if (!strcmp(reason, "paused") && p->state != IPP_PRINTER_STOPPED)
cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 1);
if (strcmp(reason, "connecting-to-device"))
{
cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
if (PrintcapFormat == PRINTCAP_PLIST)
cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
}
}
}
}
return (changed);
}
void
cupsdSetPrinterState(
cupsd_printer_t *p,
ipp_pstate_t s,
int update)
{
ipp_pstate_t old_state;
static const char * const printer_states[] =
{
"idle",
"processing",
"stopped"
};
if (p->type & CUPS_PRINTER_DISCOVERED)
return;
if (PrintcapFormat == PRINTCAP_PLIST)
cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
old_state = p->state;
p->state = s;
if (old_state != s)
{
cupsdAddEvent(s == IPP_PRINTER_STOPPED ? CUPSD_EVENT_PRINTER_STOPPED :
CUPSD_EVENT_PRINTER_STATE, p, NULL,
"%s \"%s\" state changed to %s.",
(p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
p->name, printer_states[p->state]);
BrowseNext = p;
p->state_time = time(NULL);
p->browse_time = 0;
#ifdef __sgi
write_irix_state(p);
#endif
}
if (s == IPP_PRINTER_STOPPED)
cupsdSetPrinterReasons(p, "+paused");
else
cupsdSetPrinterReasons(p, "-paused");
if (s == IPP_PRINTER_PROCESSING)
p->state_message[0] = '\0';
cupsdAddPrinterHistory(p);
if (update)
cupsdRegisterPrinter(p);
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);
}
}
void
cupsdStopPrinter(cupsd_printer_t *p,
int update)
{
cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update);
if (p->job && p->job->state_value == IPP_JOB_PROCESSING)
cupsdSetJobState(p->job, IPP_JOB_PENDING, CUPSD_JOB_DEFAULT,
"Job stopped due to printer being paused.");
}
int
cupsdUpdatePrinterPPD(
cupsd_printer_t *p,
int num_keywords,
cups_option_t *keywords)
{
int i;
cups_file_t *src,
*dst;
char srcfile[1024],
dstfile[1024],
line[1024],
keystring[41];
cups_option_t *keyword;
cupsdLogMessage(CUPSD_LOG_INFO, "Updating keywords in PPD file for %s...",
p->name);
snprintf(srcfile, sizeof(srcfile), "%s/ppd/%s.ppd.O", ServerRoot, p->name);
snprintf(dstfile, sizeof(srcfile), "%s/ppd/%s.ppd", ServerRoot, p->name);
if (rename(dstfile, srcfile))
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to backup PPD file for %s: %s",
p->name, strerror(errno));
return (0);
}
if ((src = cupsFileOpen(srcfile, "r")) == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open PPD file \"%s\": %s",
srcfile, strerror(errno));
rename(srcfile, dstfile);
return (0);
}
if ((dst = cupsFileOpen(dstfile, "w")) == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create PPD file \"%s\": %s",
dstfile, strerror(errno));
cupsFileClose(src);
rename(srcfile, dstfile);
return (0);
}
if (!cupsFileGets(src, line, sizeof(line)))
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to read PPD file \"%s\": %s",
srcfile, strerror(errno));
cupsFileClose(src);
cupsFileClose(dst);
rename(srcfile, dstfile);
return (0);
}
cupsFilePrintf(dst, "%s\n", line);
for (i = num_keywords, keyword = keywords; i > 0; i --, keyword ++)
{
cupsdLogMessage(CUPSD_LOG_DEBUG, "*%s: %s", keyword->name, keyword->value);
cupsFilePrintf(dst, "*%s: %s\n", keyword->name, keyword->value);
}
while (cupsFileGets(src, line, sizeof(line)))
{
if (sscanf(line, "*%40[^:]:", keystring) == 1 &&
cupsGetOption(keystring, num_keywords, keywords))
continue;
cupsFilePrintf(dst, "%s\n", line);
}
cupsFileClose(src);
cupsFileClose(dst);
return (1);
}
void
cupsdUpdatePrinters(void)
{
cupsd_printer_t *p;
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
p;
p = (cupsd_printer_t *)cupsArrayNext(Printers))
{
if (!Browsing &&
(p->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_DISCOVERED)))
{
if (p->type & CUPS_PRINTER_IMPLICIT)
cupsArrayRemove(ImplicitPrinters, p);
cupsArraySave(Printers);
cupsdDeletePrinter(p, 0);
cupsArrayRestore(Printers);
continue;
}
if ((p->op_policy_ptr = cupsdFindPolicy(p->op_policy)) == NULL)
p->op_policy_ptr = DefaultPolicyPtr;
if (!(p->type & CUPS_PRINTER_DISCOVERED))
cupsdSetPrinterAttrs(p);
}
}
const char *
cupsdValidateDest(
const char *uri,
cups_ptype_t *dtype,
cupsd_printer_t **printer)
{
cupsd_printer_t *p;
char localname[1024],
*lptr,
*sptr,
*rptr,
scheme[32],
username[64],
hostname[HTTP_MAX_HOST],
resource[HTTP_MAX_URI];
int port;
DEBUG_printf(("cupsdValidateDest(uri=\"%s\", dtype=%p, printer=%p)\n", uri,
dtype, printer));
if (printer)
*printer = NULL;
if (dtype)
*dtype = (cups_ptype_t)0;
httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
username, sizeof(username), hostname, sizeof(hostname),
&port, resource, sizeof(resource));
if (!strncmp(resource, "/classes/", 9))
{
rptr = resource + 9;
}
else if (!strncmp(resource, "/printers/", 10))
{
rptr = resource + 10;
}
else
{
return (NULL);
}
p = cupsdFindDest(rptr);
if (p == NULL && strchr(rptr, '@') == NULL)
return (NULL);
else if (p != NULL)
{
if (printer)
*printer = p;
if (dtype)
*dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED);
return (p->name);
}
if (!strcasecmp(hostname, "localhost"))
strlcpy(hostname, ServerName, sizeof(hostname));
strlcpy(localname, hostname, sizeof(localname));
if (!strcasecmp(hostname, ServerName))
{
lptr = strchr(localname, '.');
sptr = strchr(ServerName, '.');
if (sptr != NULL && lptr != NULL)
{
while (lptr != NULL)
{
if (!strcasecmp(lptr, sptr))
{
*lptr = '\0';
break;
}
else
lptr = strchr(lptr + 1, '.');
}
}
}
DEBUG_printf(("localized hostname is \"%s\"...\n", localname));
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
p;
p = (cupsd_printer_t *)cupsArrayNext(Printers))
if (!strcasecmp(p->hostname, localname) &&
!strcasecmp(p->name, rptr))
{
if (printer)
*printer = p;
if (dtype)
*dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED);
return (p->name);
}
return (NULL);
}
void
cupsdWritePrintcap(void)
{
int i;
cups_file_t *fp;
cupsd_printer_t *p;
#ifdef __sgi
write_irix_state(DefaultPrinter);
#endif
if (!Printcap || !*Printcap)
return;
cupsdLogMessage(CUPSD_LOG_INFO, "Generating printcap %s...", Printcap);
if ((fp = cupsFileOpen(Printcap, "w")) == NULL)
return;
if (PrintcapFormat != PRINTCAP_PLIST)
cupsFilePrintf(fp, "# This file was automatically generated by cupsd(8) "
"from the\n"
"# %s/printers.conf file. All changes to this file\n"
"# will be lost.\n", ServerRoot);
switch (PrintcapFormat)
{
case PRINTCAP_BSD :
if (DefaultPrinter)
cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", DefaultPrinter->name,
DefaultPrinter->info, ServerName,
DefaultPrinter->name);
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
p;
p = (cupsd_printer_t *)cupsArrayNext(Printers))
if (p != DefaultPrinter)
cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", p->name, p->info,
ServerName, p->name);
break;
case PRINTCAP_PLIST :
cupsFilePuts(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD "
"PLIST 1.0//EN\" \"http://www.apple.com/DTDs/"
"PropertyList-1.0.dtd\">\n"
"<plist version=\"1.0\">\n"
"<array>\n");
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
p;
p = (cupsd_printer_t *)cupsArrayNext(Printers))
{
cupsFilePuts(fp, "\t<dict>\n"
"\t\t<key>printer-name</key>\n"
"\t\t<string>");
write_xml_string(fp, p->name);
cupsFilePuts(fp, "</string>\n"
"\t\t<key>printer-info</key>\n"
"\t\t<string>");
write_xml_string(fp, p->info);
cupsFilePrintf(fp, "</string>\n"
"\t\t<key>printer-is-accepting-jobs</key>\n"
"\t\t<%s/>\n"
"\t\t<key>printer-location</key>\n"
"\t\t<string>", p->accepting ? "true" : "false");
write_xml_string(fp, p->location);
cupsFilePuts(fp, "</string>\n"
"\t\t<key>printer-make-and-model</key>\n"
"\t\t<string>");
write_xml_string(fp, p->make_model);
cupsFilePrintf(fp, "</string>\n"
"\t\t<key>printer-state</key>\n"
"\t\t<integer>%d</integer>\n"
"\t\t<key>printer-state-reasons</key>\n"
"\t\t<array>\n", p->state);
for (i = 0; i < p->num_reasons; i ++)
{
cupsFilePuts(fp, "\t\t\t<string>");
write_xml_string(fp, p->reasons[i]);
cupsFilePuts(fp, "</string>\n");
}
cupsFilePrintf(fp, "\t\t</array>\n"
"\t\t<key>printer-type</key>\n"
"\t\t<integer>%d</integer>\n"
"\t\t<key>device-uri</key>\n"
"\t\t<string>", p->type);
write_xml_string(fp, p->sanitized_device_uri);
cupsFilePuts(fp, "</string>\n"
"\t</dict>\n");
}
cupsFilePuts(fp, "</array>\n"
"</plist>\n");
break;
case PRINTCAP_SOLARIS :
cupsFilePuts(fp, "_all:all=");
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
p;
p = (cupsd_printer_t *)cupsArrayCurrent(Printers))
cupsFilePrintf(fp, "%s%c", p->name,
cupsArrayNext(Printers) ? ',' : '\n');
if (DefaultPrinter)
cupsFilePrintf(fp, "_default:use=%s\n", DefaultPrinter->name);
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
p;
p = (cupsd_printer_t *)cupsArrayNext(Printers))
cupsFilePrintf(fp, "%s:\\\n"
"\t:bsdaddr=%s,%s:\\\n"
"\t:description=%s:\n",
p->name, ServerName, p->name,
p->info ? p->info : "");
break;
}
cupsFileClose(fp);
}
static void
add_printer_defaults(cupsd_printer_t *p)
{
int i;
int num_options;
cups_option_t *options,
*option;
char name[256];
if (!CommonDefaults)
{
CommonDefaults = cupsArrayNew((cups_array_func_t)strcmp, NULL);
cupsArrayAdd(CommonDefaults, _cupsStrAlloc("copies-default"));
cupsArrayAdd(CommonDefaults, _cupsStrAlloc("document-format-default"));
cupsArrayAdd(CommonDefaults, _cupsStrAlloc("finishings-default"));
cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-hold-until-default"));
cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-priority-default"));
cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-sheets-default"));
cupsArrayAdd(CommonDefaults, _cupsStrAlloc("media-col-default"));
cupsArrayAdd(CommonDefaults, _cupsStrAlloc("number-up-default"));
cupsArrayAdd(CommonDefaults,
_cupsStrAlloc("orientation-requested-default"));
}
for (num_options = 0, options = NULL, i = p->num_options, option = p->options;
i > 0;
i --, option ++)
{
if (strcmp(option->name, "ipp-options") &&
strcmp(option->name, "job-sheets") &&
strcmp(option->name, "lease-duration"))
{
snprintf(name, sizeof(name), "%s-default", option->name);
num_options = cupsAddOption(name, option->value, num_options, &options);
if (!cupsArrayFind(CommonDefaults, name))
cupsArrayAdd(CommonDefaults, _cupsStrAlloc(name));
}
}
cupsEncodeOptions2(p->attrs, num_options, options, IPP_TAG_PRINTER);
cupsFreeOptions(num_options, options);
if (!cupsGetOption("copies", p->num_options, p->options))
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default",
1);
if (!cupsGetOption("document-format", p->num_options, p->options))
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
"document-format-default", NULL, "application/octet-stream");
if (!cupsGetOption("job-hold-until", p->num_options, p->options))
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"job-hold-until-default", NULL, "no-hold");
if (!cupsGetOption("job-priority", p->num_options, p->options))
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"job-priority-default", 50);
if (!cupsGetOption("number-up", p->num_options, p->options))
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"number-up-default", 1);
if (!cupsGetOption("notify-lease-duration", p->num_options, p->options))
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"notify-lease-duration-default", DefaultLeaseDuration);
if (!cupsGetOption("notify-events", p->num_options, p->options))
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"notify-events-default", NULL, "job-completed");
if (!cupsGetOption("orientation-requested", p->num_options, p->options))
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE,
"orientation-requested-default", NULL, NULL);
if (!cupsGetOption("print-quality", p->num_options, p->options))
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
"print-quality-default", IPP_QUALITY_NORMAL);
}
static void
add_printer_filter(
cupsd_printer_t *p,
mime_type_t *filtertype,
const char *filter)
{
char super[MIME_MAX_SUPER],
type[MIME_MAX_TYPE],
program[1024];
int cost;
mime_type_t *temptype;
char filename[1024],
*dirsep;
struct stat fileinfo;
if (sscanf(filter, "%15[^/]/%31s%d%*[ \t]%1023[^\n]", super, type, &cost,
program) != 4)
{
cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!",
p->name, filter);
return;
}
if (strcmp(program, "-"))
{
if (program[0] == '/')
strlcpy(filename, program, sizeof(filename));
else
snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program);
if (stat(filename, &fileinfo))
{
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));
cupsdSetPrinterReasons(p, "+cups-missing-filter-warning");
cupsdLogMessage(CUPSD_LOG_ERROR, "%s", p->state_message);
}
if (!RunUser)
{
if (fileinfo.st_uid || (fileinfo.st_mode & (S_ISUID | 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);
cupsdSetPrinterReasons(p, "+cups-insecure-filter-warning");
cupsdLogMessage(CUPSD_LOG_ERROR, "%s", p->state_message);
}
else if (fileinfo.st_mode)
{
if ((dirsep = strrchr(filename, '/')) != NULL)
*dirsep = '\0';
if (!stat(filename, &fileinfo) &&
(fileinfo.st_uid ||
(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);
cupsdSetPrinterReasons(p, "+cups-insecure-filter-warning");
cupsdLogMessage(CUPSD_LOG_ERROR, "%s", p->state_message);
}
}
}
}
for (temptype = mimeFirstType(MimeDatabase);
temptype;
temptype = mimeNextType(MimeDatabase))
if (((super[0] == '*' && strcasecmp(temptype->super, "printer")) ||
!strcasecmp(temptype->super, super)) &&
(type[0] == '*' || !strcasecmp(temptype->type, type)))
{
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);
}
}
static void
add_printer_formats(cupsd_printer_t *p)
{
int i;
mime_type_t *type;
cups_array_t *filters;
ipp_attribute_t *attr;
char mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
cupsArrayDelete(p->filetypes);
p->filetypes = NULL;
if (p->raw)
{
ippAddStrings(p->attrs, IPP_TAG_PRINTER,
(ipp_tag_t)(IPP_TAG_MIMETYPE | IPP_TAG_COPY),
"document-format-supported", NumMimeTypes, NULL, MimeTypes);
return;
}
cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer_formats: %d types, %d filters",
mimeNumTypes(MimeDatabase), mimeNumFilters(MimeDatabase));
p->filetypes = cupsArrayNew(NULL, NULL);
for (type = mimeFirstType(MimeDatabase);
type;
type = mimeNextType(MimeDatabase))
{
snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
if ((filters = mimeFilter(MimeDatabase, type, p->filetype, NULL)) != NULL)
{
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"add_printer_formats: %s: %s needs %d filters",
p->name, mimetype, cupsArrayCount(filters));
cupsArrayDelete(filters);
cupsArrayAdd(p->filetypes, type);
}
else
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"add_printer_formats: %s: %s not supported",
p->name, mimetype);
}
if ((type = mimeType(MimeDatabase, "application", "octet-stream")) == NULL ||
!cupsArrayFind(p->filetypes, type))
i = 1;
else
i = 0;
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"add_printer_formats: %s: %d supported types",
p->name, cupsArrayCount(p->filetypes) + i);
attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
"document-format-supported",
cupsArrayCount(p->filetypes) + i, NULL, NULL);
if (i)
attr->values[0].string.text = _cupsStrAlloc("application/octet-stream");
for (type = (mime_type_t *)cupsArrayFirst(p->filetypes);
type;
i ++, type = (mime_type_t *)cupsArrayNext(p->filetypes))
{
snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
attr->values[i].string.text = _cupsStrAlloc(mimetype);
}
#ifdef HAVE_DNSSD
{
char pdl[1024];
mime_filter_t *filter;
for (filter = (mime_filter_t *)cupsArrayFirst(MimeDatabase->filters);
filter;
filter = (mime_filter_t *)cupsArrayNext(MimeDatabase->filters))
{
if (filter->dst == p->filetype && filter->filter &&
strstr(filter->filter, "PrintJobMgr"))
break;
}
pdl[0] = '\0';
if (!filter && mimeType(MimeDatabase, "application", "octet-stream"))
strlcat(pdl, "application/octet-stream,", sizeof(pdl));
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, "urf"))
strlcat(pdl, "image/urf,", sizeof(pdl));
}
}
if (pdl[0])
pdl[strlen(pdl) - 1] = '\0';
cupsdSetString(&p->pdl, pdl);
}
#endif
}
static void
add_string_array(cups_array_t **a,
const char *s)
{
if (!*a)
*a = cupsArrayNew(NULL, NULL);
cupsArrayAdd(*a, _cupsStrAlloc(s));
}
static int
compare_printers(void *first,
void *second,
void *data)
{
return (strcasecmp(((cupsd_printer_t *)first)->name,
((cupsd_printer_t *)second)->name));
}
static void
delete_printer_filters(
cupsd_printer_t *p)
{
mime_filter_t *filter;
if (p == NULL)
return;
for (filter = mimeFirstFilter(MimeDatabase);
filter;
filter = mimeNextFilter(MimeDatabase))
if (filter->dst == p->filetype || filter->dst == p->prefiltertype)
{
mimeDeleteFilter(MimeDatabase, filter);
}
cupsdSetPrinterReasons(p, "-cups-insecure-filter-warning"
",cups-missing-filter-warning");
}
static void
delete_string_array(cups_array_t **a)
{
char *ptr;
for (ptr = (char *)cupsArrayFirst(*a);
ptr;
ptr = (char *)cupsArrayNext(*a))
_cupsStrFree(ptr);
cupsArrayDelete(*a);
*a = NULL;
}
static void
load_ppd(cupsd_printer_t *p)
{
int i, j, k;
cups_file_t *cache;
char cache_name[1024];
struct stat cache_info;
char pwg_name[1024];
struct stat pwg_info;
ppd_file_t *ppd;
char ppd_name[1024];
struct stat ppd_info;
int num_media;
ppd_size_t *size;
ppd_option_t *duplex,
*output_bin,
*output_mode,
*resolution;
ppd_choice_t *choice,
*input_slot,
*media_type;
ppd_attr_t *ppd_attr;
int xdpi,
ydpi;
const char *resptr;
_pwg_size_t *pwgsize;
_pwg_map_t *pwgsource,
*pwgtype;
ipp_attribute_t *attr;
ipp_value_t *val;
int num_finishings,
finishings[5];
int num_qualities,
qualities[3];
int num_urf;
char *urf[5],
urf_rs[255],
*urf_ptr;
int num_margins,
margins[16];
static const char * const sides[3] =
{
"one-sided",
"two-sided-long-edge",
"two-sided-short-edge"
};
static const char * const standard_commands[] =
{
"AutoConfigure",
"Clean",
"PrintSelfTestPage"
};
snprintf(cache_name, sizeof(cache_name), "%s/%s.ipp2", 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;
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)
{
cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", cache_name);
if (ippReadIO(cache, (ipp_iocb_t)cupsFileRead, 1, NULL,
p->ppd_attrs) == IPP_DATA)
{
cupsFileClose(cache);
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;
finishings[0] = IPP_FINISHINGS_NONE;
num_finishings = 1;
num_urf = 0;
if ((ppd = ppdOpenFile(ppd_name)) != NULL)
{
p->pwg = _pwgCreateWithPPD(ppd);
ppdMarkDefaults(ppd);
if (ppd->color_device)
p->type |= CUPS_PRINTER_COLOR;
if (ppd->variable_sizes)
p->type |= CUPS_PRINTER_VARIABLE;
if (!ppd->manual_copies)
p->type |= CUPS_PRINTER_COPIES;
if ((ppd_attr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL)
if (ppd_attr->value && !strcasecmp(ppd_attr->value, "true"))
p->type |= CUPS_PRINTER_FAX;
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);
}
urf[num_urf ++] = _cupsStrAlloc("W8");
if (ppd->color_device)
urf[num_urf ++] = _cupsStrAlloc("SRGB24");
if (ppd->manual_copies)
urf[num_urf ++] = _cupsStrAlloc("CP1");
else
urf[num_urf ++] = _cupsStrAlloc("CP255");
num_qualities = 0;
if ((output_mode = ppdFindOption(ppd, "OutputMode")) != NULL)
{
if (ppdFindChoice(output_mode, "draft") ||
ppdFindChoice(output_mode, "fast"))
qualities[num_qualities ++] = IPP_QUALITY_DRAFT;
if (ppdFindChoice(output_mode, "normal") ||
ppdFindChoice(output_mode, "good"))
qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
if (ppdFindChoice(output_mode, "best") ||
ppdFindChoice(output_mode, "high"))
qualities[num_qualities ++] = IPP_QUALITY_HIGH;
}
else if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL)
{
do
{
if (strstr(ppd_attr->spec, "draft") ||
strstr(ppd_attr->spec, "Draft"))
{
qualities[num_qualities ++] = IPP_QUALITY_DRAFT;
break;
}
}
while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset",
NULL)) != NULL);
qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
qualities[num_qualities ++] = IPP_QUALITY_HIGH;
}
if (num_qualities == 0)
qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
"print-quality-supported", num_qualities, qualities);
if (ppd->nickname)
{
cupsdSetString(&p->make_model, ppd->nickname);
}
else if (ppd->modelname)
{
cupsdSetString(&p->make_model, ppd->modelname);
}
else
cupsdSetString(&p->make_model, "Bad PPD File");
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
"printer-make-and-model", NULL, p->make_model);
if (ppd->num_sizes == 0 || !p->pwg)
{
if (!ppdFindAttr(ppd, "APScannerOnly", NULL))
cupsdLogMessage(CUPSD_LOG_CRIT,
"The PPD file for printer %s contains no media "
"options and is therefore invalid!", p->name);
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"media-default", NULL, "unknown");
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"media-supported", NULL, "unknown");
}
else
{
if ((size = ppdPageSize(ppd, NULL)) != NULL)
pwgsize = _pwgGetSize(p->pwg, size->name);
else
pwgsize = NULL;
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"media-default", NULL,
pwgsize ? pwgsize->map.pwg : "unknown");
if (pwgsize)
{
ipp_t *col;
input_slot = ppdFindMarkedChoice(ppd, "InputSlot");
media_type = ppdFindMarkedChoice(ppd, "MediaType");
col = new_media_col(pwgsize,
input_slot ?
_pwgGetSource(p->pwg,
input_slot->choice) :
NULL,
media_type ?
_pwgGetType(p->pwg,
media_type->choice) :
NULL);
ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-default",
col);
ippDelete(col);
}
num_media = p->pwg->num_sizes;
if (p->pwg->custom_min_keyword)
num_media += 2;
if ((attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"media-supported", num_media, NULL,
NULL)) != NULL)
{
val = attr->values;
for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes;
i > 0;
i --, pwgsize ++, val ++)
val->string.text = _cupsStrRetain(pwgsize->map.pwg);
if (p->pwg->custom_min_keyword)
{
val->string.text = _cupsStrRetain(p->pwg->custom_min_keyword);
val ++;
val->string.text = _cupsStrRetain(p->pwg->custom_max_keyword);
}
}
if (p->pwg->num_sources > 0 &&
(attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"media-source-supported", p->pwg->num_sources,
NULL, NULL)) != NULL)
{
for (i = p->pwg->num_sources, pwgsource = p->pwg->sources,
val = attr->values;
i > 0;
i --, pwgsource ++, val ++)
val->string.text = _cupsStrRetain(pwgsource->pwg);
}
if (p->pwg->num_types > 0 &&
(attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"media-type-supported", p->pwg->num_types,
NULL, NULL)) != NULL)
{
for (i = p->pwg->num_types, pwgtype = p->pwg->types,
val = attr->values;
i > 0;
i --, pwgtype ++, val ++)
val->string.text = _cupsStrRetain(pwgtype->pwg);
}
for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes, num_margins = 0;
i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
i --, pwgsize ++)
{
for (j = 0; j < num_margins; j ++)
if (pwgsize->bottom == margins[j])
break;
if (j >= num_margins)
{
margins[num_margins] = pwgsize->bottom;
num_margins ++;
}
}
if (num_margins > 0)
ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"media-bottom-margin-supported", num_margins, margins);
else
ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"media-bottom-margin-supported", 0);
for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes, num_margins = 0;
i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
i --, pwgsize ++)
{
for (j = 0; j < num_margins; j ++)
if (pwgsize->left == margins[j])
break;
if (j >= num_margins)
{
margins[num_margins] = pwgsize->left;
num_margins ++;
}
}
if (num_margins > 0)
ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"media-left-margin-supported", num_margins, margins);
else
ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"media-left-margin-supported", 0);
for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes, num_margins = 0;
i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
i --, pwgsize ++)
{
for (j = 0; j < num_margins; j ++)
if (pwgsize->right == margins[j])
break;
if (j >= num_margins)
{
margins[num_margins] = pwgsize->right;
num_margins ++;
}
}
if (num_margins > 0)
ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"media-right-margin-supported", num_margins, margins);
else
ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"media-right-margin-supported", 0);
for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes, num_margins = 0;
i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
i --, pwgsize ++)
{
for (j = 0; j < num_margins; j ++)
if (pwgsize->top == margins[j])
break;
if (j >= num_margins)
{
margins[num_margins] = pwgsize->top;
num_margins ++;
}
}
if (num_margins > 0)
ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"media-top-margin-supported", num_margins, margins);
else
ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"media-top-margin-supported", 0);
num_media = p->pwg->num_sizes;
if (p->pwg->num_sources)
{
if (p->pwg->num_types > 0)
num_media += p->pwg->num_sizes * p->pwg->num_sources *
p->pwg->num_types;
else
num_media += p->pwg->num_sizes * p->pwg->num_sources;
}
else if (p->pwg->num_types)
num_media += p->pwg->num_sizes * p->pwg->num_types;
if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER,
"media-col-database", num_media,
NULL)) != NULL)
{
for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes, val = attr->values;
i > 0;
i --, pwgsize ++)
{
ppdMarkOption(ppd, "PageSize", pwgsize->map.ppd);
val->collection = new_media_col(pwgsize, NULL, NULL);
val ++;
if (p->pwg->num_sources > 0)
{
for (j = p->pwg->num_sources, pwgsource = p->pwg->sources;
j > 0;
j --, pwgsource ++)
{
ppdMarkOption(ppd, "InputSlot", pwgsource->ppd);
if (p->pwg->num_types > 0)
{
for (k = p->pwg->num_types, pwgtype = p->pwg->types;
k > 0;
k --, pwgtype ++)
{
if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd))
{
val->collection = new_media_col(pwgsize, pwgsource->pwg,
pwgtype->pwg);
val ++;
}
}
}
else if (!ppdConflicts(ppd))
{
val->collection = new_media_col(pwgsize, pwgsource->pwg, NULL);
val ++;
}
}
}
else if (p->pwg->num_types > 0)
{
for (j = p->pwg->num_types, pwgtype = p->pwg->types;
j > 0;
j --, pwgtype ++)
{
if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd))
{
val->collection = new_media_col(pwgsize, NULL, pwgtype->pwg);
val ++;
}
}
}
}
attr->num_values = val - attr->values;
}
}
if (p->pwg && p->pwg->num_bins > 0)
{
attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"output-bin-supported", p->pwg->num_bins,
NULL, NULL);
if (attr != NULL)
{
for (i = 0, val = attr->values;
i < p->pwg->num_bins;
i ++, val ++)
val->string.text = _cupsStrAlloc(p->pwg->bins[i].pwg);
}
if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
{
for (i = 0; i < p->pwg->num_bins; i ++)
if (!strcmp(p->pwg->bins[i].ppd, output_bin->defchoice))
break;
if (i >= p->pwg->num_bins)
i = 0;
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"output-bin-default", NULL, p->pwg->bins[i].pwg);
}
else
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"output-bin-default", NULL, p->pwg->bins[0].pwg);
}
else if ((ppd_attr = ppdFindAttr(ppd, "DefaultOutputOrder",
NULL)) != NULL &&
!strcasecmp(ppd_attr->value, "Reverse"))
{
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"output-bin-supported", NULL, "face-up");
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"output-bin-default", NULL, "face-up");
}
else
{
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"output-bin-supported", NULL, "face-down");
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"output-bin-default", NULL, "face-down");
}
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");
}
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");
}
if ((resolution = ppdFindOption(ppd, "Resolution")) == NULL)
if ((resolution = ppdFindOption(ppd, "JCLResolution")) == NULL)
if ((resolution = ppdFindOption(ppd, "SetResolution")) == NULL)
resolution = ppdFindOption(ppd, "CNRes_PGP");
urf_rs[0] = '\0';
if (resolution)
{
attr = ippAddResolutions(p->ppd_attrs, IPP_TAG_PRINTER,
"printer-resolution-supported",
resolution->num_choices, IPP_RES_PER_INCH,
NULL, NULL);
for (i = 0, choice = resolution->choices;
i < resolution->num_choices;
i ++, choice ++)
{
xdpi = ydpi = (int)strtol(choice->choice, (char **)&resptr, 10);
if (resptr > choice->choice && xdpi > 0 && *resptr == 'x')
ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10);
if (xdpi <= 0 || ydpi <= 0)
{
cupsdLogMessage(CUPSD_LOG_WARN,
"Bad resolution \"%s\" for printer %s.",
choice->choice, p->name);
xdpi = ydpi = 300;
}
else if (xdpi <= 720)
{
if (!urf_rs[0])
snprintf(urf_rs, sizeof(urf_rs), "RS%d", xdpi);
else
{
urf_ptr = urf_rs + strlen(urf_rs);
snprintf(urf_ptr, sizeof(urf_rs) - (urf_ptr - urf_rs), "-%d", xdpi);
}
}
attr->values[i].resolution.xres = xdpi;
attr->values[i].resolution.yres = ydpi;
attr->values[i].resolution.units = IPP_RES_PER_INCH;
if (choice->marked)
ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
"printer-resolution-default", IPP_RES_PER_INCH,
xdpi, ydpi);
}
}
else if ((ppd_attr = ppdFindAttr(ppd, "DefaultResolution", NULL)) != NULL &&
ppd_attr->value)
{
xdpi = ydpi = (int)strtol(ppd_attr->value, (char **)&resptr, 10);
if (resptr > ppd_attr->value && xdpi > 0)
{
if (*resptr == 'x')
ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10);
else
ydpi = xdpi;
}
if (xdpi <= 0 || ydpi <= 0)
{
cupsdLogMessage(CUPSD_LOG_WARN,
"Bad default resolution \"%s\" for printer %s.",
ppd_attr->value, p->name);
xdpi = ydpi = 300;
}
else if (xdpi <= 720)
snprintf(urf_rs, sizeof(urf_rs), "RS%d", xdpi);
else
{
for (i = 2; i < 20; i ++)
if ((i * (xdpi / i)) == xdpi && (xdpi / i) <= 720)
{
snprintf(urf_rs, sizeof(urf_rs), "RS%d", xdpi / i);
break;
}
}
ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
"printer-resolution-default", IPP_RES_PER_INCH,
xdpi, ydpi);
ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
"printer-resolution-supported", IPP_RES_PER_INCH,
xdpi, ydpi);
}
else
{
ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
"printer-resolution-default", IPP_RES_PER_INCH,
300, 300);
ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
"printer-resolution-supported", IPP_RES_PER_INCH,
300, 300);
}
if (!urf_rs[0])
strlcpy(urf_rs, "RS300", sizeof(urf_rs));
urf[num_urf ++] = _cupsStrAlloc(urf_rs);
if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL)
if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL)
if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL)
if ((duplex = ppdFindOption(ppd, "KD03Duplex")) == NULL)
duplex = ppdFindOption(ppd, "JCLDuplex");
if (duplex && duplex->num_choices > 1 &&
!ppdInstallableConflict(ppd, duplex->keyword, "DuplexTumble"))
{
p->type |= CUPS_PRINTER_DUPLEX;
urf[num_urf ++] = _cupsStrAlloc("DM1");
ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"sides-supported", 3, NULL, sides);
if (!strcasecmp(duplex->defchoice, "DuplexTumble"))
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"sides-default", NULL, "two-sided-short-edge");
else if (!strcasecmp(duplex->defchoice, "DuplexNoTumble"))
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"sides-default", NULL, "two-sided-long-edge");
else
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"sides-default", NULL, "one-sided");
}
else
{
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"sides-supported", NULL, "one-sided");
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"sides-default", NULL, "one-sided");
}
if (ppdFindOption(ppd, "Collate") != NULL)
p->type |= CUPS_PRINTER_COLLATE;
if (ppdFindOption(ppd, "StapleLocation") != NULL)
{
p->type |= CUPS_PRINTER_STAPLE;
finishings[num_finishings++] = IPP_FINISHINGS_STAPLE;
}
if (ppdFindOption(ppd, "BindEdge") != NULL)
{
p->type |= CUPS_PRINTER_BIND;
finishings[num_finishings++] = IPP_FINISHINGS_BIND;
}
for (i = 0; i < ppd->num_sizes; i ++)
if (ppd->sizes[i].length > 1728)
p->type |= CUPS_PRINTER_LARGE;
else if (ppd->sizes[i].length > 1008)
p->type |= CUPS_PRINTER_MEDIUM;
else
p->type |= CUPS_PRINTER_SMALL;
if ((ppd_attr = ppdFindAttr(ppd, "APICADriver", NULL)) != NULL &&
ppd_attr->value && !strcasecmp(ppd_attr->value, "true"))
{
if ((ppd_attr = ppdFindAttr(ppd, "APScannerOnly", NULL)) != NULL &&
ppd_attr->value && !strcasecmp(ppd_attr->value, "true"))
p->type |= CUPS_PRINTER_SCANNER;
else
p->type |= CUPS_PRINTER_MFP;
}
add_string_array(&(p->filters), "application/vnd.cups-raw 0 -");
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);
}
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)
{
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))
{
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)
{
add_string_array(&(p->filters),
"application/vnd.cups-command 0 commandtops");
p->type |= CUPS_PRINTER_COMMANDS;
}
}
if (p->type & CUPS_PRINTER_COMMANDS)
{
char *commands,
*start,
*end;
int count;
if ((ppd_attr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL &&
ppd_attr->value && ppd_attr->value[0])
{
for (count = 0, start = ppd_attr->value; *start; count ++)
{
while (isspace(*start & 255))
start ++;
if (!*start)
break;
while (*start && !isspace(*start & 255))
start ++;
}
}
else
count = 0;
if (count > 0)
{
attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"printer-commands", count, NULL, NULL);
commands = strdup(ppd_attr->value);
for (count = 0, start = commands; *start; count ++)
{
while (isspace(*start & 255))
start ++;
if (!*start)
break;
end = start;
while (*end && !isspace(*end & 255))
end ++;
if (*end)
*end++ = '\0';
attr->values[count].string.text = _cupsStrAlloc(start);
start = end;
}
free(commands);
}
else
{
ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"printer-commands",
(int)(sizeof(standard_commands) /
sizeof(standard_commands[0])), NULL,
standard_commands);
}
}
else
{
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"printer-commands", NULL, "none");
}
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
NULL, p->port_monitor ? p->port_monitor : "none");
for (i = 1, ppd_attr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
ppd_attr;
i ++, ppd_attr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL));
if (ppd->protocols)
{
if (strstr(ppd->protocols, "TBCP"))
i ++;
else if (strstr(ppd->protocols, "BCP"))
i ++;
}
attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
"port-monitor-supported", i, NULL, NULL);
attr->values[0].string.text = _cupsStrAlloc("none");
for (i = 1, ppd_attr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
ppd_attr;
i ++, ppd_attr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL))
attr->values[i].string.text = _cupsStrAlloc(ppd_attr->value);
if (ppd->protocols)
{
if (strstr(ppd->protocols, "TBCP"))
attr->values[i].string.text = _cupsStrAlloc("tbcp");
else if (strstr(ppd->protocols, "BCP"))
attr->values[i].string.text = _cupsStrAlloc("bcp");
}
#ifdef HAVE_DNSSD
cupsdSetString(&p->product, ppd->product);
#endif
if (ppdFindAttr(ppd, "APRemoteQueueID", NULL))
p->type |= CUPS_PRINTER_REMOTE;
#ifdef HAVE_APPLICATIONSERVICES_H
if ((ppd_attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL &&
ppd_attr->value)
{
CGImageRef imageRef = NULL;
CGImageRef biggestIconRef = NULL;
CGImageRef closestTo128IconRef = NULL;
CGImageSourceRef sourceRef;
char outPath[HTTP_MAX_URI];
CFURLRef outUrl;
CFURLRef icnsFileUrl;
CGImageDestinationRef destRef;
size_t bytesPerRow;
CGContextRef context;
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 &&
CGImageGetWidth(imageRef) == CGImageGetHeight(imageRef))
{
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)
{
imageRef = closestTo128IconRef ? closestTo128IconRef :
biggestIconRef;
CGImageRetain(imageRef);
CGImageRelease(biggestIconRef);
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);
CFRelease(icnsFileUrl);
}
CFRelease(outUrl);
}
}
#endif
ppdClose(ppd);
}
else if (!access(ppd_name, 0))
{
int pline;
ppd_status_t pstatus;
pstatus = ppdLastError(&pline);
cupsdLogMessage(CUPSD_LOG_ERROR, "PPD file for %s cannot be loaded!",
p->name);
if (pstatus <= PPD_ALLOC_ERROR)
cupsdLogMessage(CUPSD_LOG_ERROR, "%s", strerror(errno));
else
cupsdLogMessage(CUPSD_LOG_ERROR, "%s on line %d.",
ppdErrorString(pstatus), pline);
cupsdLogMessage(CUPSD_LOG_INFO,
"Hint: Run \"cupstestppd %s\" and fix any errors.",
ppd_name);
add_string_array(&(p->filters), "application/vnd.cups-raw 0 -");
add_string_array(&(p->filters), "application/vnd.cups-postscript 0 -");
}
else
{
char interface[1024];
snprintf(interface, sizeof(interface), "%s/interfaces/%s", ServerRoot,
p->name);
if (!access(interface, X_OK))
{
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 ||
strstr(p->device_uri, "/classes/") != NULL ||
(strstr(p->device_uri, "._ipp.") != NULL &&
!strcmp(p->device_uri + strlen(p->device_uri) - 5,
"/cups"))))
{
p->type |= CUPS_PRINTER_REMOTE;
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
"printer-uri-supported", NULL, p->device_uri);
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
"printer-make-and-model", NULL, "Remote Printer");
p->raw = 1;
p->remote = 1;
}
else
{
ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
"printer-make-and-model", NULL, "Local Raw Printer");
p->raw = 1;
}
}
ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
"finishings-supported", num_finishings, finishings);
ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
"finishings-default", IPP_FINISHINGS_NONE);
if (num_urf > 0 && mimeType(MimeDatabase, "image", "urf"))
ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
"urf-supported", num_urf, NULL, (const char * const *)urf);
if (ppd && (cache = cupsFileOpen(cache_name, "w9")) != NULL)
{
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);
}
else
{
if (cache_info.st_mtime)
unlink(cache_name);
if (pwg_info.st_mtime)
unlink(pwg_name);
}
}
static ipp_t *
new_media_col(_pwg_size_t *size,
const char *source,
const char *type)
{
ipp_t *media_col,
*media_size;
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
static void
write_irix_config(cupsd_printer_t *p)
{
char filename[1024];
cups_file_t *fp;
ipp_attribute_t *attr;
snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
if (p->type & CUPS_PRINTER_CLASS)
unlink(filename);
else if ((fp = cupsFileOpen(filename, "w")) != NULL)
{
cupsFilePuts(fp, "#!/bin/sh\n");
if ((attr = ippFindAttribute(p->attrs, "printer-make-and-model",
IPP_TAG_TEXT)) != NULL)
cupsFilePrintf(fp, "NAME=\"%s\"\n", attr->values[0].string.text);
else if (p->type & CUPS_PRINTER_CLASS)
cupsFilePuts(fp, "NAME=\"Printer Class\"\n");
else
cupsFilePuts(fp, "NAME=\"Remote Destination\"\n");
if (p->type & CUPS_PRINTER_COLOR)
cupsFilePuts(fp, "TYPE=ColorPostScript\n");
else
cupsFilePuts(fp, "TYPE=MonoPostScript\n");
cupsFilePrintf(fp, "HOSTNAME=%s\n", ServerName);
cupsFilePrintf(fp, "HOSTPRINTER=%s\n", p->name);
cupsFileClose(fp);
chmod(filename, 0755);
chown(filename, User, Group);
}
snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
if (p->type & CUPS_PRINTER_CLASS)
unlink(filename);
else if ((fp = cupsFileOpen(filename, "w")) != NULL)
{
cupsFilePuts(fp, "/dev/null\n");
cupsFileClose(fp);
chmod(filename, 0644);
chown(filename, User, Group);
}
snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui", p->name);
if (p->type & CUPS_PRINTER_CLASS)
unlink(filename);
else if ((fp = cupsFileOpen(filename, "w")) != NULL)
{
cupsFilePuts(fp, "#!/bin/sh\n");
cupsFilePrintf(fp, "%s -d %s -o \"$3\"\n", PrintcapGUI, p->name);
cupsFileClose(fp);
chmod(filename, 0755);
chown(filename, User, Group);
}
snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
if (p->type & CUPS_PRINTER_CLASS)
unlink(filename);
else if ((fp = cupsFileOpen(filename, "w")) != NULL)
{
cupsFilePrintf(fp, "Printer Class | %s\n",
(p->type & CUPS_PRINTER_COLOR) ? "ColorPostScript" : "MonoPostScript");
cupsFilePrintf(fp, "Printer Model | %s\n", p->make_model ? p->make_model : "");
cupsFilePrintf(fp, "Location Code | %s\n", p->location ? p->location : "");
cupsFilePrintf(fp, "Physical Location | %s\n", p->info ? p->info : "");
cupsFilePrintf(fp, "Port Path | %s\n", p->device_uri);
cupsFilePrintf(fp, "Config Path | /var/spool/lp/pod/%s.config\n", p->name);
cupsFilePrintf(fp, "Active Status Path | /var/spool/lp/pod/%s.status\n", p->name);
cupsFilePuts(fp, "Status Update Wait | 10 seconds\n");
cupsFileClose(fp);
chmod(filename, 0664);
chown(filename, User, Group);
}
}
static void
write_irix_state(cupsd_printer_t *p)
{
char filename[1024];
cups_file_t *fp;
int tag;
if (p)
{
snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
if (p->type & CUPS_PRINTER_CLASS)
unlink(filename);
else if ((fp = cupsFileOpen(filename, "w")) != NULL)
{
cupsFilePrintf(fp, "Operational Status | %s\n",
(p->state == IPP_PRINTER_IDLE) ? "Idle" :
(p->state == IPP_PRINTER_PROCESSING) ? "Busy" :
"Faulted");
cupsFilePrintf(fp, "Information | 01 00 00 | %s\n", CUPS_SVERSION);
cupsFilePrintf(fp, "Information | 02 00 00 | Device URI: %s\n",
p->device_uri);
cupsFilePrintf(fp, "Information | 03 00 00 | %s jobs\n",
p->accepting ? "Accepting" : "Not accepting");
cupsFilePrintf(fp, "Information | 04 00 00 | %s\n", p->state_message);
cupsFileClose(fp);
chmod(filename, 0664);
chown(filename, User, Group);
}
snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
if (p->type & CUPS_PRINTER_CLASS)
unlink(filename);
else if ((fp = cupsFileOpen(filename, "w")) != NULL)
{
if (p->type & CUPS_PRINTER_COLOR)
tag = 66240;
else
tag = 66272;
if (p->type & CUPS_PRINTER_REMOTE)
tag |= 8;
if (p->state == IPP_PRINTER_PROCESSING)
tag |= 1;
else if (p->state == IPP_PRINTER_STOPPED)
tag |= 2;
cupsFilePuts(fp, "#!/bin/sh\n");
cupsFilePrintf(fp, "#Tag %d\n", tag);
cupsFileClose(fp);
chmod(filename, 0755);
chown(filename, User, Group);
}
}
snprintf(filename, sizeof(filename), "/var/spool/lp/default");
if (DefaultPrinter != NULL)
{
if ((fp = cupsFileOpen(filename, "w")) != NULL)
{
cupsFilePrintf(fp, "%s\n", DefaultPrinter->name);
cupsFileClose(fp);
chmod(filename, 0644);
chown(filename, User, Group);
}
}
else
unlink(filename);
}
#endif
static void
write_xml_string(cups_file_t *fp,
const char *s)
{
const char *start;
if (!s)
return;
for (start = s; *s; s ++)
{
if (*s == '&')
{
if (s > start)
cupsFileWrite(fp, start, s - start);
cupsFilePuts(fp, "&");
start = s + 1;
}
else if (*s == '<')
{
if (s > start)
cupsFileWrite(fp, start, s - start);
cupsFilePuts(fp, "<");
start = s + 1;
}
}
if (s > start)
cupsFilePuts(fp, start);
}