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