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