server_job_t * /* O - Job */ serverCreateJob(server_client_t *client) /* I - Client */ { server_job_t *job; /* Job */ ipp_attribute_t *attr; /* Job attribute */ char uri[1024], /* job-uri value */ uuid[64]; /* job-uuid value */ server_listener_t *lis = (server_listener_t *)cupsArrayFirst(Listeners); /* First listener */ _cupsRWLockWrite(&(client->printer->rwlock)); /* * Allocate and initialize the job object... */ if ((job = calloc(1, sizeof(server_job_t))) == NULL) { perror("Unable to allocate memory for job"); return (NULL); } job->printer = client->printer; job->attrs = ippNew(); job->state = IPP_JSTATE_HELD; job->fd = -1; /* * Copy all of the job attributes... */ serverCopyAttributes(job->attrs, client->request, NULL, IPP_TAG_JOB, 0); /* * Get the requesting-user-name, document format, and priority... */ if ((attr = ippFindAttribute(client->request, "job-priority", IPP_TAG_INTEGER)) != NULL) job->priority = ippGetInteger(attr, 0); else job->priority = 50; if ((attr = ippFindAttribute(client->request, "requesting-user-name", IPP_TAG_NAME)) != NULL) job->username = ippGetString(attr, 0, NULL); else job->username = "******"; ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-user-name", NULL, job->username); if (ippGetOperation(client->request) != IPP_OP_CREATE_JOB) { if ((attr = ippFindAttribute(job->attrs, "document-format-detected", IPP_TAG_MIMETYPE)) != NULL) job->format = ippGetString(attr, 0, NULL); else if ((attr = ippFindAttribute(job->attrs, "document-format-supplied", IPP_TAG_MIMETYPE)) != NULL) job->format = ippGetString(attr, 0, NULL); else job->format = "application/octet-stream"; } if ((attr = ippFindAttribute(client->request, "job-impressions", IPP_TAG_INTEGER)) != NULL) job->impressions = ippGetInteger(attr, 0); if ((attr = ippFindAttribute(client->request, "job-name", IPP_TAG_NAME)) != NULL) job->name = ippGetString(attr, 0, NULL); /* * Add job description attributes and add to the jobs array... */ job->id = client->printer->next_job_id ++; snprintf(uri, sizeof(uri), "%s/%d", client->printer->default_uri, job->id); httpAssembleUUID(lis->host, lis->port, client->printer->name, job->id, uuid, sizeof(uuid)); ippAddDate(job->attrs, IPP_TAG_JOB, "date-time-at-creation", ippTimeToDate(time(&job->created))); ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id); ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, uri); ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-uuid", NULL, uuid); if ((attr = ippFindAttribute(client->request, "printer-uri", IPP_TAG_URI)) != NULL) ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL, ippGetString(attr, 0, NULL)); else ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL, client->printer->default_uri); ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation", (int)(job->created - client->printer->start_time)); cupsArrayAdd(client->printer->jobs, job); cupsArrayAdd(client->printer->active_jobs, job); _cupsRWUnlock(&(client->printer->rwlock)); return (job); }
ipp_status_t /* O - IPP status code */ cupsCloseDestJob( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *info, /* I - Destination information */ int job_id) /* I - Job ID */ { int i; /* Looping var */ ipp_t *request = NULL;/* Close-Job/Send-Document request */ ipp_attribute_t *attr; /* operations-supported attribute */ DEBUG_printf(("cupsCloseDestJob(http=%p, dest=%p(%s/%s), info=%p, job_id=%d)", http, dest, dest ? dest->name : NULL, dest ? dest->instance : NULL, info, job_id)); /* * Range check input... */ if (!http || !dest || !info || job_id <= 0) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); DEBUG_puts("1cupsCloseDestJob: Bad arguments."); return (IPP_STATUS_ERROR_INTERNAL); } /* * Build a Close-Job or empty Send-Document request... */ if ((attr = ippFindAttribute(info->attrs, "operations-supported", IPP_TAG_ENUM)) != NULL) { for (i = 0; i < attr->num_values; i ++) if (attr->values[i].integer == IPP_OP_CLOSE_JOB) { request = ippNewRequest(IPP_OP_CLOSE_JOB); break; } } if (!request) request = ippNewRequest(IPP_OP_SEND_DOCUMENT); if (!request) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0); DEBUG_puts("1cupsCloseDestJob: Unable to create Close-Job/Send-Document " "request."); return (IPP_STATUS_ERROR_INTERNAL); } ippSetVersion(request, info->version / 10, info->version % 10); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, info->uri); ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job_id); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); if (ippGetOperation(request) == IPP_OP_SEND_DOCUMENT) ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1); /* * Send the request and return the status... */ ippDelete(cupsDoRequest(http, request, info->resource)); DEBUG_printf(("1cupsCloseDestJob: %s (%s)", ippErrorString(cupsLastError()), cupsLastErrorString())); return (cupsLastError()); }
void cupsEncodeOptions2( ipp_t *ipp, /* I - Request to add to */ int num_options, /* I - Number of options */ cups_option_t *options, /* I - Options */ ipp_tag_t group_tag) /* I - Group to encode */ { int i, j; /* Looping vars */ int count; /* Number of values */ char *s, /* Pointer into option value */ *val, /* Pointer to option value */ *copy, /* Copy of option value */ *sep, /* Option separator */ quote; /* Quote character */ ipp_attribute_t *attr; /* IPP attribute */ ipp_tag_t value_tag; /* IPP value tag */ cups_option_t *option; /* Current option */ ipp_t *collection; /* Collection value */ int num_cols; /* Number of collection values */ cups_option_t *cols; /* Collection values */ ipp_op_t op; /* Operation for this request */ const ipp_op_t *ops; /* List of allowed operations */ DEBUG_printf(("cupsEncodeOptions2(ipp=%p(%s), num_options=%d, options=%p, " "group_tag=%x)", ipp, ipp ? ippOpString(ippGetOperation(ipp)) : "", num_options, options, group_tag)); /* * Range check input... */ if (!ipp || num_options < 1 || !options) return; /* * Do special handling for the document-format/raw options... */ op = ippGetOperation(ipp); if (group_tag == IPP_TAG_OPERATION && (op == IPP_OP_PRINT_JOB || op == IPP_OP_PRINT_URI || op == IPP_OP_SEND_DOCUMENT || op == IPP_OP_SEND_URI)) { /* * Handle the document format stuff first... */ if ((val = (char *)cupsGetOption("document-format", num_options, options)) != NULL) ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, val); else if (cupsGetOption("raw", num_options, options)) ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, "application/vnd.cups-raw"); else ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, "application/octet-stream"); } /* * Then loop through the options... */ for (i = num_options, option = options; i > 0; i --, option ++) { _ipp_option_t *match; /* Matching attribute */ /* * Skip document format options that are handled above... */ if (!_cups_strcasecmp(option->name, "raw") || !_cups_strcasecmp(option->name, "document-format") || !option->name[0]) continue; /* * Figure out the proper value and group tags for this option... */ if ((match = _ippFindOption(option->name)) != NULL) { if (match->group_tag != group_tag && match->alt_group_tag != group_tag) continue; value_tag = match->value_tag; if (match->operations) ops = match->operations; else if (group_tag == IPP_TAG_JOB) ops = ipp_job_creation; else if (group_tag == IPP_TAG_DOCUMENT) ops = ipp_doc_creation; else if (group_tag == IPP_TAG_SUBSCRIPTION) ops = ipp_sub_creation; else if (group_tag == IPP_TAG_PRINTER) ops = ipp_set_printer; else { DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name)); continue; } } else { int namelen; /* Length of name */ namelen = (int)strlen(option->name); if (namelen < 10 || (strcmp(option->name + namelen - 8, "-default") && strcmp(option->name + namelen - 10, "-supported"))) { if (group_tag != IPP_TAG_JOB && group_tag != IPP_TAG_DOCUMENT) { DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name)); continue; } } else if (group_tag != IPP_TAG_PRINTER) { DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name)); continue; } if (group_tag == IPP_TAG_JOB) ops = ipp_job_creation; else if (group_tag == IPP_TAG_DOCUMENT) ops = ipp_doc_creation; else ops = ipp_set_printer; if (!_cups_strcasecmp(option->value, "true") || !_cups_strcasecmp(option->value, "false")) value_tag = IPP_TAG_BOOLEAN; else value_tag = IPP_TAG_NAME; } /* * Verify that we send this attribute for this operation... */ while (*ops != IPP_OP_CUPS_NONE) if (op == *ops) break; else ops ++; if (*ops == IPP_OP_CUPS_NONE && op != IPP_OP_CUPS_NONE) { DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name)); continue; } /* * Count the number of values... */ if (match && match->multivalue) { for (count = 1, sep = option->value, quote = 0; *sep; sep ++) { if (*sep == quote) quote = 0; else if (!quote && (*sep == '\'' || *sep == '\"')) { /* * Skip quoted option value... */ quote = *sep++; } else if (*sep == ',' && !quote) count ++; else if (*sep == '\\' && sep[1]) sep ++; } } else count = 1; DEBUG_printf(("2cupsEncodeOptions2: option=\"%s\", count=%d", option->name, count)); /* * Allocate memory for the attribute values... */ if ((attr = ippAddStrings(ipp, group_tag, value_tag, option->name, count, NULL, NULL)) == NULL) { /* * Ran out of memory! */ DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for attributes!"); return; } if (count > 1) { /* * Make a copy of the value we can fiddle with... */ if ((copy = strdup(option->value)) == NULL) { /* * Ran out of memory! */ DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for value copy!"); ippDeleteAttribute(ipp, attr); return; } val = copy; } else { /* * Since we have a single value, use the value directly... */ val = option->value; copy = NULL; } /* * Scan the value string for values... */ for (j = 0, sep = val; j < count; val = sep, j ++) { /* * Find the end of this value and mark it if needed... */ if (count > 1) { for (quote = 0; *sep; sep ++) { if (*sep == quote) { /* * Finish quoted value... */ quote = 0; } else if (!quote && (*sep == '\'' || *sep == '\"')) { /* * Handle quoted option value... */ quote = *sep; } else if (*sep == ',' && count > 1) break; else if (*sep == '\\' && sep[1]) { /* * Skip quoted character... */ sep ++; } } if (*sep == ',') *sep++ = '\0'; } /* * Copy the option value(s) over as needed by the type... */ switch (attr->value_tag) { case IPP_TAG_INTEGER : case IPP_TAG_ENUM : /* * Integer/enumeration value... */ attr->values[j].integer = (int)strtol(val, &s, 10); DEBUG_printf(("2cupsEncodeOptions2: Added integer option value " "%d...", attr->values[j].integer)); break; case IPP_TAG_BOOLEAN : if (!_cups_strcasecmp(val, "true") || !_cups_strcasecmp(val, "on") || !_cups_strcasecmp(val, "yes")) { /* * Boolean value - true... */ attr->values[j].boolean = 1; DEBUG_puts("2cupsEncodeOptions2: Added boolean true value..."); } else { /* * Boolean value - false... */ attr->values[j].boolean = 0; DEBUG_puts("2cupsEncodeOptions2: Added boolean false value..."); } break; case IPP_TAG_RANGE : /* * Range... */ if (*val == '-') { attr->values[j].range.lower = 1; s = val; } else attr->values[j].range.lower = (int)strtol(val, &s, 10); if (*s == '-') { if (s[1]) attr->values[j].range.upper = (int)strtol(s + 1, NULL, 10); else attr->values[j].range.upper = 2147483647; } else attr->values[j].range.upper = attr->values[j].range.lower; DEBUG_printf(("2cupsEncodeOptions2: Added range option value " "%d-%d...", attr->values[j].range.lower, attr->values[j].range.upper)); break; case IPP_TAG_RESOLUTION : /* * Resolution... */ attr->values[j].resolution.xres = (int)strtol(val, &s, 10); if (*s == 'x') attr->values[j].resolution.yres = (int)strtol(s + 1, &s, 10); else attr->values[j].resolution.yres = attr->values[j].resolution.xres; if (!_cups_strcasecmp(s, "dpc") || !_cups_strcasecmp(s, "dpcm")) attr->values[j].resolution.units = IPP_RES_PER_CM; else attr->values[j].resolution.units = IPP_RES_PER_INCH; DEBUG_printf(("2cupsEncodeOptions2: Added resolution option value " "%s...", val)); break; case IPP_TAG_STRING : /* * octet-string */ attr->values[j].unknown.length = (int)strlen(val); attr->values[j].unknown.data = strdup(val); DEBUG_printf(("2cupsEncodeOptions2: Added octet-string value " "\"%s\"...", (char *)attr->values[j].unknown.data)); break; case IPP_TAG_BEGIN_COLLECTION : /* * Collection value */ num_cols = cupsParseOptions(val, 0, &cols); if ((collection = ippNew()) == NULL) { cupsFreeOptions(num_cols, cols); if (copy) free(copy); ippDeleteAttribute(ipp, attr); return; } attr->values[j].collection = collection; cupsEncodeOptions2(collection, num_cols, cols, IPP_TAG_JOB); cupsFreeOptions(num_cols, cols); break; default : if ((attr->values[j].string.text = _cupsStrAlloc(val)) == NULL) { /* * Ran out of memory! */ DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for string!"); if (copy) free(copy); ippDeleteAttribute(ipp, attr); return; } DEBUG_printf(("2cupsEncodeOptions2: Added string value \"%s\"...", val)); break; } } if (copy) free(copy); } }