#include "cupsd.h"
printer_t *
AddClass(const char *name)
{
printer_t *c;
if ((c = AddPrinter(name)) != NULL)
{
c->type = CUPS_PRINTER_CLASS;
snprintf(c->uri, sizeof(c->uri), "ipp://%s:%d/classes/%s", ServerName,
ntohs(Listeners[0].address.sin_port), name);
SetPrinterAttrs(c);
}
return (c);
}
void
AddPrinterToClass(printer_t *c,
printer_t *p)
{
int i;
printer_t **temp;
for (i = 0; i < c->num_printers; i ++)
if (c->printers[i] == p)
return;
if (c->num_printers == 0)
temp = malloc(sizeof(printer_t *));
else
temp = realloc(c->printers, sizeof(printer_t *) * (c->num_printers + 1));
if (temp == NULL)
{
LogMessage(L_ERROR, "Unable to add printer %s to class %s!",
p->name, c->name);
return;
}
c->printers = temp;
temp += c->num_printers;
c->num_printers ++;
*temp = p;
SetPrinterAttrs(c);
}
void
DeletePrinterFromClass(printer_t *c,
printer_t *p)
{
int i;
cups_ptype_t type;
for (i = 0; i < c->num_printers; i ++)
if (p == c->printers[i])
break;
if (i < c->num_printers)
{
c->num_printers --;
if (i < c->num_printers)
memcpy(c->printers + i, c->printers + i + 1,
(c->num_printers - i) * sizeof(printer_t *));
}
if (c->num_printers > 0)
{
type = c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT);
c->type = ~CUPS_PRINTER_REMOTE;
for (i = 0; i < c->num_printers; i ++)
c->type &= c->printers[i]->type;
c->type |= type;
SetPrinterAttrs(c);
}
}
void
DeletePrinterFromClasses(printer_t *p)
{
printer_t *c,
*next;
for (c = Printers; c != NULL; c = next)
{
next = c->next;
if (c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
DeletePrinterFromClass(c, p);
}
for (c = Printers; c != NULL; c = next)
{
next = c->next;
if ((c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) &&
c->num_printers == 0)
DeletePrinter(c);
}
}
void
DeleteAllClasses(void)
{
printer_t *c,
*next;
for (c = Printers; c != NULL; c = next)
{
next = c->next;
if (c->type & CUPS_PRINTER_CLASS)
DeletePrinter(c);
}
}
printer_t *
FindAvailablePrinter(const char *name)
{
int i;
printer_t *c;
if ((c = FindClass(name)) == NULL)
{
LogMessage(L_ERROR, "Unable to find class \"%s\"!", name);
return (NULL);
}
for (i = c->last_printer + 1; ; i ++)
{
if (i >= c->num_printers)
i = 0;
if (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);
}
printer_t *
FindClass(const char *name)
{
printer_t *c;
for (c = Printers; c != NULL; c = c->next)
switch (strcasecmp(name, c->name))
{
case 0 :
if (c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
return (c);
case 1 :
break;
case -1 :
return (NULL);
}
return (NULL);
}
void
LoadAllClasses(void)
{
FILE *fp;
int linenum;
int len;
char line[1024],
name[256],
*nameptr,
*value,
*valueptr;
printer_t *p,
*temp;
snprintf(line, sizeof(line), "%s/classes.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, "<Class") == 0 ||
strcmp(name, "<DefaultClass") == 0)
{
if (line[len - 1] == '>' && p == NULL)
{
line[len - 1] = '\0';
p = AddClass(value);
p->accepting = 1;
p->state = IPP_PRINTER_IDLE;
if (strcmp(name, "<DefaultClass") == 0)
DefaultPrinter = p;
}
else
{
LogMessage(L_ERROR, "Syntax error on line %d of classes.conf.",
linenum);
return;
}
}
else if (strcmp(name, "</Class>") == 0)
{
if (p != NULL)
{
SetPrinterAttrs(p);
p = NULL;
}
else
{
LogMessage(L_ERROR, "Syntax error on line %d of classes.conf.",
linenum);
return;
}
}
else if (p == NULL)
{
LogMessage(L_ERROR, "Syntax error on line %d of classes.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, "Printer") == 0)
{
if ((temp = FindPrinter(value)) == NULL)
{
LogMessage(L_WARN, "Unknown printer %s on line %d of classes.conf.",
value, linenum);
temp = AddPrinter(value);
strcpy(temp->make_model, "Remote Printer on unknown");
temp->state = IPP_PRINTER_STOPPED;
temp->type |= CUPS_PRINTER_REMOTE;
temp->browse_time = 2147483647;
strcpy(temp->location, "Location Unknown");
strcpy(temp->info, "No Information Available");
temp->hostname[0] = '\0';
SetPrinterAttrs(temp);
}
if (temp)
AddPrinterToClass(p, temp);
}
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 classes.conf.",
name, linenum);
}
}
fclose(fp);
}
void
SaveAllClasses(void)
{
FILE *fp;
char temp[1024];
char backup[1024];
printer_t *pclass;
int i;
time_t curtime;
struct tm *curdate;
snprintf(temp, sizeof(temp), "%s/classes.conf", ServerRoot);
snprintf(backup, sizeof(backup), "%s/classes.conf.O", ServerRoot);
if (rename(temp, backup))
LogMessage(L_ERROR, "Unable to backup classes.conf - %s", strerror(errno));
if ((fp = fopen(temp, "w")) == NULL)
{
LogMessage(L_ERROR, "Unable to save classes.conf - %s", strerror(errno));
if (rename(backup, temp))
LogMessage(L_ERROR, "Unable to restore classes.conf - %s", strerror(errno));
return;
}
else
LogMessage(L_INFO, "Saving classes.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("# Class configuration file for " CUPS_SVERSION "\n", fp);
fprintf(fp, "# Written by cupsd on %s\n", temp);
for (pclass = Printers; pclass != NULL; pclass = pclass->next)
{
if ((pclass->type & CUPS_PRINTER_REMOTE) ||
(pclass->type & CUPS_PRINTER_IMPLICIT) ||
!(pclass->type & CUPS_PRINTER_CLASS))
continue;
if (pclass == DefaultPrinter)
fprintf(fp, "<DefaultClass %s>\n", pclass->name);
else
fprintf(fp, "<Class %s>\n", pclass->name);
if (pclass->info[0])
fprintf(fp, "Info %s\n", pclass->info);
if (pclass->location[0])
fprintf(fp, "Location %s\n", pclass->location);
if (pclass->state == IPP_PRINTER_STOPPED)
{
fputs("State Stopped\n", fp);
fprintf(fp, "StateMessage %s\n", pclass->state_message);
}
else
fputs("State Idle\n", fp);
if (pclass->accepting)
fputs("Accepting Yes\n", fp);
else
fputs("Accepting No\n", fp);
fprintf(fp, "JobSheets %s %s\n", pclass->job_sheets[0],
pclass->job_sheets[1]);
for (i = 0; i < pclass->num_printers; i ++)
fprintf(fp, "Printer %s\n", pclass->printers[i]->name);
fprintf(fp, "QuotaPeriod %d\n", pclass->quota_period);
fprintf(fp, "PageLimit %d\n", pclass->page_limit);
fprintf(fp, "KLimit %d\n", pclass->k_limit);
for (i = 0; i < pclass->num_users; i ++)
fprintf(fp, "%sUser %s\n", pclass->deny_users ? "Deny" : "Allow",
pclass->users[i]);
fputs("</Class>\n", fp);
}
fclose(fp);
}