Coverage Report

Created: 2022-10-31 07:00

/src/cups/cups/util.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Printing utilities for CUPS.
3
 *
4
 * Copyright © 2007-2018 by Apple Inc.
5
 * Copyright © 1997-2006 by Easy Software Products.
6
 *
7
 * These coded instructions, statements, and computer programs are the
8
 * property of Apple Inc. and are protected by Federal copyright
9
 * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
10
 * which should have been included with this file.  If this file is
11
 * missing or damaged, see the license at "http://www.cups.org/".
12
 *
13
 * This file is subject to the Apple OS-Developed Software exception.
14
 */
15
16
/*
17
 * Include necessary headers...
18
 */
19
20
#include "cups-private.h"
21
#include <fcntl.h>
22
#include <sys/stat.h>
23
#if defined(_WIN32) || defined(__EMX__)
24
#  include <io.h>
25
#else
26
#  include <unistd.h>
27
#endif /* _WIN32 || __EMX__ */
28
29
30
/*
31
 * 'cupsCancelJob()' - Cancel a print job on the default server.
32
 *
33
 * Pass @code CUPS_JOBID_ALL@ to cancel all jobs or @code CUPS_JOBID_CURRENT@
34
 * to cancel the current job on the named destination.
35
 *
36
 * Use the @link cupsLastError@ and @link cupsLastErrorString@ functions to get
37
 * the cause of any failure.
38
 *
39
 * @exclude all@
40
 */
41
42
int         /* O - 1 on success, 0 on failure */
43
cupsCancelJob(const char *name,   /* I - Name of printer or class */
44
              int        job_id)  /* I - Job ID, @code CUPS_JOBID_CURRENT@ for the current job, or @code CUPS_JOBID_ALL@ for all jobs */
45
0
{
46
0
  return (cupsCancelJob2(CUPS_HTTP_DEFAULT, name, job_id, 0)
47
0
              < IPP_STATUS_REDIRECTION_OTHER_SITE);
48
0
}
49
50
51
/*
52
 * 'cupsCancelJob2()' - Cancel or purge a print job.
53
 *
54
 * Canceled jobs remain in the job history while purged jobs are removed
55
 * from the job history.
56
 *
57
 * Pass @code CUPS_JOBID_ALL@ to cancel all jobs or @code CUPS_JOBID_CURRENT@
58
 * to cancel the current job on the named destination.
59
 *
60
 * Use the @link cupsLastError@ and @link cupsLastErrorString@ functions to get
61
 * the cause of any failure.
62
 *
63
 * @since CUPS 1.4/macOS 10.6@ @exclude all@
64
 */
65
66
ipp_status_t        /* O - IPP status */
67
cupsCancelJob2(http_t     *http,  /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
68
               const char *name,  /* I - Name of printer or class */
69
               int        job_id, /* I - Job ID, @code CUPS_JOBID_CURRENT@ for the current job, or @code CUPS_JOBID_ALL@ for all jobs */
70
         int        purge)  /* I - 1 to purge, 0 to cancel */
71
0
{
72
0
  char    uri[HTTP_MAX_URI];  /* Job/printer URI */
73
0
  ipp_t   *request;   /* IPP request */
74
75
76
 /*
77
  * Range check input...
78
  */
79
80
0
  if (job_id < -1 || (!name && job_id == 0))
81
0
  {
82
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
83
0
    return (0);
84
0
  }
85
86
 /*
87
  * Connect to the default server as needed...
88
  */
89
90
0
  if (!http)
91
0
    if ((http = _cupsConnect()) == NULL)
92
0
      return (IPP_STATUS_ERROR_SERVICE_UNAVAILABLE);
93
94
 /*
95
  * Build an IPP_CANCEL_JOB or IPP_PURGE_JOBS request, which requires the following
96
  * attributes:
97
  *
98
  *    attributes-charset
99
  *    attributes-natural-language
100
  *    job-uri or printer-uri + job-id
101
  *    requesting-user-name
102
  *    [purge-job] or [purge-jobs]
103
  */
104
105
0
  request = ippNewRequest(job_id < 0 ? IPP_OP_PURGE_JOBS : IPP_OP_CANCEL_JOB);
106
107
0
  if (name)
108
0
  {
109
0
    httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
110
0
                     "localhost", ippPort(), "/printers/%s", name);
111
112
0
    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
113
0
                 uri);
114
0
    ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
115
0
                  job_id);
116
0
  }
117
0
  else if (job_id > 0)
118
0
  {
119
0
    snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", job_id);
120
121
0
    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
122
0
  }
123
124
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
125
0
               NULL, cupsUser());
126
127
0
  if (purge && job_id >= 0)
128
0
    ippAddBoolean(request, IPP_TAG_OPERATION, "purge-job", 1);
129
0
  else if (!purge && job_id < 0)
130
0
    ippAddBoolean(request, IPP_TAG_OPERATION, "purge-jobs", 0);
131
132
 /*
133
  * Do the request...
134
  */
135
136
0
  ippDelete(cupsDoRequest(http, request, "/jobs/"));
137
138
0
  return (cupsLastError());
139
0
}
140
141
142
/*
143
 * 'cupsCreateJob()' - Create an empty job for streaming.
144
 *
145
 * Use this function when you want to stream print data using the
146
 * @link cupsStartDocument@, @link cupsWriteRequestData@, and
147
 * @link cupsFinishDocument@ functions.  If you have one or more files to
148
 * print, use the @link cupsPrintFile2@ or @link cupsPrintFiles2@ function
149
 * instead.
150
 *
151
 * @since CUPS 1.4/macOS 10.6@ @exclude all@
152
 */
153
154
int         /* O - Job ID or 0 on error */
155
cupsCreateJob(
156
    http_t        *http,    /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
157
    const char    *name,    /* I - Destination name */
158
    const char    *title,   /* I - Title of job */
159
    int           num_options,    /* I - Number of options */
160
    cups_option_t *options)   /* I - Options */
161
0
{
162
0
  int   job_id = 0;   /* job-id value */
163
0
  ipp_status_t  status;                 /* Create-Job status */
164
0
  cups_dest_t *dest;      /* Destination */
165
0
  cups_dinfo_t  *info;                  /* Destination information */
166
167
168
0
  DEBUG_printf(("cupsCreateJob(http=%p, name=\"%s\", title=\"%s\", num_options=%d, options=%p)", (void *)http, name, title, num_options, (void *)options));
169
170
 /*
171
  * Range check input...
172
  */
173
174
0
  if (!name)
175
0
  {
176
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
177
0
    return (0);
178
0
  }
179
180
 /*
181
  * Lookup the destination...
182
  */
183
184
0
  if ((dest = cupsGetNamedDest(http, name, NULL)) == NULL)
185
0
  {
186
0
    DEBUG_puts("1cupsCreateJob: Destination not found.");
187
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0);
188
0
    return (0);
189
0
  }
190
191
 /*
192
  * Query dest information and create the job...
193
  */
194
195
0
  DEBUG_puts("1cupsCreateJob: Querying destination info.");
196
0
  if ((info = cupsCopyDestInfo(http, dest)) == NULL)
197
0
  {
198
0
    DEBUG_puts("1cupsCreateJob: Query failed.");
199
0
    cupsFreeDests(1, dest);
200
0
    return (0);
201
0
  }
202
203
0
  status = cupsCreateDestJob(http, dest, info, &job_id, title, num_options, options);
204
0
  DEBUG_printf(("1cupsCreateJob: cupsCreateDestJob returned %04x (%s)", status, ippErrorString(status)));
205
206
0
  cupsFreeDestInfo(info);
207
0
  cupsFreeDests(1, dest);
208
209
 /*
210
  * Return the job...
211
  */
212
213
0
  if (status >= IPP_STATUS_REDIRECTION_OTHER_SITE)
214
0
    return (0);
215
0
  else
216
0
    return (job_id);
217
0
}
218
219
220
/*
221
 * 'cupsFinishDocument()' - Finish sending a document.
222
 *
223
 * The document must have been started using @link cupsStartDocument@.
224
 *
225
 * @since CUPS 1.4/macOS 10.6@ @exclude all@
226
 */
227
228
ipp_status_t        /* O - Status of document submission */
229
cupsFinishDocument(http_t     *http,  /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
230
                   const char *name)  /* I - Destination name */
231
0
{
232
0
  char  resource[1024];     /* Printer resource */
233
234
235
0
  snprintf(resource, sizeof(resource), "/printers/%s", name);
236
237
0
  ippDelete(cupsGetResponse(http, resource));
238
239
0
  return (cupsLastError());
240
0
}
241
242
243
/*
244
 * 'cupsFreeJobs()' - Free memory used by job data.
245
 */
246
247
void
248
cupsFreeJobs(int        num_jobs, /* I - Number of jobs */
249
             cups_job_t *jobs)    /* I - Jobs */
250
0
{
251
0
  int   i;      /* Looping var */
252
0
  cups_job_t  *job;     /* Current job */
253
254
255
0
  if (num_jobs <= 0 || !jobs)
256
0
    return;
257
258
0
  for (i = num_jobs, job = jobs; i > 0; i --, job ++)
259
0
  {
260
0
    _cupsStrFree(job->dest);
261
0
    _cupsStrFree(job->user);
262
0
    _cupsStrFree(job->format);
263
0
    _cupsStrFree(job->title);
264
0
  }
265
266
0
  free(jobs);
267
0
}
268
269
270
/*
271
 * 'cupsGetClasses()' - Get a list of printer classes from the default server.
272
 *
273
 * This function is deprecated and no longer returns a list of printer
274
 * classes - use @link cupsGetDests@ instead.
275
 *
276
 * @deprecated@ @exclude all@
277
 */
278
279
int         /* O - Number of classes */
280
cupsGetClasses(char ***classes)   /* O - Classes */
281
0
{
282
0
  if (classes)
283
0
    *classes = NULL;
284
285
0
  return (0);
286
0
}
287
288
289
/*
290
 * 'cupsGetDefault()' - Get the default printer or class for the default server.
291
 *
292
 * This function returns the default printer or class as defined by
293
 * the LPDEST or PRINTER environment variables. If these environment
294
 * variables are not set, the server default destination is returned.
295
 * Applications should use the @link cupsGetDests@ and @link cupsGetDest@
296
 * functions to get the user-defined default printer, as this function does
297
 * not support the lpoptions-defined default printer.
298
 *
299
 * @exclude all@
300
 */
301
302
const char *        /* O - Default printer or @code NULL@ */
303
cupsGetDefault(void)
304
0
{
305
 /*
306
  * Return the default printer...
307
  */
308
309
0
  return (cupsGetDefault2(CUPS_HTTP_DEFAULT));
310
0
}
311
312
313
/*
314
 * 'cupsGetDefault2()' - Get the default printer or class for the specified server.
315
 *
316
 * This function returns the default printer or class as defined by
317
 * the LPDEST or PRINTER environment variables. If these environment
318
 * variables are not set, the server default destination is returned.
319
 * Applications should use the @link cupsGetDests@ and @link cupsGetDest@
320
 * functions to get the user-defined default printer, as this function does
321
 * not support the lpoptions-defined default printer.
322
 *
323
 * @since CUPS 1.1.21/macOS 10.4@ @exclude all@
324
 */
325
326
const char *        /* O - Default printer or @code NULL@ */
327
cupsGetDefault2(http_t *http)   /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
328
0
{
329
0
  ipp_t   *request,   /* IPP Request */
330
0
    *response;    /* IPP Response */
331
0
  ipp_attribute_t *attr;    /* Current attribute */
332
0
  _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
333
334
335
 /*
336
  * See if we have a user default printer set...
337
  */
338
339
0
  if (_cupsUserDefault(cg->def_printer, sizeof(cg->def_printer)))
340
0
    return (cg->def_printer);
341
342
 /*
343
  * Connect to the server as needed...
344
  */
345
346
0
  if (!http)
347
0
    if ((http = _cupsConnect()) == NULL)
348
0
      return (NULL);
349
350
 /*
351
  * Build a CUPS_GET_DEFAULT request, which requires the following
352
  * attributes:
353
  *
354
  *    attributes-charset
355
  *    attributes-natural-language
356
  */
357
358
0
  request = ippNewRequest(IPP_OP_CUPS_GET_DEFAULT);
359
360
 /*
361
  * Do the request and get back a response...
362
  */
363
364
0
  if ((response = cupsDoRequest(http, request, "/")) != NULL)
365
0
  {
366
0
    if ((attr = ippFindAttribute(response, "printer-name",
367
0
                                 IPP_TAG_NAME)) != NULL)
368
0
    {
369
0
      strlcpy(cg->def_printer, attr->values[0].string.text,
370
0
              sizeof(cg->def_printer));
371
0
      ippDelete(response);
372
0
      return (cg->def_printer);
373
0
    }
374
375
0
    ippDelete(response);
376
0
  }
377
378
0
  return (NULL);
379
0
}
380
381
382
/*
383
 * 'cupsGetJobs()' - Get the jobs from the default server.
384
 *
385
 * A "whichjobs" value of @code CUPS_WHICHJOBS_ALL@ returns all jobs regardless
386
 * of state, while @code CUPS_WHICHJOBS_ACTIVE@ returns jobs that are
387
 * pending, processing, or held and @code CUPS_WHICHJOBS_COMPLETED@ returns
388
 * jobs that are stopped, canceled, aborted, or completed.
389
 *
390
 * @exclude all@
391
 */
392
393
int         /* O - Number of jobs */
394
cupsGetJobs(cups_job_t **jobs,    /* O - Job data */
395
            const char *name,   /* I - @code NULL@ = all destinations, otherwise show jobs for named destination */
396
            int        myjobs,    /* I - 0 = all users, 1 = mine */
397
      int        whichjobs) /* I - @code CUPS_WHICHJOBS_ALL@, @code CUPS_WHICHJOBS_ACTIVE@, or @code CUPS_WHICHJOBS_COMPLETED@ */
398
0
{
399
 /*
400
  * Return the jobs...
401
  */
402
403
0
  return (cupsGetJobs2(CUPS_HTTP_DEFAULT, jobs, name, myjobs, whichjobs));
404
0
}
405
406
407
408
/*
409
 * 'cupsGetJobs2()' - Get the jobs from the specified server.
410
 *
411
 * A "whichjobs" value of @code CUPS_WHICHJOBS_ALL@ returns all jobs regardless
412
 * of state, while @code CUPS_WHICHJOBS_ACTIVE@ returns jobs that are
413
 * pending, processing, or held and @code CUPS_WHICHJOBS_COMPLETED@ returns
414
 * jobs that are stopped, canceled, aborted, or completed.
415
 *
416
 * @since CUPS 1.1.21/macOS 10.4@
417
 */
418
419
int         /* O - Number of jobs */
420
cupsGetJobs2(http_t     *http,    /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
421
             cups_job_t **jobs,   /* O - Job data */
422
             const char *name,    /* I - @code NULL@ = all destinations, otherwise show jobs for named destination */
423
             int        myjobs,   /* I - 0 = all users, 1 = mine */
424
       int        whichjobs)  /* I - @code CUPS_WHICHJOBS_ALL@, @code CUPS_WHICHJOBS_ACTIVE@, or @code CUPS_WHICHJOBS_COMPLETED@ */
425
0
{
426
0
  int   n;      /* Number of jobs */
427
0
  ipp_t   *request,   /* IPP Request */
428
0
    *response;    /* IPP Response */
429
0
  ipp_attribute_t *attr;    /* Current attribute */
430
0
  cups_job_t  *temp;      /* Temporary pointer */
431
0
  int   id,     /* job-id */
432
0
    priority,   /* job-priority */
433
0
    size;     /* job-k-octets */
434
0
  ipp_jstate_t  state;      /* job-state */
435
0
  time_t  completed_time,   /* time-at-completed */
436
0
    creation_time,    /* time-at-creation */
437
0
    processing_time;  /* time-at-processing */
438
0
  const char  *dest,      /* job-printer-uri */
439
0
    *format,    /* document-format */
440
0
    *title,     /* job-name */
441
0
    *user;      /* job-originating-user-name */
442
0
  char    uri[HTTP_MAX_URI];  /* URI for jobs */
443
0
  _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
444
0
  static const char * const attrs[] = /* Requested attributes */
445
0
    {
446
0
      "document-format",
447
0
      "job-id",
448
0
      "job-k-octets",
449
0
      "job-name",
450
0
      "job-originating-user-name",
451
0
      "job-printer-uri",
452
0
      "job-priority",
453
0
      "job-state",
454
0
      "time-at-completed",
455
0
      "time-at-creation",
456
0
      "time-at-processing"
457
0
    };
458
459
460
 /*
461
  * Range check input...
462
  */
463
464
0
  if (!jobs)
465
0
  {
466
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
467
468
0
    return (-1);
469
0
  }
470
471
 /*
472
  * Get the right URI...
473
  */
474
475
0
  if (name)
476
0
  {
477
0
    if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
478
0
                         "localhost", 0, "/printers/%s",
479
0
                         name) < HTTP_URI_STATUS_OK)
480
0
    {
481
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
482
0
                    _("Unable to create printer-uri"), 1);
483
484
0
      return (-1);
485
0
    }
486
0
  }
487
0
  else
488
0
    strlcpy(uri, "ipp://localhost/", sizeof(uri));
489
490
0
  if (!http)
491
0
    if ((http = _cupsConnect()) == NULL)
492
0
      return (-1);
493
494
 /*
495
  * Build an IPP_GET_JOBS request, which requires the following
496
  * attributes:
497
  *
498
  *    attributes-charset
499
  *    attributes-natural-language
500
  *    printer-uri
501
  *    requesting-user-name
502
  *    which-jobs
503
  *    my-jobs
504
  *    requested-attributes
505
  */
506
507
0
  request = ippNewRequest(IPP_OP_GET_JOBS);
508
509
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
510
0
               "printer-uri", NULL, uri);
511
512
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
513
0
               "requesting-user-name", NULL, cupsUser());
514
515
0
  if (myjobs)
516
0
    ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
517
518
0
  if (whichjobs == CUPS_WHICHJOBS_COMPLETED)
519
0
    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
520
0
                 "which-jobs", NULL, "completed");
521
0
  else if (whichjobs == CUPS_WHICHJOBS_ALL)
522
0
    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
523
0
                 "which-jobs", NULL, "all");
524
525
0
  ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
526
0
                "requested-attributes", sizeof(attrs) / sizeof(attrs[0]),
527
0
    NULL, attrs);
528
529
 /*
530
  * Do the request and get back a response...
531
  */
532
533
0
  n     = 0;
534
0
  *jobs = NULL;
535
536
0
  if ((response = cupsDoRequest(http, request, "/")) != NULL)
537
0
  {
538
0
    for (attr = response->attrs; attr; attr = attr->next)
539
0
    {
540
     /*
541
      * Skip leading attributes until we hit a job...
542
      */
543
544
0
      while (attr && attr->group_tag != IPP_TAG_JOB)
545
0
        attr = attr->next;
546
547
0
      if (!attr)
548
0
        break;
549
550
     /*
551
      * Pull the needed attributes from this job...
552
      */
553
554
0
      id              = 0;
555
0
      size            = 0;
556
0
      priority        = 50;
557
0
      state           = IPP_JSTATE_PENDING;
558
0
      user            = "unknown";
559
0
      dest            = NULL;
560
0
      format          = "application/octet-stream";
561
0
      title           = "untitled";
562
0
      creation_time   = 0;
563
0
      completed_time  = 0;
564
0
      processing_time = 0;
565
566
0
      while (attr && attr->group_tag == IPP_TAG_JOB)
567
0
      {
568
0
        if (!strcmp(attr->name, "job-id") &&
569
0
      attr->value_tag == IPP_TAG_INTEGER)
570
0
    id = attr->values[0].integer;
571
0
        else if (!strcmp(attr->name, "job-state") &&
572
0
           attr->value_tag == IPP_TAG_ENUM)
573
0
    state = (ipp_jstate_t)attr->values[0].integer;
574
0
        else if (!strcmp(attr->name, "job-priority") &&
575
0
           attr->value_tag == IPP_TAG_INTEGER)
576
0
    priority = attr->values[0].integer;
577
0
        else if (!strcmp(attr->name, "job-k-octets") &&
578
0
           attr->value_tag == IPP_TAG_INTEGER)
579
0
    size = attr->values[0].integer;
580
0
        else if (!strcmp(attr->name, "time-at-completed") &&
581
0
           attr->value_tag == IPP_TAG_INTEGER)
582
0
    completed_time = attr->values[0].integer;
583
0
        else if (!strcmp(attr->name, "time-at-creation") &&
584
0
           attr->value_tag == IPP_TAG_INTEGER)
585
0
    creation_time = attr->values[0].integer;
586
0
        else if (!strcmp(attr->name, "time-at-processing") &&
587
0
           attr->value_tag == IPP_TAG_INTEGER)
588
0
    processing_time = attr->values[0].integer;
589
0
        else if (!strcmp(attr->name, "job-printer-uri") &&
590
0
           attr->value_tag == IPP_TAG_URI)
591
0
  {
592
0
    if ((dest = strrchr(attr->values[0].string.text, '/')) != NULL)
593
0
      dest ++;
594
0
        }
595
0
        else if (!strcmp(attr->name, "job-originating-user-name") &&
596
0
           attr->value_tag == IPP_TAG_NAME)
597
0
    user = attr->values[0].string.text;
598
0
        else if (!strcmp(attr->name, "document-format") &&
599
0
           attr->value_tag == IPP_TAG_MIMETYPE)
600
0
    format = attr->values[0].string.text;
601
0
        else if (!strcmp(attr->name, "job-name") &&
602
0
           (attr->value_tag == IPP_TAG_TEXT ||
603
0
      attr->value_tag == IPP_TAG_NAME))
604
0
    title = attr->values[0].string.text;
605
606
0
        attr = attr->next;
607
0
      }
608
609
     /*
610
      * See if we have everything needed...
611
      */
612
613
0
      if (!dest || !id)
614
0
      {
615
0
        if (!attr)
616
0
    break;
617
0
  else
618
0
          continue;
619
0
      }
620
621
     /*
622
      * Allocate memory for the job...
623
      */
624
625
0
      if (n == 0)
626
0
        temp = malloc(sizeof(cups_job_t));
627
0
      else
628
0
  temp = realloc(*jobs, sizeof(cups_job_t) * (size_t)(n + 1));
629
630
0
      if (!temp)
631
0
      {
632
       /*
633
        * Ran out of memory!
634
        */
635
636
0
        _cupsSetError(IPP_STATUS_ERROR_INTERNAL, NULL, 0);
637
638
0
  cupsFreeJobs(n, *jobs);
639
0
  *jobs = NULL;
640
641
0
        ippDelete(response);
642
643
0
  return (-1);
644
0
      }
645
646
0
      *jobs = temp;
647
0
      temp  += n;
648
0
      n ++;
649
650
     /*
651
      * Copy the data over...
652
      */
653
654
0
      temp->dest            = _cupsStrAlloc(dest);
655
0
      temp->user            = _cupsStrAlloc(user);
656
0
      temp->format          = _cupsStrAlloc(format);
657
0
      temp->title           = _cupsStrAlloc(title);
658
0
      temp->id              = id;
659
0
      temp->priority        = priority;
660
0
      temp->state           = state;
661
0
      temp->size            = size;
662
0
      temp->completed_time  = completed_time;
663
0
      temp->creation_time   = creation_time;
664
0
      temp->processing_time = processing_time;
665
666
0
      if (!attr)
667
0
        break;
668
0
    }
669
670
0
    ippDelete(response);
671
0
  }
672
673
0
  if (n == 0 && cg->last_error >= IPP_STATUS_ERROR_BAD_REQUEST)
674
0
    return (-1);
675
0
  else
676
0
    return (n);
677
0
}
678
679
680
/*
681
 * 'cupsGetPrinters()' - Get a list of printers from the default server.
682
 *
683
 * This function is deprecated and no longer returns a list of printers - use
684
 * @link cupsGetDests@ instead.
685
 *
686
 * @deprecated@ @exclude all@
687
 */
688
689
int         /* O - Number of printers */
690
cupsGetPrinters(char ***printers) /* O - Printers */
691
0
{
692
0
  if (printers)
693
0
    *printers = NULL;
694
695
0
  return (0);
696
0
}
697
698
699
/*
700
 * 'cupsPrintFile()' - Print a file to a printer or class on the default server.
701
 *
702
 * @exclude all@
703
 */
704
705
int         /* O - Job ID or 0 on error */
706
cupsPrintFile(const char    *name,  /* I - Destination name */
707
              const char    *filename,  /* I - File to print */
708
        const char    *title, /* I - Title of job */
709
              int           num_options,/* I - Number of options */
710
        cups_option_t *options) /* I - Options */
711
0
{
712
0
  DEBUG_printf(("cupsPrintFile(name=\"%s\", filename=\"%s\", title=\"%s\", num_options=%d, options=%p)", name, filename, title, num_options, (void *)options));
713
714
0
  return (cupsPrintFiles2(CUPS_HTTP_DEFAULT, name, 1, &filename, title,
715
0
                          num_options, options));
716
0
}
717
718
719
/*
720
 * 'cupsPrintFile2()' - Print a file to a printer or class on the specified
721
 *                      server.
722
 *
723
 * @since CUPS 1.1.21/macOS 10.4@ @exclude all@
724
 */
725
726
int         /* O - Job ID or 0 on error */
727
cupsPrintFile2(
728
    http_t        *http,    /* I - Connection to server */
729
    const char    *name,    /* I - Destination name */
730
    const char    *filename,    /* I - File to print */
731
    const char    *title,   /* I - Title of job */
732
    int           num_options,    /* I - Number of options */
733
    cups_option_t *options)   /* I - Options */
734
0
{
735
0
  DEBUG_printf(("cupsPrintFile2(http=%p, name=\"%s\", filename=\"%s\",  title=\"%s\", num_options=%d, options=%p)", (void *)http, name, filename, title, num_options, (void *)options));
736
737
0
  return (cupsPrintFiles2(http, name, 1, &filename, title, num_options,
738
0
                          options));
739
0
}
740
741
742
/*
743
 * 'cupsPrintFiles()' - Print one or more files to a printer or class on the
744
 *                      default server.
745
 *
746
 * @exclude all@
747
 */
748
749
int         /* O - Job ID or 0 on error */
750
cupsPrintFiles(
751
    const char    *name,    /* I - Destination name */
752
    int           num_files,    /* I - Number of files */
753
    const char    **files,    /* I - File(s) to print */
754
    const char    *title,   /* I - Title of job */
755
    int           num_options,    /* I - Number of options */
756
    cups_option_t *options)   /* I - Options */
757
0
{
758
0
  DEBUG_printf(("cupsPrintFiles(name=\"%s\", num_files=%d, files=%p, title=\"%s\", num_options=%d, options=%p)", name, num_files, (void *)files, title, num_options, (void *)options));
759
760
 /*
761
  * Print the file(s)...
762
  */
763
764
0
  return (cupsPrintFiles2(CUPS_HTTP_DEFAULT, name, num_files, files, title,
765
0
                          num_options, options));
766
0
}
767
768
769
/*
770
 * 'cupsPrintFiles2()' - Print one or more files to a printer or class on the
771
 *                       specified server.
772
 *
773
 * @since CUPS 1.1.21/macOS 10.4@ @exclude all@
774
 */
775
776
int         /* O - Job ID or 0 on error */
777
cupsPrintFiles2(
778
    http_t        *http,    /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
779
    const char    *name,    /* I - Destination name */
780
    int           num_files,    /* I - Number of files */
781
    const char    **files,    /* I - File(s) to print */
782
    const char    *title,   /* I - Title of job */
783
    int           num_options,    /* I - Number of options */
784
    cups_option_t *options)   /* I - Options */
785
0
{
786
0
  int   i;      /* Looping var */
787
0
  int   job_id;     /* New job ID */
788
0
  const char  *docname;   /* Basename of current filename */
789
0
  const char  *format;    /* Document format */
790
0
  cups_file_t *fp;      /* Current file */
791
0
  char    buffer[8192];   /* Copy buffer */
792
0
  ssize_t bytes;      /* Bytes in buffer */
793
0
  http_status_t status;     /* Status of write */
794
0
  _cups_globals_t *cg = _cupsGlobals(); /* Global data */
795
0
  ipp_status_t  cancel_status;    /* Status code to preserve */
796
0
  char    *cancel_message;  /* Error message to preserve */
797
798
799
0
  DEBUG_printf(("cupsPrintFiles2(http=%p, name=\"%s\", num_files=%d, files=%p, title=\"%s\", num_options=%d, options=%p)", (void *)http, name, num_files, (void *)files, title, num_options, (void *)options));
800
801
 /*
802
  * Range check input...
803
  */
804
805
0
  if (!name || num_files < 1 || !files)
806
0
  {
807
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
808
809
0
    return (0);
810
0
  }
811
812
 /*
813
  * Create the print job...
814
  */
815
816
0
  if ((job_id = cupsCreateJob(http, name, title, num_options, options)) == 0)
817
0
    return (0);
818
819
 /*
820
  * Send each of the files...
821
  */
822
823
0
  if (cupsGetOption("raw", num_options, options))
824
0
    format = CUPS_FORMAT_RAW;
825
0
  else if ((format = cupsGetOption("document-format", num_options,
826
0
           options)) == NULL)
827
0
    format = CUPS_FORMAT_AUTO;
828
829
0
  for (i = 0; i < num_files; i ++)
830
0
  {
831
   /*
832
    * Start the next file...
833
    */
834
835
0
    if ((docname = strrchr(files[i], '/')) != NULL)
836
0
      docname ++;
837
0
    else
838
0
      docname = files[i];
839
840
0
    if ((fp = cupsFileOpen(files[i], "rb")) == NULL)
841
0
    {
842
     /*
843
      * Unable to open print file, cancel the job and return...
844
      */
845
846
0
      _cupsSetError(IPP_STATUS_ERROR_DOCUMENT_ACCESS, NULL, 0);
847
0
      goto cancel_job;
848
0
    }
849
850
0
    status = cupsStartDocument(http, name, job_id, docname, format,
851
0
             i == (num_files - 1));
852
853
0
    while (status == HTTP_STATUS_CONTINUE &&
854
0
     (bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0)
855
0
      status = cupsWriteRequestData(http, buffer, (size_t)bytes);
856
857
0
    cupsFileClose(fp);
858
859
0
    if (status != HTTP_STATUS_CONTINUE || cupsFinishDocument(http, name) != IPP_STATUS_OK)
860
0
    {
861
     /*
862
      * Unable to queue, cancel the job and return...
863
      */
864
865
0
      goto cancel_job;
866
0
    }
867
0
  }
868
869
0
  return (job_id);
870
871
 /*
872
  * If we get here, something happened while sending the print job so we need
873
  * to cancel the job without setting the last error (since we need to preserve
874
  * the current error...
875
  */
876
877
0
  cancel_job:
878
879
0
  cancel_status  = cg->last_error;
880
0
  cancel_message = cg->last_status_message ?
881
0
                       _cupsStrRetain(cg->last_status_message) : NULL;
882
883
0
  cupsCancelJob2(http, name, job_id, 0);
884
885
0
  cg->last_error          = cancel_status;
886
0
  cg->last_status_message = cancel_message;
887
888
0
  return (0);
889
0
}
890
891
892
/*
893
 * 'cupsStartDocument()' - Add a document to a job created with cupsCreateJob().
894
 *
895
 * Use @link cupsWriteRequestData@ to write data for the document and
896
 * @link cupsFinishDocument@ to finish the document and get the submission status.
897
 *
898
 * The MIME type constants @code CUPS_FORMAT_AUTO@, @code CUPS_FORMAT_PDF@,
899
 * @code CUPS_FORMAT_POSTSCRIPT@, @code CUPS_FORMAT_RAW@, and
900
 * @code CUPS_FORMAT_TEXT@ are provided for the "format" argument, although
901
 * any supported MIME type string can be supplied.
902
 *
903
 * @since CUPS 1.4/macOS 10.6@ @exclude all@
904
 */
905
906
http_status_t       /* O - HTTP status of request */
907
cupsStartDocument(
908
    http_t     *http,     /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
909
    const char *name,     /* I - Destination name */
910
    int        job_id,      /* I - Job ID from @link cupsCreateJob@ */
911
    const char *docname,    /* I - Name of document */
912
    const char *format,     /* I - MIME type or @code CUPS_FORMAT_foo@ */
913
    int        last_document)   /* I - 1 for last document in job, 0 otherwise */
914
0
{
915
0
  char    resource[1024],   /* Resource for destinatio */
916
0
    printer_uri[1024];  /* Printer URI */
917
0
  ipp_t   *request;   /* Send-Document request */
918
0
  http_status_t status;     /* HTTP status */
919
920
921
 /*
922
  * Create a Send-Document request...
923
  */
924
925
0
  if ((request = ippNewRequest(IPP_OP_SEND_DOCUMENT)) == NULL)
926
0
  {
927
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0);
928
0
    return (HTTP_STATUS_ERROR);
929
0
  }
930
931
0
  httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), "ipp",
932
0
                   NULL, "localhost", ippPort(), "/printers/%s", name);
933
0
  snprintf(resource, sizeof(resource), "/printers/%s", name);
934
935
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
936
0
               NULL, printer_uri);
937
0
  ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job_id);
938
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
939
0
               NULL, cupsUser());
940
0
  if (docname)
941
0
    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-name",
942
0
                 NULL, docname);
943
0
  if (format)
944
0
    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
945
0
                 "document-format", NULL, format);
946
0
  ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", (char)last_document);
947
948
 /*
949
  * Send and delete the request, then return the status...
950
  */
951
952
0
  status = cupsSendRequest(http, request, resource, CUPS_LENGTH_VARIABLE);
953
954
0
  ippDelete(request);
955
956
0
  return (status);
957
0
}
958