Coverage Report

Created: 2026-02-14 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}