#include "cupsd.h"
#include <grp.h>
static ipp_state_t ipp_read_file(const char *filename, ipp_t *ipp);
static ipp_state_t ipp_write_file(const char *filename, 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);
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;
strlcpy(job->dest, dest, sizeof(job->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);
free(current->filetypes);
free(current);
NumJobs --;
}
return;
}
}
void
CancelJobs(const char *dest)
{
job_t *current;
for (current = Jobs; current != NULL;)
if (strcmp(current->dest, dest) == 0)
{
CancelJob(current->id, 1);
current = Jobs;
}
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;
StopAllJobs();
for (job = Jobs; job; job = next)
{
next = job->next;
ippDelete(job->attrs);
free(job->filetypes);
free(job);
}
Jobs = NULL;
}
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];
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;
if ((dir = opendir(RequestRoot)) == NULL)
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);
if (job->id >= NextJobId)
NextJobId = job->id + 1;
snprintf(filename, sizeof(filename), "%s/%s", RequestRoot, dent->d_name);
if (ipp_read_file(filename, job->attrs) != IPP_DATA)
{
LogMessage(L_ERROR, "LoadAllJobs: Unable to read job control file \"%s\"!",
filename);
ippDelete(job->attrs);
free(job);
unlink(filename);
continue;
}
job->state = ippFindAttribute(job->attrs, "job-state", IPP_TAG_ENUM);
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);
strcpy(p->make_model, "Remote Class on unknown");
}
else
{
p = AddPrinter(resource + 10);
strcpy(p->make_model, "Remote Printer on unknown");
}
p->state = IPP_PRINTER_STOPPED;
p->type |= CUPS_PRINTER_REMOTE;
p->browse_time = 2147483647;
strcpy(p->location, "Location Unknown");
strcpy(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;
}
strlcpy(job->dest, dest, sizeof(job->dest));
job->sheets = ippFindAttribute(job->attrs, "job-media-sheets-completed",
IPP_TAG_INTEGER);
job->job_sheets = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME);
attr = ippFindAttribute(job->attrs, "job-priority", IPP_TAG_INTEGER);
job->priority = attr->values[0].integer;
attr = ippFindAttribute(job->attrs, "job-name", IPP_TAG_NAME);
strlcpy(job->title, attr->values[0].string.text,
sizeof(job->title));
attr = ippFindAttribute(job->attrs, "job-originating-user-name", IPP_TAG_NAME);
strlcpy(job->username, attr->values[0].string.text,
sizeof(job->username));
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);
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)
filetypes = (mime_type_t **)calloc(sizeof(mime_type_t *), fileid);
else
filetypes = (mime_type_t **)realloc(job->filetypes,
sizeof(mime_type_t *) * fileid);
if (filetypes == NULL)
{
LogMessage(L_ERROR, "LoadAllJobs: Ran out of memory for job file types!");
continue;
}
job->filetypes = filetypes;
job->num_files = fileid;
}
job->filetypes[fileid - 1] = mimeFileType(MimeDatabase, filename);
if (job->filetypes[fileid - 1] == NULL)
job->filetypes[fileid - 1] = mimeType(MimeDatabase, "application",
"vnd.cups-raw");
}
closedir(dir);
CleanJobs();
CheckJobs();
}
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;
strlcpy(current->dest, dest, sizeof(current->dest));
current->dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE);
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->state->values[0].integer = IPP_JOB_PENDING;
SaveJob(id);
CheckJobs();
}
}
void
SaveJob(int id)
{
job_t *job;
char filename[1024];
if ((job = FindJob(id)) == NULL)
return;
snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, id);
ipp_write_file(filename, job->attrs);
}
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;
ipp_attribute_t *attr;
int pid;
int banner_page;
int statusfds[2],
filterfds[2][2];
char *argv[8],
filename[1024],
command[1024],
jobid[255],
title[IPP_MAX_NAME],
copies[255],
options[16384],
*envp[20],
path[1024],
language[255],
charset[255],
classification[1024],
content_type[1024],
device_uri[1024],
ppd[1024],
printer_name[255],
root[1024],
cache[255],
tmpdir[1024],
ldpath[1024],
nlspath[1024],
datadir[1024],
fontpath[1050];
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->type & CUPS_PRINTER_REMOTE)
{
filters = NULL;
}
else
{
filters = mimeFilter(MimeDatabase, current->filetypes[current->current_file],
printer->filetype, &num_filters);
if (num_filters == 0)
{
LogMessage(L_ERROR, "Unable to convert file %d to printable format for job %d!",
current->current_file, current->id);
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;
current->state->values[0].integer = IPP_JOB_PROCESSING;
current->status = 0;
current->printer = printer;
printer->job = current;
SetPrinterState(printer, IPP_PRINTER_PROCESSING);
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);
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)
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 &&
banner_page)
continue;
if (optptr > options)
strlcat(optptr, " ", sizeof(options) - (optptr - options));
if (attr->value_tag != IPP_TAG_BOOLEAN)
{
strlcat(optptr, attr->name, sizeof(options) - (optptr - options));
strlcat(optptr, "=", sizeof(options) - (optptr - options));
}
for (i = 0; i < attr->num_values; i ++)
{
if (i)
strlcat(optptr, ",", sizeof(options) - (optptr - options));
optptr += strlen(optptr);
switch (attr->value_tag)
{
case IPP_TAG_INTEGER :
case IPP_TAG_ENUM :
snprintf(optptr, sizeof(options) - (optptr - options),
"%d", attr->values[i].integer);
break;
case IPP_TAG_BOOLEAN :
if (!attr->values[i].boolean)
strlcat(optptr, "no", sizeof(options) - (optptr - options));
case IPP_TAG_NOVALUE :
strlcat(optptr, attr->name,
sizeof(options) - (optptr - options));
break;
case IPP_TAG_RANGE :
if (attr->values[i].range.lower == attr->values[i].range.upper)
snprintf(optptr, sizeof(options) - (optptr - options) - 1,
"%d", attr->values[i].range.lower);
else
snprintf(optptr, sizeof(options) - (optptr - options) - 1,
"%d-%d", attr->values[i].range.lower,
attr->values[i].range.upper);
break;
case IPP_TAG_RESOLUTION :
snprintf(optptr, sizeof(options) - (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, "\'", sizeof(options) - (optptr - options));
strlcat(optptr, attr->values[i].string.text,
sizeof(options) - (optptr - options));
strlcat(optptr, "\'", sizeof(options) - (optptr - options));
}
else
strlcat(optptr, attr->values[i].string.text,
sizeof(options) - (optptr - options));
break;
default :
break;
}
}
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);
if (Classification[0] && !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);
}
else
classification[0] = '\0';
if (getenv("LD_LIBRARY_PATH") != NULL)
snprintf(ldpath, sizeof(ldpath), "LD_LIBRARY_PATH=%s",
getenv("LD_LIBRARY_PATH"));
else if (getenv("DYLD_LIBRARY_PATH") != NULL)
snprintf(ldpath, sizeof(ldpath), "DYLD_LIBRARY_PATH=%s",
getenv("DYLD_LIBRARY_PATH"));
else
ldpath[0] = '\0';
if (getenv("NLSPATH") != NULL)
snprintf(nlspath, sizeof(nlspath), "NLSPATH=%s", getenv("NLSPATH"));
else
nlspath[0] = '\0';
envp[0] = path;
envp[1] = "SOFTWARE=CUPS/1.1";
envp[2] = "USER=root";
envp[3] = charset;
envp[4] = language;
envp[5] = TZ;
envp[6] = ppd;
envp[7] = root;
envp[8] = cache;
envp[9] = tmpdir;
envp[10] = content_type;
envp[11] = device_uri;
envp[12] = printer_name;
envp[13] = datadir;
envp[14] = fontpath;
envp[15] = ldpath;
envp[16] = nlspath;
envp[17] = classification;
envp[18] = NULL;
LogMessage(L_DEBUG, "StartJob: envp = \"%s\",\"%s\",\"%s\",\"%s\","
"\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\","
"\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"",
envp[0], envp[1], envp[2], envp[3], envp[4],
envp[5], envp[6], envp[7], envp[8], envp[9],
envp[10], envp[11], envp[12], envp[13], envp[14],
envp[15], envp[16], envp[17]);
current->current_file ++;
if (current->buffer == NULL)
{
LogMessage(L_DEBUG2, "UpdateJob: 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));
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));
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));
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);
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));
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)
SetPrinterState(current->printer, IPP_PRINTER_STOPPED);
else if (current->printer->state != IPP_PRINTER_STOPPED)
SetPrinterState(current->printer, IPP_PRINTER_IDLE);
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;
if ((bytes = read(job->pipe, job->buffer + job->bufused,
JOB_BUFFER_SIZE - job->bufused - 1)) > 0)
{
job->bufused += bytes;
job->buffer[job->bufused] = '\0';
lineptr = strchr(job->buffer, '\n');
}
else if (bytes < 0 && errno == EINTR)
return;
else
{
lineptr = job->buffer + job->bufused;
lineptr[1] = 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
{
loglevel = L_DEBUG;
message = job->buffer;
}
while (isspace(*message))
message ++;
if (loglevel == L_PAGE)
{
if (job->sheets != NULL)
{
if (!sscanf(message, "%*d%d", &copies))
{
job->sheets->values[0].integer ++;
if (job->printer->page_limit)
UpdateQuota(job->printer, job->username, 1, 0);
}
else
{
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_INFO)
LogMessage(loglevel, "%s", message);
if ((loglevel == L_INFO && !job->status) ||
loglevel < L_INFO)
strlcpy(job->printer->state_message, message,
sizeof(job->printer->state_message));
}
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)
{
StopJob(job->id, 0);
job->state->values[0].integer = IPP_JOB_PENDING;
SaveJob(job->id);
}
else if (job->status > 0)
{
if (job->current_file < job->num_files)
StartJob(job->id, job->printer);
else
{
CancelJob(job->id, 0);
if (JobHistory)
{
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
{
CancelJob(job->id, 0);
if (JobHistory)
{
job->state->values[0].integer = IPP_JOB_COMPLETED;
SaveJob(job->id);
}
CheckJobs();
}
}
}
}
static ipp_state_t
ipp_read_file(const char *filename,
ipp_t *ipp)
{
int fd;
int n;
unsigned char buffer[8192],
*bufptr;
ipp_attribute_t *attr;
ipp_tag_t tag;
if (filename == NULL || ipp == NULL)
return (IPP_ERROR);
if ((fd = open(filename, O_RDONLY)) == -1)
return (IPP_ERROR);
ipp->state = IPP_IDLE;
switch (ipp->state)
{
default :
break;
case IPP_IDLE :
ipp->state ++;
case IPP_HEADER :
if ((n = read(fd, buffer, 8)) < 8)
{
DEBUG_printf(("ipp_read_file: Unable to read header (%d bytes read)!\n", n));
close(fd);
return (n == 0 ? IPP_IDLE : IPP_ERROR);
}
if (buffer[0] != 1)
{
DEBUG_printf(("ipp_read_file: version number (%d.%d) is bad.\n", buffer[0],
buffer[1]));
close(fd);
return (IPP_ERROR);
}
ipp->request.any.version[0] = buffer[0];
ipp->request.any.version[1] = buffer[1];
ipp->request.any.op_status = (buffer[2] << 8) | buffer[3];
ipp->request.any.request_id = (((((buffer[4] << 8) | buffer[5]) << 8) |
buffer[6]) << 8) | buffer[7];
ipp->state = IPP_ATTRIBUTE;
ipp->current = NULL;
ipp->curtag = IPP_TAG_ZERO;
case IPP_ATTRIBUTE :
while (read(fd, buffer, 1) > 0)
{
tag = (ipp_tag_t)buffer[0];
if (tag == IPP_TAG_END)
{
DEBUG_puts("ipp_read_file: IPP_TAG_END!");
ipp->state = IPP_DATA;
break;
}
else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
{
if (ipp->curtag == tag)
ippAddSeparator(ipp);
ipp->curtag = tag;
ipp->current = NULL;
DEBUG_printf(("ipp_read_file: group tag = %x\n", tag));
continue;
}
DEBUG_printf(("ipp_read_file: value tag = %x\n", tag));
if (read(fd, buffer, 2) < 2)
{
DEBUG_puts("ipp_read_file: unable to read name length!");
close(fd);
return (IPP_ERROR);
}
n = (buffer[0] << 8) | buffer[1];
if (n > (sizeof(buffer) - 1))
{
DEBUG_printf(("ipp_read_file: bad name length %d!\n", n));
return (IPP_ERROR);
}
DEBUG_printf(("ipp_read_file: name length = %d\n", n));
if (n == 0)
{
if (ipp->current == NULL)
{
close(fd);
return (IPP_ERROR);
}
attr = ipp->current;
if ((attr->num_values % IPP_MAX_VALUES) == 0)
{
ipp_attribute_t *temp,
*ptr;
if ((temp = realloc(attr, sizeof(ipp_attribute_t) +
(attr->num_values + IPP_MAX_VALUES - 1) *
sizeof(ipp_value_t))) == NULL)
{
close(fd);
return (IPP_ERROR);
}
for (ptr = ipp->attrs; ptr && ptr->next != attr; ptr = ptr->next);
if (ptr)
ptr->next = temp;
else
ipp->attrs = temp;
attr = ipp->current = ipp->last = temp;
}
}
else
{
if (read(fd, buffer, n) < n)
{
DEBUG_puts("ipp_read_file: unable to read name!");
close(fd);
return (IPP_ERROR);
}
buffer[n] = '\0';
DEBUG_printf(("ipp_read_file: name = \'%s\'\n", buffer));
attr = ipp->current = _ipp_add_attr(ipp, IPP_MAX_VALUES);
attr->group_tag = ipp->curtag;
attr->value_tag = tag;
attr->name = strdup((char *)buffer);
attr->num_values = 0;
}
if (read(fd, buffer, 2) < 2)
{
DEBUG_puts("ipp_read_file: unable to read value length!");
close(fd);
return (IPP_ERROR);
}
n = (buffer[0] << 8) | buffer[1];
DEBUG_printf(("ipp_read_file: value length = %d\n", n));
switch (tag)
{
case IPP_TAG_INTEGER :
case IPP_TAG_ENUM :
if (read(fd, buffer, 4) < 4)
{
close(fd);
return (IPP_ERROR);
}
n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
buffer[3];
attr->values[attr->num_values].integer = n;
break;
case IPP_TAG_BOOLEAN :
if (read(fd, buffer, 1) < 1)
{
close(fd);
return (IPP_ERROR);
}
attr->values[attr->num_values].boolean = buffer[0];
break;
case IPP_TAG_TEXT :
case IPP_TAG_NAME :
case IPP_TAG_KEYWORD :
case IPP_TAG_STRING :
case IPP_TAG_URI :
case IPP_TAG_URISCHEME :
case IPP_TAG_CHARSET :
case IPP_TAG_LANGUAGE :
case IPP_TAG_MIMETYPE :
if (read(fd, buffer, n) < n)
{
close(fd);
return (IPP_ERROR);
}
buffer[n] = '\0';
DEBUG_printf(("ipp_read_file: value = \'%s\'\n", buffer));
attr->values[attr->num_values].string.text = strdup((char *)buffer);
break;
case IPP_TAG_DATE :
if (read(fd, buffer, 11) < 11)
{
close(fd);
return (IPP_ERROR);
}
memcpy(attr->values[attr->num_values].date, buffer, 11);
break;
case IPP_TAG_RESOLUTION :
if (read(fd, buffer, 9) < 9)
{
close(fd);
return (IPP_ERROR);
}
attr->values[attr->num_values].resolution.xres =
(((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
buffer[3];
attr->values[attr->num_values].resolution.yres =
(((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
buffer[7];
attr->values[attr->num_values].resolution.units =
(ipp_res_t)buffer[8];
break;
case IPP_TAG_RANGE :
if (read(fd, buffer, 8) < 8)
{
close(fd);
return (IPP_ERROR);
}
attr->values[attr->num_values].range.lower =
(((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
buffer[3];
attr->values[attr->num_values].range.upper =
(((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
buffer[7];
break;
case IPP_TAG_TEXTLANG :
case IPP_TAG_NAMELANG :
if (n > sizeof(buffer))
{
DEBUG_printf(("ipp_read_file: bad value length %d!\n", n));
return (IPP_ERROR);
}
if (read(fd, buffer, n) < n)
return (IPP_ERROR);
bufptr = buffer;
n = (bufptr[0] << 8) | bufptr[1];
attr->values[attr->num_values].string.charset = calloc(n + 1, 1);
memcpy(attr->values[attr->num_values].string.charset,
bufptr + 2, n);
bufptr += 2 + n;
n = (bufptr[0] << 8) | bufptr[1];
attr->values[attr->num_values].string.text = calloc(n + 1, 1);
memcpy(attr->values[attr->num_values].string.text,
bufptr + 2, n);
break;
default :
attr->values[attr->num_values].unknown.length = n;
if (n > 0)
{
attr->values[attr->num_values].unknown.data = malloc(n);
if (read(fd, attr->values[attr->num_values].unknown.data, n) < n)
return (IPP_ERROR);
}
else
attr->values[attr->num_values].unknown.data = NULL;
break;
}
attr->num_values ++;
}
break;
case IPP_DATA :
break;
}
close(fd);
return (ipp->state);
}
static ipp_state_t
ipp_write_file(const char *filename,
ipp_t *ipp)
{
int fd;
int i;
int n;
unsigned char buffer[8192],
*bufptr;
ipp_attribute_t *attr;
if (filename == NULL || ipp == NULL)
return (IPP_ERROR);
if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) == -1)
return (IPP_ERROR);
fchmod(fd, 0600);
fchown(fd, User, Group);
ipp->state = IPP_IDLE;
switch (ipp->state)
{
default :
break;
case IPP_IDLE :
ipp->state ++;
case IPP_HEADER :
bufptr = buffer;
*bufptr++ = ipp->request.any.version[0];
*bufptr++ = ipp->request.any.version[1];
*bufptr++ = ipp->request.any.op_status >> 8;
*bufptr++ = ipp->request.any.op_status;
*bufptr++ = ipp->request.any.request_id >> 24;
*bufptr++ = ipp->request.any.request_id >> 16;
*bufptr++ = ipp->request.any.request_id >> 8;
*bufptr++ = ipp->request.any.request_id;
if (write(fd, (char *)buffer, bufptr - buffer) < 0)
{
DEBUG_puts("ipp_write_file: Could not write IPP header...");
close(fd);
return (IPP_ERROR);
}
ipp->state = IPP_ATTRIBUTE;
ipp->current = ipp->attrs;
ipp->curtag = IPP_TAG_ZERO;
case IPP_ATTRIBUTE :
while (ipp->current != NULL)
{
bufptr = buffer;
attr = ipp->current;
ipp->current = ipp->current->next;
if (ipp->curtag != attr->group_tag)
{
ipp->curtag = attr->group_tag;
if (attr->group_tag == IPP_TAG_ZERO)
continue;
DEBUG_printf(("ipp_write_file: wrote group tag = %x\n", attr->group_tag));
*bufptr++ = attr->group_tag;
}
if ((n = strlen(attr->name)) > (sizeof(buffer) - 3))
return (IPP_ERROR);
DEBUG_printf(("ipp_write_file: writing value tag = %x\n", attr->value_tag));
DEBUG_printf(("ipp_write_file: writing name = %d, \'%s\'\n", n, attr->name));
*bufptr++ = attr->value_tag;
*bufptr++ = n >> 8;
*bufptr++ = n;
memcpy(bufptr, attr->name, n);
bufptr += n;
switch (attr->value_tag)
{
case IPP_TAG_INTEGER :
case IPP_TAG_ENUM :
for (i = 0; i < attr->num_values; i ++)
{
if ((sizeof(buffer) - (bufptr - buffer)) < 9)
{
if (write(fd, (char *)buffer, bufptr - buffer) < 0)
{
DEBUG_puts("ippWrite: Could not write IPP attribute...");
return (IPP_ERROR);
}
bufptr = buffer;
}
if (i)
{
*bufptr++ = attr->value_tag;
*bufptr++ = 0;
*bufptr++ = 0;
}
*bufptr++ = 0;
*bufptr++ = 4;
*bufptr++ = attr->values[i].integer >> 24;
*bufptr++ = attr->values[i].integer >> 16;
*bufptr++ = attr->values[i].integer >> 8;
*bufptr++ = attr->values[i].integer;
}
break;
case IPP_TAG_BOOLEAN :
for (i = 0; i < attr->num_values; i ++)
{
if ((sizeof(buffer) - (bufptr - buffer)) < 6)
{
if (write(fd, (char *)buffer, bufptr - buffer) < 0)
{
DEBUG_puts("ippWrite: Could not write IPP attribute...");
return (IPP_ERROR);
}
bufptr = buffer;
}
if (i)
{
*bufptr++ = attr->value_tag;
*bufptr++ = 0;
*bufptr++ = 0;
}
*bufptr++ = 0;
*bufptr++ = 1;
*bufptr++ = attr->values[i].boolean;
}
break;
case IPP_TAG_TEXT :
case IPP_TAG_NAME :
case IPP_TAG_KEYWORD :
case IPP_TAG_STRING :
case IPP_TAG_URI :
case IPP_TAG_URISCHEME :
case IPP_TAG_CHARSET :
case IPP_TAG_LANGUAGE :
case IPP_TAG_MIMETYPE :
for (i = 0; i < attr->num_values; i ++)
{
if (i)
{
DEBUG_printf(("ipp_write_file: writing value tag = %x\n",
attr->value_tag));
DEBUG_printf(("ipp_write_file: writing name = 0, \'\'\n"));
if ((sizeof(buffer) - (bufptr - buffer)) < 3)
{
if (write(fd, (char *)buffer, bufptr - buffer) < 0)
{
DEBUG_puts("ippWrite: Could not write IPP attribute...");
return (IPP_ERROR);
}
bufptr = buffer;
}
*bufptr++ = attr->value_tag;
*bufptr++ = 0;
*bufptr++ = 0;
}
n = strlen(attr->values[i].string.text);
if (n > sizeof(buffer))
return (IPP_ERROR);
DEBUG_printf(("ipp_write_file: writing string = %d, \'%s\'\n", n,
attr->values[i].string.text));
if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
{
if (write(fd, (char *)buffer, bufptr - buffer) < 0)
{
DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
close(fd);
return (IPP_ERROR);
}
bufptr = buffer;
}
*bufptr++ = n >> 8;
*bufptr++ = n;
memcpy(bufptr, attr->values[i].string.text, n);
bufptr += n;
}
break;
case IPP_TAG_DATE :
for (i = 0; i < attr->num_values; i ++)
{
if ((sizeof(buffer) - (bufptr - buffer)) < 16)
{
if (write(fd, (char *)buffer, bufptr - buffer) < 0)
{
DEBUG_puts("ippWrite: Could not write IPP attribute...");
return (IPP_ERROR);
}
bufptr = buffer;
}
if (i)
{
*bufptr++ = attr->value_tag;
*bufptr++ = 0;
*bufptr++ = 0;
}
*bufptr++ = 0;
*bufptr++ = 11;
memcpy(bufptr, attr->values[i].date, 11);
bufptr += 11;
}
break;
case IPP_TAG_RESOLUTION :
for (i = 0; i < attr->num_values; i ++)
{
if ((sizeof(buffer) - (bufptr - buffer)) < 14)
{
if (write(fd, (char *)buffer, bufptr - buffer) < 0)
{
DEBUG_puts("ippWrite: Could not write IPP attribute...");
return (IPP_ERROR);
}
bufptr = buffer;
}
if (i)
{
*bufptr++ = attr->value_tag;
*bufptr++ = 0;
*bufptr++ = 0;
}
*bufptr++ = 0;
*bufptr++ = 9;
*bufptr++ = attr->values[i].resolution.xres >> 24;
*bufptr++ = attr->values[i].resolution.xres >> 16;
*bufptr++ = attr->values[i].resolution.xres >> 8;
*bufptr++ = attr->values[i].resolution.xres;
*bufptr++ = attr->values[i].resolution.yres >> 24;
*bufptr++ = attr->values[i].resolution.yres >> 16;
*bufptr++ = attr->values[i].resolution.yres >> 8;
*bufptr++ = attr->values[i].resolution.yres;
*bufptr++ = attr->values[i].resolution.units;
}
break;
case IPP_TAG_RANGE :
for (i = 0; i < attr->num_values; i ++)
{
if ((sizeof(buffer) - (bufptr - buffer)) < 13)
{
if (write(fd, (char *)buffer, bufptr - buffer) < 0)
{
DEBUG_puts("ippWrite: Could not write IPP attribute...");
return (IPP_ERROR);
}
bufptr = buffer;
}
if (i)
{
*bufptr++ = attr->value_tag;
*bufptr++ = 0;
*bufptr++ = 0;
}
*bufptr++ = 0;
*bufptr++ = 8;
*bufptr++ = attr->values[i].range.lower >> 24;
*bufptr++ = attr->values[i].range.lower >> 16;
*bufptr++ = attr->values[i].range.lower >> 8;
*bufptr++ = attr->values[i].range.lower;
*bufptr++ = attr->values[i].range.upper >> 24;
*bufptr++ = attr->values[i].range.upper >> 16;
*bufptr++ = attr->values[i].range.upper >> 8;
*bufptr++ = attr->values[i].range.upper;
}
break;
case IPP_TAG_TEXTLANG :
case IPP_TAG_NAMELANG :
for (i = 0; i < attr->num_values; i ++)
{
if (i)
{
if ((sizeof(buffer) - (bufptr - buffer)) < 3)
{
if (write(fd, (char *)buffer, bufptr - buffer) < 0)
{
DEBUG_puts("ippWrite: Could not write IPP attribute...");
return (IPP_ERROR);
}
bufptr = buffer;
}
*bufptr++ = attr->value_tag;
*bufptr++ = 0;
*bufptr++ = 0;
}
n = strlen(attr->values[i].string.charset) +
strlen(attr->values[i].string.text) +
4;
if (n > sizeof(buffer))
return (IPP_ERROR);
if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
{
if (write(fd, (char *)buffer, bufptr - buffer) < 0)
{
DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
return (IPP_ERROR);
}
bufptr = buffer;
}
*bufptr++ = n >> 8;
*bufptr++ = n;
n = strlen(attr->values[i].string.charset);
*bufptr++ = n >> 8;
*bufptr++ = n;
memcpy(bufptr, attr->values[i].string.charset, n);
bufptr += n;
n = strlen(attr->values[i].string.text);
*bufptr++ = n >> 8;
*bufptr++ = n;
memcpy(bufptr, attr->values[i].string.text, n);
bufptr += n;
}
break;
default :
for (i = 0; i < attr->num_values; i ++)
{
if (i)
{
if ((sizeof(buffer) - (bufptr - buffer)) < 3)
{
if (write(fd, (char *)buffer, bufptr - buffer) < 0)
{
DEBUG_puts("ippWrite: Could not write IPP attribute...");
return (IPP_ERROR);
}
bufptr = buffer;
}
*bufptr++ = attr->value_tag;
*bufptr++ = 0;
*bufptr++ = 0;
}
n = attr->values[i].unknown.length;
if (n > sizeof(buffer))
return (IPP_ERROR);
if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
{
if (write(fd, (char *)buffer, bufptr - buffer) < 0)
{
DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
return (IPP_ERROR);
}
bufptr = buffer;
}
*bufptr++ = n >> 8;
*bufptr++ = n;
if (n > 0)
{
memcpy(bufptr, attr->values[i].unknown.data, n);
bufptr += n;
}
}
break;
}
if (write(fd, (char *)buffer, bufptr - buffer) < 0)
{
DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
close(fd);
return (IPP_ERROR);
}
DEBUG_printf(("ipp_write_file: wrote %d bytes\n", bufptr - buffer));
}
if (ipp->current == NULL)
{
buffer[0] = IPP_TAG_END;
if (write(fd, (char *)buffer, 1) < 0)
{
DEBUG_puts("ipp_write_file: Could not write IPP end-tag...");
close(fd);
return (IPP_ERROR);
}
ipp->state = IPP_DATA;
}
break;
case IPP_DATA :
break;
}
close(fd);
return (ipp->state);
}
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)
sigset_t oldmask,
newmask;
struct sigaction action;
#endif
LogMessage(L_DEBUG, "start_process(\"%s\", %p, %p, %d, %d, %d)",
command, argv, envp, infd, outfd, errfd);
#ifdef HAVE_SIGSET
sighold(SIGTERM);
sighold(SIGCHLD);
#elif defined(HAVE_SIGACTION)
sigemptyset(&newmask);
sigaddset(&newmask, SIGTERM);
sigaddset(&newmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &newmask, &oldmask);
#endif
if ((*pid = fork()) == 0)
{
#ifdef HAVE_SIGSET
sigset(SIGCHLD, SIG_DFL);
sigset(SIGTERM, SIG_DFL);
sigrelse(SIGTERM);
sigrelse(SIGCHLD);
#elif defined(HAVE_SIGACTION)
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
sigaddset(&action.sa_mask, SIGCHLD);
action.sa_handler = SIG_DFL;
sigaction(SIGCHLD, &action, NULL);
sigemptyset(&action.sa_mask);
sigaddset(&action.sa_mask, SIGTERM);
action.sa_handler = SIG_DFL;
sigaction(SIGTERM, &action, NULL);
sigprocmask(SIG_SETMASK, &oldmask, NULL);
#else
signal(SIGCHLD, SIG_DFL);
signal(SIGTERM, SIG_DFL);
#endif
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 && getuid() == 0)
{
if (setgid(Group))
exit(errno);
if (setuid(User))
exit(errno);
}
setgroups(0, NULL);
umask(077);
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;
}
#ifdef HAVE_SIGSET
sigrelse(SIGTERM);
sigrelse(SIGCHLD);
#elif defined(HAVE_SIGACTION)
sigprocmask(SIG_SETMASK, &oldmask, NULL);
#endif
return (*pid);
}