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