]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/util.c
Load cups into easysw/current.
[thirdparty/cups.git] / cups / util.c
1 /*
2 * "$Id: util.c 4987 2006-01-26 00:25:21Z mike $"
3 *
4 * Printing utilities for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products.
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
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * cupsCancelJob() - Cancel a print job on the default server.
29 * cupsDoFileRequest() - Do an IPP request.
30 * cupsFreeJobs() - Free memory used by job data.
31 * cupsGetClasses() - Get a list of printer classes from the default
32 * server.
33 * cupsGetDefault() - Get the default printer or class from the default
34 * server.
35 * cupsGetDefault2() - Get the default printer or class from the
36 * specified server.
37 * cupsGetJobs() - Get the jobs from the default server.
38 * cupsGetJobs2() - Get the jobs from the specified server.
39 * cupsGetPPD() - Get the PPD file for a printer on the default
40 * server.
41 * cupsGetPPD2() - Get the PPD file for a printer on the specified
42 * server.
43 * cupsGetPrinters() - Get a list of printers from the default server.
44 * cupsLastError() - Return the last IPP status code.
45 * cupsLastErrorString() - Return the last IPP status-message.
46 * cupsPrintFile() - Print a file to a printer or class on the default
47 * server.
48 * cupsPrintFile2() - Print a file to a printer or class on the
49 * specified server.
50 * cupsPrintFiles() - Print one or more files to a printer or class on
51 * the default server.
52 * cupsPrintFiles2() - Print one or more files to a printer or class on
53 * the specified server.
54 * cups_connect() - Connect to the specified host...
55 * cups_get_printer_uri() - Get the printer-uri-supported attribute for the
56 * first printer in a class.
57 * cups_set_error() - Set the last IPP status code and status-message.
58 */
59
60 /*
61 * Include necessary headers...
62 */
63
64 #include "globals.h"
65 #include "debug.h"
66 #include <stdlib.h>
67 #include <errno.h>
68 #include <fcntl.h>
69 #include <sys/stat.h>
70 #if defined(WIN32) || defined(__EMX__)
71 # include <io.h>
72 #else
73 # include <unistd.h>
74 #endif /* WIN32 || __EMX__ */
75
76
77 /*
78 * Local functions...
79 */
80
81 static char *cups_connect(const char *name, char *printer, char *hostname);
82 static int cups_get_printer_uri(http_t *http, const char *name,
83 char *host, int hostsize, int *port,
84 char *resource, int resourcesize,
85 int depth);
86 static void cups_set_error(ipp_status_t status, const char *message);
87
88
89 /*
90 * 'cupsCancelJob()' - Cancel a print job on the default server.
91 *
92 * Use the cupsLastError() and cupsLastErrorString() functions to get
93 * the cause of any failure.
94 */
95
96 int /* O - 1 on success, 0 on failure */
97 cupsCancelJob(const char *name, /* I - Name of printer or class */
98 int job) /* I - Job ID */
99 {
100 char printer[HTTP_MAX_URI], /* Printer name */
101 hostname[HTTP_MAX_URI], /* Hostname */
102 uri[HTTP_MAX_URI]; /* Printer URI */
103 ipp_t *request, /* IPP request */
104 *response; /* IPP response */
105 cups_lang_t *language; /* Language info */
106 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
107
108
109 /*
110 * See if we can connect to the server...
111 */
112
113 if (!cups_connect(name, printer, hostname))
114 {
115 DEBUG_puts("Unable to connect to server!");
116
117 return (0);
118 }
119
120 /*
121 * Create a printer URI...
122 */
123
124 if (httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
125 "/printers/%s", printer) != HTTP_URI_OK)
126 {
127 cups_set_error(IPP_INTERNAL_ERROR, NULL);
128
129 return (0);
130 }
131
132 /*
133 * Build an IPP_CANCEL_JOB request, which requires the following
134 * attributes:
135 *
136 * attributes-charset
137 * attributes-natural-language
138 * printer-uri
139 * job-id
140 * [requesting-user-name]
141 */
142
143 request = ippNew();
144
145 request->request.op.operation_id = IPP_CANCEL_JOB;
146 request->request.op.request_id = 1;
147
148 language = cupsLangDefault();
149
150 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
151 "attributes-charset", NULL, cupsLangEncoding(language));
152
153 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
154 "attributes-natural-language", NULL,
155 language != NULL ? language->language : "C");
156
157 cupsLangFree(language);
158
159 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
160 NULL, uri);
161
162 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job);
163
164 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
165 NULL, cupsUser());
166
167 /*
168 * Do the request...
169 */
170
171 if ((response = cupsDoRequest(cg->http, request, "/jobs/")) != NULL)
172 ippDelete(response);
173
174 return (cg->last_error < IPP_REDIRECTION_OTHER_SITE);
175 }
176
177
178 /*
179 * 'cupsDoFileRequest()' - Do an IPP request.
180 *
181 * This function sends any IPP request to the specified server, retrying
182 * and authenticating as necessary.
183 */
184
185 ipp_t * /* O - Response data */
186 cupsDoFileRequest(http_t *http, /* I - HTTP connection to server */
187 ipp_t *request, /* I - IPP request */
188 const char *resource, /* I - HTTP resource for POST */
189 const char *filename) /* I - File to send or NULL for none */
190 {
191 ipp_t *response; /* IPP response data */
192 size_t length; /* Content-Length value */
193 http_status_t status; /* Status of HTTP request */
194 FILE *file; /* File to send */
195 struct stat fileinfo; /* File information */
196 int bytes; /* Number of bytes read/written */
197 char buffer[65536]; /* Output buffer */
198
199
200 DEBUG_printf(("cupsDoFileRequest(%p, %p, \'%s\', \'%s\')\n",
201 http, request, resource ? resource : "(null)",
202 filename ? filename : "(null)"));
203
204 if (http == NULL || request == NULL || resource == NULL)
205 {
206 if (request != NULL)
207 ippDelete(request);
208
209 cups_set_error(IPP_INTERNAL_ERROR, NULL);
210
211 return (NULL);
212 }
213
214 /*
215 * See if we have a file to send...
216 */
217
218 if (filename != NULL)
219 {
220 if (stat(filename, &fileinfo))
221 {
222 /*
223 * Can't get file information!
224 */
225
226 cups_set_error(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
227 strerror(errno));
228
229 ippDelete(request);
230
231 return (NULL);
232 }
233
234 #ifdef WIN32
235 if (fileinfo.st_mode & _S_IFDIR)
236 #else
237 if (S_ISDIR(fileinfo.st_mode))
238 #endif /* WIN32 */
239 {
240 /*
241 * Can't send a directory...
242 */
243
244 ippDelete(request);
245
246 cups_set_error(IPP_NOT_POSSIBLE, NULL);
247
248 return (NULL);
249 }
250
251 if ((file = fopen(filename, "rb")) == NULL)
252 {
253 /*
254 * Can't open file!
255 */
256
257 cups_set_error(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
258 strerror(errno));
259
260 ippDelete(request);
261
262 return (NULL);
263 }
264 }
265 else
266 file = NULL;
267
268 /*
269 * Loop until we can send the request without authorization problems.
270 */
271
272 response = NULL;
273 status = HTTP_ERROR;
274
275 while (response == NULL)
276 {
277 DEBUG_puts("cupsDoFileRequest: setup...");
278
279 /*
280 * Setup the HTTP variables needed...
281 */
282
283 length = ippLength(request);
284 if (filename)
285 length += fileinfo.st_size;
286
287 httpClearFields(http);
288 httpSetLength(http, length);
289 httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
290 httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
291
292 DEBUG_printf(("cupsDoFileRequest: authstring=\"%s\"\n", http->authstring));
293
294 /*
295 * Try the request...
296 */
297
298 DEBUG_puts("cupsDoFileRequest: post...");
299
300 if (httpPost(http, resource))
301 {
302 if (httpReconnect(http))
303 {
304 status = HTTP_ERROR;
305 break;
306 }
307 else
308 continue;
309 }
310
311 /*
312 * Send the IPP data and wait for the response...
313 */
314
315 DEBUG_puts("cupsDoFileRequest: ipp write...");
316
317 request->state = IPP_IDLE;
318 status = HTTP_CONTINUE;
319
320 if (ippWrite(http, request) != IPP_ERROR)
321 if (filename != NULL)
322 {
323 DEBUG_puts("cupsDoFileRequest: file write...");
324
325 /*
326 * Send the file...
327 */
328
329 rewind(file);
330
331 while ((bytes = (int)fread(buffer, 1, sizeof(buffer), file)) > 0)
332 {
333 if (httpCheck(http))
334 {
335 if ((status = httpUpdate(http)) != HTTP_CONTINUE)
336 break;
337 }
338
339 if (httpWrite(http, buffer, bytes) < bytes)
340 break;
341 }
342 }
343
344 /*
345 * Get the server's return status...
346 */
347
348 DEBUG_puts("cupsDoFileRequest: update...");
349
350 while (status == HTTP_CONTINUE)
351 status = httpUpdate(http);
352
353 DEBUG_printf(("cupsDoFileRequest: status = %d\n", status));
354
355 if (status == HTTP_UNAUTHORIZED)
356 {
357 DEBUG_puts("cupsDoFileRequest: unauthorized...");
358
359 /*
360 * Flush any error message...
361 */
362
363 httpFlush(http);
364
365 /*
366 * See if we can do authentication...
367 */
368
369 if (cupsDoAuthentication(http, "POST", resource))
370 break;
371
372 if (httpReconnect(http))
373 {
374 status = HTTP_ERROR;
375 break;
376 }
377
378 continue;
379 }
380 else if (status == HTTP_ERROR)
381 {
382 #ifdef WIN32
383 if (http->error != WSAENETDOWN && http->error != WSAENETUNREACH)
384 #else
385 if (http->error != ENETDOWN && http->error != ENETUNREACH)
386 #endif /* WIN32 */
387 continue;
388 else
389 break;
390 }
391 #ifdef HAVE_SSL
392 else if (status == HTTP_UPGRADE_REQUIRED)
393 {
394 /* Flush any error message... */
395 httpFlush(http);
396
397 /* Reconnect... */
398 if (httpReconnect(http))
399 {
400 status = HTTP_ERROR;
401 break;
402 }
403
404 /* Upgrade with encryption... */
405 httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
406
407 /* Try again, this time with encryption enabled... */
408 continue;
409 }
410 #endif /* HAVE_SSL */
411 else if (status != HTTP_OK)
412 {
413 DEBUG_printf(("cupsDoFileRequest: error %d...\n", status));
414
415 /*
416 * Flush any error message...
417 */
418
419 httpFlush(http);
420 break;
421 }
422 else
423 {
424 /*
425 * Read the response...
426 */
427
428 DEBUG_puts("cupsDoFileRequest: response...");
429
430 response = ippNew();
431
432 if (ippRead(http, response) == IPP_ERROR)
433 {
434 /*
435 * Delete the response...
436 */
437
438 DEBUG_puts("IPP read error!");
439 ippDelete(response);
440 response = NULL;
441
442 cups_set_error(IPP_SERVICE_UNAVAILABLE, strerror(errno));
443
444 break;
445 }
446 }
447 }
448
449 /*
450 * Close the file if needed...
451 */
452
453 if (filename != NULL)
454 fclose(file);
455
456 /*
457 * Flush any remaining data...
458 */
459
460 httpFlush(http);
461
462 /*
463 * Delete the original request and return the response...
464 */
465
466 ippDelete(request);
467
468 if (response)
469 {
470 ipp_attribute_t *attr; /* status-message attribute */
471
472
473 attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT);
474
475 cups_set_error(response->request.status.status_code,
476 attr ? attr->values[0].string.text :
477 ippErrorString(response->request.status.status_code));
478 }
479 else if (status != HTTP_OK)
480 {
481 switch (status)
482 {
483 case HTTP_NOT_FOUND :
484 cups_set_error(IPP_NOT_FOUND, httpStatus(status));
485 break;
486
487 case HTTP_UNAUTHORIZED :
488 cups_set_error(IPP_NOT_AUTHORIZED, httpStatus(status));
489 break;
490
491 case HTTP_FORBIDDEN :
492 cups_set_error(IPP_FORBIDDEN, httpStatus(status));
493 break;
494
495 case HTTP_BAD_REQUEST :
496 cups_set_error(IPP_BAD_REQUEST, httpStatus(status));
497 break;
498
499 case HTTP_REQUEST_TOO_LARGE :
500 cups_set_error(IPP_REQUEST_VALUE, httpStatus(status));
501 break;
502
503 case HTTP_NOT_IMPLEMENTED :
504 cups_set_error(IPP_OPERATION_NOT_SUPPORTED, httpStatus(status));
505 break;
506
507 case HTTP_NOT_SUPPORTED :
508 cups_set_error(IPP_VERSION_NOT_SUPPORTED, httpStatus(status));
509 break;
510
511 default :
512 DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n",
513 status));
514 cups_set_error(IPP_SERVICE_UNAVAILABLE, httpStatus(status));
515 break;
516 }
517 }
518
519 return (response);
520 }
521
522
523 /*
524 * 'cupsFreeJobs()' - Free memory used by job data.
525 */
526
527 void
528 cupsFreeJobs(int num_jobs, /* I - Number of jobs */
529 cups_job_t *jobs) /* I - Jobs */
530 {
531 int i; /* Looping var */
532
533
534 if (num_jobs <= 0 || jobs == NULL)
535 return;
536
537 for (i = 0; i < num_jobs; i ++)
538 {
539 free(jobs[i].dest);
540 free(jobs[i].user);
541 free(jobs[i].format);
542 free(jobs[i].title);
543 }
544
545 free(jobs);
546 }
547
548
549 /*
550 * 'cupsGetClasses()' - Get a list of printer classes from the default server.
551 *
552 * This function is deprecated - use cupsGetDests() instead.
553 *
554 * @deprecated@
555 */
556
557 int /* O - Number of classes */
558 cupsGetClasses(char ***classes) /* O - Classes */
559 {
560 int n; /* Number of classes */
561 ipp_t *request, /* IPP Request */
562 *response; /* IPP Response */
563 ipp_attribute_t *attr; /* Current attribute */
564 cups_lang_t *language; /* Default language */
565 char **temp; /* Temporary pointer */
566 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
567
568
569 if (classes == NULL)
570 {
571 cups_set_error(IPP_INTERNAL_ERROR, NULL);
572
573 return (0);
574 }
575
576 /*
577 * Try to connect to the server...
578 */
579
580 if (!cups_connect("default", NULL, NULL))
581 {
582 DEBUG_puts("Unable to connect to server!");
583
584 return (0);
585 }
586
587 /*
588 * Build a CUPS_GET_CLASSES request, which requires the following
589 * attributes:
590 *
591 * attributes-charset
592 * attributes-natural-language
593 * requested-attributes
594 */
595
596 request = ippNew();
597
598 request->request.op.operation_id = CUPS_GET_CLASSES;
599 request->request.op.request_id = 1;
600
601 language = cupsLangDefault();
602
603 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
604 "attributes-charset", NULL, cupsLangEncoding(language));
605
606 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
607 "attributes-natural-language", NULL, language->language);
608
609 cupsLangFree(language);
610
611 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
612 "requested-attributes", NULL, "printer-name");
613
614 /*
615 * Do the request and get back a response...
616 */
617
618 n = 0;
619 *classes = NULL;
620
621 if ((response = cupsDoRequest(cg->http, request, "/")) != NULL)
622 {
623 for (attr = response->attrs; attr != NULL; attr = attr->next)
624 if (attr->name != NULL &&
625 strcasecmp(attr->name, "printer-name") == 0 &&
626 attr->value_tag == IPP_TAG_NAME)
627 {
628 if (n == 0)
629 temp = malloc(sizeof(char *));
630 else
631 temp = realloc(*classes, sizeof(char *) * (n + 1));
632
633 if (temp == NULL)
634 {
635 /*
636 * Ran out of memory!
637 */
638
639 while (n > 0)
640 {
641 n --;
642 free((*classes)[n]);
643 }
644
645 free(*classes);
646 ippDelete(response);
647 return (0);
648 }
649
650 *classes = temp;
651 temp[n] = strdup(attr->values[0].string.text);
652 n ++;
653 }
654
655 ippDelete(response);
656 }
657
658 return (n);
659 }
660
661
662 /*
663 * 'cupsGetDefault()' - Get the default printer or class for the default server.
664 *
665 * This function returns the default printer or class as defined by
666 * the LPDEST or PRINTER environment variables. If these environment
667 * variables are not set, the server default destination is returned.
668 * Applications should use the cupsGetDests() and cupsGetDest() functions
669 * to get the user-defined default printer, as this function does not
670 * support the lpoptions-defined default printer.
671 */
672
673 const char * /* O - Default printer or NULL */
674 cupsGetDefault(void)
675 {
676 const char *var; /* Environment variable */
677 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
678
679
680 /*
681 * First see if the LPDEST or PRINTER environment variables are
682 * set... However, if PRINTER is set to "lp", ignore it to work
683 * around a "feature" in most Linux distributions - the default
684 * user login scripts set PRINTER to "lp"...
685 */
686
687 if ((var = getenv("LPDEST")) != NULL)
688 return (var);
689 else if ((var = getenv("PRINTER")) != NULL && strcmp(var, "lp") != 0)
690 return (var);
691
692 /*
693 * Try to connect to the server...
694 */
695
696 if (!cups_connect("default", NULL, NULL))
697 {
698 DEBUG_puts("Unable to connect to server!");
699
700 return (NULL);
701 }
702
703 /*
704 * Return the default printer...
705 */
706
707 return (cupsGetDefault2(cg->http));
708 }
709
710
711 /*
712 * 'cupsGetDefault2()' - Get the default printer or class for the specified server.
713 *
714 * This function returns the default printer or class as defined by
715 * the LPDEST or PRINTER environment variables. If these environment
716 * variables are not set, the server default destination is returned.
717 * Applications should use the cupsGetDests() and cupsGetDest() functions
718 * to get the user-defined default printer, as this function does not
719 * support the lpoptions-defined default printer.
720 *
721 * @since CUPS 1.1.21@
722 */
723
724 const char * /* O - Default printer or NULL */
725 cupsGetDefault2(http_t *http) /* I - HTTP connection */
726 {
727 ipp_t *request, /* IPP Request */
728 *response; /* IPP Response */
729 ipp_attribute_t *attr; /* Current attribute */
730 cups_lang_t *language; /* Default language */
731 const char *var; /* Environment variable */
732 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
733
734
735 /*
736 * First see if the LPDEST or PRINTER environment variables are
737 * set... However, if PRINTER is set to "lp", ignore it to work
738 * around a "feature" in most Linux distributions - the default
739 * user login scripts set PRINTER to "lp"...
740 */
741
742 if ((var = getenv("LPDEST")) != NULL)
743 return (var);
744 else if ((var = getenv("PRINTER")) != NULL && strcmp(var, "lp") != 0)
745 return (var);
746
747 /*
748 * Range check input...
749 */
750
751 if (!http)
752 return (NULL);
753
754 /*
755 * Build a CUPS_GET_DEFAULT request, which requires the following
756 * attributes:
757 *
758 * attributes-charset
759 * attributes-natural-language
760 */
761
762 request = ippNew();
763
764 request->request.op.operation_id = CUPS_GET_DEFAULT;
765 request->request.op.request_id = 1;
766
767 language = cupsLangDefault();
768
769 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
770 "attributes-charset", NULL, cupsLangEncoding(language));
771
772 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
773 "attributes-natural-language", NULL, language->language);
774
775 cupsLangFree(language);
776
777 /*
778 * Do the request and get back a response...
779 */
780
781 if ((response = cupsDoRequest(http, request, "/")) != NULL)
782 {
783 if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL)
784 {
785 strlcpy(cg->def_printer, attr->values[0].string.text, sizeof(cg->def_printer));
786 ippDelete(response);
787 return (cg->def_printer);
788 }
789
790 ippDelete(response);
791 }
792
793 return (NULL);
794 }
795
796
797 /*
798 * 'cupsGetJobs()' - Get the jobs from the default server.
799 */
800
801 int /* O - Number of jobs */
802 cupsGetJobs(cups_job_t **jobs, /* O - Job data */
803 const char *mydest, /* I - Only show jobs for dest? */
804 int myjobs, /* I - Only show my jobs? */
805 int completed) /* I - Only show completed jobs? */
806 {
807 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
808
809 /*
810 * Try to connect to the server...
811 */
812
813 if (!cups_connect("default", NULL, NULL))
814 {
815 DEBUG_puts("Unable to connect to server!");
816
817 return (-1);
818 }
819
820 /*
821 * Return the jobs...
822 */
823
824 return (cupsGetJobs2(cg->http, jobs, mydest, myjobs, completed));
825 }
826
827
828
829 /*
830 * 'cupsGetJobs2()' - Get the jobs from the specified server.
831 *
832 * @since CUPS 1.1.21@
833 */
834
835 int /* O - Number of jobs */
836 cupsGetJobs2(http_t *http, /* I - HTTP connection */
837 cups_job_t **jobs, /* O - Job data */
838 const char *mydest, /* I - Only show jobs for dest? */
839 int myjobs, /* I - Only show my jobs? */
840 int completed) /* I - Only show completed jobs? */
841 {
842 int n; /* Number of jobs */
843 ipp_t *request, /* IPP Request */
844 *response; /* IPP Response */
845 ipp_attribute_t *attr; /* Current attribute */
846 cups_lang_t *language; /* Default language */
847 cups_job_t *temp; /* Temporary pointer */
848 int id, /* job-id */
849 priority, /* job-priority */
850 size; /* job-k-octets */
851 ipp_jstate_t state; /* job-state */
852 time_t completed_time, /* time-at-completed */
853 creation_time, /* time-at-creation */
854 processing_time; /* time-at-processing */
855 const char *dest, /* job-printer-uri */
856 *format, /* document-format */
857 *title, /* job-name */
858 *user; /* job-originating-user-name */
859 char uri[HTTP_MAX_URI]; /* URI for jobs */
860 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
861 static const char * const attrs[] = /* Requested attributes */
862 {
863 "job-id",
864 "job-priority",
865 "job-k-octets",
866 "job-state",
867 "time-at-completed",
868 "time-at-creation",
869 "time-at-processing",
870 "job-printer-uri",
871 "document-format",
872 "job-name",
873 "job-originating-user-name"
874 };
875
876
877 /*
878 * Range check input...
879 */
880
881 if (!http || !jobs)
882 {
883 cups_set_error(IPP_INTERNAL_ERROR, NULL);
884
885 return (-1);
886 }
887
888 /*
889 * Get the right URI...
890 */
891
892 if (mydest)
893 {
894 if (httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
895 "/printers/%s", mydest) != HTTP_URI_OK)
896 {
897 cups_set_error(IPP_INTERNAL_ERROR, NULL);
898
899 return (-1);
900 }
901 }
902 else
903 strcpy(uri, "ipp://localhost/jobs");
904
905
906 /*
907 * Build an IPP_GET_JOBS request, which requires the following
908 * attributes:
909 *
910 * attributes-charset
911 * attributes-natural-language
912 * printer-uri
913 * requesting-user-name
914 * which-jobs
915 * my-jobs
916 * requested-attributes
917 */
918
919 request = ippNew();
920
921 request->request.op.operation_id = IPP_GET_JOBS;
922 request->request.op.request_id = 1;
923
924 language = cupsLangDefault();
925
926 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
927 "attributes-charset", NULL, cupsLangEncoding(language));
928
929 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
930 "attributes-natural-language", NULL, language->language);
931
932 cupsLangFree(language);
933
934 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
935 "printer-uri", NULL, uri);
936
937 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
938 "requesting-user-name", NULL, cupsUser());
939
940 if (myjobs)
941 ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
942
943 if (completed)
944 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
945 "which-jobs", NULL, "completed");
946
947 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
948 "requested-attributes", sizeof(attrs) / sizeof(attrs[0]),
949 NULL, attrs);
950
951 /*
952 * Do the request and get back a response...
953 */
954
955 n = 0;
956 *jobs = NULL;
957
958 if ((response = cupsDoRequest(http, request, "/")) != NULL)
959 {
960 for (attr = response->attrs; attr != NULL; attr = attr->next)
961 {
962 /*
963 * Skip leading attributes until we hit a job...
964 */
965
966 while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
967 attr = attr->next;
968
969 if (attr == NULL)
970 break;
971
972 /*
973 * Pull the needed attributes from this job...
974 */
975
976 id = 0;
977 size = 0;
978 priority = 50;
979 state = IPP_JOB_PENDING;
980 user = "unknown";
981 dest = NULL;
982 format = "application/octet-stream";
983 title = "untitled";
984 creation_time = 0;
985 completed_time = 0;
986 processing_time = 0;
987
988 while (attr != NULL && attr->group_tag == IPP_TAG_JOB)
989 {
990 if (strcmp(attr->name, "job-id") == 0 &&
991 attr->value_tag == IPP_TAG_INTEGER)
992 id = attr->values[0].integer;
993 else if (strcmp(attr->name, "job-state") == 0 &&
994 attr->value_tag == IPP_TAG_ENUM)
995 state = (ipp_jstate_t)attr->values[0].integer;
996 else if (strcmp(attr->name, "job-priority") == 0 &&
997 attr->value_tag == IPP_TAG_INTEGER)
998 priority = attr->values[0].integer;
999 else if (strcmp(attr->name, "job-k-octets") == 0 &&
1000 attr->value_tag == IPP_TAG_INTEGER)
1001 size = attr->values[0].integer;
1002 else if (strcmp(attr->name, "time-at-completed") == 0 &&
1003 attr->value_tag == IPP_TAG_INTEGER)
1004 completed_time = attr->values[0].integer;
1005 else if (strcmp(attr->name, "time-at-creation") == 0 &&
1006 attr->value_tag == IPP_TAG_INTEGER)
1007 creation_time = attr->values[0].integer;
1008 else if (strcmp(attr->name, "time-at-processing") == 0 &&
1009 attr->value_tag == IPP_TAG_INTEGER)
1010 processing_time = attr->values[0].integer;
1011 else if (strcmp(attr->name, "job-printer-uri") == 0 &&
1012 attr->value_tag == IPP_TAG_URI)
1013 {
1014 if ((dest = strrchr(attr->values[0].string.text, '/')) != NULL)
1015 dest ++;
1016 }
1017 else if (strcmp(attr->name, "job-originating-user-name") == 0 &&
1018 attr->value_tag == IPP_TAG_NAME)
1019 user = attr->values[0].string.text;
1020 else if (strcmp(attr->name, "document-format") == 0 &&
1021 attr->value_tag == IPP_TAG_MIMETYPE)
1022 format = attr->values[0].string.text;
1023 else if (strcmp(attr->name, "job-name") == 0 &&
1024 (attr->value_tag == IPP_TAG_TEXT ||
1025 attr->value_tag == IPP_TAG_NAME))
1026 title = attr->values[0].string.text;
1027
1028 attr = attr->next;
1029 }
1030
1031 /*
1032 * See if we have everything needed...
1033 */
1034
1035 if (dest == NULL || id == 0)
1036 {
1037 if (attr == NULL)
1038 break;
1039 else
1040 continue;
1041 }
1042
1043 /*
1044 * Allocate memory for the job...
1045 */
1046
1047 if (n == 0)
1048 temp = malloc(sizeof(cups_job_t));
1049 else
1050 temp = realloc(*jobs, sizeof(cups_job_t) * (n + 1));
1051
1052 if (temp == NULL)
1053 {
1054 /*
1055 * Ran out of memory!
1056 */
1057
1058 cupsFreeJobs(n, *jobs);
1059 *jobs = NULL;
1060
1061 ippDelete(response);
1062 return (0);
1063 }
1064
1065 *jobs = temp;
1066 temp += n;
1067 n ++;
1068
1069 /*
1070 * Copy the data over...
1071 */
1072
1073 temp->dest = strdup(dest);
1074 temp->user = strdup(user);
1075 temp->format = strdup(format);
1076 temp->title = strdup(title);
1077 temp->id = id;
1078 temp->priority = priority;
1079 temp->state = state;
1080 temp->size = size;
1081 temp->completed_time = completed_time;
1082 temp->creation_time = creation_time;
1083 temp->processing_time = processing_time;
1084
1085 if (attr == NULL)
1086 break;
1087 }
1088
1089 ippDelete(response);
1090 }
1091
1092 if (n == 0 && cg->last_error >= IPP_BAD_REQUEST)
1093 return (-1);
1094 else
1095 return (n);
1096 }
1097
1098
1099 /*
1100 * 'cupsGetPPD()' - Get the PPD file for a printer on the default server.
1101 *
1102 * For classes, cupsGetPPD() returns the PPD file for the first printer
1103 * in the class.
1104 */
1105
1106 const char * /* O - Filename for PPD file */
1107 cupsGetPPD(const char *name) /* I - Printer name */
1108 {
1109 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
1110
1111 /*
1112 * See if we can connect to the server...
1113 */
1114
1115 if (!cups_connect(name, NULL, NULL))
1116 {
1117 DEBUG_puts("Unable to connect to server!");
1118
1119 return (NULL);
1120 }
1121
1122 /*
1123 * Return the PPD file...
1124 */
1125
1126 return (cupsGetPPD2(cg->http, name));
1127 }
1128
1129
1130 /*
1131 * 'cupsGetPPD2()' - Get the PPD file for a printer from the specified server.
1132 *
1133 * For classes, cupsGetPPD2() returns the PPD file for the first printer
1134 * in the class.
1135 *
1136 * @since CUPS 1.1.21@
1137 */
1138
1139 const char * /* O - Filename for PPD file */
1140 cupsGetPPD2(http_t *http, /* I - HTTP connection */
1141 const char *name) /* I - Printer name */
1142 {
1143 int http_port; /* Port number */
1144 http_t *http2; /* Alternate HTTP connection */
1145 int fd; /* PPD file */
1146 char localhost[HTTP_MAX_URI],/* Local hostname */
1147 hostname[HTTP_MAX_URI], /* Hostname */
1148 resource[HTTP_MAX_URI]; /* Resource name */
1149 int port; /* Port number */
1150 http_status_t status; /* HTTP status from server */
1151 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
1152
1153
1154 /*
1155 * Range check input...
1156 */
1157
1158 DEBUG_printf(("cupsGetPPD2(http=%p, name=\"%s\")\n", http,
1159 name ? name : "(null)"));
1160
1161 if (!http || !name)
1162 {
1163 cups_set_error(IPP_INTERNAL_ERROR, NULL);
1164
1165 return (NULL);
1166 }
1167
1168 /*
1169 * Try finding a printer URI for this printer...
1170 */
1171
1172 if (!cups_get_printer_uri(http, name, hostname, sizeof(hostname), &port,
1173 resource, sizeof(resource), 0))
1174 return (NULL);
1175
1176 /*
1177 * Remap local hostname to localhost...
1178 */
1179
1180 httpGetHostname(localhost, sizeof(localhost));
1181
1182 if (!strcasecmp(localhost, hostname))
1183 strcpy(hostname, "localhost");
1184
1185 /*
1186 * Get the port number we are connected to...
1187 */
1188
1189 #ifdef AF_INET6
1190 if (http->hostaddr->addr.sa_family == AF_INET6)
1191 http_port = ntohs(http->hostaddr->ipv6.sin6_port);
1192 else
1193 #endif /* AF_INET6 */
1194 if (http->hostaddr->addr.sa_family == AF_INET)
1195 http_port = ntohs(http->hostaddr->ipv4.sin_port);
1196 else
1197 http_port = ippPort();
1198
1199 /*
1200 * Reconnect to the correct server as needed...
1201 */
1202
1203 if (!strcasecmp(http->hostname, hostname) && port == http_port)
1204 http2 = http;
1205 else if ((http2 = httpConnectEncrypt(hostname, port,
1206 cupsEncryption())) == NULL)
1207 {
1208 DEBUG_puts("Unable to connect to server!");
1209
1210 return (NULL);
1211 }
1212
1213 /*
1214 * Get a temp file...
1215 */
1216
1217 if ((fd = cupsTempFd(cg->ppd_filename, sizeof(cg->ppd_filename))) < 0)
1218 {
1219 /*
1220 * Can't open file; close the server connection and return NULL...
1221 */
1222
1223 cups_set_error(IPP_INTERNAL_ERROR, strerror(errno));
1224
1225 if (http2 != http)
1226 httpClose(http2);
1227
1228 return (NULL);
1229 }
1230
1231 /*
1232 * And send a request to the HTTP server...
1233 */
1234
1235 strlcat(resource, ".ppd", sizeof(resource));
1236
1237 status = cupsGetFd(http2, resource, fd);
1238
1239 close(fd);
1240
1241 if (http2 != http)
1242 httpClose(http2);
1243
1244 /*
1245 * See if we actually got the file or an error...
1246 */
1247
1248 if (status != HTTP_OK)
1249 {
1250 switch (status)
1251 {
1252 case HTTP_NOT_FOUND :
1253 cups_set_error(IPP_NOT_FOUND, httpStatus(status));
1254 break;
1255
1256 case HTTP_UNAUTHORIZED :
1257 cups_set_error(IPP_NOT_AUTHORIZED, httpStatus(status));
1258 break;
1259
1260 default :
1261 DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n",
1262 status));
1263 cups_set_error(IPP_SERVICE_UNAVAILABLE, httpStatus(status));
1264 break;
1265 }
1266
1267 unlink(cg->ppd_filename);
1268
1269 return (NULL);
1270 }
1271
1272 /*
1273 * Return the PPD file...
1274 */
1275
1276 return (cg->ppd_filename);
1277 }
1278
1279
1280 /*
1281 * 'cupsGetPrinters()' - Get a list of printers from the default server.
1282 *
1283 * This function is deprecated - use cupsGetDests() instead.
1284 *
1285 * @deprecated@
1286 */
1287
1288 int /* O - Number of printers */
1289 cupsGetPrinters(char ***printers) /* O - Printers */
1290 {
1291 int n; /* Number of printers */
1292 ipp_t *request, /* IPP Request */
1293 *response; /* IPP Response */
1294 ipp_attribute_t *attr; /* Current attribute */
1295 cups_lang_t *language; /* Default language */
1296 char **temp; /* Temporary pointer */
1297 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
1298
1299
1300 if (printers == NULL)
1301 {
1302 cups_set_error(IPP_INTERNAL_ERROR, NULL);
1303
1304 return (0);
1305 }
1306
1307 /*
1308 * Try to connect to the server...
1309 */
1310
1311 if (!cups_connect("default", NULL, NULL))
1312 {
1313 DEBUG_puts("Unable to connect to server!");
1314
1315 return (0);
1316 }
1317
1318 /*
1319 * Build a CUPS_GET_PRINTERS request, which requires the following
1320 * attributes:
1321 *
1322 * attributes-charset
1323 * attributes-natural-language
1324 * requested-attributes
1325 */
1326
1327 request = ippNew();
1328
1329 request->request.op.operation_id = CUPS_GET_PRINTERS;
1330 request->request.op.request_id = 1;
1331
1332 language = cupsLangDefault();
1333
1334 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1335 "attributes-charset", NULL, cupsLangEncoding(language));
1336
1337 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1338 "attributes-natural-language", NULL, language->language);
1339
1340 cupsLangFree(language);
1341
1342 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1343 "requested-attributes", NULL, "printer-name");
1344
1345 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
1346 "printer-type", 0);
1347
1348 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
1349 "printer-type-mask", CUPS_PRINTER_CLASS);
1350
1351 /*
1352 * Do the request and get back a response...
1353 */
1354
1355 n = 0;
1356 *printers = NULL;
1357
1358 if ((response = cupsDoRequest(cg->http, request, "/")) != NULL)
1359 {
1360 for (attr = response->attrs; attr != NULL; attr = attr->next)
1361 if (attr->name != NULL &&
1362 strcasecmp(attr->name, "printer-name") == 0 &&
1363 attr->value_tag == IPP_TAG_NAME)
1364 {
1365 if (n == 0)
1366 temp = malloc(sizeof(char *));
1367 else
1368 temp = realloc(*printers, sizeof(char *) * (n + 1));
1369
1370 if (temp == NULL)
1371 {
1372 /*
1373 * Ran out of memory!
1374 */
1375
1376 while (n > 0)
1377 {
1378 n --;
1379 free((*printers)[n]);
1380 }
1381
1382 free(*printers);
1383 ippDelete(response);
1384 return (0);
1385 }
1386
1387 *printers = temp;
1388 temp[n] = strdup(attr->values[0].string.text);
1389 n ++;
1390 }
1391
1392 ippDelete(response);
1393 }
1394
1395 return (n);
1396 }
1397
1398
1399 /*
1400 * 'cupsLastError()' - Return the last IPP status code.
1401 */
1402
1403 ipp_status_t /* O - IPP status code from last request */
1404 cupsLastError(void)
1405 {
1406 return (_cupsGlobals()->last_error);
1407 }
1408
1409
1410 /*
1411 * 'cupsLastErrorString()' - Return the last IPP status-message.
1412 *
1413 * @since CUPS 1.2@
1414 */
1415
1416 const char * /* O - status-message text from last request */
1417 cupsLastErrorString(void)
1418 {
1419 return (_cupsGlobals()->last_status_message);
1420 }
1421
1422
1423 /*
1424 * 'cupsPrintFile()' - Print a file to a printer or class on the default server.
1425 */
1426
1427 int /* O - Job ID */
1428 cupsPrintFile(const char *name, /* I - Printer or class name */
1429 const char *filename, /* I - File to print */
1430 const char *title, /* I - Title of job */
1431 int num_options,/* I - Number of options */
1432 cups_option_t *options) /* I - Options */
1433 {
1434 DEBUG_printf(("cupsPrintFile(name=\"%s\", filename=\"%s\", "
1435 "title=\"%s\", num_options=%d, options=%p)\n",
1436 name, filename, title, num_options, options));
1437
1438 return (cupsPrintFiles(name, 1, &filename, title, num_options, options));
1439 }
1440
1441
1442 /*
1443 * 'cupsPrintFile2()' - Print a file to a printer or class on the specified server.
1444 *
1445 * @since CUPS 1.1.21@
1446 */
1447
1448 int /* O - Job ID */
1449 cupsPrintFile2(http_t *http, /* I - HTTP connection */
1450 const char *name, /* I - Printer or class name */
1451 const char *filename, /* I - File to print */
1452 const char *title, /* I - Title of job */
1453 int num_options,
1454 /* I - Number of options */
1455 cups_option_t *options) /* I - Options */
1456 {
1457 DEBUG_printf(("cupsPrintFile2(http=%p, name=\"%s\", filename=\"%s\", "
1458 "title=\"%s\", num_options=%d, options=%p)\n",
1459 http, name, filename, title, num_options, options));
1460
1461 return (cupsPrintFiles2(http, name, 1, &filename, title, num_options, options));
1462 }
1463
1464
1465 /*
1466 * 'cupsPrintFiles()' - Print one or more files to a printer or class on the
1467 * default server.
1468 */
1469
1470 int /* O - Job ID */
1471 cupsPrintFiles(const char *name, /* I - Printer or class name */
1472 int num_files, /* I - Number of files */
1473 const char **files, /* I - File(s) to print */
1474 const char *title, /* I - Title of job */
1475 int num_options,
1476 /* I - Number of options */
1477 cups_option_t *options) /* I - Options */
1478 {
1479 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
1480
1481 DEBUG_printf(("cupsPrintFiles(name=\"%s\", num_files=%d, "
1482 "files=%p, title=\"%s\", num_options=%d, options=%p)\n",
1483 name, num_files, files, title, num_options, options));
1484
1485
1486 /*
1487 * Setup a connection and request data...
1488 */
1489
1490 if (!cups_connect(name, NULL, NULL))
1491 {
1492 DEBUG_printf(("cupsPrintFiles: Unable to open connection - %s.\n",
1493 strerror(errno)));
1494 DEBUG_puts("Unable to connect to server!");
1495
1496 return (0);
1497 }
1498
1499 /*
1500 * Print the file(s)...
1501 */
1502
1503 return (cupsPrintFiles2(cg->http, name, num_files, files, title,
1504 num_options, options));
1505 }
1506
1507
1508
1509 /*
1510 * 'cupsPrintFiles2()' - Print one or more files to a printer or class on the
1511 * specified server.
1512 *
1513 * @since CUPS 1.1.21@
1514 */
1515
1516 int /* O - Job ID */
1517 cupsPrintFiles2(http_t *http, /* I - HTTP connection */
1518 const char *name, /* I - Printer or class name */
1519 int num_files,/* I - Number of files */
1520 const char **files, /* I - File(s) to print */
1521 const char *title, /* I - Title of job */
1522 int num_options,
1523 /* I - Number of options */
1524 cups_option_t *options) /* I - Options */
1525 {
1526 int i; /* Looping var */
1527 const char *val; /* Pointer to option value */
1528 ipp_t *request; /* IPP request */
1529 ipp_t *response; /* IPP response */
1530 ipp_attribute_t *attr; /* IPP job-id attribute */
1531 char uri[HTTP_MAX_URI]; /* Printer URI */
1532 cups_lang_t *language; /* Language to use */
1533 int jobid; /* New job ID */
1534
1535
1536 DEBUG_printf(("cupsPrintFiles(http=%p, name=\"%s\", num_files=%d, "
1537 "files=%p, title=\"%s\", num_options=%d, options=%p)\n",
1538 http, name, num_files, files, title, num_options, options));
1539
1540 /*
1541 * Range check input...
1542 */
1543
1544 if (!http || !name || num_files < 1 || files == NULL)
1545 {
1546 cups_set_error(IPP_INTERNAL_ERROR, NULL);
1547
1548 return (0);
1549 }
1550
1551 /*
1552 * Setup the printer URI...
1553 */
1554
1555 if (httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
1556 "/printers/%s", name) != HTTP_URI_OK)
1557 {
1558 cups_set_error(IPP_INTERNAL_ERROR, NULL);
1559
1560 return (0);
1561 }
1562
1563 /*
1564 * Setup the request data...
1565 */
1566
1567 language = cupsLangDefault();
1568
1569 /*
1570 * Build a standard CUPS URI for the printer and fill the standard IPP
1571 * attributes...
1572 */
1573
1574 if ((request = ippNew()) == NULL)
1575 {
1576 cups_set_error(IPP_INTERNAL_ERROR, NULL);
1577
1578 return (0);
1579 }
1580
1581 request->request.op.operation_id = num_files == 1 ? IPP_PRINT_JOB :
1582 IPP_CREATE_JOB;
1583 request->request.op.request_id = 1;
1584
1585 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1586 "attributes-charset", NULL, cupsLangEncoding(language));
1587
1588 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1589 "attributes-natural-language", NULL,
1590 language != NULL ? language->language : "C");
1591
1592 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1593 NULL, uri);
1594
1595 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1596 NULL, cupsUser());
1597
1598 if (title)
1599 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
1600 title);
1601
1602 /*
1603 * Then add all options...
1604 */
1605
1606 cupsEncodeOptions(request, num_options, options);
1607
1608 /*
1609 * Do the request...
1610 */
1611
1612 snprintf(uri, sizeof(uri), "/printers/%s", name);
1613
1614 if (num_files == 1)
1615 response = cupsDoFileRequest(http, request, uri, *files);
1616 else
1617 response = cupsDoRequest(http, request, uri);
1618
1619 if (response == NULL)
1620 jobid = 0;
1621 else if (response->request.status.status_code > IPP_OK_CONFLICT)
1622 {
1623 DEBUG_printf(("IPP response code was 0x%x!\n",
1624 response->request.status.status_code));
1625 jobid = 0;
1626 }
1627 else if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL)
1628 {
1629 DEBUG_puts("No job ID!");
1630
1631 cups_set_error(IPP_INTERNAL_ERROR, NULL);
1632
1633 jobid = 0;
1634 }
1635 else
1636 jobid = attr->values[0].integer;
1637
1638 if (response != NULL)
1639 ippDelete(response);
1640
1641 /*
1642 * Handle multiple file jobs if the create-job operation worked...
1643 */
1644
1645 if (jobid > 0 && num_files > 1)
1646 for (i = 0; i < num_files; i ++)
1647 {
1648 /*
1649 * Build a standard CUPS URI for the job and fill the standard IPP
1650 * attributes...
1651 */
1652
1653 if ((request = ippNew()) == NULL)
1654 return (0);
1655
1656 request->request.op.operation_id = IPP_SEND_DOCUMENT;
1657 request->request.op.request_id = 1;
1658
1659 snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", jobid);
1660
1661 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1662 "attributes-charset", NULL, cupsLangEncoding(language));
1663
1664 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1665 "attributes-natural-language", NULL,
1666 language != NULL ? language->language : "C");
1667
1668 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
1669 NULL, uri);
1670
1671 /*
1672 * Handle raw print files...
1673 */
1674
1675 if (cupsGetOption("raw", num_options, options))
1676 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
1677 "document-format", NULL, "application/vnd.cups-raw");
1678 else if ((val = cupsGetOption("document-format", num_options,
1679 options)) != NULL)
1680 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
1681 "document-format", NULL, val);
1682 else
1683 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
1684 "document-format", NULL, "application/octet-stream");
1685
1686 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1687 "requesting-user-name", NULL, cupsUser());
1688
1689 /*
1690 * Is this the last document?
1691 */
1692
1693 if (i == (num_files - 1))
1694 ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
1695
1696 /*
1697 * Send the file...
1698 */
1699
1700 snprintf(uri, sizeof(uri), "/printers/%s", name);
1701
1702 if ((response = cupsDoFileRequest(http, request, uri,
1703 files[i])) != NULL)
1704 ippDelete(response);
1705 }
1706
1707 cupsLangFree(language);
1708
1709 return (jobid);
1710 }
1711
1712
1713 /*
1714 * 'cups_connect()' - Connect to the specified host...
1715 */
1716
1717 static char * /* I - Printer name or NULL */
1718 cups_connect(const char *name, /* I - Destination (printer[@host]) */
1719 char *printer, /* O - Printer name [HTTP_MAX_URI] */
1720 char *hostname) /* O - Hostname [HTTP_MAX_URI] */
1721 {
1722 char hostbuf[HTTP_MAX_URI]; /* Name of host */
1723 _cups_globals_t *cg = _cupsGlobals();/* Pointer to library globals */
1724
1725
1726 DEBUG_printf(("cups_connect(\"%s\", %p, %p)\n", name, printer, hostname));
1727
1728 if (name == NULL)
1729 {
1730 cups_set_error(IPP_BAD_REQUEST, NULL);
1731
1732 return (NULL);
1733 }
1734
1735 /*
1736 * All jobs are now queued to cupsServer() to avoid hostname
1737 * resolution problems and to ensure that the user sees all
1738 * locally queued jobs locally.
1739 */
1740
1741 strlcpy(hostbuf, cupsServer(), sizeof(hostbuf));
1742
1743 if (hostname != NULL)
1744 strlcpy(hostname, hostbuf, HTTP_MAX_URI);
1745 else
1746 hostname = hostbuf;
1747
1748 if (printer != NULL)
1749 strlcpy(printer, name, HTTP_MAX_URI);
1750 else
1751 printer = (char *)name;
1752
1753 if (cg->http != NULL)
1754 {
1755 if (!strcasecmp(cg->http->hostname, hostname))
1756 return (printer);
1757
1758 httpClose(cg->http);
1759 }
1760
1761 DEBUG_printf(("connecting to %s on port %d...\n", hostname, ippPort()));
1762
1763 if ((cg->http = httpConnectEncrypt(hostname, ippPort(),
1764 cupsEncryption())) == NULL)
1765 {
1766 DEBUG_puts("Unable to connect to server!");
1767
1768 cups_set_error(IPP_SERVICE_UNAVAILABLE, strerror(errno));
1769
1770 return (NULL);
1771 }
1772 else
1773 return (printer);
1774 }
1775
1776
1777 /*
1778 * 'cups_get_printer_uri()' - Get the printer-uri-supported attribute for the first printer in a class.
1779 */
1780
1781 static int /* O - 1 on success, 0 on failure */
1782 cups_get_printer_uri(
1783 http_t *http, /* I - HTTP connection */
1784 const char *name, /* I - Name of printer or class */
1785 char *host, /* I - Hostname buffer */
1786 int hostsize, /* I - Size of hostname buffer */
1787 int *port, /* O - Port number */
1788 char *resource, /* I - Resource buffer */
1789 int resourcesize, /* I - Size of resource buffer */
1790 int depth) /* I - Depth of query */
1791 {
1792 int i; /* Looping var */
1793 int http_port; /* Port number */
1794 http_t *http2; /* Alternate HTTP connection */
1795 ipp_t *request, /* IPP request */
1796 *response; /* IPP response */
1797 ipp_attribute_t *attr; /* Current attribute */
1798 char uri[HTTP_MAX_URI], /* printer-uri attribute */
1799 scheme[HTTP_MAX_URI], /* Scheme name */
1800 username[HTTP_MAX_URI], /* Username:password */
1801 classname[255]; /* Temporary class name */
1802 static const char * const requested_attrs[] =
1803 { /* Requested attributes */
1804 "printer-uri-supported",
1805 "printer-type",
1806 "member-uris"
1807 };
1808
1809
1810 DEBUG_printf(("cups_get_printer_uri(http=%p, name=\"%s\", host=%p, "
1811 "hostsize=%d, resource=%p, resourcesize=%d, depth=%d)\n",
1812 http, name ? name : "(null)", host, hostsize,
1813 resource, resourcesize, depth));
1814
1815 /*
1816 * Setup the printer URI...
1817 */
1818
1819 if (httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
1820 "/printers/%s", name) != HTTP_URI_OK)
1821 {
1822 cups_set_error(IPP_INTERNAL_ERROR, NULL);
1823
1824 *host = '\0';
1825 *resource = '\0';
1826
1827 return (0);
1828 }
1829
1830 DEBUG_printf(("cups_get_printer_uri: printer-uri=\"%s\"\n", uri));
1831
1832 /*
1833 * Get the port number we are connected to...
1834 */
1835
1836 #ifdef AF_INET6
1837 if (http->hostaddr->addr.sa_family == AF_INET6)
1838 http_port = ntohs(http->hostaddr->ipv6.sin6_port);
1839 else
1840 #endif /* AF_INET6 */
1841 if (http->hostaddr->addr.sa_family == AF_INET)
1842 http_port = ntohs(http->hostaddr->ipv4.sin_port);
1843 else
1844 http_port = ippPort();
1845
1846 /*
1847 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
1848 * attributes:
1849 *
1850 * attributes-charset
1851 * attributes-natural-language
1852 * printer-uri
1853 * requested-attributes
1854 */
1855
1856 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
1857
1858 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1859 NULL, uri);
1860
1861 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1862 "requested-attributes",
1863 sizeof(requested_attrs) / sizeof(requested_attrs[0]),
1864 NULL, requested_attrs);
1865
1866 /*
1867 * Do the request and get back a response...
1868 */
1869
1870 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1871 {
1872 if ((attr = ippFindAttribute(response, "member-uris", IPP_TAG_URI)) != NULL)
1873 {
1874 /*
1875 * Get the first actual printer name in the class...
1876 */
1877
1878 for (i = 0; i < attr->num_values; i ++)
1879 {
1880 httpSeparateURI(attr->values[i].string.text, scheme, sizeof(scheme),
1881 username, sizeof(username), host, hostsize,
1882 port, resource, resourcesize);
1883 if (!strncmp(resource, "/printers/", 10))
1884 {
1885 /*
1886 * Found a printer!
1887 */
1888
1889 ippDelete(response);
1890
1891 return (1);
1892 }
1893 }
1894
1895 /*
1896 * No printers in this class - try recursively looking for a printer,
1897 * but not more than 3 levels deep...
1898 */
1899
1900 if (depth < 3)
1901 {
1902 for (i = 0; i < attr->num_values; i ++)
1903 {
1904 httpSeparateURI(attr->values[i].string.text, scheme, sizeof(scheme),
1905 username, sizeof(username), host, hostsize,
1906 port, resource, resourcesize);
1907 if (!strncmp(resource, "/classes/", 9))
1908 {
1909 /*
1910 * Found a class! Connect to the right server...
1911 */
1912
1913 if (!strcasecmp(http->hostname, host) && *port == http_port)
1914 http2 = http;
1915 else if ((http2 = httpConnectEncrypt(host, *port,
1916 cupsEncryption())) == NULL)
1917 {
1918 DEBUG_puts("Unable to connect to server!");
1919
1920 continue;
1921 }
1922
1923 /*
1924 * Look up printers on that server...
1925 */
1926
1927 strlcpy(classname, resource + 9, sizeof(classname));
1928
1929 cups_get_printer_uri(http2, classname, host, hostsize, port,
1930 resource, resourcesize, depth + 1);
1931
1932 /*
1933 * Close the connection as needed...
1934 */
1935
1936 if (http2 != http)
1937 httpClose(http2);
1938
1939 if (*host)
1940 return (1);
1941 }
1942 }
1943 }
1944 }
1945 else if ((attr = ippFindAttribute(response, "printer-uri-supported",
1946 IPP_TAG_URI)) != NULL)
1947 {
1948 httpSeparateURI(attr->values[0].string.text, scheme, sizeof(scheme),
1949 username, sizeof(username), host, hostsize,
1950 port, resource, resourcesize);
1951 ippDelete(response);
1952
1953 return (1);
1954 }
1955
1956 ippDelete(response);
1957 }
1958
1959 *host = '\0';
1960 *resource = '\0';
1961
1962 return (0);
1963 }
1964
1965
1966 /*
1967 * 'cups_set_error()' - Set the last IPP status code and status-message.
1968 */
1969
1970 static void
1971 cups_set_error(ipp_status_t status, /* I - IPP status code */
1972 const char *message) /* I - status-message value */
1973 {
1974 _cups_globals_t *cg; /* Global data */
1975
1976
1977 cg = _cupsGlobals();
1978 cg->last_error = status;
1979
1980 if (cg->last_status_message)
1981 {
1982 free(cg->last_status_message);
1983
1984 cg->last_status_message = NULL;
1985 }
1986
1987 if (message)
1988 cg->last_status_message = strdup(message);
1989 }
1990
1991
1992 /*
1993 * End of "$Id: util.c 4987 2006-01-26 00:25:21Z mike $".
1994 */