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