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