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