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 */
cupsCancelDestJob(http_t * http,cups_dest_t * dest,int job_id)35 cupsCancelDestJob(http_t *http, /* I - Connection to destination */
36 cups_dest_t *dest, /* I - Destination */
37 int job_id) /* I - Job ID */
38 {
39 cups_dinfo_t *info; /* Destination information */
40
41
42 if ((info = cupsCopyDestInfo(http, dest)) != NULL)
43 {
44 ipp_t *request; /* Cancel-Job request */
45
46 request = ippNewRequest(IPP_OP_CANCEL_JOB);
47
48 ippSetVersion(request, info->version / 10, info->version % 10);
49
50 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, info->uri);
51 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job_id);
52 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
53
54 ippDelete(cupsDoRequest(http, request, info->resource));
55 cupsFreeDestInfo(info);
56 }
57
58 return (cupsLastError());
59 }
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 */
cupsCloseDestJob(http_t * http,cups_dest_t * dest,cups_dinfo_t * info,int job_id)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 {
79 int i; /* Looping var */
80 ipp_t *request = NULL;/* Close-Job/Send-Document request */
81 ipp_attribute_t *attr; /* operations-supported attribute */
82
83
84 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 if (!http)
91 http = _cupsConnect();
92
93 /*
94 * Range check input...
95 */
96
97 if (!http || !dest || !info || job_id <= 0)
98 {
99 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
100 DEBUG_puts("1cupsCloseDestJob: Bad arguments.");
101 return (IPP_STATUS_ERROR_INTERNAL);
102 }
103
104 /*
105 * Build a Close-Job or empty Send-Document request...
106 */
107
108 if ((attr = ippFindAttribute(info->attrs, "operations-supported",
109 IPP_TAG_ENUM)) != NULL)
110 {
111 for (i = 0; i < attr->num_values; i ++)
112 if (attr->values[i].integer == IPP_OP_CLOSE_JOB)
113 {
114 request = ippNewRequest(IPP_OP_CLOSE_JOB);
115 break;
116 }
117 }
118
119 if (!request)
120 request = ippNewRequest(IPP_OP_SEND_DOCUMENT);
121
122 if (!request)
123 {
124 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0);
125 DEBUG_puts("1cupsCloseDestJob: Unable to create Close-Job/Send-Document "
126 "request.");
127 return (IPP_STATUS_ERROR_INTERNAL);
128 }
129
130 ippSetVersion(request, info->version / 10, info->version % 10);
131
132 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
133 NULL, info->uri);
134 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
135 job_id);
136 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
137 NULL, cupsUser());
138 if (ippGetOperation(request) == IPP_OP_SEND_DOCUMENT)
139 ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
140
141 /*
142 * Send the request and return the status...
143 */
144
145 ippDelete(cupsDoRequest(http, request, info->resource));
146
147 DEBUG_printf(("1cupsCloseDestJob: %s (%s)", ippErrorString(cupsLastError()),
148 cupsLastErrorString()));
149
150 return (cupsLastError());
151 }
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 */
cupsCreateDestJob(http_t * http,cups_dest_t * dest,cups_dinfo_t * info,int * job_id,const char * title,int num_options,cups_option_t * options)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 {
173 ipp_t *request, /* Create-Job request */
174 *response; /* Create-Job response */
175 ipp_attribute_t *attr; /* job-id attribute */
176
177
178 DEBUG_printf(("cupsCreateDestJob(http=%p, dest=%p(%s/%s), info=%p, "
179 "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 if (!http)
186 http = _cupsConnect();
187
188 /*
189 * Range check input...
190 */
191
192 if (job_id)
193 *job_id = 0;
194
195 if (!http || !dest || !info || !job_id)
196 {
197 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
198 DEBUG_puts("1cupsCreateDestJob: Bad arguments.");
199 return (IPP_STATUS_ERROR_INTERNAL);
200 }
201
202 /*
203 * Build a Create-Job request...
204 */
205
206 if ((request = ippNewRequest(IPP_OP_CREATE_JOB)) == NULL)
207 {
208 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0);
209 DEBUG_puts("1cupsCreateDestJob: Unable to create Create-Job request.");
210 return (IPP_STATUS_ERROR_INTERNAL);
211 }
212
213 ippSetVersion(request, info->version / 10, info->version % 10);
214
215 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
216 NULL, info->uri);
217 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
218 NULL, cupsUser());
219 if (title)
220 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
221 title);
222
223 cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION);
224 cupsEncodeOptions2(request, num_options, options, IPP_TAG_JOB);
225 cupsEncodeOptions2(request, num_options, options, IPP_TAG_SUBSCRIPTION);
226
227 /*
228 * Send the request and get the job-id...
229 */
230
231 response = cupsDoRequest(http, request, info->resource);
232
233 if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL)
234 {
235 *job_id = attr->values[0].integer;
236 DEBUG_printf(("1cupsCreateDestJob: job-id=%d", *job_id));
237 }
238
239 ippDelete(response);
240
241 /*
242 * Return the status code from the Create-Job request...
243 */
244
245 DEBUG_printf(("1cupsCreateDestJob: %s (%s)", ippErrorString(cupsLastError()),
246 cupsLastErrorString()));
247
248 return (cupsLastError());
249 }
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 */
cupsFinishDestDocument(http_t * http,cups_dest_t * dest,cups_dinfo_t * info)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 {
266 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 if (!http)
273 http = _cupsConnect();
274
275 /*
276 * Range check input...
277 */
278
279 if (!http || !dest || !info)
280 {
281 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
282 DEBUG_puts("1cupsFinishDestDocument: Bad arguments.");
283 return (IPP_STATUS_ERROR_INTERNAL);
284 }
285
286 /*
287 * Get the response at the end of the document and return it...
288 */
289
290 ippDelete(cupsGetResponse(http, info->resource));
291
292 DEBUG_printf(("1cupsFinishDestDocument: %s (%s)",
293 ippErrorString(cupsLastError()), cupsLastErrorString()));
294
295 return (cupsLastError());
296 }
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 */
cupsStartDestDocument(http_t * http,cups_dest_t * dest,cups_dinfo_t * info,int job_id,const char * docname,const char * format,int num_options,cups_option_t * options,int last_document)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 {
324 ipp_t *request; /* Send-Document request */
325 http_status_t status; /* HTTP status */
326
327
328 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 if (!http)
335 http = _cupsConnect();
336
337 /*
338 * Range check input...
339 */
340
341 if (!http || !dest || !info || job_id <= 0)
342 {
343 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
344 DEBUG_puts("1cupsStartDestDocument: Bad arguments.");
345 return (HTTP_STATUS_ERROR);
346 }
347
348 /*
349 * Create a Send-Document request...
350 */
351
352 if ((request = ippNewRequest(IPP_OP_SEND_DOCUMENT)) == NULL)
353 {
354 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0);
355 DEBUG_puts("1cupsStartDestDocument: Unable to create Send-Document "
356 "request.");
357 return (HTTP_STATUS_ERROR);
358 }
359
360 ippSetVersion(request, info->version / 10, info->version % 10);
361
362 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
363 NULL, info->uri);
364 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job_id);
365 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
366 NULL, cupsUser());
367 if (docname)
368 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-name",
369 NULL, docname);
370 if (format)
371 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
372 "document-format", NULL, format);
373 ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", (char)last_document);
374
375 cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION);
376 cupsEncodeOptions2(request, num_options, options, IPP_TAG_DOCUMENT);
377
378 /*
379 * Send and delete the request, then return the status...
380 */
381
382 status = cupsSendRequest(http, request, info->resource, CUPS_LENGTH_VARIABLE);
383
384 ippDelete(request);
385
386 return (status);
387 }
388