#include "cupsd.h"
#include <grp.h>
static mime_filter_t gziptoany_filter =
{
NULL,
NULL,
0,
"gziptoany"
};
static int ipp_length(ipp_t *ipp);
static void set_time(job_t *job, const char *name);
static int start_process(const char *command, char *argv[],
char *envp[], int in, int out, int err,
int root, int *pid);
static void set_hold_until(job_t *job, time_t holdtime);
job_t *
AddJob(int priority,
const char *dest)
{
job_t *job,
*current,
*prev;
job = calloc(sizeof(job_t), 1);
job->id = NextJobId ++;
job->priority = priority;
SetString(&job->dest, dest);
NumJobs ++;
for (current = Jobs, prev = NULL;
current != NULL;
prev = current, current = current->next)
if (job->priority > current->priority)
break;
job->next = current;
if (prev != NULL)
prev->next = job;
else
Jobs = job;
return (job);
}
void
CancelJob(int id,
int purge)
{
int i;
job_t *current,
*prev;
char filename[1024];
LogMessage(L_DEBUG, "CancelJob: id = %d", id);
for (current = Jobs, prev = NULL; current != NULL; prev = current, current = current->next)
if (current->id == id)
{
DEBUG_puts("CancelJob: found job in list.");
if (current->state->values[0].integer == IPP_JOB_PROCESSING)
StopJob(current->id, 0);
current->state->values[0].integer = IPP_JOB_CANCELLED;
set_time(current, "time-at-completed");
current->current_file = 0;
if (!JobHistory || !JobFiles || purge ||
(current->dtype & CUPS_PRINTER_REMOTE))
for (i = 1; i <= current->num_files; i ++)
{
snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
current->id, i);
unlink(filename);
}
if (JobHistory && !purge && !(current->dtype & CUPS_PRINTER_REMOTE))
{
SaveJob(current->id);
}
else
{
snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot,
current->id);
unlink(filename);
if (prev == NULL)
Jobs = current->next;
else
prev->next = current->next;
if (current->attrs != NULL)
ippDelete(current->attrs);
if (current->num_files > 0)
{
free(current->compressions);
free(current->filetypes);
}
ClearString(¤t->username);
ClearString(¤t->dest);
free(current);
NumJobs --;
}
return;
}
}
void
CancelJobs(const char *dest,
const char *username,
int purge)
{
job_t *current,
*next;
for (current = Jobs; current != NULL;)
if ((dest == NULL || !strcmp(current->dest, dest)) &&
(username == NULL || !strcmp(current->username, username)))
{
next = current->next;
CancelJob(current->id, purge);
current = next;
}
else
current = current->next;
CheckJobs();
}
void
CheckJobs(void)
{
job_t *current,
*next;
printer_t *printer,
*pclass;
DEBUG_puts("CheckJobs()");
for (current = Jobs; current != NULL; current = next)
{
next = current->next;
if (current->state->values[0].integer == IPP_JOB_HELD &&
current->hold_until &&
current->hold_until < time(NULL))
current->state->values[0].integer = IPP_JOB_PENDING;
if (current->state->values[0].integer == IPP_JOB_PENDING)
{
if ((pclass = FindClass(current->dest)) != NULL)
{
if (pclass->type & CUPS_PRINTER_REMOTE)
printer = pclass;
else if (pclass->state != IPP_PRINTER_STOPPED)
printer = FindAvailablePrinter(current->dest);
else
printer = NULL;
}
else
printer = FindPrinter(current->dest);
if (printer != NULL && (printer->type & CUPS_PRINTER_IMPLICIT))
{
pclass = printer;
if (pclass->state != IPP_PRINTER_STOPPED)
printer = FindAvailablePrinter(current->dest);
else
printer = NULL;
}
if (printer == NULL && pclass == NULL)
{
LogMessage(L_WARN, "Printer/class %s has gone away; cancelling job %d!",
current->dest, current->id);
CancelJob(current->id, 1);
}
else if (printer != NULL)
{
if (printer->state == IPP_PRINTER_IDLE ||
((printer->type & CUPS_PRINTER_REMOTE) &&
!printer->job))
StartJob(current->id, printer);
}
}
}
}
void
CleanJobs(void)
{
job_t *job,
*next;
if (MaxJobs == 0)
return;
for (job = Jobs; job && NumJobs >= MaxJobs; job = next)
{
next = job->next;
if (job->state->values[0].integer >= IPP_JOB_CANCELLED)
CancelJob(job->id, 1);
}
}
void
FreeAllJobs(void)
{
job_t *job,
*next;
HoldSignals();
StopAllJobs();
for (job = Jobs; job; job = next)
{
next = job->next;
ippDelete(job->attrs);
if (job->num_files > 0)
{
free(job->compressions);
free(job->filetypes);
}
free(job);
}
Jobs = NULL;
ReleaseSignals();
}
job_t *
FindJob(int id)
{
job_t *current;
for (current = Jobs; current != NULL; current = current->next)
if (current->id == id)
break;
return (current);
}
int
GetPrinterJobCount(const char *dest)
{
int count;
job_t *job;
for (job = Jobs, count = 0; job != NULL; job = job->next)
if (job->state->values[0].integer <= IPP_JOB_PROCESSING &&
strcasecmp(job->dest, dest) == 0)
count ++;
return (count);
}
int
GetUserJobCount(const char *username)
{
int count;
job_t *job;
for (job = Jobs, count = 0; job != NULL; job = job->next)
if (job->state->values[0].integer <= IPP_JOB_PROCESSING &&
strcmp(job->username, username) == 0)
count ++;
return (count);
}
void
HoldJob(int id)
{
job_t *job;
LogMessage(L_DEBUG, "HoldJob: id = %d", id);
if ((job = FindJob(id)) == NULL)
return;
if (job->state->values[0].integer == IPP_JOB_PROCESSING)
StopJob(id, 0);
DEBUG_puts("HoldJob: setting state to held...");
job->state->values[0].integer = IPP_JOB_HELD;
SaveJob(id);
CheckJobs();
}
void
LoadAllJobs(void)
{
DIR *dir;
DIRENT *dent;
char filename[1024];
int fd;
job_t *job,
*current,
*prev;
int jobid,
fileid;
ipp_attribute_t *attr;
char method[HTTP_MAX_URI],
username[HTTP_MAX_URI],
host[HTTP_MAX_URI],
resource[HTTP_MAX_URI];
int port;
printer_t *p;
const char *dest;
mime_type_t **filetypes;
int *compressions;
LogMessage(L_DEBUG, "LoadAllJobs: Scanning %s...", RequestRoot);
NumJobs = 0;
if ((dir = opendir(RequestRoot)) == NULL)
{
LogMessage(L_ERROR, "LoadAllJobs: Unable to open spool directory %s: %s",
RequestRoot, strerror(errno));
return;
}
while ((dent = readdir(dir)) != NULL)
if (NAMLEN(dent) == 6 && dent->d_name[0] == 'c')
{
if ((job = calloc(sizeof(job_t), 1)) == NULL)
{
LogMessage(L_ERROR, "LoadAllJobs: Ran out of memory for jobs!");
closedir(dir);
return;
}
if ((job->attrs = ippNew()) == NULL)
{
free(job);
LogMessage(L_ERROR, "LoadAllJobs: Ran out of memory for job attributes!");
closedir(dir);
return;
}
job->id = atoi(dent->d_name + 1);
LogMessage(L_DEBUG, "LoadAllJobs: Loading attributes for job %d...\n",
job->id);
if (job->id >= NextJobId)
NextJobId = job->id + 1;
snprintf(filename, sizeof(filename), "%s/%s", RequestRoot, dent->d_name);
if ((fd = open(filename, O_RDONLY)) < 0)
{
LogMessage(L_ERROR, "LoadAllJobs: Unable to open job control file \"%s\" - %s!",
filename, strerror(errno));
ippDelete(job->attrs);
free(job);
unlink(filename);
continue;
}
else
{
if (ippReadFile(fd, job->attrs) != IPP_DATA)
{
LogMessage(L_ERROR, "LoadAllJobs: Unable to read job control file \"%s\"!",
filename);
close(fd);
ippDelete(job->attrs);
free(job);
unlink(filename);
continue;
}
close(fd);
}
if ((job->state = ippFindAttribute(job->attrs, "job-state", IPP_TAG_ENUM)) == NULL)
{
LogMessage(L_ERROR, "LoadAllJobs: Missing or bad job-state attribute in control file \"%s\"!",
filename);
ippDelete(job->attrs);
free(job);
unlink(filename);
continue;
}
if ((attr = ippFindAttribute(job->attrs, "job-printer-uri", IPP_TAG_URI)) == NULL)
{
LogMessage(L_ERROR, "LoadAllJobs: No job-printer-uri attribute in control file \"%s\"!",
filename);
ippDelete(job->attrs);
free(job);
unlink(filename);
continue;
}
httpSeparate(attr->values[0].string.text, method, username, host,
&port, resource);
if ((dest = ValidateDest(host, resource, &(job->dtype))) == NULL &&
job->state != NULL &&
job->state->values[0].integer <= IPP_JOB_PROCESSING)
{
if (strncmp(resource, "/classes/", 9) == 0)
{
p = AddClass(resource + 9);
SetString(&p->make_model, "Remote Class on unknown");
}
else
{
p = AddPrinter(resource + 10);
SetString(&p->make_model, "Remote Printer on unknown");
}
p->state = IPP_PRINTER_STOPPED;
p->type |= CUPS_PRINTER_REMOTE;
p->browse_time = 2147483647;
SetString(&p->location, "Location Unknown");
SetString(&p->info, "No Information Available");
p->hostname[0] = '\0';
SetPrinterAttrs(p);
dest = p->name;
}
if (dest == NULL)
{
LogMessage(L_ERROR, "LoadAllJobs: Unable to queue job for destination \"%s\"!",
attr->values[0].string.text);
ippDelete(job->attrs);
free(job);
unlink(filename);
continue;
}
SetString(&job->dest, dest);
job->sheets = ippFindAttribute(job->attrs, "job-media-sheets-completed",
IPP_TAG_INTEGER);
job->job_sheets = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME);
if ((attr = ippFindAttribute(job->attrs, "job-priority", IPP_TAG_INTEGER)) == NULL)
{
LogMessage(L_ERROR, "LoadAllJobs: Missing or bad job-priority attribute in control file \"%s\"!",
filename);
ippDelete(job->attrs);
free(job);
unlink(filename);
continue;
}
job->priority = attr->values[0].integer;
if ((attr = ippFindAttribute(job->attrs, "job-originating-user-name", IPP_TAG_NAME)) == NULL)
{
LogMessage(L_ERROR, "LoadAllJobs: Missing or bad job-originating-user-name attribute in control file \"%s\"!",
filename);
ippDelete(job->attrs);
free(job);
unlink(filename);
continue;
}
SetString(&job->username, attr->values[0].string.text);
for (current = Jobs, prev = NULL;
current != NULL;
prev = current, current = current->next)
if (job->priority > current->priority)
break;
else if (job->priority == current->priority && job->id < current->id)
break;
job->next = current;
if (prev != NULL)
prev->next = job;
else
Jobs = job;
NumJobs ++;
if (job->state->values[0].integer == IPP_JOB_HELD)
{
if ((attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD)) == NULL)
attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
if (attr == NULL)
job->state->values[0].integer = IPP_JOB_PENDING;
else
SetJobHoldUntil(job->id, attr->values[0].string.text);
}
else if (job->state->values[0].integer == IPP_JOB_PROCESSING)
job->state->values[0].integer = IPP_JOB_PENDING;
}
rewinddir(dir);
while ((dent = readdir(dir)) != NULL)
if (NAMLEN(dent) > 7 && dent->d_name[0] == 'd')
{
jobid = atoi(dent->d_name + 1);
fileid = atoi(dent->d_name + 7);
LogMessage(L_DEBUG, "LoadAllJobs: Auto-typing document file %s...",
dent->d_name);
snprintf(filename, sizeof(filename), "%s/%s", RequestRoot, dent->d_name);
if ((job = FindJob(jobid)) == NULL)
{
LogMessage(L_ERROR, "LoadAllJobs: Orphaned print file \"%s\"!",
filename);
unlink(filename);
continue;
}
if (fileid > job->num_files)
{
if (job->num_files == 0)
{
compressions = (int *)calloc(fileid, sizeof(int));
filetypes = (mime_type_t **)calloc(fileid, sizeof(mime_type_t *));
}
else
{
compressions = (int *)realloc(job->compressions,
sizeof(int) * fileid);
filetypes = (mime_type_t **)realloc(job->filetypes,
sizeof(mime_type_t *) * fileid);
}
if (compressions == NULL || filetypes == NULL)
{
LogMessage(L_ERROR, "LoadAllJobs: Ran out of memory for job file types!");
continue;
}
job->compressions = compressions;
job->filetypes = filetypes;
job->num_files = fileid;
}
job->filetypes[fileid - 1] = mimeFileType(MimeDatabase, filename,
job->compressions + fileid - 1);
if (job->filetypes[fileid - 1] == NULL)
job->filetypes[fileid - 1] = mimeType(MimeDatabase, "application",
"vnd.cups-raw");
}
closedir(dir);
CleanJobs();
}
void
MoveJob(int id,
const char *dest)
{
job_t *current;
ipp_attribute_t *attr;
printer_t *p;
if ((p = FindPrinter(dest)) == NULL)
p = FindClass(dest);
if (p == NULL)
return;
for (current = Jobs; current != NULL; current = current->next)
if (current->id == id)
{
if (current->state->values[0].integer >= IPP_JOB_PROCESSING)
break;
SetString(¤t->dest, dest);
current->dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE |
CUPS_PRINTER_IMPLICIT);
if ((attr = ippFindAttribute(current->attrs, "job-printer-uri", IPP_TAG_URI)) != NULL)
{
free(attr->values[0].string.text);
attr->values[0].string.text = strdup(p->uri);
}
SaveJob(current->id);
return;
}
}
void
ReleaseJob(int id)
{
job_t *job;
LogMessage(L_DEBUG, "ReleaseJob: id = %d", id);
if ((job = FindJob(id)) == NULL)
return;
if (job->state->values[0].integer == IPP_JOB_HELD)
{
DEBUG_puts("ReleaseJob: setting state to pending...");
job->state->values[0].integer = IPP_JOB_PENDING;
SaveJob(id);
CheckJobs();
}
}
void
RestartJob(int id)
{
job_t *job;
if ((job = FindJob(id)) == NULL)
return;
if (job->state->values[0].integer == IPP_JOB_STOPPED || JobFiles)
{
job->tries = 0;
job->state->values[0].integer = IPP_JOB_PENDING;
SaveJob(id);
CheckJobs();
}
}
void
SaveJob(int id)
{
job_t *job;
char filename[1024];
int fd;
if ((job = FindJob(id)) == NULL)
return;
snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, id);
if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
{
LogMessage(L_ERROR, "SaveJob: Unable to create job control file \"%s\" - %s.",
filename, strerror(errno));
return;
}
fchmod(fd, 0600);
fchown(fd, User, Group);
ippWriteFile(fd, job->attrs);
LogMessage(L_DEBUG2, "SaveJob: Closing file %d...", fd);
close(fd);
}
void
SetJobHoldUntil(int id,
const char *when)
{
job_t *job;
time_t curtime;
struct tm *curdate;
int hour;
int minute;
int second;
LogMessage(L_DEBUG, "SetJobHoldUntil(%d, \"%s\")", id, when);
if ((job = FindJob(id)) == NULL)
return;
second = 0;
if (strcmp(when, "indefinite") == 0)
{
job->hold_until = 0;
}
else if (strcmp(when, "day-time") == 0)
{
curtime = time(NULL);
curdate = localtime(&curtime);
if (curdate->tm_hour < 18)
job->hold_until = curtime;
else
job->hold_until = curtime +
((29 - curdate->tm_hour) * 60 + 59 -
curdate->tm_min) * 60 + 60 - curdate->tm_sec;
}
else if (strcmp(when, "evening") == 0 || strcmp(when, "night") == 0)
{
curtime = time(NULL);
curdate = localtime(&curtime);
if (curdate->tm_hour < 6 || curdate->tm_hour >= 18)
job->hold_until = curtime;
else
job->hold_until = curtime +
((17 - curdate->tm_hour) * 60 + 59 -
curdate->tm_min) * 60 + 60 - curdate->tm_sec;
}
else if (strcmp(when, "second-shift") == 0)
{
curtime = time(NULL);
curdate = localtime(&curtime);
if (curdate->tm_hour >= 16)
job->hold_until = curtime;
else
job->hold_until = curtime +
((15 - curdate->tm_hour) * 60 + 59 -
curdate->tm_min) * 60 + 60 - curdate->tm_sec;
}
else if (strcmp(when, "third-shift") == 0)
{
curtime = time(NULL);
curdate = localtime(&curtime);
if (curdate->tm_hour < 8)
job->hold_until = curtime;
else
job->hold_until = curtime +
((23 - curdate->tm_hour) * 60 + 59 -
curdate->tm_min) * 60 + 60 - curdate->tm_sec;
}
else if (strcmp(when, "weekend") == 0)
{
curtime = time(NULL);
curdate = localtime(&curtime);
if (curdate->tm_wday == 0 || curdate->tm_wday == 6)
job->hold_until = curtime;
else
job->hold_until = curtime +
(((5 - curdate->tm_wday) * 24 +
(17 - curdate->tm_hour)) * 60 + 59 -
curdate->tm_min) * 60 + 60 - curdate->tm_sec;
}
else if (sscanf(when, "%d:%d:%d", &hour, &minute, &second) >= 2)
{
curtime = time(NULL);
curdate = gmtime(&curtime);
job->hold_until = curtime +
((hour - curdate->tm_hour) * 60 + minute -
curdate->tm_min) * 60 + second - curdate->tm_sec;
if (job->hold_until < curtime)
job->hold_until += 24 * 60 * 60 * 60;
}
LogMessage(L_DEBUG, "SetJobHoldUntil: hold_until = %d", (int)job->hold_until);
}
void
SetJobPriority(int id,
int priority)
{
job_t *job,
*current,
*prev;
ipp_attribute_t *attr;
for (current = Jobs, prev = NULL;
current != NULL;
prev = current, current = current->next)
if (current->id == id)
break;
if (current == NULL)
return;
job = current;
job->priority = priority;
if ((attr = ippFindAttribute(job->attrs, "job-priority", IPP_TAG_INTEGER)) != NULL)
attr->values[0].integer = priority;
else
ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-priority",
priority);
SaveJob(job->id);
if ((prev == NULL || job->priority < prev->priority) &&
(job->next == NULL || job->next->priority < job->priority))
return;
if (prev == NULL)
Jobs = job->next;
else
prev->next = job->next;
for (current = Jobs, prev = NULL;
current != NULL;
prev = current, current = current->next)
if (job->priority > current->priority)
break;
job->next = current;
if (prev != NULL)
prev->next = job;
else
Jobs = job;
}
void
StartJob(int id,
printer_t *printer)
{
job_t *current;
int i;
int slot;
int num_filters;
mime_filter_t *filters;
char method[255],
*optptr,
*optlog;
ipp_attribute_t *attr;
int pid;
int banner_page;
int statusfds[2],
filterfds[2][2];
int envc;
char *argv[8],
filename[1024],
command[1024],
jobid[255],
title[IPP_MAX_NAME],
copies[255],
*envp[100],
#ifdef __APPLE__
processPath[1050],
#endif
path[1024],
ipp_port[1024],
language[255],
charset[255],
classification[1024],
content_type[1024],
device_uri[1024],
ppd[1024],
class_name[255],
printer_name[255],
root[1024],
cache[255],
tmpdir[1024],
ld_library_path[1024],
ld_preload[1024],
dyld_library_path[1024],
shlib_path[1024],
nlspath[1024],
datadir[1024],
fontpath[1050],
vg_args[1024],
ld_assume_kernel[1024];
static char *options = NULL;
static int optlength = 0;
LogMessage(L_DEBUG, "StartJob(%d, %p)", id, printer);
for (current = Jobs; current != NULL; current = current->next)
if (current->id == id)
break;
if (current == NULL)
return;
LogMessage(L_DEBUG, "StartJob() id = %d, file = %d/%d", id,
current->current_file, current->num_files);
if (current->num_files == 0)
{
LogMessage(L_ERROR, "Job ID %d has no files! Cancelling it!", id);
CancelJob(id, 0);
return;
}
num_filters = 0;
current->cost = 0;
if (printer->raw)
{
LogMessage(L_DEBUG, "StartJob: Sending job to queue tagged as raw...");
filters = NULL;
}
else
{
filters = mimeFilter(MimeDatabase, current->filetypes[current->current_file],
printer->filetype, &num_filters, MAX_FILTERS - 1);
if (num_filters == 0)
{
LogMessage(L_ERROR, "Unable to convert file %d to printable format for job %d!",
current->current_file, current->id);
LogMessage(L_INFO, "Hint: Do you have ESP Ghostscript installed?");
if (LogLevel < L_DEBUG)
LogMessage(L_INFO, "Hint: Try setting the LogLevel to \"debug\".");
current->current_file ++;
if (current->current_file == current->num_files)
CancelJob(current->id, 0);
return;
}
for (i = 0; i < num_filters;)
if (strcmp(filters[i].filter, "-") == 0)
{
num_filters --;
if (i < num_filters)
memcpy(filters + i, filters + i + 1,
(num_filters - i) * sizeof(mime_filter_t));
}
else
i ++;
if (num_filters == 0)
{
free(filters);
filters = NULL;
}
else
{
for (i = 0; i < num_filters; i ++)
current->cost += filters[i].cost;
}
}
if ((FilterLevel + current->cost) > FilterLimit && FilterLevel > 0 &&
FilterLimit > 0)
{
if (filters != NULL)
free(filters);
LogMessage(L_INFO, "Holding job %d because filter limit has been reached.",
id);
LogMessage(L_DEBUG, "StartJob: id = %d, file = %d, "
"cost = %d, level = %d, limit = %d",
id, current->current_file, current->cost, FilterLevel,
FilterLimit);
return;
}
FilterLevel += current->cost;
if (current->compressions[current->current_file])
{
mime_filter_t *temp_filters;
if (num_filters == 0)
temp_filters = malloc(sizeof(mime_filter_t));
else
temp_filters = realloc(filters,
sizeof(mime_filter_t) * (num_filters + 1));
if (temp_filters == NULL)
{
LogMessage(L_ERROR, "Unable to add decompression filter - %s",
strerror(errno));
free(filters);
current->current_file ++;
if (current->current_file == current->num_files)
CancelJob(current->id, 0);
return;
}
filters = temp_filters;
memmove(filters + 1, filters, num_filters * sizeof(mime_filter_t));
*filters = gziptoany_filter;
num_filters ++;
}
current->state->values[0].integer = IPP_JOB_PROCESSING;
current->status = 0;
current->printer = printer;
printer->job = current;
SetPrinterState(printer, IPP_PRINTER_PROCESSING, 0);
if (current->current_file == 0)
set_time(current, "time-at-processing");
if (current->job_sheets == NULL)
{
LogMessage(L_DEBUG, "No job-sheets attribute.");
if ((current->job_sheets =
ippFindAttribute(current->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL)
LogMessage(L_DEBUG, "... but someone added one without setting job_sheets!");
}
else if (current->job_sheets->num_values == 1)
LogMessage(L_DEBUG, "job-sheets=%s",
current->job_sheets->values[0].string.text);
else
LogMessage(L_DEBUG, "job-sheets=%s,%s",
current->job_sheets->values[0].string.text,
current->job_sheets->values[1].string.text);
if (printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))
banner_page = 0;
else if (current->job_sheets == NULL)
banner_page = 0;
else if (strcasecmp(current->job_sheets->values[0].string.text, "none") != 0 &&
current->current_file == 0)
banner_page = 1;
else if (current->job_sheets->num_values > 1 &&
strcasecmp(current->job_sheets->values[1].string.text, "none") != 0 &&
current->current_file == (current->num_files - 1))
banner_page = 1;
else
banner_page = 0;
LogMessage(L_DEBUG, "banner_page = %d", banner_page);
i = ipp_length(current->attrs);
if (i > optlength)
{
if (optlength == 0)
optptr = malloc(i);
else
optptr = realloc(options, i);
if (optptr == NULL)
{
LogMessage(L_CRIT, "StartJob: Unable to allocate %d bytes for option buffer for job %d!",
i, id);
if (filters != NULL)
free(filters);
FilterLevel -= current->cost;
CancelJob(id, 0);
return;
}
options = optptr;
optlength = i;
}
optptr = options;
*optptr = '\0';
snprintf(title, sizeof(title), "%s-%d", printer->name, current->id);
strcpy(copies, "1");
for (attr = current->attrs->attrs; attr != NULL; attr = attr->next)
{
if (strcmp(attr->name, "copies") == 0 &&
attr->value_tag == IPP_TAG_INTEGER)
{
if (!banner_page)
sprintf(copies, "%d", attr->values[0].integer);
}
else if (strcmp(attr->name, "job-name") == 0 &&
(attr->value_tag == IPP_TAG_NAME ||
attr->value_tag == IPP_TAG_NAMELANG))
strlcpy(title, attr->values[0].string.text, sizeof(title));
else if (attr->group_tag == IPP_TAG_JOB)
{
if (attr->value_tag == IPP_TAG_MIMETYPE ||
attr->value_tag == IPP_TAG_NAMELANG ||
attr->value_tag == IPP_TAG_TEXTLANG ||
attr->value_tag == IPP_TAG_URI ||
attr->value_tag == IPP_TAG_URISCHEME ||
attr->value_tag == IPP_TAG_BEGIN_COLLECTION)
continue;
if (strncmp(attr->name, "time-", 5) == 0)
continue;
if (strncmp(attr->name, "job-", 4) == 0 &&
!(printer->type & CUPS_PRINTER_REMOTE))
continue;
if (strncmp(attr->name, "job-", 4) == 0 &&
strcmp(attr->name, "job-billing") != 0 &&
strcmp(attr->name, "job-sheets") != 0 &&
strcmp(attr->name, "job-hold-until") != 0 &&
strcmp(attr->name, "job-priority") != 0)
continue;
if ((strcmp(attr->name, "page-label") == 0 ||
strcmp(attr->name, "page-border") == 0 ||
strncmp(attr->name, "number-up", 9) == 0) &&
banner_page)
continue;
if (optptr > options)
{
strlcat(optptr, " ", optlength - (optptr - options));
optptr++;
}
optlog = optptr;
if (attr->value_tag != IPP_TAG_BOOLEAN)
{
strlcat(optptr, attr->name, optlength - (optptr - options));
strlcat(optptr, "=", optlength - (optptr - options));
}
for (i = 0; i < attr->num_values; i ++)
{
if (i)
strlcat(optptr, ",", optlength - (optptr - options));
optptr += strlen(optptr);
switch (attr->value_tag)
{
case IPP_TAG_INTEGER :
case IPP_TAG_ENUM :
snprintf(optptr, optlength - (optptr - options),
"%d", attr->values[i].integer);
break;
case IPP_TAG_BOOLEAN :
if (!attr->values[i].boolean)
strlcat(optptr, "no", optlength - (optptr - options));
case IPP_TAG_NOVALUE :
strlcat(optptr, attr->name,
optlength - (optptr - options));
break;
case IPP_TAG_RANGE :
if (attr->values[i].range.lower == attr->values[i].range.upper)
snprintf(optptr, optlength - (optptr - options) - 1,
"%d", attr->values[i].range.lower);
else
snprintf(optptr, optlength - (optptr - options) - 1,
"%d-%d", attr->values[i].range.lower,
attr->values[i].range.upper);
break;
case IPP_TAG_RESOLUTION :
snprintf(optptr, optlength - (optptr - options) - 1,
"%dx%d%s", attr->values[i].resolution.xres,
attr->values[i].resolution.yres,
attr->values[i].resolution.units == IPP_RES_PER_INCH ?
"dpi" : "dpc");
break;
case IPP_TAG_STRING :
case IPP_TAG_TEXT :
case IPP_TAG_NAME :
case IPP_TAG_KEYWORD :
case IPP_TAG_CHARSET :
case IPP_TAG_LANGUAGE :
if (strchr(attr->values[i].string.text, ' ') != NULL ||
strchr(attr->values[i].string.text, '\t') != NULL ||
strchr(attr->values[i].string.text, '\n') != NULL)
{
strlcat(optptr, "\'", optlength - (optptr - options));
strlcat(optptr, attr->values[i].string.text,
optlength - (optptr - options));
strlcat(optptr, "\'", optlength - (optptr - options));
}
else
strlcat(optptr, attr->values[i].string.text,
optlength - (optptr - options));
break;
default :
break;
}
}
LogMessage(L_DEBUG, "StartJob: option = \"%s\"", optlog);
optptr += strlen(optptr);
}
}
sprintf(jobid, "%d", current->id);
snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
current->id, current->current_file + 1);
argv[0] = printer->name;
argv[1] = jobid;
argv[2] = current->username;
argv[3] = title;
argv[4] = copies;
argv[5] = options;
argv[6] = filename;
argv[7] = NULL;
LogMessage(L_DEBUG, "StartJob: argv = \"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"",
argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
attr = ippFindAttribute(current->attrs, "attributes-natural-language",
IPP_TAG_LANGUAGE);
switch (strlen(attr->values[0].string.text))
{
default :
strcpy(language, "LANG=C");
break;
case 2 :
snprintf(language, sizeof(language), "LANG=%s",
attr->values[0].string.text);
break;
case 5 :
snprintf(language, sizeof(language), "LANG=%c%c_%c%c",
attr->values[0].string.text[0],
attr->values[0].string.text[1],
toupper(attr->values[0].string.text[3]),
toupper(attr->values[0].string.text[4]));
break;
}
attr = ippFindAttribute(current->attrs, "document-format",
IPP_TAG_MIMETYPE);
if (attr != NULL &&
(optptr = strstr(attr->values[0].string.text, "charset=")) != NULL)
snprintf(charset, sizeof(charset), "CHARSET=%s", optptr + 8);
else
{
attr = ippFindAttribute(current->attrs, "attributes-charset",
IPP_TAG_CHARSET);
snprintf(charset, sizeof(charset), "CHARSET=%s",
attr->values[0].string.text);
}
snprintf(path, sizeof(path), "PATH=%s/filter:/bin:/usr/bin", ServerBin);
snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s/%s",
current->filetypes[current->current_file]->super,
current->filetypes[current->current_file]->type);
snprintf(device_uri, sizeof(device_uri), "DEVICE_URI=%s", printer->device_uri);
snprintf(ppd, sizeof(ppd), "PPD=%s/ppd/%s.ppd", ServerRoot, printer->name);
snprintf(printer_name, sizeof(printer_name), "PRINTER=%s", printer->name);
snprintf(cache, sizeof(cache), "RIP_MAX_CACHE=%s", RIPCache);
snprintf(root, sizeof(root), "CUPS_SERVERROOT=%s", ServerRoot);
snprintf(tmpdir, sizeof(tmpdir), "TMPDIR=%s", TempDir);
snprintf(datadir, sizeof(datadir), "CUPS_DATADIR=%s", DataDir);
snprintf(fontpath, sizeof(fontpath), "CUPS_FONTPATH=%s", FontPath);
sprintf(ipp_port, "IPP_PORT=%d", LocalPort);
envc = 0;
envp[envc ++] = path;
envp[envc ++] = "SOFTWARE=CUPS/1.1";
envp[envc ++] = "USER=root";
envp[envc ++] = charset;
envp[envc ++] = language;
if (TZ && TZ[0])
envp[envc ++] = TZ;
envp[envc ++] = ppd;
envp[envc ++] = root;
envp[envc ++] = cache;
envp[envc ++] = tmpdir;
envp[envc ++] = content_type;
envp[envc ++] = device_uri;
envp[envc ++] = printer_name;
envp[envc ++] = datadir;
envp[envc ++] = fontpath;
envp[envc ++] = "CUPS_SERVER=localhost";
envp[envc ++] = ipp_port;
if (getenv("VG_ARGS") != NULL)
{
snprintf(vg_args, sizeof(vg_args), "VG_ARGS=%s", getenv("VG_ARGS"));
envp[envc ++] = vg_args;
}
if (getenv("LD_ASSUME_KERNEL") != NULL)
{
snprintf(ld_assume_kernel, sizeof(ld_assume_kernel), "LD_ASSUME_KERNEL=%s",
getenv("LD_ASSUME_KERNEL"));
envp[envc ++] = ld_assume_kernel;
}
if (getenv("LD_LIBRARY_PATH") != NULL)
{
snprintf(ld_library_path, sizeof(ld_library_path), "LD_LIBRARY_PATH=%s",
getenv("LD_LIBRARY_PATH"));
envp[envc ++] = ld_library_path;
}
if (getenv("LD_PRELOAD") != NULL)
{
snprintf(ld_preload, sizeof(ld_preload), "LD_PRELOAD=%s",
getenv("LD_PRELOAD"));
envp[envc ++] = ld_preload;
}
if (getenv("DYLD_LIBRARY_PATH") != NULL)
{
snprintf(dyld_library_path, sizeof(dyld_library_path), "DYLD_LIBRARY_PATH=%s",
getenv("DYLD_LIBRARY_PATH"));
envp[envc ++] = dyld_library_path;
}
if (getenv("SHLIB_PATH") != NULL)
{
snprintf(shlib_path, sizeof(shlib_path), "SHLIB_PATH=%s",
getenv("SHLIB_PATH"));
envp[envc ++] = shlib_path;
}
if (getenv("NLSPATH") != NULL)
{
snprintf(nlspath, sizeof(nlspath), "NLSPATH=%s", getenv("NLSPATH"));
envp[envc ++] = nlspath;
}
if (Classification && !banner_page)
{
if ((attr = ippFindAttribute(current->attrs, "job-sheets",
IPP_TAG_NAME)) == NULL)
snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
Classification);
else if (attr->num_values > 1 &&
strcmp(attr->values[1].string.text, "none") != 0)
snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
attr->values[1].string.text);
else
snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
attr->values[0].string.text);
envp[envc ++] = classification;
}
if (current->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
{
snprintf(class_name, sizeof(class_name), "CLASS=%s", current->dest);
envp[envc ++] = class_name;
}
#ifdef __APPLE__
strlcpy(processPath, "<CFProcessPath>", sizeof(processPath));
envp[envc ++] = processPath;
#endif
envp[envc] = NULL;
for (i = 0; i < envc; i ++)
LogMessage(L_DEBUG, "StartJob: envp[%d]=\"%s\"", i, envp[i]);
current->current_file ++;
if (current->buffer == NULL)
{
LogMessage(L_DEBUG2, "StartJob: Allocating status buffer...");
if ((current->buffer = malloc(JOB_BUFFER_SIZE)) == NULL)
{
LogMessage(L_EMERG, "Unable to allocate memory for job status buffer - %s",
strerror(errno));
CancelJob(current->id, 0);
return;
}
current->bufused = 0;
}
if (pipe(statusfds))
{
LogMessage(L_ERROR, "Unable to create job status pipes - %s.",
strerror(errno));
snprintf(printer->state_message, sizeof(printer->state_message),
"Unable to create status pipes - %s.", strerror(errno));
AddPrinterHistory(printer);
return;
}
LogMessage(L_DEBUG, "StartJob: statusfds = [ %d %d ]",
statusfds[0], statusfds[1]);
current->pipe = statusfds[0];
current->status = 0;
memset(current->procs, 0, sizeof(current->procs));
filterfds[1][0] = open("/dev/null", O_RDONLY);
filterfds[1][1] = -1;
LogMessage(L_DEBUG, "StartJob: filterfds[%d] = [ %d %d ]", 1, filterfds[1][0],
filterfds[1][1]);
for (i = 0, slot = 0; i < num_filters; i ++)
{
if (filters[i].filter[0] != '/')
snprintf(command, sizeof(command), "%s/filter/%s", ServerBin,
filters[i].filter);
else
strlcpy(command, filters[i].filter, sizeof(command));
#ifdef __APPLE__
snprintf(processPath, sizeof(processPath), "CFProcessPath=%s", command);
LogMessage(L_DEBUG, "StartJob: %s\n", processPath);
#endif
if (i < (num_filters - 1) ||
strncmp(printer->device_uri, "file:", 5) != 0)
pipe(filterfds[slot]);
else
{
filterfds[slot][0] = -1;
if (strncmp(printer->device_uri, "file:/dev/", 10) == 0)
filterfds[slot][1] = open(printer->device_uri + 5,
O_WRONLY | O_EXCL);
else
filterfds[slot][1] = open(printer->device_uri + 5,
O_WRONLY | O_CREAT | O_TRUNC, 0600);
}
LogMessage(L_DEBUG, "StartJob: filter = \"%s\"", command);
LogMessage(L_DEBUG, "StartJob: filterfds[%d] = [ %d %d ]",
slot, filterfds[slot][0], filterfds[slot][1]);
pid = start_process(command, argv, envp, filterfds[!slot][0],
filterfds[slot][1], statusfds[1], 0,
current->procs + i);
close(filterfds[!slot][0]);
close(filterfds[!slot][1]);
if (pid == 0)
{
LogMessage(L_ERROR, "Unable to start filter \"%s\" - %s.",
filters[i].filter, strerror(errno));
snprintf(printer->state_message, sizeof(printer->state_message),
"Unable to start filter \"%s\" - %s.",
filters[i].filter, strerror(errno));
AddPrinterHistory(printer);
if (filters != NULL)
free(filters);
CancelJob(current->id, 0);
return;
}
LogMessage(L_INFO, "Started filter %s (PID %d) for job %d.",
command, pid, current->id);
argv[6] = NULL;
slot = !slot;
}
if (filters != NULL)
free(filters);
if (strncmp(printer->device_uri, "file:", 5) != 0)
{
sscanf(printer->device_uri, "%254[^:]", method);
snprintf(command, sizeof(command), "%s/backend/%s", ServerBin, method);
#ifdef __APPLE__
snprintf(processPath, sizeof(processPath), "CFProcessPath=%s", command);
LogMessage(L_DEBUG, "StartJob: %s\n", processPath);
#endif
argv[0] = printer->device_uri;
filterfds[slot][0] = -1;
filterfds[slot][1] = open("/dev/null", O_WRONLY);
LogMessage(L_DEBUG, "StartJob: backend = \"%s\"", command);
LogMessage(L_DEBUG, "StartJob: filterfds[%d] = [ %d %d ]",
slot, filterfds[slot][0], filterfds[slot][1]);
pid = start_process(command, argv, envp, filterfds[!slot][0],
filterfds[slot][1], statusfds[1], 1,
current->procs + i);
close(filterfds[!slot][0]);
close(filterfds[!slot][1]);
if (pid == 0)
{
LogMessage(L_ERROR, "Unable to start backend \"%s\" - %s.",
method, strerror(errno));
snprintf(printer->state_message, sizeof(printer->state_message),
"Unable to start backend \"%s\" - %s.", method, strerror(errno));
AddPrinterHistory(printer);
CancelJob(current->id, 0);
return;
}
else
{
LogMessage(L_INFO, "Started backend %s (PID %d) for job %d.", command, pid,
current->id);
}
}
else
{
filterfds[slot][0] = -1;
filterfds[slot][1] = -1;
close(filterfds[!slot][0]);
close(filterfds[!slot][1]);
}
close(filterfds[slot][0]);
close(filterfds[slot][1]);
close(statusfds[1]);
LogMessage(L_DEBUG2, "StartJob: Adding fd %d to InputSet...", current->pipe);
FD_SET(current->pipe, InputSet);
}
void
StopAllJobs(void)
{
job_t *current;
DEBUG_puts("StopAllJobs()");
for (current = Jobs; current != NULL; current = current->next)
if (current->state->values[0].integer == IPP_JOB_PROCESSING)
{
StopJob(current->id, 1);
current->state->values[0].integer = IPP_JOB_PENDING;
}
}
void
StopJob(int id,
int force)
{
int i;
job_t *current;
LogMessage(L_DEBUG, "StopJob: id = %d, force = %d", id, force);
for (current = Jobs; current != NULL; current = current->next)
if (current->id == id)
{
DEBUG_puts("StopJob: found job in list.");
if (current->state->values[0].integer == IPP_JOB_PROCESSING)
{
DEBUG_puts("StopJob: job state is \'processing\'.");
FilterLevel -= current->cost;
if (current->status < 0 &&
!(current->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) &&
!(current->printer->type & CUPS_PRINTER_FAX))
SetPrinterState(current->printer, IPP_PRINTER_STOPPED, 1);
else if (current->printer->state != IPP_PRINTER_STOPPED)
SetPrinterState(current->printer, IPP_PRINTER_IDLE, 0);
LogMessage(L_DEBUG, "StopJob: printer state is %d", current->printer->state);
current->state->values[0].integer = IPP_JOB_STOPPED;
current->printer->job = NULL;
current->printer = NULL;
current->current_file --;
for (i = 0; current->procs[i]; i ++)
if (current->procs[i] > 0)
{
kill(current->procs[i], force ? SIGKILL : SIGTERM);
current->procs[i] = 0;
}
if (current->pipe)
{
LogMessage(L_DEBUG2, "StopJob: Removing fd %d from InputSet...",
current->pipe);
close(current->pipe);
FD_CLR(current->pipe, InputSet);
current->pipe = 0;
}
if (current->buffer)
{
LogMessage(L_DEBUG2, "StopJob: Freeing status buffer...");
free(current->buffer);
current->buffer = NULL;
current->bufused = 0;
}
}
return;
}
}
void
UpdateJob(job_t *job)
{
int bytes;
int copies;
char *lineptr,
*message;
int loglevel;
int job_history;
cups_ptype_t ptype;
if ((bytes = read(job->pipe, job->buffer + job->bufused,
JOB_BUFFER_SIZE - job->bufused - 1)) > 0)
{
job->bufused += bytes;
job->buffer[job->bufused] = '\0';
if ((lineptr = strchr(job->buffer, '\n')) == NULL &&
job->bufused == (JOB_BUFFER_SIZE - 1))
lineptr = job->buffer + job->bufused;
}
else if (bytes < 0 && errno == EINTR)
return;
else
{
lineptr = job->buffer + job->bufused;
*lineptr = '\0';
}
if (job->bufused == 0 && bytes == 0)
lineptr = NULL;
while (lineptr != NULL)
{
*lineptr++ = '\0';
if (strncmp(job->buffer, "EMERG:", 6) == 0)
{
loglevel = L_EMERG;
message = job->buffer + 6;
}
else if (strncmp(job->buffer, "ALERT:", 6) == 0)
{
loglevel = L_ALERT;
message = job->buffer + 6;
}
else if (strncmp(job->buffer, "CRIT:", 5) == 0)
{
loglevel = L_CRIT;
message = job->buffer + 5;
}
else if (strncmp(job->buffer, "ERROR:", 6) == 0)
{
loglevel = L_ERROR;
message = job->buffer + 6;
}
else if (strncmp(job->buffer, "WARNING:", 8) == 0)
{
loglevel = L_WARN;
message = job->buffer + 8;
}
else if (strncmp(job->buffer, "NOTICE:", 6) == 0)
{
loglevel = L_NOTICE;
message = job->buffer + 6;
}
else if (strncmp(job->buffer, "INFO:", 5) == 0)
{
loglevel = L_INFO;
message = job->buffer + 5;
}
else if (strncmp(job->buffer, "DEBUG:", 6) == 0)
{
loglevel = L_DEBUG;
message = job->buffer + 6;
}
else if (strncmp(job->buffer, "DEBUG2:", 7) == 0)
{
loglevel = L_DEBUG2;
message = job->buffer + 7;
}
else if (strncmp(job->buffer, "PAGE:", 5) == 0)
{
loglevel = L_PAGE;
message = job->buffer + 5;
}
else if (strncmp(job->buffer, "STATE:", 6) == 0)
{
loglevel = L_STATE;
message = job->buffer + 6;
}
else
{
loglevel = L_DEBUG;
message = job->buffer;
}
while (isspace(*message))
message ++;
if (loglevel == L_PAGE)
{
if (job->sheets != NULL)
{
if (!strncasecmp(message, "total ", 6))
{
copies = atoi(message + 6);
copies -= job->sheets->values[0].integer;
}
else if (!sscanf(message, "%*d%d", &copies))
copies = 1;
job->sheets->values[0].integer += copies;
if (job->printer->page_limit)
UpdateQuota(job->printer, job->username, copies, 0);
}
LogPage(job, message);
}
else if (loglevel == L_STATE)
SetPrinterReasons(job->printer, message);
else
{
if (loglevel != L_INFO || LogLevel == L_DEBUG2)
LogMessage(loglevel, "[Job %d] %s", job->id, message);
if ((loglevel == L_INFO && !job->status) ||
loglevel < L_INFO)
{
strlcpy(job->printer->state_message, message,
sizeof(job->printer->state_message));
AddPrinterHistory(job->printer);
}
}
cups_strcpy(job->buffer, lineptr);
job->bufused -= lineptr - job->buffer;
if (job->bufused < 0)
job->bufused = 0;
lineptr = strchr(job->buffer, '\n');
}
if (bytes <= 0)
{
LogMessage(L_DEBUG, "UpdateJob: job %d, file %d is complete.",
job->id, job->current_file - 1);
if (job->pipe)
{
LogMessage(L_DEBUG2, "UpdateJob: Removing fd %d from InputSet...",
job->pipe);
close(job->pipe);
FD_CLR(job->pipe, InputSet);
job->pipe = 0;
}
if (job->status < 0)
{
ptype = job->printer->type;
StopJob(job->id, 0);
job->state->values[0].integer = IPP_JOB_PENDING;
SaveJob(job->id);
if (job->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
CheckJobs();
else if (ptype & CUPS_PRINTER_FAX)
{
job->tries ++;
if (job->tries >= FaxRetryLimit)
{
LogMessage(L_ERROR, "Canceling fax job %d since it could not be sent after %d tries.",
job->id, FaxRetryLimit);
CancelJob(job->id, 0);
}
else
{
set_hold_until(job, time(NULL) + FaxRetryInterval);
}
CheckJobs();
}
}
else if (job->status > 0)
{
if (job->current_file < job->num_files)
StartJob(job->id, job->printer);
else
{
job_history = JobHistory && !(job->dtype & CUPS_PRINTER_REMOTE);
CancelJob(job->id, 0);
if (job_history)
{
job->state->values[0].integer = IPP_JOB_ABORTED;
SaveJob(job->id);
}
CheckJobs();
}
}
else
{
if (job->current_file < job->num_files)
{
FilterLevel -= job->cost;
StartJob(job->id, job->printer);
}
else
{
job_history = JobHistory && !(job->dtype & CUPS_PRINTER_REMOTE);
CancelJob(job->id, 0);
if (job_history)
{
job->state->values[0].integer = IPP_JOB_COMPLETED;
SaveJob(job->id);
}
CheckJobs();
}
}
}
}
int
ipp_length(ipp_t *ipp)
{
int bytes;
int i;
ipp_attribute_t *attr;
bytes = 0;
for (attr = ipp->attrs; attr != NULL; attr = attr->next)
{
if (attr->value_tag == IPP_TAG_MIMETYPE ||
attr->value_tag == IPP_TAG_NAMELANG ||
attr->value_tag == IPP_TAG_TEXTLANG ||
attr->value_tag == IPP_TAG_URI ||
attr->value_tag == IPP_TAG_URISCHEME)
continue;
if (strncmp(attr->name, "time-", 5) == 0)
continue;
bytes ++;
bytes += attr->num_values;
if (attr->value_tag != IPP_TAG_BOOLEAN)
bytes += strlen(attr->name);
else
bytes += attr->num_values * strlen(attr->name);
switch (attr->value_tag)
{
case IPP_TAG_INTEGER :
case IPP_TAG_ENUM :
bytes += attr->num_values * 11;
break;
case IPP_TAG_BOOLEAN :
for (i = 0; i < attr->num_values; i ++)
if (!attr->values[i].boolean)
bytes += 2;
break;
case IPP_TAG_RANGE :
bytes += attr->num_values * 23;
break;
case IPP_TAG_RESOLUTION :
bytes += attr->num_values * 26;
break;
case IPP_TAG_STRING :
case IPP_TAG_TEXT :
case IPP_TAG_NAME :
case IPP_TAG_KEYWORD :
case IPP_TAG_CHARSET :
case IPP_TAG_LANGUAGE :
for (i = 0; i < attr->num_values; i ++)
bytes += 2 * strlen(attr->values[i].string.text) + 2;
break;
default :
break;
}
}
return (bytes);
}
static void
set_time(job_t *job,
const char *name)
{
ipp_attribute_t *attr;
if ((attr = ippFindAttribute(job->attrs, name, IPP_TAG_ZERO)) != NULL)
{
attr->value_tag = IPP_TAG_INTEGER;
attr->values[0].integer = time(NULL);
}
}
static int
start_process(const char *command,
char *argv[],
char *envp[],
int infd,
int outfd,
int errfd,
int root,
int *pid)
{
int fd;
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
struct sigaction action;
#endif
LogMessage(L_DEBUG, "start_process(\"%s\", %p, %p, %d, %d, %d)",
command, argv, envp, infd, outfd, errfd);
HoldSignals();
if ((*pid = fork()) == 0)
{
close(0);
dup(infd);
close(1);
dup(outfd);
if (errfd > 2)
{
close(2);
dup(errfd);
}
for (fd = 3; fd < MaxFDs; fd ++)
close(fd);
if (!root)
nice(FilterNice);
if (!root && getuid() == 0)
{
if (setgid(Group))
exit(errno);
if (setgroups(1, &Group))
exit(errno);
if (setuid(User))
exit(errno);
}
else
{
setgroups(1, &Group);
}
umask(077);
#ifdef HAVE_SIGSET
sigset(SIGTERM, SIG_DFL);
sigset(SIGCHLD, SIG_DFL);
#elif defined(HAVE_SIGACTION)
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
action.sa_handler = SIG_DFL;
sigaction(SIGTERM, &action, NULL);
sigaction(SIGCHLD, &action, NULL);
#else
signal(SIGTERM, SIG_DFL);
signal(SIGCHLD, SIG_DFL);
#endif
ReleaseSignals();
execve(command, argv, envp);
perror(command);
exit(errno);
}
else if (*pid < 0)
{
LogMessage(L_ERROR, "Unable to fork %s - %s.", command, strerror(errno));
*pid = 0;
}
ReleaseSignals();
return (*pid);
}
static void
set_hold_until(job_t *job,
time_t holdtime)
{
ipp_attribute_t *attr;
struct tm *holddate;
char holdstr[64];
LogMessage(L_DEBUG, "set_hold_until: hold_until = %d", (int)holdtime);
job->state->values[0].integer = IPP_JOB_HELD;
job->hold_until = holdtime;
holddate = gmtime(&holdtime);
snprintf(holdstr, sizeof(holdstr), "%d:%d:%d", holddate->tm_hour,
holddate->tm_min,
holddate->tm_sec);
if ((attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD)) == NULL)
attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
if (attr == NULL)
attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
"job-hold-until", NULL, holdstr);
else
SetString(&attr->values[0].string.text, holdstr);
SaveJob(job->id);
}