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