#include "cupsd.h"
static void write_printcap(void);
#ifdef __sgi
static void write_irix_config(printer_t *p);
static void write_irix_state(printer_t *p);
#endif
printer_t *
AddPrinter(const char *name)
{
printer_t *p,
*current,
*prev;
DEBUG_printf(("AddPrinter(\"%s\")\n", name));
if (name == NULL)
return (NULL);
if ((p = calloc(1, sizeof(printer_t))) == NULL)
return (NULL);
strlcpy(p->name, name, sizeof(p->name));
strlcpy(p->info, name, sizeof(p->info));
strlcpy(p->hostname, ServerName, sizeof(p->hostname));
snprintf(p->uri, sizeof(p->uri), "ipp://%s:%d/printers/%s", ServerName,
ntohs(Listeners[0].address.sin_port), name);
p->state = IPP_PRINTER_STOPPED;
p->accepting = 0;
p->filetype = mimeAddType(MimeDatabase, "printer", name);
strcpy(p->job_sheets[0], "none");
strcpy(p->job_sheets[1], "none");
SetPrinterAttrs(p);
for (prev = NULL, current = Printers;
current != NULL;
prev = current, current = current->next)
if (strcasecmp(p->name, current->name) < 0)
break;
if (prev == NULL)
Printers = p;
else
prev->next = p;
p->next = current;
write_printcap();
return (p);
}
void
AddPrinterFilter(printer_t *p,
const char *filter)
{
int i;
char super[MIME_MAX_SUPER],
type[MIME_MAX_TYPE],
program[1024];
int cost;
mime_type_t **temptype;
if (p == NULL || filter == NULL)
return;
if (sscanf(filter, "%15[^/]/%31s%d%1023s", super, type, &cost, program) != 4)
{
LogMessage(L_ERROR, "AddPrinterFilter: Invalid filter string \"%s\"!",
filter);
return;
}
for (temptype = MimeDatabase->types, i = MimeDatabase->num_types;
i > 0;
i --, temptype ++)
if (((super[0] == '*' && strcmp((*temptype)->super, "printer") != 0) ||
strcmp((*temptype)->super, super) == 0) &&
(type[0] == '*' || strcmp((*temptype)->type, type) == 0))
{
LogMessage(L_DEBUG2, "Adding filter %s/%s %s/%s %d %s",
(*temptype)->super, (*temptype)->type,
p->filetype->super, p->filetype->type,
cost, program);
mimeAddFilter(MimeDatabase, *temptype, p->filetype, cost, program);
}
}
void
AddPrinterUser(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
DeleteAllPrinters(void)
{
printer_t *p,
*next;
for (p = Printers; p != NULL; p = next)
{
next = p->next;
if (!(p->type & CUPS_PRINTER_CLASS))
DeletePrinter(p);
}
}
void
DeletePrinter(printer_t *p)
{
printer_t *current,
*prev;
#ifdef __sgi
char filename[1024];
#endif
DEBUG_printf(("DeletePrinter(%08x): p->name = \"%s\"...\n", p, p->name));
if (p == NULL)
return;
for (prev = NULL, current = Printers;
current != NULL;
prev = current, current = current->next)
if (p == current)
break;
if (current == NULL)
{
LogMessage(L_ERROR, "Tried to delete a non-existent printer %s!\n",
p->name);
return;
}
if (prev == NULL)
Printers = p->next;
else
prev->next = p->next;
StopPrinter(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 = Printers;
#ifdef __sgi
write_irix_state(DefaultPrinter);
#endif
}
if (!(p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)))
DeletePrinterFromClasses(p);
if (p->printers != NULL)
free(p->printers);
ippDelete(p->attrs);
DeletePrinterFilters(p);
FreePrinterUsers(p);
FreeQuotas(p);
free(p);
write_printcap();
}
void
DeletePrinterFilters(printer_t *p)
{
int i;
mime_filter_t *filter;
if (p == NULL)
return;
for (filter = MimeDatabase->filters, i = MimeDatabase->num_filters;
i > 0;
i --, filter ++)
if (filter->dst == p->filetype)
{
MimeDatabase->num_filters --;
if (i > 1)
memcpy(filter, filter + 1, sizeof(mime_filter_t) * (i - 1));
filter --;
}
}
printer_t *
FindPrinter(const char *name)
{
printer_t *p;
for (p = Printers; p != NULL; p = p->next)
switch (strcasecmp(name, p->name))
{
case 0 :
if (!(p->type & CUPS_PRINTER_CLASS))
return (p);
case 1 :
break;
case -1 :
return (NULL);
}
return (NULL);
}
void
FreePrinterUsers(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
LoadAllPrinters(void)
{
FILE *fp;
int linenum;
int len;
char line[1024],
name[256],
*nameptr,
*value,
*valueptr;
printer_t *p;
snprintf(line, sizeof(line), "%s/printers.conf", ServerRoot);
if ((fp = fopen(line, "r")) == NULL)
return;
linenum = 0;
p = NULL;
while (fgets(line, sizeof(line), fp) != NULL)
{
linenum ++;
if (line[0] == '#')
continue;
len = strlen(line);
while (len > 0 && isspace(line[len - 1]))
{
len --;
line[len] = '\0';
}
for (value = line; isspace(*value); value ++);
for (nameptr = name; *value != '\0' && !isspace(*value) &&
nameptr < (name + sizeof(name) - 1);)
*nameptr++ = *value++;
*nameptr = '\0';
while (isspace(*value))
value ++;
if (name[0] == '\0')
continue;
if (strcmp(name, "<Printer") == 0 ||
strcmp(name, "<DefaultPrinter") == 0)
{
if (line[len - 1] == '>' && p == NULL)
{
line[len - 1] = '\0';
p = AddPrinter(value);
p->accepting = 1;
p->state = IPP_PRINTER_IDLE;
if (strcmp(name, "<DefaultPrinter") == 0)
DefaultPrinter = p;
}
else
{
LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
linenum);
return;
}
}
else if (strcmp(name, "</Printer>") == 0)
{
if (p != NULL)
{
SetPrinterAttrs(p);
p = NULL;
}
else
{
LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
linenum);
return;
}
}
else if (p == NULL)
{
LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
linenum);
return;
}
else if (strcmp(name, "Info") == 0)
strlcpy(p->info, value, sizeof(p->info));
else if (strcmp(name, "Location") == 0)
strlcpy(p->location, value, sizeof(p->location));
else if (strcmp(name, "DeviceURI") == 0)
strlcpy(p->device_uri, value, sizeof(p->device_uri));
else if (strcmp(name, "State") == 0)
{
if (strcasecmp(value, "idle") == 0)
p->state = IPP_PRINTER_IDLE;
else if (strcasecmp(value, "stopped") == 0)
p->state = IPP_PRINTER_STOPPED;
}
else if (strcmp(name, "StateMessage") == 0)
{
while (isspace(*value))
value ++;
strlcpy(p->state_message, value, sizeof(p->state_message));
}
else if (strcmp(name, "Accepting") == 0)
{
if (strcasecmp(value, "yes") == 0)
p->accepting = 1;
else
p->accepting = 0;
}
else if (strcmp(name, "JobSheets") == 0)
{
for (valueptr = value; *valueptr && !isspace(*valueptr); valueptr ++);
if (*valueptr)
*valueptr++ = '\0';
strlcpy(p->job_sheets[0], value, sizeof(p->job_sheets[0]));
while (isspace(*valueptr))
valueptr ++;
if (*valueptr)
{
for (value = valueptr; *valueptr && !isspace(*valueptr); valueptr ++);
if (*valueptr)
*valueptr++ = '\0';
strlcpy(p->job_sheets[1], value, sizeof(p->job_sheets[1]));
}
}
else if (strcmp(name, "AllowUser") == 0)
{
p->deny_users = 0;
AddPrinterUser(p, value);
}
else if (strcmp(name, "DenyUser") == 0)
{
p->deny_users = 1;
AddPrinterUser(p, value);
}
else if (strcmp(name, "QuotaPeriod") == 0)
p->quota_period = atoi(value);
else if (strcmp(name, "PageLimit") == 0)
p->page_limit = atoi(value);
else if (strcmp(name, "KLimit") == 0)
p->k_limit = atoi(value);
else
{
LogMessage(L_ERROR, "Unknown configuration directive %s on line %d of printers.conf.",
name, linenum);
}
}
fclose(fp);
}
void
SaveAllPrinters(void)
{
int i;
FILE *fp;
char temp[1024];
char backup[1024];
printer_t *printer;
time_t curtime;
struct tm *curdate;
snprintf(temp, sizeof(temp), "%s/printers.conf", ServerRoot);
snprintf(backup, sizeof(backup), "%s/printers.conf.O", ServerRoot);
if (rename(temp, backup))
LogMessage(L_ERROR, "Unable to backup printers.conf - %s", strerror(errno));
if ((fp = fopen(temp, "w")) == NULL)
{
LogMessage(L_ERROR, "Unable to save printers.conf - %s", strerror(errno));
if (rename(backup, temp))
LogMessage(L_ERROR, "Unable to restore printers.conf - %s", strerror(errno));
return;
}
else
LogMessage(L_INFO, "Saving printers.conf...");
fchown(fileno(fp), User, Group);
fchmod(fileno(fp), 0600);
curtime = time(NULL);
curdate = gmtime(&curtime);
strftime(temp, sizeof(temp) - 1, CUPS_STRFTIME_FORMAT, curdate);
fputs("# Printer configuration file for " CUPS_SVERSION "\n", fp);
fprintf(fp, "# Written by cupsd on %s\n", temp);
for (printer = Printers; printer != NULL; printer = printer->next)
{
if ((printer->type & CUPS_PRINTER_REMOTE) ||
(printer->type & CUPS_PRINTER_CLASS) ||
(printer->type & CUPS_PRINTER_IMPLICIT))
continue;
if (printer == DefaultPrinter)
fprintf(fp, "<DefaultPrinter %s>\n", printer->name);
else
fprintf(fp, "<Printer %s>\n", printer->name);
if (printer->info[0])
fprintf(fp, "Info %s\n", printer->info);
if (printer->location[0])
fprintf(fp, "Location %s\n", printer->location);
if (printer->device_uri[0])
fprintf(fp, "DeviceURI %s\n", printer->device_uri);
if (printer->state == IPP_PRINTER_STOPPED)
{
fputs("State Stopped\n", fp);
fprintf(fp, "StateMessage %s\n", printer->state_message);
}
else
fputs("State Idle\n", fp);
if (printer->accepting)
fputs("Accepting Yes\n", fp);
else
fputs("Accepting No\n", fp);
fprintf(fp, "JobSheets %s %s\n", printer->job_sheets[0],
printer->job_sheets[1]);
fprintf(fp, "QuotaPeriod %d\n", printer->quota_period);
fprintf(fp, "PageLimit %d\n", printer->page_limit);
fprintf(fp, "KLimit %d\n", printer->k_limit);
for (i = 0; i < printer->num_users; i ++)
fprintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow",
printer->users[i]);
fputs("</Printer>\n", fp);
#ifdef __sgi
write_irix_state(printer);
#endif
}
fclose(fp);
}
void
SetPrinterAttrs(printer_t *p)
{
char uri[HTTP_MAX_URI];
char method[HTTP_MAX_URI],
username[HTTP_MAX_URI],
host[HTTP_MAX_URI],
resource[HTTP_MAX_URI];
int port;
int i;
char filename[1024];
int num_media;
location_t *auth;
const char *auth_supported;
cups_ptype_t printer_type;
ppd_file_t *ppd;
ppd_option_t *input_slot,
*media_type,
*page_size,
*output_bin;
ipp_attribute_t *attr;
ipp_value_t *val;
int nups[] =
{ 1, 2, 4, 6, 9, 16 };
ipp_orient_t orients[4] =
{
IPP_PORTRAIT,
IPP_LANDSCAPE,
IPP_REVERSE_LANDSCAPE,
IPP_REVERSE_PORTRAIT
};
const char *sides[3] =
{
"one",
"two-long-edge",
"two-short-edge"
};
const char *versions[] =
{
"1.0",
"1.1"
};
ipp_op_t 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_JOB_ATTRIBUTES,
IPP_ENABLE_PRINTER,
IPP_DISABLE_PRINTER,
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_GET_DEVICES,
CUPS_GET_PPDS,
IPP_RESTART_JOB
};
const char *charsets[] =
{
"us-ascii",
"iso-8859-1",
"iso-8859-2",
"iso-8859-3",
"iso-8859-4",
"iso-8859-5",
"iso-8859-6",
"iso-8859-7",
"iso-8859-8",
"iso-8859-9",
"iso-8859-10",
"iso-8859-13",
"iso-8859-14",
"iso-8859-15",
"utf-8",
"windows-874",
"windows-1250",
"windows-1251",
"windows-1252",
"windows-1253",
"windows-1254",
"windows-1255",
"windows-1256",
"windows-1257",
"windows-1258",
"koi8-r",
"koi8-u",
};
int num_finishings;
ipp_finish_t finishings[5];
const char *multiple_document_handling[] =
{
"separate-documents-uncollated-copies",
"separate-documents-collated-copies"
};
DEBUG_printf(("SetPrinterAttrs: entering name = %s, type = %x\n", p->name,
p->type));
DeletePrinterFilters(p);
AddPrinterFilter(p, "application/vnd.cups-raw 0 -");
auth_supported = "requesting-user-name";
if (!(p->type & CUPS_PRINTER_REMOTE))
{
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 = FindBest(resource, HTTP_POST)) != NULL)
{
if (auth->type == AUTH_BASIC || auth->type == AUTH_BASICDIGEST)
auth_supported = "basic";
else if (auth->type == AUTH_DIGEST)
auth_supported = "digest";
}
}
if (p->attrs)
ippDelete(p->attrs);
p->attrs = ippNew();
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported",
NULL, p->uri);
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);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
NULL, p->info);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info",
NULL, p->uri);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"pdl-override-supported", NULL, "not-attempted");
ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"ipp-versions-supported", sizeof(versions) / sizeof(versions[0]),
NULL, versions);
ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "operations-supported",
sizeof(ops) / sizeof(ops[0]) + JobFiles - 1, (int *)ops);
ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "multiple-document-jobs-supported", 1);
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"multiple-operation-time-out", 60);
ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"multiple-document-handling-supported",
sizeof(multiple_document_handling) /
sizeof(multiple_document_handling[0]), NULL,
multiple_document_handling);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_CHARSET, "charset-configured",
NULL, DefaultCharset);
ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_CHARSET, "charset-supported",
sizeof(charsets) / sizeof(charsets[0]), NULL, charsets);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
"natural-language-configured", NULL, DefaultLanguage);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
"generated-natural-language-supported", NULL, DefaultLanguage);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
"document-format-default", NULL, "application/octet-stream");
ippAddStrings(p->attrs, IPP_TAG_PRINTER,
(ipp_tag_t)(IPP_TAG_MIMETYPE | IPP_TAG_COPY),
"document-format-supported", NumMimeTypes, NULL, MimeTypes);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"compression-supported", NULL, "none");
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"job-priority-supported", 100);
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"job-priority-default", 50);
ippAddRange(p->attrs, IPP_TAG_PRINTER, "copies-supported", 1, 65535);
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"copies-default", 1);
ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "page-ranges-supported", 1);
ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"number-up-supported", sizeof(nups) / sizeof(nups[0]), nups);
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"number-up-default", 1);
ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
"orientation-requested-supported", 4, (int *)orients);
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
"orientation-requested-default", IPP_PORTRAIT);
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);
if (NumBanners > 0)
{
if (Classification[0] && !ClassifyOverride)
attr = ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
"job-sheets-supported", NULL, Classification);
else
attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
"job-sheets-supported", NumBanners + 1, NULL, NULL);
if (attr == NULL)
LogMessage(L_EMERG, "SetPrinterAttrs: Unable to allocate memory for "
"job-sheets-supported attribute: %s!",
strerror(errno));
else if (!Classification[0] || ClassifyOverride)
{
attr->values[0].string.text = strdup("none");
for (i = 0; i < NumBanners; i ++)
attr->values[i + 1].string.text = strdup(Banners[i].name);
}
if (!(p->type & CUPS_PRINTER_REMOTE))
{
attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
"job-sheets-default", 2, NULL, NULL);
if (attr != NULL)
{
attr->values[0].string.text = strdup(Classification[0] ?
Classification : p->job_sheets[0]);
attr->values[1].string.text = strdup(Classification[0] ?
Classification : p->job_sheets[1]);
}
}
}
printer_type = p->type;
if (p->type & CUPS_PRINTER_REMOTE)
{
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
"printer-make-and-model", NULL, p->make_model);
}
else
{
p->type &= ~CUPS_PRINTER_OPTIONS;
if (p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
{
if ((p->type & CUPS_PRINTER_IMPLICIT) && p->num_printers > 0)
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");
if (p->num_printers > 0)
{
attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
"member-uris", 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 = strdup(p->printers[i]->uri);
p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
}
attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
"member-names", p->num_printers, NULL, NULL);
if (attr != NULL)
{
for (i = 0; i < p->num_printers; i ++)
attr->values[i].string.text = strdup(p->printers[i]->name);
}
}
}
else
{
if (strstr(p->device_uri, "://") != NULL)
{
httpSeparate(p->device_uri, method, username, host, &port, resource);
if (port)
snprintf(uri, sizeof(uri), "%s://%s:%d%s", method, host, port,
resource);
else
snprintf(uri, sizeof(uri), "%s://%s%s", method, host, resource);
}
else
{
strcpy(uri, p->device_uri);
}
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
uri);
p->type |= CUPS_PRINTER_BW;
finishings[0] = IPP_FINISHINGS_NONE;
num_finishings = 1;
snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot,
p->name);
if ((ppd = ppdOpenFile(filename)) != NULL)
{
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;
ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "color-supported",
ppd->color_device);
if (ppd->throughput)
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"pages-per-minute", ppd->throughput);
if (ppd->nickname)
strlcpy(p->make_model, ppd->nickname, sizeof(p->make_model));
else if (ppd->modelname)
strlcpy(p->make_model, ppd->modelname, sizeof(p->make_model));
else
strcpy(p->make_model, "Bad PPD File");
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
"printer-make-and-model", NULL, p->make_model);
if ((input_slot = ppdFindOption(ppd, "InputSlot")) != NULL)
num_media = input_slot->num_choices;
else
num_media = 0;
if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL)
num_media += media_type->num_choices;
if ((page_size = ppdFindOption(ppd, "PageSize")) != NULL)
num_media += page_size->num_choices;
attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"media-supported", num_media, NULL, NULL);
if (attr != NULL)
{
val = attr->values;
if (input_slot != NULL)
for (i = 0; i < input_slot->num_choices; i ++, val ++)
val->string.text = strdup(input_slot->choices[i].choice);
if (media_type != NULL)
for (i = 0; i < media_type->num_choices; i ++, val ++)
val->string.text = strdup(media_type->choices[i].choice);
if (page_size != NULL)
{
for (i = 0; i < page_size->num_choices; i ++, val ++)
val->string.text = strdup(page_size->choices[i].choice);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
NULL, page_size->defchoice);
}
else if (input_slot != NULL)
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
NULL, input_slot->defchoice);
else if (media_type != NULL)
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
NULL, media_type->defchoice);
else
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
NULL, "none");
}
if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
{
attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"output-bin-supported", output_bin->num_choices,
NULL, NULL);
if (attr != NULL)
{
for (i = 0, val = attr->values;
i < output_bin->num_choices;
i ++, val ++)
val->string.text = strdup(output_bin->choices[i].choice);
}
}
if (ppdFindOption(ppd, "Duplex") != NULL)
{
p->type |= CUPS_PRINTER_DUPLEX;
ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "sides-supported",
3, NULL, sides);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "sides-default",
NULL, "one");
}
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;
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]));
AddPrinterFilter(p, ppd->filters[i]);
}
if (ppd->num_filters == 0)
AddPrinterFilter(p, "application/vnd.cups-postscript 0 -");
ppdClose(ppd);
printer_type = p->type;
}
else if (access(filename, 0) == 0)
{
LogMessage(L_ERROR, "PPD file for %s cannot be loaded!", p->name);
AddPrinterFilter(p, "application/vnd.cups-postscript 0 -");
}
else
{
snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot,
p->name);
if (access(filename, X_OK) == 0)
{
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
"printer-make-and-model", NULL, "Local System V Printer");
snprintf(filename, sizeof(filename), "*/* 0 %s/interfaces/%s",
ServerRoot, p->name);
AddPrinterFilter(p, filename);
}
else if (strncmp(p->device_uri, "ipp://", 6) == 0 &&
(strstr(p->device_uri, "/printers/") != NULL ||
strstr(p->device_uri, "/classes/") != NULL))
{
printer_type |= CUPS_PRINTER_REMOTE;
attr = ippFindAttribute(p->attrs, "printer-uri-supported", IPP_TAG_URI);
free(attr->values[0].string.text);
attr->values[0].string.text = strdup(p->device_uri);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
"printer-make-and-model", NULL, "Remote Printer");
AddPrinterFilter(p, "*/* 0 -");
}
else
{
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
"printer-make-and-model", NULL, "Local Raw Printer");
AddPrinterFilter(p, "*/* 0 -");
}
}
ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
"finishings-supported", num_finishings, (int *)finishings);
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
"finishings-default", IPP_FINISHINGS_NONE);
}
}
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-type",
printer_type);
DEBUG_printf(("SetPrinterAttrs: leaving name = %s, type = %x\n", p->name,
p->type));
#ifdef __sgi
write_irix_config(p);
write_irix_state(p);
#endif
}
void
SetPrinterState(printer_t *p,
ipp_pstate_t s)
{
ipp_pstate_t old_state;
if (p->type & CUPS_PRINTER_REMOTE)
return;
old_state = p->state;
p->state = s;
p->state_time = time(NULL);
if (old_state != s)
{
p->browse_time = 0;
#ifdef __sgi
write_irix_state(p);
#endif
}
if ((old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED))
SaveAllPrinters();
CheckJobs();
}
void
SortPrinters(void)
{
printer_t *current,
*prev,
*next;
int did_swap;
do
{
for (did_swap = 0, current = Printers, prev = NULL; current != NULL;)
if (current->next == NULL)
break;
else if (strcasecmp(current->name, current->next->name) > 0)
{
DEBUG_printf(("Swapping %s and %s...\n", current->name,
current->next->name));
did_swap = 1;
if (prev == NULL)
Printers = current->next;
else
prev->next = current->next;
next = current->next;
current->next = next->next;
next->next = current;
prev = next;
}
else
{
prev = current;
current = current->next;
}
}
while (did_swap);
}
void
StopPrinter(printer_t *p)
{
job_t *job;
p->state = IPP_PRINTER_STOPPED;
if (p->job)
{
job = (job_t *)p->job;
StopJob(job->id, 0);
job->state->values[0].integer = IPP_JOB_PENDING;
SaveJob(job->id);
}
}
const char *
ValidateDest(const char *hostname,
const char *resource,
cups_ptype_t *dtype)
{
printer_t *p;
char localname[1024],
*lptr,
*sptr;
DEBUG_printf(("ValidateDest(\"%s\", \"%s\", %p)\n", hostname, resource, dtype));
if (strncmp(resource, "/classes/", 9) == 0)
{
resource += 9;
}
else if (strncmp(resource, "/printers/", 10) == 0)
{
resource += 10;
}
else
{
return (NULL);
}
if ((p = FindPrinter(resource)) == NULL)
p = FindClass(resource);
if (p == NULL && strchr(resource, '@') == NULL)
return (NULL);
else if (p != NULL)
{
*dtype = p->type & CUPS_PRINTER_CLASS;
return (p->name);
}
if (strcasecmp(hostname, "localhost") == 0)
hostname = ServerName;
strlcpy(localname, hostname, sizeof(localname));
if (strcasecmp(hostname, ServerName) != 0)
{
lptr = strchr(localname, '.');
sptr = strchr(ServerName, '.');
if (sptr != NULL && lptr != NULL)
{
while (lptr != NULL)
{
if (strcasecmp(lptr, sptr) == 0)
{
*lptr = '\0';
break;
}
else
lptr = strchr(lptr + 1, '.');
}
}
}
DEBUG_printf(("localized hostname is \"%s\"...\n", localname));
for (p = Printers; p != NULL; p = p->next)
if (strcasecmp(p->hostname, localname) == 0 &&
strcasecmp(p->name, resource) == 0)
{
*dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE);
return (p->name);
}
return (NULL);
}
static void
write_printcap(void)
{
FILE *fp;
printer_t *p;
if (!Printcap[0])
return;
if ((fp = fopen(Printcap, "w")) == NULL)
return;
fputs("# This file was automatically generated by cupsd(1m) from the\n", fp);
fprintf(fp, "# %s/printers.conf file. All changes to this file\n",
ServerRoot);
fputs("# will be lost.\n", fp);
switch (PrintcapFormat)
{
case PRINTCAP_BSD:
if (DefaultPrinter)
fprintf(fp, "%s:\n", DefaultPrinter->name);
for (p = Printers; p != NULL; p = p->next)
if (p != DefaultPrinter)
fprintf(fp, "%s:\n", p->name);
break;
case PRINTCAP_SOLARIS:
fputs("_all:all=", fp);
for (p = Printers; p != NULL; p = p->next)
fprintf(fp, "%s%c", p->name, p->next ? ',' : '\n');
if (DefaultPrinter)
fprintf(fp, "_default:use=%s\n", DefaultPrinter->name);
for (p = Printers; p != NULL; p = p->next)
fprintf(fp, "%s:\\\n"
"\t:bsdaddr=%s,%s:\\\n"
"\t:description=%s:\n",
p->name, ServerName, p->name, p->info);
break;
}
fclose(fp);
}
#ifdef __sgi
static void
write_irix_config(printer_t *p)
{
char filename[1024];
FILE *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 = fopen(filename, "w")) != NULL)
{
fputs("#!/bin/sh\n", fp);
if ((attr = ippFindAttribute(p->attrs, "printer-make-and-model",
IPP_TAG_TEXT)) != NULL)
fprintf(fp, "NAME=\"%s\"\n", attr->values[0].string.text);
else if (p->type & CUPS_PRINTER_CLASS)
fputs("NAME=\"Printer Class\"\n", fp);
else
fputs("NAME=\"Remote Destination\"\n", fp);
if (p->type & CUPS_PRINTER_COLOR)
fputs("TYPE=ColorPostScript\n", fp);
else
fputs("TYPE=MonoPostScript\n", fp);
fprintf(fp, "HOSTNAME=%s\n", ServerName);
fprintf(fp, "HOSTPRINTER=%s\n", p->name);
fclose(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 = fopen(filename, "w")) != NULL)
{
fputs("/dev/null\n", fp);
fclose(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 = fopen(filename, "w")) != NULL)
{
fputs("#!/bin/sh\n", fp);
fprintf(fp, "%s -d %s -o \"$3\"\n", PrintcapGUI, p->name);
fclose(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 = fopen(filename, "w")) != NULL)
{
fprintf(fp, "Printer Class | %s\n",
(p->type & CUPS_PRINTER_COLOR) ? "ColorPostScript" : "MonoPostScript");
fprintf(fp, "Printer Model | %s\n", p->make_model);
fprintf(fp, "Location Code | %s\n", p->location);
fprintf(fp, "Physical Location | %s\n", p->info);
fprintf(fp, "Port Path | %s\n", p->device_uri);
fprintf(fp, "Config Path | /var/spool/lp/pod/%s.config\n", p->name);
fprintf(fp, "Active Status Path | /var/spool/lp/pod/%s.status\n", p->name);
fputs("Status Update Wait | 10 seconds\n", fp);
fclose(fp);
chmod(filename, 0664);
chown(filename, User, Group);
}
}
static void
write_irix_state(printer_t *p)
{
char filename[1024];
FILE *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 = fopen(filename, "w")) != NULL)
{
fprintf(fp, "Operational Status | %s\n",
(p->state == IPP_PRINTER_IDLE) ? "Idle" :
(p->state == IPP_PRINTER_PROCESSING) ? "Busy" :
"Faulted");
fprintf(fp, "Information | 01 00 00 | %s\n", CUPS_SVERSION);
fprintf(fp, "Information | 02 00 00 | Device URI: %s\n", p->device_uri);
fprintf(fp, "Information | 03 00 00 | %s jobs\n",
p->accepting ? "Accepting" : "Not accepting");
fprintf(fp, "Information | 04 00 00 | %s\n", p->state_message);
fclose(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 = fopen(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;
fputs("#!/bin/sh\n", fp);
fprintf(fp, "#Tag %d\n", tag);
fclose(fp);
chmod(filename, 0755);
chown(filename, User, Group);
}
}
snprintf(filename, sizeof(filename), "/var/spool/lp/default");
if (DefaultPrinter != NULL)
{
if ((fp = fopen(filename, "w")) != NULL)
{
fprintf(fp, "%s\n", DefaultPrinter->name);
fclose(fp);
chmod(filename, 0644);
chown(filename, User, Group);
}
}
else
unlink(filename);
}
#endif