/*
* "$Id: ipp.c 7944 2008-09-16 22:32:42Z mike $"
*
- * IPP routines for the Common UNIX Printing System (CUPS) scheduler.
+ * IPP routines for the CUPS scheduler.
*
* Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
* printer.
* apply_printer_defaults() - Apply printer default options to a job.
* authenticate_job() - Set job authentication info.
- * cancel_all_jobs() - Cancel all print jobs.
+ * cancel_all_jobs() - Cancel all or selected print jobs.
* cancel_job() - Cancel a print job.
* cancel_subscription() - Cancel a subscription.
- * check_quotas() - Check quotas for a printer and user.
* check_rss_recipient() - Check that we do not have a duplicate RSS
* feed URI.
+ * check_quotas() - Check quotas for a printer and user.
+ * close_job() - Close a multi-file job.
* copy_attribute() - Copy a single attribute.
* copy_attrs() - Copy attributes from one request to another.
* copy_banner() - Copy a banner file to the requests directory
* get_ppds() - Get the list of PPD files on the local
* system.
* get_printer_attrs() - Get printer attributes.
+ * get_printer_supported() - Get printer supported values.
* get_printers() - Get a list of printers or classes.
* get_subscription_attrs() - Get subscription attributes.
* get_subscriptions() - Get subscriptions.
* get_username() - Get the username associated with a request.
* hold_job() - Hold a print job.
+ * hold_new_jobs() - Hold pending/new jobs on a printer or class.
* move_job() - Move a job to a new destination.
* ppd_parse_line() - Parse a PPD default line.
* print_job() - Print a file to a printer or class.
* read_job_ticket() - Read a job ticket embedded in a print file.
* reject_jobs() - Reject print jobs to a printer.
+ * release_held_new_jobs() - Release pending/new jobs on a printer or
+ * class.
* release_job() - Release a held print job.
* renew_subscription() - Renew an existing subscription...
* restart_job() - Restart an old print job.
static int check_quotas(cupsd_client_t *con, cupsd_printer_t *p);
static ipp_attribute_t *copy_attribute(ipp_t *to, ipp_attribute_t *attr,
int quickcopy);
+static void close_job(cupsd_client_t *con, ipp_attribute_t *uri);
static void copy_attrs(ipp_t *to, ipp_t *from, cups_array_t *ra,
ipp_tag_t group, int quickcopy);
static int copy_banner(cupsd_client_t *con, cupsd_job_t *job,
break;
case IPP_PURGE_JOBS :
+ case IPP_CANCEL_JOBS :
+ case IPP_CANCEL_MY_JOBS :
cancel_all_jobs(con, uri);
break;
release_held_new_jobs(con, uri);
break;
+ case IPP_CLOSE_JOB :
+ close_job(con, uri);
+ break;
+
case CUPS_GET_DEFAULT :
get_default(con);
break;
send_ipp_status(con, IPP_OK_SUBST, _("Unsupported margins."));
unsup_col = ippNew();
- ippAddCollection(con->response, IPP_TAG_UNSUPPORTED_GROUP, "media-col",
- unsup_col);
-
if ((media_margin = ippFindAttribute(media_col->values[0].collection,
"media-bottom-margin",
IPP_TAG_INTEGER)) != NULL)
IPP_TAG_INTEGER)) != NULL)
ippAddInteger(unsup_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
"media-top-margin", media_margin->values[0].integer);
+
+ ippAddCollection(con->response, IPP_TAG_UNSUPPORTED_GROUP, "media-col",
+ unsup_col);
+ ippDelete(unsup_col);
}
}
/*
- * 'cancel_all_jobs()' - Cancel all print jobs.
+ * 'cancel_all_jobs()' - Cancel all or selected print jobs.
*/
static void
cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */
ipp_attribute_t *uri) /* I - Job or Printer URI */
{
+ int i; /* Looping var */
http_status_t status; /* Policy status */
cups_ptype_t dtype; /* Destination type */
char scheme[HTTP_MAX_URI], /* Scheme portion of URI */
resource[HTTP_MAX_URI]; /* Resource portion of URI */
int port; /* Port portion of URI */
ipp_attribute_t *attr; /* Attribute in request */
- const char *username; /* Username */
- cupsd_jobaction_t purge; /* Purge? */
+ const char *username = NULL; /* Username */
+ cupsd_jobaction_t purge = CUPSD_JOB_DEFAULT;
+ /* Purge? */
cupsd_printer_t *printer; /* Printer */
+ ipp_attribute_t *job_ids; /* job-ids attribute */
+ cupsd_job_t *job; /* Job */
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_all_jobs(%p[%d], %s)", con,
con->http.fd, uri->values[0].string.text);
/*
- * See if we have a printer URI...
+ * Get the jobs to cancel/purge...
*/
- if (strcmp(uri->name, "printer-uri"))
+ switch (con->request->request.op.operation_id)
{
- send_ipp_status(con, IPP_BAD_REQUEST,
- _("The printer-uri attribute is required"));
- return;
- }
+ case IPP_PURGE_JOBS :
+ /*
+ * Get the username (if any) for the jobs we want to cancel (only if
+ * "my-jobs" is specified...
+ */
- /*
- * Get the username (if any) for the jobs we want to cancel (only if
- * "my-jobs" is specified...
- */
+ if ((attr = ippFindAttribute(con->request, "my-jobs",
+ IPP_TAG_BOOLEAN)) != NULL &&
+ attr->values[0].boolean)
+ {
+ if ((attr = ippFindAttribute(con->request, "requesting-user-name",
+ IPP_TAG_NAME)) != NULL)
+ username = attr->values[0].string.text;
+ else
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Missing requesting-user-name attribute"));
+ return;
+ }
+ }
- if ((attr = ippFindAttribute(con->request, "my-jobs",
- IPP_TAG_BOOLEAN)) != NULL &&
- attr->values[0].boolean)
- {
- if ((attr = ippFindAttribute(con->request, "requesting-user-name",
- IPP_TAG_NAME)) != NULL)
- username = attr->values[0].string.text;
- else
- {
- send_ipp_status(con, IPP_BAD_REQUEST,
- _("Missing requesting-user-name attribute"));
- return;
- }
+ /*
+ * Look for the "purge-jobs" attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "purge-jobs",
+ IPP_TAG_BOOLEAN)) != NULL)
+ purge = attr->values[0].boolean ? CUPSD_JOB_PURGE : CUPSD_JOB_DEFAULT;
+ else
+ purge = CUPSD_JOB_PURGE;
+ break;
+
+ case IPP_CANCEL_MY_JOBS :
+ if (con->username[0])
+ username = con->username;
+ else if ((attr = ippFindAttribute(con->request, "requesting-user-name",
+ IPP_TAG_NAME)) != NULL)
+ username = attr->values[0].string.text;
+ else
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Missing requesting-user-name attribute"));
+ return;
+ }
+
+ default :
+ break;
}
- else
- username = NULL;
+
+ job_ids = ippFindAttribute(con->request, "job-ids", IPP_TAG_INTEGER);
/*
- * Look for the "purge-jobs" attribute...
+ * See if we have a printer URI...
*/
- if ((attr = ippFindAttribute(con->request, "purge-jobs",
- IPP_TAG_BOOLEAN)) != NULL)
- purge = attr->values[0].boolean ? CUPSD_JOB_PURGE : CUPSD_JOB_DEFAULT;
- else
- purge = CUPSD_JOB_PURGE;
+ if (strcmp(uri->name, "printer-uri"))
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("The printer-uri attribute is required"));
+ return;
+ }
/*
* And if the destination is valid...
return;
}
- /*
- * Cancel all jobs on all printers...
- */
+ if (job_ids)
+ {
+ for (i = 0; i < job_ids->num_values; i ++)
+ {
+ if ((job = cupsdFindJob(job_ids->values[i].integer)) == NULL)
+ break;
+ }
+
+ if (i < job_ids->num_values)
+ {
+ send_ipp_status(con, IPP_NOT_FOUND, _("job-id %d not found."),
+ job_ids->values[i].integer);
+ return;
+ }
+
+ for (i = 0; i < job_ids->num_values; i ++)
+ {
+ job = cupsdFindJob(job_ids->values[i].integer);
+
+ cupsdSetJobState(job, IPP_JOB_CANCELED, purge,
+ purge == CUPSD_JOB_PURGE ? "Job purged by user." :
+ "Job canceled by user.");
+ }
- cupsdCancelJobs(NULL, username, purge);
+ cupsdLogMessage(CUPSD_LOG_INFO, "Selected jobs were %s by \"%s\".",
+ purge == CUPSD_JOB_PURGE ? "purged" : "canceled",
+ get_username(con));
+ }
+ else
+ {
+ /*
+ * Cancel all jobs on all printers...
+ */
- cupsdLogMessage(CUPSD_LOG_INFO, "All jobs were %s by \"%s\".",
- purge == CUPSD_JOB_PURGE ? "purged" : "canceled",
- get_username(con));
+ cupsdCancelJobs(NULL, username, purge);
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "All jobs were %s by \"%s\".",
+ purge == CUPSD_JOB_PURGE ? "purged" : "canceled",
+ get_username(con));
+ }
}
else
{
return;
}
- /*
- * Cancel all of the jobs on the named printer...
- */
+ if (job_ids)
+ {
+ for (i = 0; i < job_ids->num_values; i ++)
+ {
+ if ((job = cupsdFindJob(job_ids->values[i].integer)) == NULL ||
+ strcasecmp(job->dest, printer->name))
+ break;
+ }
+
+ if (i < job_ids->num_values)
+ {
+ send_ipp_status(con, IPP_NOT_FOUND, _("job-id %d not found."),
+ job_ids->values[i].integer);
+ return;
+ }
+
+ for (i = 0; i < job_ids->num_values; i ++)
+ {
+ job = cupsdFindJob(job_ids->values[i].integer);
- cupsdCancelJobs(printer->name, username, purge);
+ cupsdSetJobState(job, IPP_JOB_CANCELED, purge,
+ purge == CUPSD_JOB_PURGE ? "Job purged by user." :
+ "Job canceled by user.");
+ }
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Selected jobs were %s by \"%s\".",
+ purge == CUPSD_JOB_PURGE ? "purged" : "canceled",
+ get_username(con));
+ }
+ else
+ {
+ /*
+ * Cancel all of the jobs on the named printer...
+ */
+
+ cupsdCancelJobs(printer->name, username, purge);
- cupsdLogMessage(CUPSD_LOG_INFO, "All jobs on \"%s\" were %s by \"%s\".",
- printer->name,
- purge == CUPSD_JOB_PURGE ? "purged" : "canceled",
- get_username(con));
+ cupsdLogMessage(CUPSD_LOG_INFO, "All jobs on \"%s\" were %s by \"%s\".",
+ printer->name,
+ purge == CUPSD_JOB_PURGE ? "purged" : "canceled",
+ get_username(con));
+ }
}
con->response->request.status.status_code = IPP_OK;
}
+/*
+ * 'close_job()' - Close a multi-file job.
+ */
+
+static void
+close_job(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ cupsd_job_t *job; /* Job */
+ cupsd_printer_t *printer; /* Printer */
+ ipp_attribute_t *attr; /* Attribute */
+ char job_uri[HTTP_MAX_URI],
+ /* Job URI */
+ username[256]; /* User name */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "close_job(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (strcmp(uri->name, "printer-uri"))
+ {
+ /*
+ * job-uri is not supported by Close-Job!
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Close-Job doesn't support the job-uri attribute."));
+ return;
+ }
+
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Got a printer-uri attribute but no job-id"));
+ return;
+ }
+
+ if ((job = cupsdFindJob(attr->values[0].integer)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist"),
+ attr->values[0].integer);
+ return;
+ }
+
+ printer = cupsdFindDest(job->dest);
+
+ /*
+ * See if the job is owned by the requesting user...
+ */
+
+ if (!validate_user(job, con, job->username, username, sizeof(username)))
+ {
+ send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
+ cupsdFindDest(job->dest));
+ return;
+ }
+
+ /*
+ * Add any ending sheet...
+ */
+
+ if (cupsdTimeoutJob(job))
+ return;
+
+ if (job->state_value == IPP_JOB_STOPPED)
+ {
+ job->state->values[0].integer = IPP_JOB_PENDING;
+ job->state_value = IPP_JOB_PENDING;
+ }
+ else if (job->state_value == 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 || !strcmp(attr->values[0].string.text, "no-hold"))
+ {
+ job->state->values[0].integer = IPP_JOB_PENDING;
+ job->state_value = IPP_JOB_PENDING;
+ }
+ }
+
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+
+ /*
+ * Fill in the response info...
+ */
+
+ snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d", ServerName,
+ LocalPort, job->id);
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL,
+ job_uri);
+
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
+
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state",
+ job->state_value);
+
+ add_job_state_reasons(con, job);
+
+ con->response->request.status.status_code = IPP_OK;
+
+ /*
+ * Start the job if necessary...
+ */
+
+ cupsdCheckJobs();
+}
+
+
/*
* 'copy_attribute()' - Copy a single attribute.
*/
for (i = 0; i < attr->num_values; i ++)
{
- toattr->values[i].collection = ippNew();
- toattr->values[i].collection->request.status.version[0] = 2;
- copy_attrs(toattr->values[i].collection, attr->values[i].collection,
- NULL, IPP_TAG_ZERO, quickcopy);
+ toattr->values[i].collection = attr->values[i].collection;
+ attr->values[i].collection->use ++;
}
break;
host[HTTP_MAX_URI], /* Host portion of URI */
resource[HTTP_MAX_URI]; /* Resource portion of URI */
int port; /* Port portion of URI */
- int completed; /* Completed jobs? */
+ int job_comparison; /* Job comparison */
+ ipp_jstate_t job_state; /* job-state value */
int first_job_id; /* First job ID */
int limit; /* Maximum number of jobs to return */
int count; /* Number of jobs that match */
+ ipp_attribute_t *job_ids; /* job-ids attribute */
cupsd_job_t *job; /* Current job pointer */
cupsd_printer_t *printer; /* Printer */
cups_array_t *list; /* Which job list... */
return;
}
+ job_ids = ippFindAttribute(con->request, "job-ids", IPP_TAG_INTEGER);
+
/*
* See if the "which-jobs" attribute have been specified...
*/
if ((attr = ippFindAttribute(con->request, "which-jobs",
- IPP_TAG_KEYWORD)) != NULL &&
- !strcmp(attr->values[0].string.text, "completed"))
+ IPP_TAG_KEYWORD)) != NULL && job_ids)
+ {
+ send_ipp_status(con, IPP_CONFLICT,
+ _("The %s attribute cannot be provided with job-ids."),
+ "which-jobs");
+ return;
+ }
+ else if (!attr || !strcmp(attr->values[0].string.text, "not-completed"))
+ {
+ job_comparison = -1;
+ job_state = IPP_JOB_STOPPED;
+ list = Jobs;
+ }
+ else if (!strcmp(attr->values[0].string.text, "completed"))
+ {
+ job_comparison = 1;
+ job_state = IPP_JOB_CANCELED;
+ list = Jobs;
+ }
+ else if (!strcmp(attr->values[0].string.text, "aborted"))
+ {
+ job_comparison = 0;
+ job_state = IPP_JOB_ABORTED;
+ list = Jobs;
+ }
+ else if (!strcmp(attr->values[0].string.text, "all"))
+ {
+ job_comparison = 1;
+ job_state = IPP_JOB_PENDING;
+ list = Jobs;
+ }
+ else if (!strcmp(attr->values[0].string.text, "canceled"))
+ {
+ job_comparison = 0;
+ job_state = IPP_JOB_CANCELED;
+ list = Jobs;
+ }
+ else if (!strcmp(attr->values[0].string.text, "pending"))
+ {
+ job_comparison = 0;
+ job_state = IPP_JOB_PENDING;
+ list = ActiveJobs;
+ }
+ else if (!strcmp(attr->values[0].string.text, "pending-held"))
{
- completed = 1;
- list = Jobs;
+ job_comparison = 0;
+ job_state = IPP_JOB_HELD;
+ list = ActiveJobs;
}
- else if (attr && !strcmp(attr->values[0].string.text, "all"))
+ else if (!strcmp(attr->values[0].string.text, "processing"))
{
- completed = 0;
- list = Jobs;
+ job_comparison = 0;
+ job_state = IPP_JOB_PROCESSING;
+ list = PrintingJobs;
}
- else if (attr && !strcmp(attr->values[0].string.text, "processing"))
+ else if (!strcmp(attr->values[0].string.text, "processing-stopped"))
{
- completed = 0;
- list = PrintingJobs;
+ job_comparison = 0;
+ job_state = IPP_JOB_STOPPED;
+ list = ActiveJobs;
}
else
{
- completed = 0;
- list = ActiveJobs;
+ send_ipp_status(con, IPP_ATTRIBUTES,
+ _("The which-jobs value \"%s\" is not supported."),
+ attr->values[0].string.text);
+ ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
+ "which-jobs", NULL, attr->values[0].string.text);
+ return;
}
/*
if ((attr = ippFindAttribute(con->request, "limit",
IPP_TAG_INTEGER)) != NULL)
+ {
+ if (job_ids)
+ {
+ send_ipp_status(con, IPP_CONFLICT,
+ _("The %s attribute cannot be provided with job-ids."),
+ "limit");
+ return;
+ }
+
limit = attr->values[0].integer;
+ }
else
limit = 0;
if ((attr = ippFindAttribute(con->request, "first-job-id",
IPP_TAG_INTEGER)) != NULL)
+ {
+ if (job_ids)
+ {
+ send_ipp_status(con, IPP_CONFLICT,
+ _("The %s attribute cannot be provided with job-ids."),
+ "first-job-id");
+ return;
+ }
+
first_job_id = attr->values[0].integer;
+ }
else
first_job_id = 1;
*/
if ((attr = ippFindAttribute(con->request, "my-jobs",
- IPP_TAG_BOOLEAN)) != NULL &&
- attr->values[0].boolean)
+ IPP_TAG_BOOLEAN)) != NULL && job_ids)
+ {
+ send_ipp_status(con, IPP_CONFLICT,
+ _("The %s attribute cannot be provided with job-ids."),
+ "my-jobs");
+ return;
+ }
+ else if (attr && attr->values[0].boolean)
strlcpy(username, get_username(con), sizeof(username));
else
username[0] = '\0';
* OK, build a list of jobs for this printer...
*/
- for (count = 0, job = (cupsd_job_t *)cupsArrayFirst(list);
- (limit <= 0 || count < limit) && job;
- job = (cupsd_job_t *)cupsArrayNext(list))
+ if (job_ids)
{
- /*
- * Filter out jobs that don't match...
- */
+ int i; /* Looping var */
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "get_jobs: job->id=%d, dest=\"%s\", username=\"%s\", "
- "state_value=%d, attrs=%p", job->id, job->dest,
- job->username, job->state_value, job->attrs);
+ for (i = 0; i < job_ids->num_values; i ++)
+ {
+ if ((job = cupsdFindJob(job_ids->values[i].integer)) == NULL)
+ break;
+ }
- if (!job->dest || !job->username)
- cupsdLoadJob(job);
+ if (i < job_ids->num_values)
+ {
+ send_ipp_status(con, IPP_NOT_FOUND, _("job-id %d not found."),
+ job_ids->values[i].integer);
+ return;
+ }
- if (!job->dest || !job->username)
- continue;
+ for (i = 0; i < job_ids->num_values; i ++)
+ {
+ job = cupsdFindJob(job_ids->values[i].integer);
- if ((dest && strcmp(job->dest, dest)) &&
- (!job->printer || !dest || strcmp(job->printer->name, dest)))
- continue;
- if ((job->dtype & dmask) != dtype &&
- (!job->printer || (job->printer->type & dmask) != dtype))
- continue;
- if (completed && job->state_value <= IPP_JOB_STOPPED)
- continue;
+ cupsdLoadJob(job);
- if (job->id < first_job_id)
- continue;
+ if (!job->attrs)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d",
+ job->id);
+ continue;
+ }
- cupsdLoadJob(job);
+ if (i > 0)
+ ippAddSeparator(con->response);
- if (!job->attrs)
- {
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d",
- job->id);
- continue;
+ copy_job_attrs(con, job, ra);
}
+ }
+ else
+ {
+ for (count = 0, job = (cupsd_job_t *)cupsArrayFirst(list);
+ (limit <= 0 || count < limit) && job;
+ job = (cupsd_job_t *)cupsArrayNext(list))
+ {
+ /*
+ * Filter out jobs that don't match...
+ */
- if (username[0] && strcasecmp(username, job->username))
- continue;
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "get_jobs: job->id=%d, dest=\"%s\", username=\"%s\", "
+ "state_value=%d, attrs=%p", job->id, job->dest,
+ job->username, job->state_value, job->attrs);
- if (count > 0)
- ippAddSeparator(con->response);
+ if (!job->dest || !job->username)
+ cupsdLoadJob(job);
- count ++;
+ if (!job->dest || !job->username)
+ continue;
- copy_job_attrs(con, job, ra);
- }
+ if ((dest && strcmp(job->dest, dest)) &&
+ (!job->printer || !dest || strcmp(job->printer->name, dest)))
+ continue;
+ if ((job->dtype & dmask) != dtype &&
+ (!job->printer || (job->printer->type & dmask) != dtype))
+ continue;
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: count=%d", count);
+ if ((job_comparison < 0 && job->state_value > job_state) ||
+ (job_comparison == 0 && job->state_value != job_state) ||
+ (job_comparison > 0 && job->state_value < job_state))
+ continue;
+
+ if (job->id < first_job_id)
+ continue;
+
+ cupsdLoadJob(job);
+
+ if (!job->attrs)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d",
+ job->id);
+ continue;
+ }
+
+ if (username[0] && strcasecmp(username, job->username))
+ continue;
+
+ if (count > 0)
+ ippAddSeparator(con->response);
+
+ count ++;
+
+ copy_job_attrs(con, job, ra);
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: count=%d", count);
+ }
cupsArrayDelete(ra);