]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/util.c
Add strlcat() and strlcpy() checks and emulation functions.
[thirdparty/cups.git] / cups / util.c
CommitLineData
3b960317 1/*
17438bf4 2 * "$Id: util.c,v 1.94 2002/05/16 13:44:55 mike Exp $"
3b960317 3 *
4 * Printing utilities for the Common UNIX Printing System (CUPS).
5 *
efb2f309 6 * Copyright 1997-2002 by Easy Software Products.
3b960317 7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
8784b6a6 17 * 44141 Airport View Drive, Suite 204
3b960317 18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
34410ef2 24 * This file is subject to the Apple OS-Developed Software exception.
25 *
3b960317 26 * Contents:
27 *
3270670b 28 * cupsCancelJob() - Cancel a print job.
018b8ca8 29 * cupsDoFileRequest() - Do an IPP request...
d6baddaa 30 * cupsFreeJobs() - Free memory used by job data.
3270670b 31 * cupsGetClasses() - Get a list of printer classes.
32 * cupsGetDefault() - Get the default printer or class.
d6baddaa 33 * cupsGetJobs() - Get the jobs from the server.
3270670b 34 * cupsGetPPD() - Get the PPD file for a printer.
35 * cupsGetPrinters() - Get a list of printers.
486cdc15 36 * cupsLastError() - Return the last IPP error that occurred.
3270670b 37 * cupsPrintFile() - Print a file to a printer or class.
c7c24dd7 38 * cupsPrintFiles() - Print one or more files to a printer or class.
3270670b 39 * cups_connect() - Connect to the specified host...
d2122fde 40 * cups_local_auth() - Get the local authorization certificate if
41 * available/applicable...
3b960317 42 */
43
44/*
45 * Include necessary headers...
46 */
47
48#include "cups.h"
4a73831b 49#include "ipp.h"
50#include "language.h"
51#include "string.h"
52#include "debug.h"
aeabf506 53#include <stdlib.h>
54#include <ctype.h>
4a73831b 55#include <errno.h>
04115410 56#include <fcntl.h>
4a73831b 57#include <sys/stat.h>
d23a857a 58#if defined(WIN32) || defined(__EMX__)
59# include <io.h>
60#else
61# include <unistd.h>
62#endif /* WIN32 || __EMX__ */
3b960317 63
64
113aba7a 65/*
66 * Local globals...
67 */
68
3095105a 69static http_t *cups_server = NULL; /* Current server connection */
70static ipp_status_t last_error = IPP_OK; /* Last IPP error */
24bc843e 71static char authstring[HTTP_MAX_VALUE] = "";
72 /* Authorization string */
73static char pwdstring[33] = ""; /* Last password string */
d23a857a 74
75
76/*
77 * Local functions...
78 */
79
063e1ac7 80static char *cups_connect(const char *name, char *printer, char *hostname);
d2122fde 81static int cups_local_auth(http_t *http);
113aba7a 82
83
8431231f 84/*
85 * 'cupsCancelJob()' - Cancel a print job.
86 */
87
d23a857a 88int /* O - 1 on success, 0 on failure */
063e1ac7 89cupsCancelJob(const char *name, /* I - Name of printer or class */
90 int job) /* I - Job ID */
3b960317 91{
d23a857a 92 char printer[HTTP_MAX_URI], /* Printer name */
93 hostname[HTTP_MAX_URI], /* Hostname */
94 uri[HTTP_MAX_URI]; /* Printer URI */
95 ipp_t *request, /* IPP request */
96 *response; /* IPP response */
97 cups_lang_t *language; /* Language info */
98
99
100 /*
101 * See if we can connect to the server...
102 */
103
104 if (!cups_connect(name, printer, hostname))
9aebebc3 105 {
106 last_error = IPP_SERVICE_UNAVAILABLE;
2bffb563 107 return (0);
9aebebc3 108 }
d23a857a 109
110 /*
111 * Build an IPP_CANCEL_JOB request, which requires the following
112 * attributes:
113 *
114 * attributes-charset
115 * attributes-natural-language
116 * printer-uri
117 * job-id
8b06ca19 118 * [requesting-user-name]
d23a857a 119 */
120
121 request = ippNew();
122
123 request->request.op.operation_id = IPP_CANCEL_JOB;
124 request->request.op.request_id = 1;
125
126 language = cupsLangDefault();
127
128 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
129 "attributes-charset", NULL, cupsLangEncoding(language));
130
131 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
132 "attributes-natural-language", NULL,
133 language != NULL ? language->language : "C");
134
04de52f8 135 snprintf(uri, sizeof(uri), "ipp://%s:%d/printers/%s", hostname, ippPort(), printer);
d23a857a 136 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
137 NULL, uri);
138
6d0582d2 139 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job);
d23a857a 140
8b06ca19 141 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
142 NULL, cupsUser());
143
d23a857a 144 /*
145 * Do the request...
146 */
147
148 if ((response = cupsDoRequest(cups_server, request, "/jobs/")) == NULL)
8b06ca19 149 {
150 last_error = IPP_BAD_REQUEST;
d23a857a 151 return (0);
8b06ca19 152 }
153 else
154 {
155 last_error = response->request.status.status_code;
156 ippDelete(response);
d23a857a 157
8b06ca19 158 return (1);
159 }
3b960317 160}
161
162
113aba7a 163/*
3270670b 164 * 'cupsDoFileRequest()' - Do an IPP request...
113aba7a 165 */
166
3270670b 167ipp_t * /* O - Response data */
063e1ac7 168cupsDoFileRequest(http_t *http, /* I - HTTP connection to server */
169 ipp_t *request, /* I - IPP request */
170 const char *resource, /* I - HTTP resource for POST */
171 const char *filename) /* I - File to send or NULL */
113aba7a 172{
83e740a5 173 ipp_t *response; /* IPP response data */
174 char length[255]; /* Content-Length field */
175 http_status_t status; /* Status of HTTP request */
176 FILE *file; /* File to send */
177 struct stat fileinfo; /* File information */
178 int bytes; /* Number of bytes read/written */
57887694 179 char buffer[32768]; /* Output buffer */
83e740a5 180 const char *password; /* Password string */
181 char realm[HTTP_MAX_VALUE], /* realm="xyz" string */
182 nonce[HTTP_MAX_VALUE], /* nonce="xyz" string */
183 plain[255], /* Plaintext username:password */
d2e58bfa 184 encode[512]; /* Encoded username:password */
3026be56 185 char prompt[1024]; /* Prompt string */
24bc843e 186 int digest_tries; /* Number of tries with Digest */
113aba7a 187
188
0f6a2276 189 if (http == NULL || request == NULL || resource == NULL)
190 {
191 if (request != NULL)
192 ippDelete(request);
193
194 last_error = IPP_INTERNAL_ERROR;
195 return (NULL);
196 }
197
880dc0ce 198 DEBUG_printf(("cupsDoFileRequest(%p, %08x, \'%s\', \'%s\')\n",
3270670b 199 http, request, resource, filename ? filename : "(null)"));
113aba7a 200
201 /*
3270670b 202 * See if we have a file to send...
113aba7a 203 */
204
3270670b 205 if (filename != NULL)
206 {
207 if (stat(filename, &fileinfo))
208 {
209 /*
210 * Can't get file information!
211 */
113aba7a 212
3270670b 213 ippDelete(request);
9aebebc3 214 last_error = IPP_NOT_FOUND;
3270670b 215 return (NULL);
216 }
113aba7a 217
3270670b 218 if ((file = fopen(filename, "rb")) == NULL)
877378d9 219 {
3270670b 220 /*
221 * Can't open file!
222 */
223
877378d9 224 ippDelete(request);
9aebebc3 225 last_error = IPP_NOT_FOUND;
877378d9 226 return (NULL);
227 }
3270670b 228 }
d21a7597 229 else
230 file = NULL;
113aba7a 231
232 /*
3270670b 233 * Loop until we can send the request without authorization problems.
113aba7a 234 */
235
24bc843e 236 response = NULL;
237 status = HTTP_ERROR;
238 digest_tries = 0;
d23a857a 239
3270670b 240 while (response == NULL)
d23a857a 241 {
3270670b 242 DEBUG_puts("cupsDoFileRequest: setup...");
243
d23a857a 244 /*
3270670b 245 * Setup the HTTP variables needed...
d23a857a 246 */
247
3270670b 248 if (filename != NULL)
0e0ac99a 249 sprintf(length, "%lu", (unsigned long)(ippLength(request) +
250 (size_t)fileinfo.st_size));
3270670b 251 else
0e0ac99a 252 sprintf(length, "%lu", (unsigned long)ippLength(request));
d23a857a 253
3270670b 254 httpClearFields(http);
255 httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, length);
256 httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
257 httpSetField(http, HTTP_FIELD_AUTHORIZATION, authstring);
258
259 /*
260 * Try the request...
261 */
262
263 DEBUG_puts("cupsDoFileRequest: post...");
264
265 if (httpPost(http, resource))
dbb05cda 266 {
267 if (httpReconnect(http))
268 {
9d13ae31 269 status = HTTP_ERROR;
dbb05cda 270 break;
271 }
272 else
273 continue;
274 }
3270670b 275
276 /*
277 * Send the IPP data and wait for the response...
278 */
279
280 DEBUG_puts("cupsDoFileRequest: ipp write...");
281
282 request->state = IPP_IDLE;
018b8ca8 283 if (ippWrite(http, request) != IPP_ERROR)
284 if (filename != NULL)
285 {
286 DEBUG_puts("cupsDoFileRequest: file write...");
d23a857a 287
018b8ca8 288 /*
289 * Send the file...
290 */
d23a857a 291
018b8ca8 292 rewind(file);
d23a857a 293
018b8ca8 294 while ((bytes = fread(buffer, 1, sizeof(buffer), file)) > 0)
295 if (httpWrite(http, buffer, bytes) < bytes)
296 break;
297 }
d23a857a 298
d23a857a 299 /*
3270670b 300 * Get the server's return status...
d23a857a 301 */
302
3270670b 303 DEBUG_puts("cupsDoFileRequest: update...");
d23a857a 304
018b8ca8 305 while ((status = httpUpdate(http)) == HTTP_CONTINUE);
306
018b8ca8 307 if (status == HTTP_UNAUTHORIZED)
3270670b 308 {
309 DEBUG_puts("cupsDoFileRequest: unauthorized...");
113aba7a 310
3270670b 311 /*
312 * Flush any error message...
313 */
314
315 httpFlush(http);
316
d2122fde 317 /*
318 * See if we can do local authentication...
319 */
320
321 if (cups_local_auth(http))
322 continue;
323
324 /*
24bc843e 325 * See if we should retry the current digest password...
d2122fde 326 */
327
24bc843e 328 if (strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Basic", 5) == 0 ||
329 digest_tries > 1 || !pwdstring[0])
3270670b 330 {
331 /*
24bc843e 332 * Nope - get a password from the user...
3270670b 333 */
113aba7a 334
24bc843e 335 snprintf(prompt, sizeof(prompt), "Password for %s on %s? ", cupsUser(),
336 http->hostname);
3270670b 337
24bc843e 338 if ((password = cupsGetPassword(prompt)) == NULL)
339 break;
340 if (!password[0])
341 break;
83e740a5 342
17438bf4 343 strlcpy(pwdstring, password, sizeof(pwdstring));
83e740a5 344
24bc843e 345 digest_tries = 0;
346 }
347 else
348 digest_tries ++;
83e740a5 349
24bc843e 350 /*
351 * Got a password; encode it for the server...
352 */
353
354 if (strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Basic", 5) == 0)
355 {
356 /*
357 * Basic authentication...
358 */
359
360 snprintf(plain, sizeof(plain), "%s:%s", cupsUser(), pwdstring);
361 httpEncode64(encode, plain);
362 snprintf(authstring, sizeof(authstring), "Basic %s", encode);
3270670b 363 }
3da4463c 364 else
24bc843e 365 {
366 /*
367 * Digest authentication...
368 */
369
370 httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "realm", realm);
371 httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "nonce", nonce);
372
373 httpMD5(cupsUser(), realm, pwdstring, encode);
374 httpMD5Final(nonce, "POST", resource, encode);
375 snprintf(authstring, sizeof(authstring),
376 "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", "
377 "response=\"%s\"", cupsUser(), realm, nonce, encode);
378 }
379
380 continue;
3270670b 381 }
77be8777 382 else if (status == HTTP_ERROR)
383 {
3620d932 384#ifdef WIN32
977acbd3 385 if (http->error != WSAENETDOWN && http->error != WSAENETUNREACH)
386#else
77be8777 387 if (http->error != ENETDOWN && http->error != ENETUNREACH)
3620d932 388#endif /* WIN32 */
77be8777 389 continue;
390 else
391 break;
392 }
4c6f986f 393#ifdef HAVE_LIBSSL
394 else if (status == HTTP_UPGRADE_REQUIRED)
395 {
396 /*
397 * Flush any error message...
398 */
399
400 httpFlush(http);
401
24bc843e 402 /*
403 * Upgrade with encryption...
404 */
405
406 httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
407
4c6f986f 408 /*
409 * Try again, this time with encryption enabled...
410 */
411
412 continue;
413 }
414#endif /* HAVE_LIBSSL */
77be8777 415 else if (status != HTTP_OK)
113aba7a 416 {
3270670b 417 DEBUG_printf(("cupsDoFileRequest: error %d...\n", status));
d23a857a 418
419 /*
3270670b 420 * Flush any error message...
d23a857a 421 */
422
69ee1496 423 httpFlush(http);
3270670b 424 break;
425 }
426 else
427 {
428 /*
429 * Read the response...
430 */
431
432 DEBUG_puts("cupsDoFileRequest: response...");
433
434 response = ippNew();
435
436 if (ippRead(http, response) == IPP_ERROR)
437 {
438 /*
439 * Delete the response...
440 */
441
442 ippDelete(response);
443 response = NULL;
444
9aebebc3 445 last_error = IPP_SERVICE_UNAVAILABLE;
3270670b 446 break;
447 }
113aba7a 448 }
449 }
450
3270670b 451 /*
452 * Close the file if needed...
453 */
454
455 if (filename != NULL)
456 fclose(file);
457
f37fe731 458 /*
459 * Flush any remaining data...
460 */
461
462 httpFlush(http);
463
113aba7a 464 /*
465 * Delete the original request and return the response...
466 */
467
468 ippDelete(request);
469
9aebebc3 470 if (response)
471 last_error = response->request.status.status_code;
472 else if (status == HTTP_NOT_FOUND)
473 last_error = IPP_NOT_FOUND;
474 else if (status == HTTP_UNAUTHORIZED)
475 last_error = IPP_NOT_AUTHORIZED;
476 else if (status != HTTP_OK)
477 last_error = IPP_SERVICE_UNAVAILABLE;
478
113aba7a 479 return (response);
480}
481
482
d6baddaa 483/*
484 * 'cupsFreeJobs()' - Free memory used by job data.
485 */
486
487void
488cupsFreeJobs(int num_jobs,/* I - Number of jobs */
489 cups_job_t *jobs) /* I - Jobs */
490{
491 int i; /* Looping var */
492
493
494 if (num_jobs <= 0 || jobs == NULL)
495 return;
496
497 for (i = 0; i < num_jobs; i ++)
498 {
499 free(jobs[i].dest);
500 free(jobs[i].user);
501 free(jobs[i].format);
502 free(jobs[i].title);
503 }
504
505 free(jobs);
506}
507
508
8431231f 509/*
510 * 'cupsGetClasses()' - Get a list of printer classes.
511 */
512
d23a857a 513int /* O - Number of classes */
514cupsGetClasses(char ***classes) /* O - Classes */
3b960317 515{
d23a857a 516 int n; /* Number of classes */
517 ipp_t *request, /* IPP Request */
518 *response; /* IPP Response */
519 ipp_attribute_t *attr; /* Current attribute */
520 cups_lang_t *language; /* Default language */
a9b97a87 521 char **temp; /* Temporary pointer */
d23a857a 522
523
0f6a2276 524 if (classes == NULL)
525 {
526 last_error = IPP_INTERNAL_ERROR;
527 return (0);
528 }
529
d23a857a 530 /*
531 * Try to connect to the server...
532 */
533
534 if (!cups_connect("default", NULL, NULL))
9aebebc3 535 {
536 last_error = IPP_SERVICE_UNAVAILABLE;
2bffb563 537 return (0);
9aebebc3 538 }
d23a857a 539
540 /*
541 * Build a CUPS_GET_CLASSES request, which requires the following
542 * attributes:
543 *
544 * attributes-charset
545 * attributes-natural-language
27d555e8 546 * requested-attributes
d23a857a 547 */
548
549 request = ippNew();
550
551 request->request.op.operation_id = CUPS_GET_CLASSES;
552 request->request.op.request_id = 1;
553
554 language = cupsLangDefault();
555
556 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
a9b97a87 557 "attributes-charset", NULL, cupsLangEncoding(language));
d23a857a 558
559 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
a9b97a87 560 "attributes-natural-language", NULL, language->language);
d23a857a 561
27d555e8 562 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
563 "requested-attributes", NULL, "printer-name");
564
d23a857a 565 /*
566 * Do the request and get back a response...
567 */
568
569 n = 0;
570 *classes = NULL;
571
a9b97a87 572 if ((response = cupsDoRequest(cups_server, request, "/")) != NULL)
d23a857a 573 {
8b06ca19 574 last_error = response->request.status.status_code;
575
d23a857a 576 for (attr = response->attrs; attr != NULL; attr = attr->next)
fbc6b634 577 if (attr->name != NULL &&
578 strcasecmp(attr->name, "printer-name") == 0 &&
d23a857a 579 attr->value_tag == IPP_TAG_NAME)
580 {
581 if (n == 0)
a9b97a87 582 temp = malloc(sizeof(char *));
d23a857a 583 else
a9b97a87 584 temp = realloc(*classes, sizeof(char *) * (n + 1));
d23a857a 585
a9b97a87 586 if (temp == NULL)
d23a857a 587 {
a9b97a87 588 /*
589 * Ran out of memory!
590 */
591
592 while (n > 0)
593 {
594 n --;
595 free((*classes)[n]);
596 }
597
598 free(*classes);
d23a857a 599 ippDelete(response);
600 return (0);
601 }
602
a9b97a87 603 *classes = temp;
604 temp[n] = strdup(attr->values[0].string.text);
d23a857a 605 n ++;
606 }
607
608 ippDelete(response);
609 }
8b06ca19 610 else
611 last_error = IPP_BAD_REQUEST;
d23a857a 612
613 return (n);
3b960317 614}
615
616
8431231f 617/*
618 * 'cupsGetDefault()' - Get the default printer or class.
619 */
620
063e1ac7 621const char * /* O - Default printer or NULL */
4a73831b 622cupsGetDefault(void)
623{
113aba7a 624 ipp_t *request, /* IPP Request */
625 *response; /* IPP Response */
626 ipp_attribute_t *attr; /* Current attribute */
627 cups_lang_t *language; /* Default language */
9aebebc3 628 const char *var; /* Environment variable */
ddcb19a4 629 static char def_printer[256];/* Default printer */
113aba7a 630
631
632 /*
633 * First see if the LPDEST or PRINTER environment variables are
9aebebc3 634 * set... However, if PRINTER is set to "lp", ignore it to work
635 * around a "feature" in most Linux distributions - the default
636 * user login scripts set PRINTER to "lp"...
113aba7a 637 */
638
9aebebc3 639 if ((var = getenv("LPDEST")) != NULL)
640 return (var);
641 else if ((var = getenv("PRINTER")) != NULL && strcmp(var, "lp") != 0)
642 return (var);
113aba7a 643
644 /*
645 * Try to connect to the server...
646 */
647
d23a857a 648 if (!cups_connect("default", NULL, NULL))
9aebebc3 649 {
650 last_error = IPP_SERVICE_UNAVAILABLE;
d23a857a 651 return (NULL);
9aebebc3 652 }
113aba7a 653
654 /*
655 * Build a CUPS_GET_DEFAULT request, which requires the following
656 * attributes:
657 *
658 * attributes-charset
659 * attributes-natural-language
660 */
661
662 request = ippNew();
663
664 request->request.op.operation_id = CUPS_GET_DEFAULT;
665 request->request.op.request_id = 1;
666
667 language = cupsLangDefault();
668
d23a857a 669 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
670 "attributes-charset", NULL, cupsLangEncoding(language));
113aba7a 671
d23a857a 672 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
673 "attributes-natural-language", NULL, language->language);
113aba7a 674
675 /*
676 * Do the request and get back a response...
677 */
678
8b06ca19 679 if ((response = cupsDoRequest(cups_server, request, "/")) != NULL)
113aba7a 680 {
8b06ca19 681 last_error = response->request.status.status_code;
682
113aba7a 683 if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL)
684 {
17438bf4 685 strlcpy(def_printer, attr->values[0].string.text, sizeof(def_printer));
113aba7a 686 ippDelete(response);
687 return (def_printer);
688 }
689
690 ippDelete(response);
691 }
8b06ca19 692 else
693 last_error = IPP_BAD_REQUEST;
113aba7a 694
695 return (NULL);
4a73831b 696}
697
698
d6baddaa 699/*
700 * 'cupsGetJobs()' - Get the jobs from the server.
701 */
702
703int /* O - Number of jobs */
704cupsGetJobs(cups_job_t **jobs, /* O - Job data */
705 const char *mydest, /* I - Only show jobs for dest? */
706 int myjobs, /* I - Only show my jobs? */
707 int completed) /* I - Only show completed jobs? */
708{
709 int n; /* Number of jobs */
710 ipp_t *request, /* IPP Request */
711 *response; /* IPP Response */
712 ipp_attribute_t *attr; /* Current attribute */
713 cups_lang_t *language; /* Default language */
714 cups_job_t *temp; /* Temporary pointer */
715 int id, /* job-id */
716 priority, /* job-priority */
717 size; /* job-k-octets */
718 ipp_jstate_t state; /* job-state */
719 time_t completed_time, /* time-at-completed */
720 creation_time, /* time-at-creation */
721 processing_time; /* time-at-processing */
722 const char *dest, /* job-printer-uri */
723 *format, /* document-format */
724 *title, /* job-name */
725 *user; /* job-originating-user-name */
726 char uri[HTTP_MAX_URI]; /* URI for jobs */
727 static const char *attrs[] = /* Requested attributes */
728 {
729 "job-id",
730 "job-priority",
731 "job-k-octets",
732 "job-state",
733 "time-at-completed",
734 "time-at-creation",
735 "time-at-processing",
736 "job-printer-uri",
737 "document-format",
738 "job-name",
739 "job-originating-user-name"
740 };
741
742
743 if (jobs == NULL)
744 {
745 last_error = IPP_INTERNAL_ERROR;
746 return (0);
747 }
748
749 /*
750 * Try to connect to the server...
751 */
752
753 if (!cups_connect("default", NULL, NULL))
754 {
755 last_error = IPP_SERVICE_UNAVAILABLE;
756 return (0);
757 }
758
759 /*
760 * Build an IPP_GET_JOBS request, which requires the following
761 * attributes:
762 *
763 * attributes-charset
764 * attributes-natural-language
765 * printer-uri
766 * requesting-user-name
767 * which-jobs
768 * my-jobs
769 * requested-attributes
770 */
771
772 request = ippNew();
773
774 request->request.op.operation_id = IPP_GET_JOBS;
775 request->request.op.request_id = 1;
776
777 language = cupsLangDefault();
778
779 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
780 "attributes-charset", NULL, cupsLangEncoding(language));
781
782 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
783 "attributes-natural-language", NULL, language->language);
784
785 if (mydest)
786 snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", mydest);
787 else
788 strcpy(uri, "ipp://localhost/jobs");
789
790 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
791 "printer-uri", NULL, uri);
792
793 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
794 "requesting-user-name", NULL, cupsUser());
795
796 if (myjobs)
797 ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
798
799 if (completed)
800 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
801 "which-jobs", NULL, "completed");
802
803 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
804 "requested-attributes", sizeof(attrs) / sizeof(attrs[0]),
805 NULL, attrs);
806
807 /*
808 * Do the request and get back a response...
809 */
810
811 n = 0;
812 *jobs = NULL;
813
814 if ((response = cupsDoRequest(cups_server, request, "/")) != NULL)
815 {
816 last_error = response->request.status.status_code;
817
818 for (attr = response->attrs; attr != NULL; attr = attr->next)
819 {
820 /*
821 * Skip leading attributes until we hit a job...
822 */
823
824 while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
825 attr = attr->next;
826
827 if (attr == NULL)
828 break;
829
830 /*
831 * Pull the needed attributes from this job...
832 */
833
834 id = 0;
835 size = 0;
836 priority = 50;
837 state = IPP_JOB_PENDING;
838 user = NULL;
839 dest = NULL;
840 format = NULL;
841 title = NULL;
842 creation_time = 0;
843 completed_time = 0;
844 processing_time = 0;
845
846 while (attr != NULL && attr->group_tag == IPP_TAG_JOB)
847 {
848 if (strcmp(attr->name, "job-id") == 0 &&
849 attr->value_tag == IPP_TAG_INTEGER)
850 id = attr->values[0].integer;
851 else if (strcmp(attr->name, "job-state") == 0 &&
852 attr->value_tag == IPP_TAG_ENUM)
853 state = (ipp_jstate_t)attr->values[0].integer;
854 else if (strcmp(attr->name, "job-priority") == 0 &&
855 attr->value_tag == IPP_TAG_INTEGER)
856 priority = attr->values[0].integer;
857 else if (strcmp(attr->name, "job-k-octets") == 0 &&
858 attr->value_tag == IPP_TAG_INTEGER)
859 size = attr->values[0].integer;
860 else if (strcmp(attr->name, "time-at-completed") == 0 &&
861 attr->value_tag == IPP_TAG_INTEGER)
862 completed_time = attr->values[0].integer;
863 else if (strcmp(attr->name, "time-at-creation") == 0 &&
864 attr->value_tag == IPP_TAG_INTEGER)
865 creation_time = attr->values[0].integer;
866 else if (strcmp(attr->name, "time-at-processing") == 0 &&
867 attr->value_tag == IPP_TAG_INTEGER)
868 processing_time = attr->values[0].integer;
869 else if (strcmp(attr->name, "job-printer-uri") == 0 &&
870 attr->value_tag == IPP_TAG_URI)
871 {
872 if ((dest = strrchr(attr->values[0].string.text, '/')) != NULL)
873 dest ++;
874 }
875 else if (strcmp(attr->name, "job-originating-user-name") == 0 &&
876 attr->value_tag == IPP_TAG_NAME)
877 user = attr->values[0].string.text;
878 else if (strcmp(attr->name, "document-format") == 0 &&
879 attr->value_tag == IPP_TAG_MIMETYPE)
880 format = attr->values[0].string.text;
881 else if (strcmp(attr->name, "job-name") == 0 &&
a55826ba 882 (attr->value_tag == IPP_TAG_TEXT ||
883 attr->value_tag == IPP_TAG_NAME))
d6baddaa 884 title = attr->values[0].string.text;
885
886 attr = attr->next;
887 }
888
889 /*
890 * See if we have everything needed...
891 */
892
a55826ba 893 if (dest == NULL || title == NULL || user == NULL || id == 0)
d6baddaa 894 {
895 if (attr == NULL)
896 break;
897 else
898 continue;
899 }
900
a55826ba 901 if (format == NULL)
902 format = "application/octet-stream";
903
d6baddaa 904 /*
905 * Allocate memory for the job...
906 */
907
908 if (n == 0)
909 temp = malloc(sizeof(cups_job_t));
910 else
911 temp = realloc(*jobs, sizeof(cups_job_t) * (n + 1));
912
913 if (temp == NULL)
914 {
915 /*
916 * Ran out of memory!
917 */
918
919 cupsFreeJobs(n, *jobs);
920 *jobs = NULL;
921
922 ippDelete(response);
923 return (0);
924 }
925
926 *jobs = temp;
927 temp += n;
928 n ++;
929
930 /*
931 * Copy the data over...
932 */
933
934 temp->dest = strdup(dest);
935 temp->user = strdup(user);
936 temp->format = strdup(format);
937 temp->title = strdup(title);
938 temp->id = id;
939 temp->priority = priority;
940 temp->state = state;
941 temp->size = size;
942 temp->completed_time = completed_time;
943 temp->creation_time = creation_time;
944 temp->processing_time = processing_time;
a55826ba 945
946 if (attr == NULL)
947 break;
d6baddaa 948 }
949
950 ippDelete(response);
951 }
952 else
953 last_error = IPP_BAD_REQUEST;
954
955 return (n);
956}
957
958
8431231f 959/*
960 * 'cupsGetPPD()' - Get the PPD file for a printer.
961 */
962
83e740a5 963const char * /* O - Filename for PPD file */
964cupsGetPPD(const char *name) /* I - Printer name */
3b960317 965{
ce314a94 966 int i; /* Looping var */
bc16fd64 967 ipp_t *request, /* IPP request */
968 *response; /* IPP response */
969 ipp_attribute_t *attr; /* Current attribute */
970 cups_lang_t *language; /* Local language */
1b5bf964 971 int fd; /* PPD file */
d23a857a 972 int bytes; /* Number of bytes read */
973 char buffer[8192]; /* Buffer for file */
974 char printer[HTTP_MAX_URI], /* Printer name */
bc16fd64 975 method[HTTP_MAX_URI], /* Method/scheme name */
976 username[HTTP_MAX_URI], /* Username:password */
d23a857a 977 hostname[HTTP_MAX_URI], /* Hostname */
978 resource[HTTP_MAX_URI]; /* Resource name */
bc16fd64 979 int port; /* Port number */
3095105a 980 const char *password; /* Password string */
83e740a5 981 char realm[HTTP_MAX_VALUE], /* realm="xyz" string */
982 nonce[HTTP_MAX_VALUE], /* nonce="xyz" string */
983 plain[255], /* Plaintext username:password */
d2e58bfa 984 encode[512]; /* Encoded username:password */
3095105a 985 http_status_t status; /* HTTP status from server */
3026be56 986 char prompt[1024]; /* Prompt string */
24bc843e 987 int digest_tries; /* Number of tries with Digest */
3095105a 988 static char filename[HTTP_MAX_URI]; /* Local filename */
ce314a94 989 static const char *requested_attrs[] =/* Requested attributes */
990 {
991 "printer-uri-supported",
992 "printer-type",
993 "member-uris"
994 };
d23a857a 995
996
0f6a2276 997 if (name == NULL)
998 {
999 last_error = IPP_INTERNAL_ERROR;
1000 return (NULL);
1001 }
1002
d23a857a 1003 /*
1004 * See if we can connect to the server...
1005 */
1006
1007 if (!cups_connect(name, printer, hostname))
9aebebc3 1008 {
1009 last_error = IPP_SERVICE_UNAVAILABLE;
d23a857a 1010 return (NULL);
9aebebc3 1011 }
d23a857a 1012
ce314a94 1013 /*
1014 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
1015 * attributes:
1016 *
1017 * attributes-charset
1018 * attributes-natural-language
1019 * printer-uri
1020 * requested-attributes
1021 */
1022
1023 request = ippNew();
1024
1025 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1026 request->request.op.request_id = 1;
bc16fd64 1027
ce314a94 1028 language = cupsLangDefault();
bc16fd64 1029
ce314a94 1030 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1031 "attributes-charset", NULL, cupsLangEncoding(language));
bc16fd64 1032
ce314a94 1033 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1034 "attributes-natural-language", NULL, language->language);
bc16fd64 1035
5e1a998c 1036 snprintf(buffer, sizeof(buffer), "ipp://localhost/printers/%s", printer);
ce314a94 1037 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1038 "printer-uri", NULL, buffer);
bc16fd64 1039
ce314a94 1040 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1041 "requested-attributes",
1042 sizeof(requested_attrs) / sizeof(requested_attrs[0]),
1043 NULL, requested_attrs);
bc16fd64 1044
ce314a94 1045 /*
1046 * Do the request and get back a response...
1047 */
bc16fd64 1048
ce314a94 1049 if ((response = cupsDoRequest(cups_server, request, "/")) != NULL)
1050 {
1051 last_error = response->request.status.status_code;
1052 printer[0] = '\0';
1053 hostname[0] = '\0';
bc16fd64 1054
ce314a94 1055 if ((attr = ippFindAttribute(response, "member-uris", IPP_TAG_URI)) != NULL)
bc16fd64 1056 {
ce314a94 1057 /*
1058 * Get the first actual server and printer name in the class...
1059 */
bc16fd64 1060
ce314a94 1061 for (i = 0; i < attr->num_values; i ++)
bc16fd64 1062 {
ce314a94 1063 httpSeparate(attr->values[0].string.text, method, username, hostname,
bc16fd64 1064 &port, resource);
ce314a94 1065 if (strncmp(resource, "/printers/", 10) == 0)
1066 {
1067 /*
1068 * Found a printer!
1069 */
bc16fd64 1070
17438bf4 1071 strlcpy(printer, resource + 10, sizeof(printer));
ce314a94 1072 break;
1073 }
bc16fd64 1074 }
ce314a94 1075 }
1076 else if ((attr = ippFindAttribute(response, "printer-uri-supported",
1077 IPP_TAG_URI)) != NULL)
1078 {
1079 /*
1080 * Get the actual server and printer names...
1081 */
bc16fd64 1082
ce314a94 1083 httpSeparate(attr->values[0].string.text, method, username, hostname,
1084 &port, resource);
17438bf4 1085 strlcpy(printer, strrchr(resource, '/') + 1, sizeof(printer));
bc16fd64 1086 }
1087
ce314a94 1088 ippDelete(response);
bc16fd64 1089
1090 /*
ce314a94 1091 * Remap local hostname to localhost...
bc16fd64 1092 */
1093
ce314a94 1094 gethostname(buffer, sizeof(buffer));
bc16fd64 1095
ce314a94 1096 if (strcasecmp(buffer, hostname) == 0)
1097 strcpy(hostname, "localhost");
1098 }
1099
1100 cupsLangFree(language);
1101
1102 if (!printer[0])
1103 return (NULL);
1104
1105 /*
1106 * Reconnect to the correct server as needed...
1107 */
1108
1109 if (strcasecmp(cups_server->hostname, hostname) != 0)
1110 {
1111 httpClose(cups_server);
1112
a1793153 1113 if ((cups_server = httpConnectEncrypt(hostname, ippPort(),
1114 cupsEncryption())) == NULL)
ce314a94 1115 {
1116 last_error = IPP_SERVICE_UNAVAILABLE;
1117 return (NULL);
bc16fd64 1118 }
1119 }
1120
d23a857a 1121 /*
082b40d2 1122 * Get a temp file...
d23a857a 1123 */
1124
1b5bf964 1125 if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
1126 {
1127 /*
1128 * Can't open file; close the server connection and return NULL...
1129 */
1130
1131 httpFlush(cups_server);
1132 httpClose(cups_server);
1133 cups_server = NULL;
1134 return (NULL);
1135 }
d23a857a 1136
1137 /*
e269c4f8 1138 * And send a request to the HTTP server...
d23a857a 1139 */
1140
04de52f8 1141 snprintf(resource, sizeof(resource), "/printers/%s.ppd", printer);
d23a857a 1142
24bc843e 1143 digest_tries = 0;
1144
3095105a 1145 do
d23a857a 1146 {
3095105a 1147 httpClearFields(cups_server);
1148 httpSetField(cups_server, HTTP_FIELD_HOST, hostname);
1149 httpSetField(cups_server, HTTP_FIELD_AUTHORIZATION, authstring);
1150
1151 if (httpGet(cups_server, resource))
1152 {
dbb05cda 1153 if (httpReconnect(cups_server))
1154 {
1155 status = HTTP_ERROR;
1156 break;
1157 }
1158 else
1159 {
1160 status = HTTP_UNAUTHORIZED;
1161 continue;
1162 }
3095105a 1163 }
1164
1165 while ((status = httpUpdate(cups_server)) == HTTP_CONTINUE);
1166
1167 if (status == HTTP_UNAUTHORIZED)
1168 {
1169 DEBUG_puts("cupsGetPPD: unauthorized...");
1170
1171 /*
1172 * Flush any error message...
1173 */
1174
1175 httpFlush(cups_server);
1176
d2122fde 1177 /*
1178 * See if we can do local authentication...
1179 */
1180
1181 if (cups_local_auth(cups_server))
1182 continue;
1183
1184 /*
24bc843e 1185 * See if we should retry the current digest password...
d2122fde 1186 */
1187
24bc843e 1188 if (strncmp(cups_server->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Basic", 5) == 0 ||
1189 digest_tries > 1 || !pwdstring[0])
3095105a 1190 {
1191 /*
24bc843e 1192 * Nope - get a password from the user...
3095105a 1193 */
1194
24bc843e 1195 snprintf(prompt, sizeof(prompt), "Password for %s on %s? ", cupsUser(),
1196 cups_server->hostname);
3095105a 1197
24bc843e 1198 if ((password = cupsGetPassword(prompt)) == NULL)
1199 break;
1200 if (!password[0])
1201 break;
83e740a5 1202
17438bf4 1203 strlcpy(pwdstring, password, sizeof(pwdstring));
83e740a5 1204
24bc843e 1205 digest_tries = 0;
1206 }
1207 else
1208 digest_tries ++;
83e740a5 1209
24bc843e 1210 /*
1211 * Got a password; encode it for the server...
1212 */
1213
1214 if (strncmp(cups_server->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Basic", 5) == 0)
1215 {
1216 /*
1217 * Basic authentication...
1218 */
1219
1220 snprintf(plain, sizeof(plain), "%s:%s", cupsUser(), pwdstring);
1221 httpEncode64(encode, plain);
1222 snprintf(authstring, sizeof(authstring), "Basic %s", encode);
3095105a 1223 }
1224 else
24bc843e 1225 {
1226 /*
1227 * Digest authentication...
1228 */
1229
1230 httpGetSubField(cups_server, HTTP_FIELD_WWW_AUTHENTICATE, "realm", realm);
1231 httpGetSubField(cups_server, HTTP_FIELD_WWW_AUTHENTICATE, "nonce", nonce);
1232
1233 httpMD5(cupsUser(), realm, pwdstring, encode);
1234 httpMD5Final(nonce, "GET", resource, encode);
1235 snprintf(authstring, sizeof(authstring),
1236 "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", "
1237 "response=\"%s\"", cupsUser(), realm, nonce, encode);
1238 }
1239
1240 continue;
3095105a 1241 }
24bc843e 1242#ifdef HAVE_LIBSSL
1243 else if (status == HTTP_UPGRADE_REQUIRED)
1244 {
1245 /*
1246 * Flush any error message...
1247 */
1248
1249 httpFlush(cups_server);
1250
1251 /*
1252 * Upgrade with encryption...
1253 */
1254
1255 httpEncryption(cups_server, HTTP_ENCRYPT_REQUIRED);
1256
1257 /*
1258 * Try again, this time with encryption enabled...
1259 */
1260
1261 continue;
1262 }
1263#endif /* HAVE_LIBSSL */
d23a857a 1264 }
4c6f986f 1265 while (status == HTTP_UNAUTHORIZED || status == HTTP_UPGRADE_REQUIRED);
d23a857a 1266
1267 /*
1b5bf964 1268 * See if we actually got the file or an error...
d23a857a 1269 */
1270
1b5bf964 1271 if (status != HTTP_OK)
d23a857a 1272 {
1b5bf964 1273 unlink(filename);
bc16fd64 1274 httpFlush(cups_server);
d23a857a 1275 httpClose(cups_server);
1276 cups_server = NULL;
1277 return (NULL);
1278 }
1279
1b5bf964 1280 /*
1281 * OK, we need to copy the file...
1282 */
1283
d23a857a 1284 while ((bytes = httpRead(cups_server, buffer, sizeof(buffer))) > 0)
1b5bf964 1285 write(fd, buffer, bytes);
d23a857a 1286
1b5bf964 1287 close(fd);
d23a857a 1288
1289 return (filename);
3b960317 1290}
1291
1292
8431231f 1293/*
1294 * 'cupsGetPrinters()' - Get a list of printers.
1295 */
1296
d23a857a 1297int /* O - Number of printers */
1298cupsGetPrinters(char ***printers) /* O - Printers */
3b960317 1299{
d23a857a 1300 int n; /* Number of printers */
1301 ipp_t *request, /* IPP Request */
1302 *response; /* IPP Response */
1303 ipp_attribute_t *attr; /* Current attribute */
1304 cups_lang_t *language; /* Default language */
a9b97a87 1305 char **temp; /* Temporary pointer */
d23a857a 1306
1307
0f6a2276 1308 if (printers == NULL)
1309 {
1310 last_error = IPP_INTERNAL_ERROR;
1311 return (0);
1312 }
1313
d23a857a 1314 /*
1315 * Try to connect to the server...
1316 */
1317
1318 if (!cups_connect("default", NULL, NULL))
9aebebc3 1319 {
1320 last_error = IPP_SERVICE_UNAVAILABLE;
2bffb563 1321 return (0);
9aebebc3 1322 }
d23a857a 1323
1324 /*
1325 * Build a CUPS_GET_PRINTERS request, which requires the following
1326 * attributes:
1327 *
1328 * attributes-charset
1329 * attributes-natural-language
27d555e8 1330 * requested-attributes
d23a857a 1331 */
1332
1333 request = ippNew();
1334
1335 request->request.op.operation_id = CUPS_GET_PRINTERS;
1336 request->request.op.request_id = 1;
1337
1338 language = cupsLangDefault();
1339
1340 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
a9b97a87 1341 "attributes-charset", NULL, cupsLangEncoding(language));
d23a857a 1342
1343 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
a9b97a87 1344 "attributes-natural-language", NULL, language->language);
d23a857a 1345
27d555e8 1346 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1347 "requested-attributes", NULL, "printer-name");
1348
d23a857a 1349 /*
1350 * Do the request and get back a response...
1351 */
1352
1353 n = 0;
1354 *printers = NULL;
1355
a9b97a87 1356 if ((response = cupsDoRequest(cups_server, request, "/")) != NULL)
d23a857a 1357 {
8b06ca19 1358 last_error = response->request.status.status_code;
1359
d23a857a 1360 for (attr = response->attrs; attr != NULL; attr = attr->next)
fbc6b634 1361 if (attr->name != NULL &&
1362 strcasecmp(attr->name, "printer-name") == 0 &&
d23a857a 1363 attr->value_tag == IPP_TAG_NAME)
1364 {
1365 if (n == 0)
a9b97a87 1366 temp = malloc(sizeof(char *));
d23a857a 1367 else
a9b97a87 1368 temp = realloc(*printers, sizeof(char *) * (n + 1));
d23a857a 1369
a9b97a87 1370 if (temp == NULL)
d23a857a 1371 {
a9b97a87 1372 /*
1373 * Ran out of memory!
1374 */
1375
1376 while (n > 0)
1377 {
1378 n --;
1379 free((*printers)[n]);
1380 }
1381
1382 free(*printers);
d23a857a 1383 ippDelete(response);
1384 return (0);
1385 }
1386
a9b97a87 1387 *printers = temp;
1388 temp[n] = strdup(attr->values[0].string.text);
d23a857a 1389 n ++;
1390 }
1391
1392 ippDelete(response);
1393 }
8b06ca19 1394 else
1395 last_error = IPP_BAD_REQUEST;
d23a857a 1396
1397 return (n);
3b960317 1398}
1399
1400
8b06ca19 1401/*
1402 * 'cupsLastError()' - Return the last IPP error that occurred.
1403 */
1404
1405ipp_status_t /* O - IPP error code */
1406cupsLastError(void)
1407{
1408 return (last_error);
1409}
1410
1411
4a73831b 1412/*
1413 * 'cupsPrintFile()' - Print a file to a printer or class.
1414 */
1415
1416int /* O - Job ID */
063e1ac7 1417cupsPrintFile(const char *name, /* I - Printer or class name */
1418 const char *filename, /* I - File to print */
1419 const char *title, /* I - Title of job */
4a73831b 1420 int num_options,/* I - Number of options */
1421 cups_option_t *options) /* I - Options */
501b59e2 1422{
183914a3 1423 DEBUG_printf(("cupsPrintFile(\'%s\', \'%s\', %d, %p)\n",
880dc0ce 1424 name, filename, num_options, options));
501b59e2 1425
1426 return (cupsPrintFiles(name, 1, &filename, title, num_options, options));
1427}
1428
1429
1430/*
1431 * 'cupsPrintFiles()' - Print one or more files to a printer or class.
1432 */
1433
1434int /* O - Job ID */
1435cupsPrintFiles(const char *name, /* I - Printer or class name */
1436 int num_files, /* I - Number of files */
1437 const char **files, /* I - File(s) to print */
1438 const char *title, /* I - Title of job */
1439 int num_options,/* I - Number of options */
1440 cups_option_t *options) /* I - Options */
3b960317 1441{
d23a857a 1442 int i; /* Looping var */
501b59e2 1443 const char *val; /* Pointer to option value */
d23a857a 1444 ipp_t *request; /* IPP request */
1445 ipp_t *response; /* IPP response */
1446 ipp_attribute_t *attr; /* IPP job-id attribute */
1447 char hostname[HTTP_MAX_URI], /* Hostname */
1448 printer[HTTP_MAX_URI], /* Printer or class name */
1449 uri[HTTP_MAX_URI]; /* Printer URI */
1450 cups_lang_t *language; /* Language to use */
d23a857a 1451 int jobid; /* New job ID */
1452
4a73831b 1453
183914a3 1454 DEBUG_printf(("cupsPrintFiles(\'%s\', %d, %p, %d, %p)\n",
880dc0ce 1455 name, num_files, files, num_options, options));
4a73831b 1456
501b59e2 1457 if (name == NULL || num_files < 1 || files == NULL)
4a73831b 1458 return (0);
1459
4a73831b 1460 /*
1461 * Setup a connection and request data...
1462 */
1463
d23a857a 1464 if (!cups_connect(name, printer, hostname))
1465 {
1466 DEBUG_printf(("cupsPrintFile: Unable to open connection - %s.\n",
1467 strerror(errno)));
9aebebc3 1468 last_error = IPP_SERVICE_UNAVAILABLE;
d23a857a 1469 return (0);
1470 }
4a73831b 1471
501b59e2 1472 language = cupsLangDefault();
1473
4a73831b 1474 /*
1475 * Build a standard CUPS URI for the printer and fill the standard IPP
1476 * attributes...
1477 */
1478
c7c24dd7 1479 if ((request = ippNew()) == NULL)
1480 return (0);
1481
501b59e2 1482 request->request.op.operation_id = num_files == 1 ? IPP_PRINT_JOB :
1483 IPP_CREATE_JOB;
4a73831b 1484 request->request.op.request_id = 1;
1485
04de52f8 1486 snprintf(uri, sizeof(uri), "ipp://%s:%d/printers/%s", hostname, ippPort(), printer);
4a73831b 1487
d23a857a 1488 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1489 "attributes-charset", NULL, cupsLangEncoding(language));
4a73831b 1490
d23a857a 1491 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1492 "attributes-natural-language", NULL,
1493 language != NULL ? language->language : "C");
4a73831b 1494
d23a857a 1495 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1496 NULL, uri);
4a73831b 1497
6d0582d2 1498 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
ac4c1450 1499 NULL, cupsUser());
4a73831b 1500
d23a857a 1501 if (title)
6d0582d2 1502 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, title);
d23a857a 1503
4a73831b 1504 /*
183914a3 1505 * Then add all options...
4a73831b 1506 */
1507
183914a3 1508 cupsEncodeOptions(request, num_options, options);
4a73831b 1509
1510 /*
501b59e2 1511 * Do the request...
4a73831b 1512 */
1513
04de52f8 1514 snprintf(uri, sizeof(uri), "/printers/%s", printer);
4a73831b 1515
501b59e2 1516 if (num_files == 1)
1517 response = cupsDoFileRequest(cups_server, request, uri, *files);
1518 else
1519 response = cupsDoRequest(cups_server, request, uri);
1520
1521 if (response == NULL)
3270670b 1522 jobid = 0;
1523 else if (response->request.status.status_code > IPP_OK_CONFLICT)
4a73831b 1524 {
3270670b 1525 DEBUG_printf(("IPP response code was 0x%x!\n",
1526 response->request.status.status_code));
4a73831b 1527 jobid = 0;
1528 }
3270670b 1529 else if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL)
4a73831b 1530 {
3270670b 1531 DEBUG_puts("No job ID!");
4a73831b 1532 jobid = 0;
1533 }
1534 else
3270670b 1535 jobid = attr->values[0].integer;
4a73831b 1536
3270670b 1537 if (response != NULL)
1538 ippDelete(response);
4a73831b 1539
501b59e2 1540 /*
1541 * Handle multiple file jobs if the create-job operation worked...
1542 */
1543
1544 if (jobid > 0 && num_files > 1)
1545 for (i = 0; i < num_files; i ++)
1546 {
1547 /*
1548 * Build a standard CUPS URI for the job and fill the standard IPP
1549 * attributes...
1550 */
1551
c7c24dd7 1552 if ((request = ippNew()) == NULL)
1553 return (0);
1554
501b59e2 1555 request->request.op.operation_id = IPP_SEND_DOCUMENT;
1556 request->request.op.request_id = 1;
1557
04de52f8 1558 snprintf(uri, sizeof(uri), "ipp://%s:%d/jobs/%d", hostname, ippPort(),
501b59e2 1559 jobid);
1560
1561 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1562 "attributes-charset", NULL, cupsLangEncoding(language));
1563
1564 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1565 "attributes-natural-language", NULL,
1566 language != NULL ? language->language : "C");
1567
1568 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
1569 NULL, uri);
1570
1571 /*
1572 * Handle raw print files...
1573 */
1574
1575 if (cupsGetOption("raw", num_options, options))
1576 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
1577 NULL, "application/vnd.cups-raw");
1578 else if ((val = cupsGetOption("document-format", num_options, options)) != NULL)
1579 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
1580 NULL, val);
1581 else
1582 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
1583 NULL, "application/octet-stream");
1584
1585 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1586 NULL, cupsUser());
1587
1588 /*
1589 * Is this the last document?
1590 */
1591
1592 if (i == (num_files - 1))
1593 ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
1594
1595 /*
1596 * Send the file...
1597 */
1598
04de52f8 1599 snprintf(uri, sizeof(uri), "/printers/%s", printer);
501b59e2 1600
1601 if ((response = cupsDoFileRequest(cups_server, request, uri,
1602 files[i])) != NULL)
1603 ippDelete(response);
1604 }
1605
4a73831b 1606 return (jobid);
3b960317 1607}
1608
1609
1610/*
d23a857a 1611 * 'cups_connect()' - Connect to the specified host...
1612 */
1613
063e1ac7 1614static char * /* I - Printer name or NULL */
1615cups_connect(const char *name, /* I - Destination (printer[@host]) */
970017a4 1616 char *printer, /* O - Printer name [HTTP_MAX_URI] */
1617 char *hostname) /* O - Hostname [HTTP_MAX_URI] */
d23a857a 1618{
1b5bf964 1619 char hostbuf[HTTP_MAX_URI]; /* Name of host */
d23a857a 1620 static char printerbuf[HTTP_MAX_URI];
1b5bf964 1621 /* Name of printer or class */
d23a857a 1622
1623
139b5b53 1624 DEBUG_printf(("cups_connect(\"%s\", %p, %p)\n", name, printer, hostname));
1625
d23a857a 1626 if (name == NULL)
8b06ca19 1627 {
1628 last_error = IPP_BAD_REQUEST;
d23a857a 1629 return (NULL);
8b06ca19 1630 }
d23a857a 1631
04d61d56 1632 if (sscanf(name, "%1023[^@]@%1023s", printerbuf, hostbuf) == 1)
17438bf4 1633 strlcpy(hostbuf, cupsServer(), sizeof(hostbuf));
d23a857a 1634
1635 if (hostname != NULL)
17438bf4 1636 strlcpy(hostname, hostbuf, HTTP_MAX_URI);
d23a857a 1637 else
1638 hostname = hostbuf;
1639
1640 if (printer != NULL)
17438bf4 1641 strlcpy(printer, printerbuf, HTTP_MAX_URI);
d23a857a 1642 else
1643 printer = printerbuf;
1644
1645 if (cups_server != NULL)
1646 {
1647 if (strcasecmp(cups_server->hostname, hostname) == 0)
1648 return (printer);
1649
1650 httpClose(cups_server);
1651 }
1652
139b5b53 1653 DEBUG_printf(("connecting to %s on port %d...\n", hostname, ippPort()));
1654
a1793153 1655 if ((cups_server = httpConnectEncrypt(hostname, ippPort(),
1656 cupsEncryption())) == NULL)
8b06ca19 1657 {
1658 last_error = IPP_SERVICE_UNAVAILABLE;
d23a857a 1659 return (NULL);
8b06ca19 1660 }
d23a857a 1661 else
1662 return (printer);
1663}
1664
1665
1666/*
d2122fde 1667 * 'cups_local_auth()' - Get the local authorization certificate if
1668 * available/applicable...
1669 */
1670
1671static int /* O - 1 if available, 0 if not */
1672cups_local_auth(http_t *http) /* I - Connection */
1673{
1674#if defined(WIN32) || defined(__EMX__)
1675 /*
1676 * Currently WIN32 and OS-2 do not support the CUPS server...
1677 */
1678
1679 return (0);
1680#else
a6988fb1 1681 int pid; /* Current process ID */
1682 FILE *fp; /* Certificate file */
1683 char filename[1024], /* Certificate filename */
1684 certificate[33];/* Certificate string */
1685 const char *root; /* Server root directory */
d2122fde 1686
1687
1688 /*
1689 * See if we are accessing localhost...
1690 */
1691
1692 if (ntohl(http->hostaddr.sin_addr.s_addr) != 0x7f000001 &&
1693 strcasecmp(http->hostname, "localhost") != 0)
1694 return (0);
1695
1696 /*
1697 * Try opening a certificate file for this PID. If that fails,
1698 * try the root certificate...
1699 */
1700
a6988fb1 1701 if ((root = getenv("CUPS_SERVERROOT")) == NULL)
1702 root = CUPS_SERVERROOT;
1703
d2122fde 1704 pid = getpid();
a6988fb1 1705 snprintf(filename, sizeof(filename), "%s/certs/%d", root, pid);
d2122fde 1706 if ((fp = fopen(filename, "r")) == NULL && pid > 0)
a6988fb1 1707 {
1708 snprintf(filename, sizeof(filename), "%s/certs/0", root);
1709 fp = fopen(filename, "r");
1710 }
d2122fde 1711
1712 if (fp == NULL)
1713 return (0);
1714
1715 /*
1716 * Read the certificate from the file...
1717 */
1718
1719 fgets(certificate, sizeof(certificate), fp);
1720 fclose(fp);
1721
1722 /*
1723 * Set the authorization string and return...
1724 */
1725
a6988fb1 1726 snprintf(authstring, sizeof(authstring), "Local %s", certificate);
d2122fde 1727
1728 return (1);
1729#endif /* WIN32 || __EMX__ */
1730}
1731
1732
1733/*
17438bf4 1734 * End of "$Id: util.c,v 1.94 2002/05/16 13:44:55 mike Exp $".
3b960317 1735 */