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