]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/util.c
Load cups into easysw/current.
[thirdparty/cups.git] / cups / util.c
CommitLineData
ef416fc2 1/*
bd7854cb 2 * "$Id: util.c 5064 2006-02-03 16:51:05Z mike $"
ef416fc2 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 *
fa73b229 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.
ef416fc2 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
81static char *cups_connect(const char *name, char *printer, char *hostname);
fa73b229 82static 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);
ef416fc2 86static 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
96int /* O - 1 on success, 0 on failure */
97cupsCancelJob(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
a4d04587 124 if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
125 "localhost", 0, "/printers/%s", printer) != HTTP_URI_OK)
ef416fc2 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
185ipp_t * /* O - Response data */
186cupsDoFileRequest(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
a4d04587 339 if (httpWrite2(http, buffer, bytes) < bytes)
ef416fc2 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
fa73b229 372 if (httpReconnect(http))
373 {
374 status = HTTP_ERROR;
375 break;
376 }
ef416fc2 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
527void
528cupsFreeJobs(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
557int /* O - Number of classes */
558cupsGetClasses(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
673const char * /* O - Default printer or NULL */
674cupsGetDefault(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
724const char * /* O - Default printer or NULL */
725cupsGetDefault2(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
801int /* O - Number of jobs */
802cupsGetJobs(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
835int /* O - Number of jobs */
836cupsGetJobs2(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 {
a4d04587 894 if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
895 "localhost", 0, "/printers/%s", mydest) != HTTP_URI_OK)
ef416fc2 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
1106const char * /* O - Filename for PPD file */
1107cupsGetPPD(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
1139const char * /* O - Filename for PPD file */
1140cupsGetPPD2(http_t *http, /* I - HTTP connection */
1141 const char *name) /* I - Printer name */
1142{
ef416fc2 1143 int http_port; /* Port number */
1144 http_t *http2; /* Alternate HTTP connection */
ef416fc2 1145 int fd; /* PPD file */
fa73b229 1146 char localhost[HTTP_MAX_URI],/* Local hostname */
ef416fc2 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 */
ef416fc2 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 /*
fa73b229 1169 * Try finding a printer URI for this printer...
ef416fc2 1170 */
1171
fa73b229 1172 if (!cups_get_printer_uri(http, name, hostname, sizeof(hostname), &port,
1173 resource, sizeof(resource), 0))
ef416fc2 1174 return (NULL);
ef416fc2 1175
1176 /*
fa73b229 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...
ef416fc2 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
ef416fc2 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
fa73b229 1235 strlcat(resource, ".ppd", sizeof(resource));
ef416fc2 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
1288int /* O - Number of printers */
1289cupsGetPrinters(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
1403ipp_status_t /* O - IPP status code from last request */
1404cupsLastError(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
1416const char * /* O - status-message text from last request */
1417cupsLastErrorString(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
1427int /* O - Job ID */
1428cupsPrintFile(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
1448int /* O - Job ID */
1449cupsPrintFile2(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/*
fa73b229 1466 * 'cupsPrintFiles()' - Print one or more files to a printer or class on the
1467 * default server.
ef416fc2 1468 */
1469
1470int /* O - Job ID */
1471cupsPrintFiles(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/*
fa73b229 1510 * 'cupsPrintFiles2()' - Print one or more files to a printer or class on the
1511 * specified server.
ef416fc2 1512 *
1513 * @since CUPS 1.1.21@
1514 */
1515
1516int /* O - Job ID */
1517cupsPrintFiles2(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 */
bd7854cb 1534 const char *base; /* Basename of current filename */
ef416fc2 1535
1536
1537 DEBUG_printf(("cupsPrintFiles(http=%p, name=\"%s\", num_files=%d, "
1538 "files=%p, title=\"%s\", num_options=%d, options=%p)\n",
1539 http, name, num_files, files, title, num_options, options));
1540
1541 /*
1542 * Range check input...
1543 */
1544
1545 if (!http || !name || num_files < 1 || files == NULL)
1546 {
1547 cups_set_error(IPP_INTERNAL_ERROR, NULL);
1548
1549 return (0);
1550 }
1551
1552 /*
1553 * Setup the printer URI...
1554 */
1555
a4d04587 1556 if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1557 "localhost", 0, "/printers/%s", name) != HTTP_URI_OK)
ef416fc2 1558 {
1559 cups_set_error(IPP_INTERNAL_ERROR, NULL);
1560
1561 return (0);
1562 }
1563
1564 /*
1565 * Setup the request data...
1566 */
1567
1568 language = cupsLangDefault();
1569
1570 /*
1571 * Build a standard CUPS URI for the printer and fill the standard IPP
1572 * attributes...
1573 */
1574
1575 if ((request = ippNew()) == NULL)
1576 {
1577 cups_set_error(IPP_INTERNAL_ERROR, NULL);
1578
1579 return (0);
1580 }
1581
1582 request->request.op.operation_id = num_files == 1 ? IPP_PRINT_JOB :
1583 IPP_CREATE_JOB;
1584 request->request.op.request_id = 1;
1585
1586 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1587 "attributes-charset", NULL, cupsLangEncoding(language));
1588
1589 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1590 "attributes-natural-language", NULL,
1591 language != NULL ? language->language : "C");
1592
1593 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1594 NULL, uri);
1595
1596 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1597 NULL, cupsUser());
1598
1599 if (title)
1600 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
1601 title);
1602
1603 /*
1604 * Then add all options...
1605 */
1606
1607 cupsEncodeOptions(request, num_options, options);
1608
1609 /*
1610 * Do the request...
1611 */
1612
1613 snprintf(uri, sizeof(uri), "/printers/%s", name);
1614
1615 if (num_files == 1)
1616 response = cupsDoFileRequest(http, request, uri, *files);
1617 else
1618 response = cupsDoRequest(http, request, uri);
1619
1620 if (response == NULL)
1621 jobid = 0;
1622 else if (response->request.status.status_code > IPP_OK_CONFLICT)
1623 {
1624 DEBUG_printf(("IPP response code was 0x%x!\n",
1625 response->request.status.status_code));
1626 jobid = 0;
1627 }
1628 else if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL)
1629 {
1630 DEBUG_puts("No job ID!");
1631
1632 cups_set_error(IPP_INTERNAL_ERROR, NULL);
1633
1634 jobid = 0;
1635 }
1636 else
1637 jobid = attr->values[0].integer;
1638
1639 if (response != NULL)
1640 ippDelete(response);
1641
1642 /*
1643 * Handle multiple file jobs if the create-job operation worked...
1644 */
1645
1646 if (jobid > 0 && num_files > 1)
1647 for (i = 0; i < num_files; i ++)
1648 {
1649 /*
1650 * Build a standard CUPS URI for the job and fill the standard IPP
1651 * attributes...
1652 */
1653
1654 if ((request = ippNew()) == NULL)
1655 return (0);
1656
1657 request->request.op.operation_id = IPP_SEND_DOCUMENT;
1658 request->request.op.request_id = 1;
1659
1660 snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", jobid);
1661
1662 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1663 "attributes-charset", NULL, cupsLangEncoding(language));
1664
1665 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1666 "attributes-natural-language", NULL,
1667 language != NULL ? language->language : "C");
1668
1669 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
1670 NULL, uri);
1671
1672 /*
1673 * Handle raw print files...
1674 */
1675
1676 if (cupsGetOption("raw", num_options, options))
fa73b229 1677 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
1678 "document-format", NULL, "application/vnd.cups-raw");
1679 else if ((val = cupsGetOption("document-format", num_options,
1680 options)) != NULL)
1681 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
1682 "document-format", NULL, val);
ef416fc2 1683 else
fa73b229 1684 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
1685 "document-format", NULL, "application/octet-stream");
ef416fc2 1686
fa73b229 1687 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1688 "requesting-user-name", NULL, cupsUser());
ef416fc2 1689
bd7854cb 1690 /*
1691 * Add the original document filename...
1692 */
1693
1694 if ((base = strrchr(files[i], '/')) != NULL)
1695 base ++;
1696 else
1697 base = files[i];
1698
1699 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-name",
1700 NULL, base);
1701
ef416fc2 1702 /*
1703 * Is this the last document?
1704 */
1705
1706 if (i == (num_files - 1))
1707 ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
1708
1709 /*
1710 * Send the file...
1711 */
1712
1713 snprintf(uri, sizeof(uri), "/printers/%s", name);
1714
1715 if ((response = cupsDoFileRequest(http, request, uri,
1716 files[i])) != NULL)
1717 ippDelete(response);
1718 }
1719
1720 cupsLangFree(language);
1721
1722 return (jobid);
1723}
1724
1725
1726/*
1727 * 'cups_connect()' - Connect to the specified host...
1728 */
1729
1730static char * /* I - Printer name or NULL */
1731cups_connect(const char *name, /* I - Destination (printer[@host]) */
1732 char *printer, /* O - Printer name [HTTP_MAX_URI] */
1733 char *hostname) /* O - Hostname [HTTP_MAX_URI] */
1734{
1735 char hostbuf[HTTP_MAX_URI]; /* Name of host */
fa73b229 1736 _cups_globals_t *cg = _cupsGlobals();/* Pointer to library globals */
ef416fc2 1737
1738
1739 DEBUG_printf(("cups_connect(\"%s\", %p, %p)\n", name, printer, hostname));
1740
1741 if (name == NULL)
1742 {
1743 cups_set_error(IPP_BAD_REQUEST, NULL);
1744
1745 return (NULL);
1746 }
1747
1748 /*
1749 * All jobs are now queued to cupsServer() to avoid hostname
1750 * resolution problems and to ensure that the user sees all
1751 * locally queued jobs locally.
1752 */
1753
1754 strlcpy(hostbuf, cupsServer(), sizeof(hostbuf));
1755
1756 if (hostname != NULL)
1757 strlcpy(hostname, hostbuf, HTTP_MAX_URI);
1758 else
1759 hostname = hostbuf;
1760
1761 if (printer != NULL)
1762 strlcpy(printer, name, HTTP_MAX_URI);
1763 else
1764 printer = (char *)name;
1765
1766 if (cg->http != NULL)
1767 {
1768 if (!strcasecmp(cg->http->hostname, hostname))
1769 return (printer);
1770
1771 httpClose(cg->http);
1772 }
1773
1774 DEBUG_printf(("connecting to %s on port %d...\n", hostname, ippPort()));
1775
1776 if ((cg->http = httpConnectEncrypt(hostname, ippPort(),
fa73b229 1777 cupsEncryption())) == NULL)
ef416fc2 1778 {
1779 DEBUG_puts("Unable to connect to server!");
1780
1781 cups_set_error(IPP_SERVICE_UNAVAILABLE, strerror(errno));
1782
1783 return (NULL);
1784 }
1785 else
1786 return (printer);
1787}
1788
1789
fa73b229 1790/*
1791 * 'cups_get_printer_uri()' - Get the printer-uri-supported attribute for the first printer in a class.
1792 */
1793
1794static int /* O - 1 on success, 0 on failure */
1795cups_get_printer_uri(
1796 http_t *http, /* I - HTTP connection */
1797 const char *name, /* I - Name of printer or class */
1798 char *host, /* I - Hostname buffer */
1799 int hostsize, /* I - Size of hostname buffer */
1800 int *port, /* O - Port number */
1801 char *resource, /* I - Resource buffer */
1802 int resourcesize, /* I - Size of resource buffer */
1803 int depth) /* I - Depth of query */
1804{
1805 int i; /* Looping var */
1806 int http_port; /* Port number */
1807 http_t *http2; /* Alternate HTTP connection */
1808 ipp_t *request, /* IPP request */
1809 *response; /* IPP response */
1810 ipp_attribute_t *attr; /* Current attribute */
1811 char uri[HTTP_MAX_URI], /* printer-uri attribute */
1812 scheme[HTTP_MAX_URI], /* Scheme name */
1813 username[HTTP_MAX_URI], /* Username:password */
1814 classname[255]; /* Temporary class name */
1815 static const char * const requested_attrs[] =
1816 { /* Requested attributes */
1817 "printer-uri-supported",
1818 "printer-type",
1819 "member-uris"
1820 };
1821
1822
1823 DEBUG_printf(("cups_get_printer_uri(http=%p, name=\"%s\", host=%p, "
1824 "hostsize=%d, resource=%p, resourcesize=%d, depth=%d)\n",
1825 http, name ? name : "(null)", host, hostsize,
1826 resource, resourcesize, depth));
1827
1828 /*
1829 * Setup the printer URI...
1830 */
1831
a4d04587 1832 if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1833 "localhost", 0, "/printers/%s", name) != HTTP_URI_OK)
fa73b229 1834 {
1835 cups_set_error(IPP_INTERNAL_ERROR, NULL);
1836
1837 *host = '\0';
1838 *resource = '\0';
1839
1840 return (0);
1841 }
1842
1843 DEBUG_printf(("cups_get_printer_uri: printer-uri=\"%s\"\n", uri));
1844
1845 /*
1846 * Get the port number we are connected to...
1847 */
1848
1849#ifdef AF_INET6
1850 if (http->hostaddr->addr.sa_family == AF_INET6)
1851 http_port = ntohs(http->hostaddr->ipv6.sin6_port);
1852 else
1853#endif /* AF_INET6 */
1854 if (http->hostaddr->addr.sa_family == AF_INET)
1855 http_port = ntohs(http->hostaddr->ipv4.sin_port);
1856 else
1857 http_port = ippPort();
1858
1859 /*
1860 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
1861 * attributes:
1862 *
1863 * attributes-charset
1864 * attributes-natural-language
1865 * printer-uri
1866 * requested-attributes
1867 */
1868
1869 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
1870
1871 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1872 NULL, uri);
1873
1874 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1875 "requested-attributes",
1876 sizeof(requested_attrs) / sizeof(requested_attrs[0]),
1877 NULL, requested_attrs);
1878
1879 /*
1880 * Do the request and get back a response...
1881 */
1882
1883 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1884 {
1885 if ((attr = ippFindAttribute(response, "member-uris", IPP_TAG_URI)) != NULL)
1886 {
1887 /*
1888 * Get the first actual printer name in the class...
1889 */
1890
1891 for (i = 0; i < attr->num_values; i ++)
1892 {
a4d04587 1893 httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[i].string.text,
1894 scheme, sizeof(scheme), username, sizeof(username),
1895 host, hostsize, port, resource, resourcesize);
fa73b229 1896 if (!strncmp(resource, "/printers/", 10))
1897 {
1898 /*
1899 * Found a printer!
1900 */
1901
1902 ippDelete(response);
1903
1904 return (1);
1905 }
1906 }
1907
1908 /*
1909 * No printers in this class - try recursively looking for a printer,
1910 * but not more than 3 levels deep...
1911 */
1912
1913 if (depth < 3)
1914 {
1915 for (i = 0; i < attr->num_values; i ++)
1916 {
a4d04587 1917 httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[i].string.text,
1918 scheme, sizeof(scheme), username, sizeof(username),
1919 host, hostsize, port, resource, resourcesize);
fa73b229 1920 if (!strncmp(resource, "/classes/", 9))
1921 {
1922 /*
1923 * Found a class! Connect to the right server...
1924 */
1925
1926 if (!strcasecmp(http->hostname, host) && *port == http_port)
1927 http2 = http;
1928 else if ((http2 = httpConnectEncrypt(host, *port,
1929 cupsEncryption())) == NULL)
1930 {
1931 DEBUG_puts("Unable to connect to server!");
1932
1933 continue;
1934 }
1935
1936 /*
1937 * Look up printers on that server...
1938 */
1939
1940 strlcpy(classname, resource + 9, sizeof(classname));
1941
1942 cups_get_printer_uri(http2, classname, host, hostsize, port,
1943 resource, resourcesize, depth + 1);
1944
1945 /*
1946 * Close the connection as needed...
1947 */
1948
1949 if (http2 != http)
1950 httpClose(http2);
1951
1952 if (*host)
1953 return (1);
1954 }
1955 }
1956 }
1957 }
1958 else if ((attr = ippFindAttribute(response, "printer-uri-supported",
1959 IPP_TAG_URI)) != NULL)
1960 {
a4d04587 1961 httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text,
1962 scheme, sizeof(scheme), username, sizeof(username),
1963 host, hostsize, port, resource, resourcesize);
fa73b229 1964 ippDelete(response);
1965
1966 return (1);
1967 }
1968
1969 ippDelete(response);
1970 }
1971
1972 *host = '\0';
1973 *resource = '\0';
1974
1975 return (0);
1976}
1977
1978
ef416fc2 1979/*
1980 * 'cups_set_error()' - Set the last IPP status code and status-message.
1981 */
1982
1983static void
1984cups_set_error(ipp_status_t status, /* I - IPP status code */
1985 const char *message) /* I - status-message value */
1986{
1987 _cups_globals_t *cg; /* Global data */
1988
1989
1990 cg = _cupsGlobals();
1991 cg->last_error = status;
1992
1993 if (cg->last_status_message)
1994 {
1995 free(cg->last_status_message);
1996
1997 cg->last_status_message = NULL;
1998 }
1999
2000 if (message)
2001 cg->last_status_message = strdup(message);
2002}
2003
2004
2005/*
bd7854cb 2006 * End of "$Id: util.c 5064 2006-02-03 16:51:05Z mike $".
ef416fc2 2007 */