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