]>
Commit | Line | Data |
---|---|---|
dcb445bc | 1 | /* |
7e86f2f6 | 2 | * Destination job support for CUPS. |
dcb445bc | 3 | * |
7536de1a | 4 | * Copyright 2012-2017 by Apple Inc. |
dcb445bc | 5 | * |
e3101897 | 6 | * Licensed under Apache License v2.0. See the file "LICENSE" for more information. |
dcb445bc MS |
7 | */ |
8 | ||
9 | /* | |
10 | * Include necessary headers... | |
11 | */ | |
12 | ||
13 | #include "cups-private.h" | |
fb863569 | 14 | #include "debug-internal.h" |
dcb445bc MS |
15 | |
16 | ||
17 | /* | |
18 | * 'cupsCancelDestJob()' - Cancel a job on a destination. | |
19 | * | |
20 | * The "job_id" is the number returned by cupsCreateDestJob. | |
21 | * | |
46385a1a | 22 | * Returns @code IPP_STATUS_OK@ on success and |
98d88c8d | 23 | * @code IPP_STATUS_ERROR_NOT_AUTHORIZED@ or |
46385a1a | 24 | * @code IPP_STATUS_ERROR_FORBIDDEN@ on failure. |
dcb445bc | 25 | * |
8072030b | 26 | * @since CUPS 1.6/macOS 10.8@ |
dcb445bc MS |
27 | */ |
28 | ||
98d88c8d | 29 | ipp_status_t /* O - Status of cancel operation */ |
dcb445bc MS |
30 | cupsCancelDestJob(http_t *http, /* I - Connection to destination */ |
31 | cups_dest_t *dest, /* I - Destination */ | |
32 | int job_id) /* I - Job ID */ | |
33 | { | |
46385a1a MS |
34 | cups_dinfo_t *info; /* Destination information */ |
35 | ||
36 | ||
37 | if ((info = cupsCopyDestInfo(http, dest)) != NULL) | |
38 | { | |
39 | ipp_t *request; /* Cancel-Job request */ | |
40 | ||
41 | request = ippNewRequest(IPP_OP_CANCEL_JOB); | |
42 | ||
43 | ippSetVersion(request, info->version / 10, info->version % 10); | |
44 | ||
45 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, info->uri); | |
46 | ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job_id); | |
47 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); | |
7e86f2f6 | 48 | |
46385a1a MS |
49 | ippDelete(cupsDoRequest(http, request, info->resource)); |
50 | cupsFreeDestInfo(info); | |
51 | } | |
52 | ||
53 | return (cupsLastError()); | |
dcb445bc MS |
54 | } |
55 | ||
56 | ||
57 | /* | |
58 | * 'cupsCloseDestJob()' - Close a job and start printing. | |
59 | * | |
60 | * Use when the last call to cupsStartDocument passed 0 for "last_document". | |
cb7f98ee | 61 | * "job_id" is the job ID returned by cupsCreateDestJob. Returns @code IPP_STATUS_OK@ |
82cc1f9a | 62 | * on success. |
dcb445bc | 63 | * |
8072030b | 64 | * @since CUPS 1.6/macOS 10.8@ |
dcb445bc MS |
65 | */ |
66 | ||
82cc1f9a | 67 | ipp_status_t /* O - IPP status code */ |
dcb445bc | 68 | cupsCloseDestJob( |
82cc1f9a MS |
69 | http_t *http, /* I - Connection to destination */ |
70 | cups_dest_t *dest, /* I - Destination */ | |
71 | cups_dinfo_t *info, /* I - Destination information */ | |
72 | int job_id) /* I - Job ID */ | |
dcb445bc | 73 | { |
82cc1f9a MS |
74 | int i; /* Looping var */ |
75 | ipp_t *request = NULL;/* Close-Job/Send-Document request */ | |
76 | ipp_attribute_t *attr; /* operations-supported attribute */ | |
77 | ||
78 | ||
807315e6 | 79 | DEBUG_printf(("cupsCloseDestJob(http=%p, dest=%p(%s/%s), info=%p, job_id=%d)", (void *)http, (void *)dest, dest ? dest->name : NULL, dest ? dest->instance : NULL, (void *)info, job_id)); |
82cc1f9a | 80 | |
7536de1a MS |
81 | /* |
82 | * Get the default connection as needed... | |
83 | */ | |
84 | ||
85 | if (!http) | |
86 | http = _cupsConnect(); | |
87 | ||
82cc1f9a MS |
88 | /* |
89 | * Range check input... | |
90 | */ | |
91 | ||
92 | if (!http || !dest || !info || job_id <= 0) | |
93 | { | |
cb7f98ee | 94 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); |
82cc1f9a | 95 | DEBUG_puts("1cupsCloseDestJob: Bad arguments."); |
cb7f98ee | 96 | return (IPP_STATUS_ERROR_INTERNAL); |
82cc1f9a MS |
97 | } |
98 | ||
99 | /* | |
100 | * Build a Close-Job or empty Send-Document request... | |
101 | */ | |
102 | ||
103 | if ((attr = ippFindAttribute(info->attrs, "operations-supported", | |
104 | IPP_TAG_ENUM)) != NULL) | |
105 | { | |
106 | for (i = 0; i < attr->num_values; i ++) | |
cb7f98ee | 107 | if (attr->values[i].integer == IPP_OP_CLOSE_JOB) |
82cc1f9a | 108 | { |
cb7f98ee | 109 | request = ippNewRequest(IPP_OP_CLOSE_JOB); |
82cc1f9a MS |
110 | break; |
111 | } | |
112 | } | |
113 | ||
114 | if (!request) | |
cb7f98ee | 115 | request = ippNewRequest(IPP_OP_SEND_DOCUMENT); |
82cc1f9a MS |
116 | |
117 | if (!request) | |
118 | { | |
cb7f98ee | 119 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0); |
82cc1f9a MS |
120 | DEBUG_puts("1cupsCloseDestJob: Unable to create Close-Job/Send-Document " |
121 | "request."); | |
cb7f98ee | 122 | return (IPP_STATUS_ERROR_INTERNAL); |
82cc1f9a MS |
123 | } |
124 | ||
6961465f MS |
125 | ippSetVersion(request, info->version / 10, info->version % 10); |
126 | ||
82cc1f9a MS |
127 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", |
128 | NULL, info->uri); | |
129 | ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", | |
130 | job_id); | |
131 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", | |
132 | NULL, cupsUser()); | |
cb7f98ee | 133 | if (ippGetOperation(request) == IPP_OP_SEND_DOCUMENT) |
82cc1f9a MS |
134 | ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1); |
135 | ||
136 | /* | |
137 | * Send the request and return the status... | |
138 | */ | |
139 | ||
140 | ippDelete(cupsDoRequest(http, request, info->resource)); | |
141 | ||
142 | DEBUG_printf(("1cupsCloseDestJob: %s (%s)", ippErrorString(cupsLastError()), | |
143 | cupsLastErrorString())); | |
144 | ||
145 | return (cupsLastError()); | |
dcb445bc MS |
146 | } |
147 | ||
148 | ||
149 | /* | |
150 | * 'cupsCreateDestJob()' - Create a job on a destination. | |
151 | * | |
cb7f98ee | 152 | * Returns @code IPP_STATUS_OK@ or @code IPP_STATUS_OK_SUBST@ on success, saving the job ID |
82cc1f9a | 153 | * in the variable pointed to by "job_id". |
dcb445bc | 154 | * |
8072030b | 155 | * @since CUPS 1.6/macOS 10.8@ |
dcb445bc MS |
156 | */ |
157 | ||
158 | ipp_status_t /* O - IPP status code */ | |
159 | cupsCreateDestJob( | |
160 | http_t *http, /* I - Connection to destination */ | |
161 | cups_dest_t *dest, /* I - Destination */ | |
162 | cups_dinfo_t *info, /* I - Destination information */ | |
163 | int *job_id, /* O - Job ID or 0 on error */ | |
164 | const char *title, /* I - Job name */ | |
165 | int num_options, /* I - Number of job options */ | |
166 | cups_option_t *options) /* I - Job options */ | |
167 | { | |
82cc1f9a MS |
168 | ipp_t *request, /* Create-Job request */ |
169 | *response; /* Create-Job response */ | |
170 | ipp_attribute_t *attr; /* job-id attribute */ | |
171 | ||
172 | ||
173 | DEBUG_printf(("cupsCreateDestJob(http=%p, dest=%p(%s/%s), info=%p, " | |
807315e6 | 174 | "job_id=%p, title=\"%s\", num_options=%d, options=%p)", (void *)http, (void *)dest, dest ? dest->name : NULL, dest ? dest->instance : NULL, (void *)info, (void *)job_id, title, num_options, (void *)options)); |
82cc1f9a | 175 | |
7536de1a MS |
176 | /* |
177 | * Get the default connection as needed... | |
178 | */ | |
179 | ||
180 | if (!http) | |
181 | http = _cupsConnect(); | |
182 | ||
82cc1f9a MS |
183 | /* |
184 | * Range check input... | |
185 | */ | |
186 | ||
187 | if (job_id) | |
188 | *job_id = 0; | |
189 | ||
190 | if (!http || !dest || !info || !job_id) | |
191 | { | |
cb7f98ee | 192 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); |
82cc1f9a | 193 | DEBUG_puts("1cupsCreateDestJob: Bad arguments."); |
cb7f98ee | 194 | return (IPP_STATUS_ERROR_INTERNAL); |
82cc1f9a MS |
195 | } |
196 | ||
197 | /* | |
198 | * Build a Create-Job request... | |
199 | */ | |
200 | ||
cb7f98ee | 201 | if ((request = ippNewRequest(IPP_OP_CREATE_JOB)) == NULL) |
82cc1f9a | 202 | { |
cb7f98ee | 203 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0); |
82cc1f9a | 204 | DEBUG_puts("1cupsCreateDestJob: Unable to create Create-Job request."); |
cb7f98ee | 205 | return (IPP_STATUS_ERROR_INTERNAL); |
82cc1f9a MS |
206 | } |
207 | ||
6961465f MS |
208 | ippSetVersion(request, info->version / 10, info->version % 10); |
209 | ||
82cc1f9a MS |
210 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", |
211 | NULL, info->uri); | |
212 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", | |
213 | NULL, cupsUser()); | |
214 | if (title) | |
215 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, | |
216 | title); | |
a29fd7dd | 217 | |
a469f8a5 | 218 | cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION); |
a29fd7dd MS |
219 | cupsEncodeOptions2(request, num_options, options, IPP_TAG_JOB); |
220 | cupsEncodeOptions2(request, num_options, options, IPP_TAG_SUBSCRIPTION); | |
82cc1f9a MS |
221 | |
222 | /* | |
223 | * Send the request and get the job-id... | |
224 | */ | |
dcb445bc | 225 | |
82cc1f9a MS |
226 | response = cupsDoRequest(http, request, info->resource); |
227 | ||
228 | if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL) | |
229 | { | |
230 | *job_id = attr->values[0].integer; | |
231 | DEBUG_printf(("1cupsCreateDestJob: job-id=%d", *job_id)); | |
232 | } | |
233 | ||
234 | ippDelete(response); | |
235 | ||
236 | /* | |
237 | * Return the status code from the Create-Job request... | |
238 | */ | |
239 | ||
240 | DEBUG_printf(("1cupsCreateDestJob: %s (%s)", ippErrorString(cupsLastError()), | |
241 | cupsLastErrorString())); | |
242 | ||
243 | return (cupsLastError()); | |
dcb445bc MS |
244 | } |
245 | ||
246 | ||
247 | /* | |
248 | * 'cupsFinishDestDocument()' - Finish the current document. | |
249 | * | |
cb7f98ee | 250 | * Returns @code IPP_STATUS_OK@ or @code IPP_STATUS_OK_SUBST@ on success. |
dcb445bc | 251 | * |
8072030b | 252 | * @since CUPS 1.6/macOS 10.8@ |
dcb445bc MS |
253 | */ |
254 | ||
82cc1f9a | 255 | ipp_status_t /* O - Status of document submission */ |
dcb445bc | 256 | cupsFinishDestDocument( |
82cc1f9a MS |
257 | http_t *http, /* I - Connection to destination */ |
258 | cups_dest_t *dest, /* I - Destination */ | |
259 | cups_dinfo_t *info) /* I - Destination information */ | |
dcb445bc | 260 | { |
807315e6 | 261 | DEBUG_printf(("cupsFinishDestDocument(http=%p, dest=%p(%s/%s), info=%p)", (void *)http, (void *)dest, dest ? dest->name : NULL, dest ? dest->instance : NULL, (void *)info)); |
82cc1f9a | 262 | |
7536de1a MS |
263 | /* |
264 | * Get the default connection as needed... | |
265 | */ | |
266 | ||
267 | if (!http) | |
268 | http = _cupsConnect(); | |
269 | ||
82cc1f9a MS |
270 | /* |
271 | * Range check input... | |
272 | */ | |
273 | ||
274 | if (!http || !dest || !info) | |
275 | { | |
cb7f98ee | 276 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); |
82cc1f9a | 277 | DEBUG_puts("1cupsFinishDestDocument: Bad arguments."); |
cb7f98ee | 278 | return (IPP_STATUS_ERROR_INTERNAL); |
82cc1f9a MS |
279 | } |
280 | ||
281 | /* | |
282 | * Get the response at the end of the document and return it... | |
283 | */ | |
284 | ||
285 | ippDelete(cupsGetResponse(http, info->resource)); | |
286 | ||
287 | DEBUG_printf(("1cupsFinishDestDocument: %s (%s)", | |
288 | ippErrorString(cupsLastError()), cupsLastErrorString())); | |
289 | ||
290 | return (cupsLastError()); | |
dcb445bc MS |
291 | } |
292 | ||
293 | ||
294 | /* | |
295 | * 'cupsStartDestDocument()' - Start a new document. | |
296 | * | |
297 | * "job_id" is the job ID returned by cupsCreateDestJob. "docname" is the name | |
298 | * of the document/file being printed, "format" is the MIME media type for the | |
299 | * document (see CUPS_FORMAT_xxx constants), and "num_options" and "options" | |
300 | * are the options do be applied to the document. "last_document" should be 1 | |
301 | * if this is the last document to be submitted in the job. Returns | |
82cc1f9a | 302 | * @code HTTP_CONTINUE@ on success. |
dcb445bc | 303 | * |
8072030b | 304 | * @since CUPS 1.6/macOS 10.8@ |
dcb445bc MS |
305 | */ |
306 | ||
82cc1f9a | 307 | http_status_t /* O - Status of document creation */ |
dcb445bc MS |
308 | cupsStartDestDocument( |
309 | http_t *http, /* I - Connection to destination */ | |
310 | cups_dest_t *dest, /* I - Destination */ | |
311 | cups_dinfo_t *info, /* I - Destination information */ | |
312 | int job_id, /* I - Job ID */ | |
313 | const char *docname, /* I - Document name */ | |
314 | const char *format, /* I - Document format */ | |
315 | int num_options, /* I - Number of document options */ | |
316 | cups_option_t *options, /* I - Document options */ | |
317 | int last_document) /* I - 1 if this is the last document */ | |
318 | { | |
82cc1f9a MS |
319 | ipp_t *request; /* Send-Document request */ |
320 | http_status_t status; /* HTTP status */ | |
321 | ||
322 | ||
807315e6 | 323 | DEBUG_printf(("cupsStartDestDocument(http=%p, dest=%p(%s/%s), info=%p, job_id=%d, docname=\"%s\", format=\"%s\", num_options=%d, options=%p, last_document=%d)", (void *)http, (void *)dest, dest ? dest->name : NULL, dest ? dest->instance : NULL, (void *)info, job_id, docname, format, num_options, (void *)options, last_document)); |
82cc1f9a | 324 | |
7536de1a MS |
325 | /* |
326 | * Get the default connection as needed... | |
327 | */ | |
328 | ||
329 | if (!http) | |
330 | http = _cupsConnect(); | |
331 | ||
82cc1f9a MS |
332 | /* |
333 | * Range check input... | |
334 | */ | |
335 | ||
336 | if (!http || !dest || !info || job_id <= 0) | |
337 | { | |
cb7f98ee | 338 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); |
82cc1f9a | 339 | DEBUG_puts("1cupsStartDestDocument: Bad arguments."); |
cb7f98ee | 340 | return (HTTP_STATUS_ERROR); |
82cc1f9a MS |
341 | } |
342 | ||
343 | /* | |
344 | * Create a Send-Document request... | |
345 | */ | |
346 | ||
cb7f98ee | 347 | if ((request = ippNewRequest(IPP_OP_SEND_DOCUMENT)) == NULL) |
82cc1f9a | 348 | { |
cb7f98ee | 349 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0); |
82cc1f9a MS |
350 | DEBUG_puts("1cupsStartDestDocument: Unable to create Send-Document " |
351 | "request."); | |
cb7f98ee | 352 | return (HTTP_STATUS_ERROR); |
82cc1f9a MS |
353 | } |
354 | ||
6961465f MS |
355 | ippSetVersion(request, info->version / 10, info->version % 10); |
356 | ||
82cc1f9a MS |
357 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", |
358 | NULL, info->uri); | |
359 | ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job_id); | |
360 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", | |
361 | NULL, cupsUser()); | |
362 | if (docname) | |
363 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-name", | |
364 | NULL, docname); | |
365 | if (format) | |
366 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, | |
367 | "document-format", NULL, format); | |
7e86f2f6 | 368 | ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", (char)last_document); |
82cc1f9a | 369 | |
a469f8a5 | 370 | cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION); |
82cc1f9a MS |
371 | cupsEncodeOptions2(request, num_options, options, IPP_TAG_DOCUMENT); |
372 | ||
373 | /* | |
374 | * Send and delete the request, then return the status... | |
375 | */ | |
376 | ||
377 | status = cupsSendRequest(http, request, info->resource, CUPS_LENGTH_VARIABLE); | |
378 | ||
379 | ippDelete(request); | |
380 | ||
381 | return (status); | |
dcb445bc | 382 | } |