mirror of https://gitee.com/openkylin/cups.git
810 lines
20 KiB
C
810 lines
20 KiB
C
|
/*
|
||
|
* Printer class routines for the CUPS scheduler.
|
||
|
*
|
||
|
* Copyright 2007-2017 by Apple Inc.
|
||
|
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
|
||
|
*
|
||
|
* Licensed under Apache License v2.0. See the file "LICENSE" for more information.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Include necessary headers...
|
||
|
*/
|
||
|
|
||
|
#include "cupsd.h"
|
||
|
|
||
|
|
||
|
/*
|
||
|
* 'cupsdAddClass()' - Add a class to the system.
|
||
|
*/
|
||
|
|
||
|
cupsd_printer_t * /* O - New class */
|
||
|
cupsdAddClass(const char *name) /* I - Name of class */
|
||
|
{
|
||
|
cupsd_printer_t *c; /* New class */
|
||
|
char uri[1024]; /* Class URI */
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Add the printer and set the type to "class"...
|
||
|
*/
|
||
|
|
||
|
if ((c = cupsdAddPrinter(name)) != NULL)
|
||
|
{
|
||
|
/*
|
||
|
* Change from a printer to a class...
|
||
|
*/
|
||
|
|
||
|
c->type = CUPS_PRINTER_CLASS;
|
||
|
|
||
|
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
|
||
|
ServerName, RemotePort, "/classes/%s", name);
|
||
|
cupsdSetString(&c->uri, uri);
|
||
|
|
||
|
cupsdSetString(&c->error_policy, "retry-current-job");
|
||
|
}
|
||
|
|
||
|
return (c);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* 'cupsdAddPrinterToClass()' - Add a printer to a class...
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
cupsdAddPrinterToClass(
|
||
|
cupsd_printer_t *c, /* I - Class to add to */
|
||
|
cupsd_printer_t *p) /* I - Printer to add */
|
||
|
{
|
||
|
int i; /* Looping var */
|
||
|
cupsd_printer_t **temp; /* Pointer to printer array */
|
||
|
|
||
|
|
||
|
/*
|
||
|
* See if this printer is already a member of the class...
|
||
|
*/
|
||
|
|
||
|
for (i = 0; i < c->num_printers; i ++)
|
||
|
if (c->printers[i] == p)
|
||
|
return;
|
||
|
|
||
|
/*
|
||
|
* Allocate memory as needed...
|
||
|
*/
|
||
|
|
||
|
if (c->num_printers == 0)
|
||
|
temp = malloc(sizeof(cupsd_printer_t *));
|
||
|
else
|
||
|
temp = realloc(c->printers, sizeof(cupsd_printer_t *) * (size_t)(c->num_printers + 1));
|
||
|
|
||
|
if (temp == NULL)
|
||
|
{
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to add printer %s to class %s!",
|
||
|
p->name, c->name);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Add the printer to the end of the array and update the number of printers.
|
||
|
*/
|
||
|
|
||
|
c->printers = temp;
|
||
|
temp += c->num_printers;
|
||
|
c->num_printers ++;
|
||
|
|
||
|
*temp = p;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* 'cupsdDeletePrinterFromClass()' - Delete a printer from a class.
|
||
|
*/
|
||
|
|
||
|
int /* O - 1 if class changed, 0 otherwise */
|
||
|
cupsdDeletePrinterFromClass(
|
||
|
cupsd_printer_t *c, /* I - Class to delete from */
|
||
|
cupsd_printer_t *p) /* I - Printer to delete */
|
||
|
{
|
||
|
int i; /* Looping var */
|
||
|
|
||
|
|
||
|
/*
|
||
|
* See if the printer is in the class...
|
||
|
*/
|
||
|
|
||
|
for (i = 0; i < c->num_printers; i ++)
|
||
|
if (p == c->printers[i])
|
||
|
break;
|
||
|
|
||
|
/*
|
||
|
* If it is, remove it from the list...
|
||
|
*/
|
||
|
|
||
|
if (i < c->num_printers)
|
||
|
{
|
||
|
/*
|
||
|
* Yes, remove the printer...
|
||
|
*/
|
||
|
|
||
|
c->num_printers --;
|
||
|
if (i < c->num_printers)
|
||
|
memmove(c->printers + i, c->printers + i + 1,
|
||
|
(size_t)(c->num_printers - i) * sizeof(cupsd_printer_t *));
|
||
|
}
|
||
|
else
|
||
|
return (0);
|
||
|
|
||
|
/*
|
||
|
* Update the IPP attributes (have to do this for member-names)...
|
||
|
*/
|
||
|
|
||
|
cupsdSetPrinterAttrs(c);
|
||
|
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* 'cupsdDeletePrinterFromClasses()' - Delete a printer from all classes.
|
||
|
*/
|
||
|
|
||
|
int /* O - 1 if class changed, 0 otherwise */
|
||
|
cupsdDeletePrinterFromClasses(
|
||
|
cupsd_printer_t *p) /* I - Printer to delete */
|
||
|
{
|
||
|
int changed = 0; /* Any class changed? */
|
||
|
cupsd_printer_t *c; /* Pointer to current class */
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Loop through the printer/class list and remove the printer
|
||
|
* from each class listed...
|
||
|
*/
|
||
|
|
||
|
for (c = (cupsd_printer_t *)cupsArrayFirst(Printers);
|
||
|
c;
|
||
|
c = (cupsd_printer_t *)cupsArrayNext(Printers))
|
||
|
if (c->type & CUPS_PRINTER_CLASS)
|
||
|
changed |= cupsdDeletePrinterFromClass(c, p);
|
||
|
|
||
|
return (changed);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* 'cupsdFindAvailablePrinter()' - Find an available printer in a class.
|
||
|
*/
|
||
|
|
||
|
cupsd_printer_t * /* O - Available printer or NULL */
|
||
|
cupsdFindAvailablePrinter(
|
||
|
const char *name) /* I - Class to check */
|
||
|
{
|
||
|
int i; /* Looping var */
|
||
|
cupsd_printer_t *c; /* Printer class */
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Find the class...
|
||
|
*/
|
||
|
|
||
|
if ((c = cupsdFindClass(name)) == NULL)
|
||
|
{
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to find class \"%s\"!", name);
|
||
|
return (NULL);
|
||
|
}
|
||
|
|
||
|
if (c->num_printers == 0)
|
||
|
return (NULL);
|
||
|
|
||
|
/*
|
||
|
* Make sure that the last printer is also a valid index into the printer
|
||
|
* array. If not, reset the last printer to 0...
|
||
|
*/
|
||
|
|
||
|
if (c->last_printer >= c->num_printers)
|
||
|
c->last_printer = 0;
|
||
|
|
||
|
/*
|
||
|
* Loop through the printers in the class and return the first idle
|
||
|
* printer... We keep track of the last printer that we used so that
|
||
|
* a "round robin" type of scheduling is realized (otherwise the first
|
||
|
* server might be saturated with print jobs...)
|
||
|
*
|
||
|
* Thanks to Joel Fredrikson for helping us get this right!
|
||
|
*/
|
||
|
|
||
|
for (i = c->last_printer + 1; ; i ++)
|
||
|
{
|
||
|
if (i >= c->num_printers)
|
||
|
i = 0;
|
||
|
|
||
|
if (c->printers[i]->accepting &&
|
||
|
(c->printers[i]->state == IPP_PRINTER_IDLE ||
|
||
|
((c->printers[i]->type & CUPS_PRINTER_REMOTE) && !c->printers[i]->job)))
|
||
|
{
|
||
|
c->last_printer = i;
|
||
|
return (c->printers[i]);
|
||
|
}
|
||
|
|
||
|
if (i == c->last_printer)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return (NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* 'cupsdFindClass()' - Find the named class.
|
||
|
*/
|
||
|
|
||
|
cupsd_printer_t * /* O - Matching class or NULL */
|
||
|
cupsdFindClass(const char *name) /* I - Name of class */
|
||
|
{
|
||
|
cupsd_printer_t *c; /* Current class/printer */
|
||
|
|
||
|
|
||
|
if ((c = cupsdFindDest(name)) != NULL && (c->type & CUPS_PRINTER_CLASS))
|
||
|
return (c);
|
||
|
else
|
||
|
return (NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* 'cupsdLoadAllClasses()' - Load classes from the classes.conf file.
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
cupsdLoadAllClasses(void)
|
||
|
{
|
||
|
int i; /* Looping var */
|
||
|
cups_file_t *fp; /* classes.conf file */
|
||
|
int linenum; /* Current line number */
|
||
|
char line[4096], /* Line from file */
|
||
|
*value, /* Pointer to value */
|
||
|
*valueptr; /* Pointer into value */
|
||
|
cupsd_printer_t *p, /* Current printer class */
|
||
|
*temp; /* Temporary pointer to printer */
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Open the classes.conf file...
|
||
|
*/
|
||
|
|
||
|
snprintf(line, sizeof(line), "%s/classes.conf", ServerRoot);
|
||
|
if ((fp = cupsdOpenConfFile(line)) == NULL)
|
||
|
return;
|
||
|
|
||
|
/*
|
||
|
* Read class configurations until we hit EOF...
|
||
|
*/
|
||
|
|
||
|
linenum = 0;
|
||
|
p = NULL;
|
||
|
|
||
|
while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
|
||
|
{
|
||
|
/*
|
||
|
* Decode the directive...
|
||
|
*/
|
||
|
|
||
|
if (!_cups_strcasecmp(line, "<Class") ||
|
||
|
!_cups_strcasecmp(line, "<DefaultClass"))
|
||
|
{
|
||
|
/*
|
||
|
* <Class name> or <DefaultClass name>
|
||
|
*/
|
||
|
|
||
|
if (p == NULL && value)
|
||
|
{
|
||
|
cupsdLogMessage(CUPSD_LOG_DEBUG, "Loading class %s...", value);
|
||
|
|
||
|
/*
|
||
|
* Since prior classes may have implicitly defined this class,
|
||
|
* see if it already exists...
|
||
|
*/
|
||
|
|
||
|
if ((p = cupsdFindDest(value)) != NULL)
|
||
|
{
|
||
|
p->type = CUPS_PRINTER_CLASS;
|
||
|
cupsdSetStringf(&p->uri, "ipp://%s:%d/classes/%s", ServerName,
|
||
|
LocalPort, value);
|
||
|
cupsdSetString(&p->error_policy, "retry-job");
|
||
|
}
|
||
|
else
|
||
|
p = cupsdAddClass(value);
|
||
|
|
||
|
p->accepting = 1;
|
||
|
p->state = IPP_PRINTER_IDLE;
|
||
|
|
||
|
if (!_cups_strcasecmp(line, "<DefaultClass"))
|
||
|
DefaultPrinter = p;
|
||
|
}
|
||
|
else
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR,
|
||
|
"Syntax error on line %d of classes.conf.", linenum);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "</Class>") || !_cups_strcasecmp(line, "</DefaultClass>"))
|
||
|
{
|
||
|
if (p != NULL)
|
||
|
{
|
||
|
cupsdSetPrinterAttrs(p);
|
||
|
p = NULL;
|
||
|
}
|
||
|
else
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR,
|
||
|
"Syntax error on line %d of classes.conf.", linenum);
|
||
|
}
|
||
|
else if (!p)
|
||
|
{
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR,
|
||
|
"Syntax error on line %d of classes.conf.", linenum);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "PrinterId"))
|
||
|
{
|
||
|
if (value && (i = atoi(value)) > 0)
|
||
|
p->printer_id = i;
|
||
|
else
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR, "Bad PrinterId on line %d of classes.conf.", linenum);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "UUID"))
|
||
|
{
|
||
|
if (value && !strncmp(value, "urn:uuid:", 9))
|
||
|
cupsdSetString(&(p->uuid), value);
|
||
|
else
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR,
|
||
|
"Bad UUID on line %d of classes.conf.", linenum);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "AuthInfoRequired"))
|
||
|
{
|
||
|
if (!cupsdSetAuthInfoRequired(p, value, NULL))
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR,
|
||
|
"Bad AuthInfoRequired on line %d of classes.conf.",
|
||
|
linenum);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "Info"))
|
||
|
{
|
||
|
if (value)
|
||
|
cupsdSetString(&p->info, value);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "Location"))
|
||
|
{
|
||
|
if (value)
|
||
|
cupsdSetString(&p->location, value);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "Option") && value)
|
||
|
{
|
||
|
/*
|
||
|
* Option name value
|
||
|
*/
|
||
|
|
||
|
for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
|
||
|
|
||
|
if (!*valueptr)
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR,
|
||
|
"Syntax error on line %d of classes.conf.", linenum);
|
||
|
else
|
||
|
{
|
||
|
for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
|
||
|
|
||
|
p->num_options = cupsAddOption(value, valueptr, p->num_options,
|
||
|
&(p->options));
|
||
|
}
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "Printer"))
|
||
|
{
|
||
|
if (!value)
|
||
|
{
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR,
|
||
|
"Syntax error on line %d of classes.conf.", linenum);
|
||
|
continue;
|
||
|
}
|
||
|
else if ((temp = cupsdFindPrinter(value)) == NULL)
|
||
|
{
|
||
|
cupsdLogMessage(CUPSD_LOG_WARN,
|
||
|
"Unknown printer %s on line %d of classes.conf.",
|
||
|
value, linenum);
|
||
|
|
||
|
/*
|
||
|
* Add the missing remote printer...
|
||
|
*/
|
||
|
|
||
|
if ((temp = cupsdAddPrinter(value)) != NULL)
|
||
|
{
|
||
|
cupsdSetString(&temp->make_model, "Remote Printer on unknown");
|
||
|
|
||
|
temp->state = IPP_PRINTER_STOPPED;
|
||
|
temp->type |= CUPS_PRINTER_REMOTE;
|
||
|
|
||
|
cupsdSetString(&temp->location, "Location Unknown");
|
||
|
cupsdSetString(&temp->info, "No Information Available");
|
||
|
temp->hostname[0] = '\0';
|
||
|
|
||
|
cupsdSetPrinterAttrs(temp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (temp)
|
||
|
cupsdAddPrinterToClass(p, temp);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "State"))
|
||
|
{
|
||
|
/*
|
||
|
* Set the initial queue state...
|
||
|
*/
|
||
|
|
||
|
if (!_cups_strcasecmp(value, "idle"))
|
||
|
p->state = IPP_PRINTER_IDLE;
|
||
|
else if (!_cups_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 classes.conf.",
|
||
|
linenum);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "StateMessage"))
|
||
|
{
|
||
|
/*
|
||
|
* Set the initial queue state message...
|
||
|
*/
|
||
|
|
||
|
if (value)
|
||
|
strlcpy(p->state_message, value, sizeof(p->state_message));
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "StateTime"))
|
||
|
{
|
||
|
/*
|
||
|
* Set the state time...
|
||
|
*/
|
||
|
|
||
|
if (value)
|
||
|
p->state_time = atoi(value);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "Accepting"))
|
||
|
{
|
||
|
/*
|
||
|
* Set the initial accepting state...
|
||
|
*/
|
||
|
|
||
|
if (value &&
|
||
|
(!_cups_strcasecmp(value, "yes") ||
|
||
|
!_cups_strcasecmp(value, "on") ||
|
||
|
!_cups_strcasecmp(value, "true")))
|
||
|
p->accepting = 1;
|
||
|
else if (value &&
|
||
|
(!_cups_strcasecmp(value, "no") ||
|
||
|
!_cups_strcasecmp(value, "off") ||
|
||
|
!_cups_strcasecmp(value, "false")))
|
||
|
p->accepting = 0;
|
||
|
else
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR,
|
||
|
"Syntax error on line %d of classes.conf.",
|
||
|
linenum);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "Shared"))
|
||
|
{
|
||
|
/*
|
||
|
* Set the initial shared state...
|
||
|
*/
|
||
|
|
||
|
if (value &&
|
||
|
(!_cups_strcasecmp(value, "yes") ||
|
||
|
!_cups_strcasecmp(value, "on") ||
|
||
|
!_cups_strcasecmp(value, "true")))
|
||
|
p->shared = 1;
|
||
|
else if (value &&
|
||
|
(!_cups_strcasecmp(value, "no") ||
|
||
|
!_cups_strcasecmp(value, "off") ||
|
||
|
!_cups_strcasecmp(value, "false")))
|
||
|
p->shared = 0;
|
||
|
else
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR,
|
||
|
"Syntax error on line %d of classes.conf.",
|
||
|
linenum);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "JobSheets"))
|
||
|
{
|
||
|
/*
|
||
|
* Set the initial job sheets...
|
||
|
*/
|
||
|
|
||
|
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 classes.conf.", linenum);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "AllowUser"))
|
||
|
{
|
||
|
if (value)
|
||
|
{
|
||
|
p->deny_users = 0;
|
||
|
cupsdAddString(&(p->users), value);
|
||
|
}
|
||
|
else
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR,
|
||
|
"Syntax error on line %d of classes.conf.", linenum);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "DenyUser"))
|
||
|
{
|
||
|
if (value)
|
||
|
{
|
||
|
p->deny_users = 1;
|
||
|
cupsdAddString(&(p->users), value);
|
||
|
}
|
||
|
else
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR,
|
||
|
"Syntax error on line %d of classes.conf.", linenum);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "QuotaPeriod"))
|
||
|
{
|
||
|
if (value)
|
||
|
p->quota_period = atoi(value);
|
||
|
else
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR,
|
||
|
"Syntax error on line %d of classes.conf.", linenum);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "PageLimit"))
|
||
|
{
|
||
|
if (value)
|
||
|
p->page_limit = atoi(value);
|
||
|
else
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR,
|
||
|
"Syntax error on line %d of classes.conf.", linenum);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "KLimit"))
|
||
|
{
|
||
|
if (value)
|
||
|
p->k_limit = atoi(value);
|
||
|
else
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR,
|
||
|
"Syntax error on line %d of classes.conf.", linenum);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "OpPolicy"))
|
||
|
{
|
||
|
if (value)
|
||
|
{
|
||
|
cupsd_policy_t *pol; /* Policy */
|
||
|
|
||
|
|
||
|
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 classes.conf",
|
||
|
value, linenum);
|
||
|
}
|
||
|
else
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR,
|
||
|
"Syntax error on line %d of classes.conf.", linenum);
|
||
|
}
|
||
|
else if (!_cups_strcasecmp(line, "ErrorPolicy"))
|
||
|
{
|
||
|
if (value)
|
||
|
{
|
||
|
if (strcmp(value, "retry-current-job") && strcmp(value, "retry-job"))
|
||
|
cupsdLogMessage(CUPSD_LOG_WARN,
|
||
|
"ErrorPolicy %s ignored on line %d of classes.conf",
|
||
|
value, linenum);
|
||
|
}
|
||
|
else
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR,
|
||
|
"Syntax error on line %d of classes.conf.", linenum);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/*
|
||
|
* Something else we don't understand...
|
||
|
*/
|
||
|
|
||
|
cupsdLogMessage(CUPSD_LOG_ERROR,
|
||
|
"Unknown configuration directive %s on line %d of classes.conf.",
|
||
|
line, linenum);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cupsFileClose(fp);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* 'cupsdSaveAllClasses()' - Save classes to the classes.conf file.
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
cupsdSaveAllClasses(void)
|
||
|
{
|
||
|
cups_file_t *fp; /* classes.conf file */
|
||
|
char filename[1024], /* classes.conf filename */
|
||
|
temp[1024], /* Temporary string */
|
||
|
value[2048], /* Value string */
|
||
|
*name; /* Current user name */
|
||
|
cupsd_printer_t *pclass; /* Current printer class */
|
||
|
int i; /* Looping var */
|
||
|
time_t curtime; /* Current time */
|
||
|
struct tm curdate; /* Current date */
|
||
|
cups_option_t *option; /* Current option */
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Create the classes.conf file...
|
||
|
*/
|
||
|
|
||
|
snprintf(filename, sizeof(filename), "%s/classes.conf", ServerRoot);
|
||
|
|
||
|
if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm)) == NULL)
|
||
|
return;
|
||
|
|
||
|
cupsdLogMessage(CUPSD_LOG_INFO, "Saving classes.conf...");
|
||
|
|
||
|
/*
|
||
|
* Write a small header to the file...
|
||
|
*/
|
||
|
|
||
|
time(&curtime);
|
||
|
localtime_r(&curtime, &curdate);
|
||
|
strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", &curdate);
|
||
|
|
||
|
cupsFilePuts(fp, "# Class 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");
|
||
|
|
||
|
/*
|
||
|
* Write each local class known to the system...
|
||
|
*/
|
||
|
|
||
|
for (pclass = (cupsd_printer_t *)cupsArrayFirst(Printers);
|
||
|
pclass;
|
||
|
pclass = (cupsd_printer_t *)cupsArrayNext(Printers))
|
||
|
{
|
||
|
/*
|
||
|
* Skip remote destinations and regular printers...
|
||
|
*/
|
||
|
|
||
|
if ((pclass->type & CUPS_PRINTER_REMOTE) ||
|
||
|
!(pclass->type & CUPS_PRINTER_CLASS))
|
||
|
continue;
|
||
|
|
||
|
/*
|
||
|
* Write printers as needed...
|
||
|
*/
|
||
|
|
||
|
if (pclass == DefaultPrinter)
|
||
|
cupsFilePrintf(fp, "<DefaultClass %s>\n", pclass->name);
|
||
|
else
|
||
|
cupsFilePrintf(fp, "<Class %s>\n", pclass->name);
|
||
|
|
||
|
if (pclass->printer_id)
|
||
|
cupsFilePrintf(fp, "PrinterId %d\n", pclass->printer_id);
|
||
|
|
||
|
cupsFilePrintf(fp, "UUID %s\n", pclass->uuid);
|
||
|
|
||
|
if (pclass->num_auth_info_required > 0)
|
||
|
{
|
||
|
switch (pclass->num_auth_info_required)
|
||
|
{
|
||
|
case 1 :
|
||
|
strlcpy(value, pclass->auth_info_required[0], sizeof(value));
|
||
|
break;
|
||
|
|
||
|
case 2 :
|
||
|
snprintf(value, sizeof(value), "%s,%s",
|
||
|
pclass->auth_info_required[0],
|
||
|
pclass->auth_info_required[1]);
|
||
|
break;
|
||
|
|
||
|
case 3 :
|
||
|
default :
|
||
|
snprintf(value, sizeof(value), "%s,%s,%s",
|
||
|
pclass->auth_info_required[0],
|
||
|
pclass->auth_info_required[1],
|
||
|
pclass->auth_info_required[2]);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
cupsFilePutConf(fp, "AuthInfoRequired", value);
|
||
|
}
|
||
|
|
||
|
if (pclass->info)
|
||
|
cupsFilePutConf(fp, "Info", pclass->info);
|
||
|
|
||
|
if (pclass->location)
|
||
|
cupsFilePutConf(fp, "Location", pclass->location);
|
||
|
|
||
|
if (pclass->state == IPP_PRINTER_STOPPED)
|
||
|
cupsFilePuts(fp, "State Stopped\n");
|
||
|
else
|
||
|
cupsFilePuts(fp, "State Idle\n");
|
||
|
|
||
|
cupsFilePrintf(fp, "StateTime %d\n", (int)pclass->state_time);
|
||
|
|
||
|
if (pclass->accepting)
|
||
|
cupsFilePuts(fp, "Accepting Yes\n");
|
||
|
else
|
||
|
cupsFilePuts(fp, "Accepting No\n");
|
||
|
|
||
|
if (pclass->shared)
|
||
|
cupsFilePuts(fp, "Shared Yes\n");
|
||
|
else
|
||
|
cupsFilePuts(fp, "Shared No\n");
|
||
|
|
||
|
snprintf(value, sizeof(value), "%s %s", pclass->job_sheets[0],
|
||
|
pclass->job_sheets[1]);
|
||
|
cupsFilePutConf(fp, "JobSheets", value);
|
||
|
|
||
|
for (i = 0; i < pclass->num_printers; i ++)
|
||
|
cupsFilePrintf(fp, "Printer %s\n", pclass->printers[i]->name);
|
||
|
|
||
|
cupsFilePrintf(fp, "QuotaPeriod %d\n", pclass->quota_period);
|
||
|
cupsFilePrintf(fp, "PageLimit %d\n", pclass->page_limit);
|
||
|
cupsFilePrintf(fp, "KLimit %d\n", pclass->k_limit);
|
||
|
|
||
|
for (name = (char *)cupsArrayFirst(pclass->users);
|
||
|
name;
|
||
|
name = (char *)cupsArrayNext(pclass->users))
|
||
|
cupsFilePutConf(fp, pclass->deny_users ? "DenyUser" : "AllowUser", name);
|
||
|
|
||
|
if (pclass->op_policy)
|
||
|
cupsFilePutConf(fp, "OpPolicy", pclass->op_policy);
|
||
|
if (pclass->error_policy)
|
||
|
cupsFilePutConf(fp, "ErrorPolicy", pclass->error_policy);
|
||
|
|
||
|
for (i = pclass->num_options, option = pclass->options;
|
||
|
i > 0;
|
||
|
i --, option ++)
|
||
|
{
|
||
|
snprintf(value, sizeof(value), "%s %s", option->name, option->value);
|
||
|
cupsFilePutConf(fp, "Option", value);
|
||
|
}
|
||
|
|
||
|
if (pclass == DefaultPrinter)
|
||
|
cupsFilePuts(fp, "</DefaultClass>\n");
|
||
|
else
|
||
|
cupsFilePuts(fp, "</Class>\n");
|
||
|
}
|
||
|
|
||
|
cupsdCloseCreatedConfFile(fp, filename);
|
||
|
}
|