2 * "$Id: util.c 5235 2006-03-06 13:02:23Z mike $"
4 * Printing utilities for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2006 by Easy Software Products.
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
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * This file is subject to the Apple OS-Developed Software exception.
28 * cupsCancelJob() - Cancel a print job on the default server.
29 * cupsFreeJobs() - Free memory used by job data.
30 * cupsGetClasses() - Get a list of printer classes from the default
32 * cupsGetDefault() - Get the default printer or class from the default
34 * cupsGetDefault2() - Get the default printer or class from the
36 * cupsGetJobs() - Get the jobs from the default server.
37 * cupsGetJobs2() - Get the jobs from the specified server.
38 * cupsGetPPD() - Get the PPD file for a printer on the default
40 * cupsGetPPD2() - Get the PPD file for a printer on the specified
42 * cupsGetPrinters() - Get a list of printers from the default server.
43 * cupsLastError() - Return the last IPP status code.
44 * cupsLastErrorString() - Return the last IPP status-message.
45 * cupsPrintFile() - Print a file to a printer or class on the default
47 * cupsPrintFile2() - Print a file to a printer or class on the
49 * cupsPrintFiles() - Print one or more files to a printer or class on
51 * cupsPrintFiles2() - Print one or more files to a printer or class on
52 * the specified server.
53 * cups_connect() - Connect to the specified host...
54 * cups_get_printer_uri() - Get the printer-uri-supported attribute for the
55 * first printer in a class.
59 * Include necessary headers...
68 #if defined(WIN32) || defined(__EMX__)
72 #endif /* WIN32 || __EMX__ */
79 static char *cups_connect(const char *name
, char *printer
, char *hostname
);
80 static int cups_get_printer_uri(http_t
*http
, const char *name
,
81 char *host
, int hostsize
, int *port
,
82 char *resource
, int resourcesize
,
87 * 'cupsCancelJob()' - Cancel a print job on the default server.
89 * Use the cupsLastError() and cupsLastErrorString() functions to get
90 * the cause of any failure.
93 int /* O - 1 on success, 0 on failure */
94 cupsCancelJob(const char *name
, /* I - Name of printer or class */
95 int job
) /* I - Job ID */
97 char printer
[HTTP_MAX_URI
], /* Printer name */
98 hostname
[HTTP_MAX_URI
], /* Hostname */
99 uri
[HTTP_MAX_URI
]; /* Printer URI */
100 ipp_t
*request
, /* IPP request */
101 *response
; /* IPP response */
102 cups_lang_t
*language
; /* Language info */
103 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
107 * See if we can connect to the server...
110 if (!cups_connect(name
, printer
, hostname
))
112 DEBUG_puts("Unable to connect to server!");
118 * Create a printer URI...
121 if (httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
122 "localhost", 0, "/printers/%s", printer
) != HTTP_URI_OK
)
124 _cupsSetError(IPP_INTERNAL_ERROR
, NULL
);
130 * Build an IPP_CANCEL_JOB request, which requires the following
134 * attributes-natural-language
137 * [requesting-user-name]
142 request
->request
.op
.operation_id
= IPP_CANCEL_JOB
;
143 request
->request
.op
.request_id
= 1;
145 language
= cupsLangDefault();
147 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
148 "attributes-charset", NULL
, cupsLangEncoding(language
));
150 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
151 "attributes-natural-language", NULL
,
152 language
!= NULL
? language
->language
: "C");
154 cupsLangFree(language
);
156 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
159 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
, "job-id", job
);
161 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
168 if ((response
= cupsDoRequest(cg
->http
, request
, "/jobs/")) != NULL
)
171 return (cg
->last_error
< IPP_REDIRECTION_OTHER_SITE
);
176 * 'cupsFreeJobs()' - Free memory used by job data.
180 cupsFreeJobs(int num_jobs
, /* I - Number of jobs */
181 cups_job_t
*jobs
) /* I - Jobs */
183 int i
; /* Looping var */
186 if (num_jobs
<= 0 || jobs
== NULL
)
189 for (i
= 0; i
< num_jobs
; i
++)
193 free(jobs
[i
].format
);
202 * 'cupsGetClasses()' - Get a list of printer classes from the default server.
204 * This function is deprecated - use cupsGetDests() instead.
209 int /* O - Number of classes */
210 cupsGetClasses(char ***classes
) /* O - Classes */
212 int n
; /* Number of classes */
213 ipp_t
*request
, /* IPP Request */
214 *response
; /* IPP Response */
215 ipp_attribute_t
*attr
; /* Current attribute */
216 cups_lang_t
*language
; /* Default language */
217 char **temp
; /* Temporary pointer */
218 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
223 _cupsSetError(IPP_INTERNAL_ERROR
, NULL
);
229 * Try to connect to the server...
232 if (!cups_connect("default", NULL
, NULL
))
234 DEBUG_puts("Unable to connect to server!");
240 * Build a CUPS_GET_CLASSES request, which requires the following
244 * attributes-natural-language
245 * requested-attributes
250 request
->request
.op
.operation_id
= CUPS_GET_CLASSES
;
251 request
->request
.op
.request_id
= 1;
253 language
= cupsLangDefault();
255 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
256 "attributes-charset", NULL
, cupsLangEncoding(language
));
258 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
259 "attributes-natural-language", NULL
, language
->language
);
261 cupsLangFree(language
);
263 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
264 "requested-attributes", NULL
, "printer-name");
267 * Do the request and get back a response...
273 if ((response
= cupsDoRequest(cg
->http
, request
, "/")) != NULL
)
275 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
276 if (attr
->name
!= NULL
&&
277 strcasecmp(attr
->name
, "printer-name") == 0 &&
278 attr
->value_tag
== IPP_TAG_NAME
)
281 temp
= malloc(sizeof(char *));
283 temp
= realloc(*classes
, sizeof(char *) * (n
+ 1));
303 temp
[n
] = strdup(attr
->values
[0].string
.text
);
315 * 'cupsGetDefault()' - Get the default printer or class for the default server.
317 * This function returns the default printer or class as defined by
318 * the LPDEST or PRINTER environment variables. If these environment
319 * variables are not set, the server default destination is returned.
320 * Applications should use the cupsGetDests() and cupsGetDest() functions
321 * to get the user-defined default printer, as this function does not
322 * support the lpoptions-defined default printer.
325 const char * /* O - Default printer or NULL */
328 const char *var
; /* Environment variable */
329 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
333 * First see if the LPDEST or PRINTER environment variables are
334 * set... However, if PRINTER is set to "lp", ignore it to work
335 * around a "feature" in most Linux distributions - the default
336 * user login scripts set PRINTER to "lp"...
339 if ((var
= getenv("LPDEST")) != NULL
)
341 else if ((var
= getenv("PRINTER")) != NULL
&& strcmp(var
, "lp") != 0)
345 * Try to connect to the server...
348 if (!cups_connect("default", NULL
, NULL
))
350 DEBUG_puts("Unable to connect to server!");
356 * Return the default printer...
359 return (cupsGetDefault2(cg
->http
));
364 * 'cupsGetDefault2()' - Get the default printer or class for the specified server.
366 * This function returns the default printer or class as defined by
367 * the LPDEST or PRINTER environment variables. If these environment
368 * variables are not set, the server default destination is returned.
369 * Applications should use the cupsGetDests() and cupsGetDest() functions
370 * to get the user-defined default printer, as this function does not
371 * support the lpoptions-defined default printer.
373 * @since CUPS 1.1.21@
376 const char * /* O - Default printer or NULL */
377 cupsGetDefault2(http_t
*http
) /* I - HTTP connection */
379 ipp_t
*request
, /* IPP Request */
380 *response
; /* IPP Response */
381 ipp_attribute_t
*attr
; /* Current attribute */
382 cups_lang_t
*language
; /* Default language */
383 const char *var
; /* Environment variable */
384 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
388 * First see if the LPDEST or PRINTER environment variables are
389 * set... However, if PRINTER is set to "lp", ignore it to work
390 * around a "feature" in most Linux distributions - the default
391 * user login scripts set PRINTER to "lp"...
394 if ((var
= getenv("LPDEST")) != NULL
)
396 else if ((var
= getenv("PRINTER")) != NULL
&& strcmp(var
, "lp") != 0)
400 * Range check input...
407 * Build a CUPS_GET_DEFAULT request, which requires the following
411 * attributes-natural-language
416 request
->request
.op
.operation_id
= CUPS_GET_DEFAULT
;
417 request
->request
.op
.request_id
= 1;
419 language
= cupsLangDefault();
421 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
422 "attributes-charset", NULL
, cupsLangEncoding(language
));
424 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
425 "attributes-natural-language", NULL
, language
->language
);
427 cupsLangFree(language
);
430 * Do the request and get back a response...
433 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
435 if ((attr
= ippFindAttribute(response
, "printer-name", IPP_TAG_NAME
)) != NULL
)
437 strlcpy(cg
->def_printer
, attr
->values
[0].string
.text
, sizeof(cg
->def_printer
));
439 return (cg
->def_printer
);
450 * 'cupsGetJobs()' - Get the jobs from the default server.
453 int /* O - Number of jobs */
454 cupsGetJobs(cups_job_t
**jobs
, /* O - Job data */
455 const char *mydest
, /* I - NULL = all destinations, *
456 * otherwise show jobs for mydest */
457 int myjobs
, /* I - 0 = all users, 1 = mine */
458 int completed
) /* I - -1 = show all, 0 = active, *
459 * 1 = completed jobs */
461 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
464 * Try to connect to the server...
467 if (!cups_connect("default", NULL
, NULL
))
469 DEBUG_puts("Unable to connect to server!");
478 return (cupsGetJobs2(cg
->http
, jobs
, mydest
, myjobs
, completed
));
484 * 'cupsGetJobs2()' - Get the jobs from the specified server.
486 * @since CUPS 1.1.21@
489 int /* O - Number of jobs */
490 cupsGetJobs2(http_t
*http
, /* I - HTTP connection */
491 cups_job_t
**jobs
, /* O - Job data */
492 const char *mydest
, /* I - NULL = all destinations, *
493 * otherwise show jobs for mydest */
494 int myjobs
, /* I - 0 = all users, 1 = mine */
495 int completed
) /* I - -1 = show all, 0 = active, *
496 * 1 = completed jobs */
498 int n
; /* Number of jobs */
499 ipp_t
*request
, /* IPP Request */
500 *response
; /* IPP Response */
501 ipp_attribute_t
*attr
; /* Current attribute */
502 cups_lang_t
*language
; /* Default language */
503 cups_job_t
*temp
; /* Temporary pointer */
505 priority
, /* job-priority */
506 size
; /* job-k-octets */
507 ipp_jstate_t state
; /* job-state */
508 time_t completed_time
, /* time-at-completed */
509 creation_time
, /* time-at-creation */
510 processing_time
; /* time-at-processing */
511 const char *dest
, /* job-printer-uri */
512 *format
, /* document-format */
513 *title
, /* job-name */
514 *user
; /* job-originating-user-name */
515 char uri
[HTTP_MAX_URI
]; /* URI for jobs */
516 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
517 static const char * const attrs
[] = /* Requested attributes */
525 "time-at-processing",
529 "job-originating-user-name"
534 * Range check input...
539 _cupsSetError(IPP_INTERNAL_ERROR
, NULL
);
545 * Get the right URI...
550 if (httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
551 "localhost", 0, "/printers/%s", mydest
) != HTTP_URI_OK
)
553 _cupsSetError(IPP_INTERNAL_ERROR
, NULL
);
559 strcpy(uri
, "ipp://localhost/jobs");
563 * Build an IPP_GET_JOBS request, which requires the following
567 * attributes-natural-language
569 * requesting-user-name
572 * requested-attributes
577 request
->request
.op
.operation_id
= IPP_GET_JOBS
;
578 request
->request
.op
.request_id
= 1;
580 language
= cupsLangDefault();
582 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
583 "attributes-charset", NULL
, cupsLangEncoding(language
));
585 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
586 "attributes-natural-language", NULL
, language
->language
);
588 cupsLangFree(language
);
590 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
591 "printer-uri", NULL
, uri
);
593 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
594 "requesting-user-name", NULL
, cupsUser());
597 ippAddBoolean(request
, IPP_TAG_OPERATION
, "my-jobs", 1);
600 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
601 "which-jobs", NULL
, "completed");
602 else if (completed
< 0)
603 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
604 "which-jobs", NULL
, "all");
606 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
607 "requested-attributes", sizeof(attrs
) / sizeof(attrs
[0]),
611 * Do the request and get back a response...
617 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
619 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
622 * Skip leading attributes until we hit a job...
625 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_JOB
)
632 * Pull the needed attributes from this job...
638 state
= IPP_JOB_PENDING
;
641 format
= "application/octet-stream";
647 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_JOB
)
649 if (strcmp(attr
->name
, "job-id") == 0 &&
650 attr
->value_tag
== IPP_TAG_INTEGER
)
651 id
= attr
->values
[0].integer
;
652 else if (strcmp(attr
->name
, "job-state") == 0 &&
653 attr
->value_tag
== IPP_TAG_ENUM
)
654 state
= (ipp_jstate_t
)attr
->values
[0].integer
;
655 else if (strcmp(attr
->name
, "job-priority") == 0 &&
656 attr
->value_tag
== IPP_TAG_INTEGER
)
657 priority
= attr
->values
[0].integer
;
658 else if (strcmp(attr
->name
, "job-k-octets") == 0 &&
659 attr
->value_tag
== IPP_TAG_INTEGER
)
660 size
= attr
->values
[0].integer
;
661 else if (strcmp(attr
->name
, "time-at-completed") == 0 &&
662 attr
->value_tag
== IPP_TAG_INTEGER
)
663 completed_time
= attr
->values
[0].integer
;
664 else if (strcmp(attr
->name
, "time-at-creation") == 0 &&
665 attr
->value_tag
== IPP_TAG_INTEGER
)
666 creation_time
= attr
->values
[0].integer
;
667 else if (strcmp(attr
->name
, "time-at-processing") == 0 &&
668 attr
->value_tag
== IPP_TAG_INTEGER
)
669 processing_time
= attr
->values
[0].integer
;
670 else if (strcmp(attr
->name
, "job-printer-uri") == 0 &&
671 attr
->value_tag
== IPP_TAG_URI
)
673 if ((dest
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
)
676 else if (strcmp(attr
->name
, "job-originating-user-name") == 0 &&
677 attr
->value_tag
== IPP_TAG_NAME
)
678 user
= attr
->values
[0].string
.text
;
679 else if (strcmp(attr
->name
, "document-format") == 0 &&
680 attr
->value_tag
== IPP_TAG_MIMETYPE
)
681 format
= attr
->values
[0].string
.text
;
682 else if (strcmp(attr
->name
, "job-name") == 0 &&
683 (attr
->value_tag
== IPP_TAG_TEXT
||
684 attr
->value_tag
== IPP_TAG_NAME
))
685 title
= attr
->values
[0].string
.text
;
691 * See if we have everything needed...
694 if (dest
== NULL
|| id
== 0)
703 * Allocate memory for the job...
707 temp
= malloc(sizeof(cups_job_t
));
709 temp
= realloc(*jobs
, sizeof(cups_job_t
) * (n
+ 1));
717 cupsFreeJobs(n
, *jobs
);
729 * Copy the data over...
732 temp
->dest
= strdup(dest
);
733 temp
->user
= strdup(user
);
734 temp
->format
= strdup(format
);
735 temp
->title
= strdup(title
);
737 temp
->priority
= priority
;
740 temp
->completed_time
= completed_time
;
741 temp
->creation_time
= creation_time
;
742 temp
->processing_time
= processing_time
;
751 if (n
== 0 && cg
->last_error
>= IPP_BAD_REQUEST
)
759 * 'cupsGetPPD()' - Get the PPD file for a printer on the default server.
761 * For classes, cupsGetPPD() returns the PPD file for the first printer
765 const char * /* O - Filename for PPD file */
766 cupsGetPPD(const char *name
) /* I - Printer name */
768 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
771 * See if we can connect to the server...
774 if (!cups_connect(name
, NULL
, NULL
))
776 DEBUG_puts("Unable to connect to server!");
782 * Return the PPD file...
785 return (cupsGetPPD2(cg
->http
, name
));
790 * 'cupsGetPPD2()' - Get the PPD file for a printer from the specified server.
792 * For classes, cupsGetPPD2() returns the PPD file for the first printer
795 * @since CUPS 1.1.21@
798 const char * /* O - Filename for PPD file */
799 cupsGetPPD2(http_t
*http
, /* I - HTTP connection */
800 const char *name
) /* I - Printer name */
802 int http_port
; /* Port number */
803 http_t
*http2
; /* Alternate HTTP connection */
804 int fd
; /* PPD file */
805 char localhost
[HTTP_MAX_URI
],/* Local hostname */
806 hostname
[HTTP_MAX_URI
], /* Hostname */
807 resource
[HTTP_MAX_URI
]; /* Resource name */
808 int port
; /* Port number */
809 http_status_t status
; /* HTTP status from server */
810 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
814 * Range check input...
817 DEBUG_printf(("cupsGetPPD2(http=%p, name=\"%s\")\n", http
,
818 name
? name
: "(null)"));
823 _cupsSetError(IPP_INTERNAL_ERROR
, "No HTTP connection!");
825 _cupsSetError(IPP_INTERNAL_ERROR
, "No printer name!");
831 * Try finding a printer URI for this printer...
834 if (!cups_get_printer_uri(http
, name
, hostname
, sizeof(hostname
), &port
,
835 resource
, sizeof(resource
), 0))
839 * Remap local hostname to localhost...
842 httpGetHostname(NULL
, localhost
, sizeof(localhost
));
844 if (!strcasecmp(localhost
, hostname
))
845 strcpy(hostname
, "localhost");
848 * Get the port number we are connected to...
852 if (http
->hostaddr
->addr
.sa_family
== AF_INET6
)
853 http_port
= ntohs(http
->hostaddr
->ipv6
.sin6_port
);
855 #endif /* AF_INET6 */
856 if (http
->hostaddr
->addr
.sa_family
== AF_INET
)
857 http_port
= ntohs(http
->hostaddr
->ipv4
.sin_port
);
859 http_port
= ippPort();
862 * Reconnect to the correct server as needed...
865 if (!strcasecmp(http
->hostname
, hostname
) && port
== http_port
)
867 else if ((http2
= httpConnectEncrypt(hostname
, port
,
868 cupsEncryption())) == NULL
)
870 DEBUG_puts("Unable to connect to server!");
879 if ((fd
= cupsTempFd(cg
->ppd_filename
, sizeof(cg
->ppd_filename
))) < 0)
882 * Can't open file; close the server connection and return NULL...
885 _cupsSetError(IPP_INTERNAL_ERROR
, strerror(errno
));
894 * And send a request to the HTTP server...
897 strlcat(resource
, ".ppd", sizeof(resource
));
899 status
= cupsGetFd(http2
, resource
, fd
);
907 * See if we actually got the file or an error...
910 if (status
!= HTTP_OK
)
914 case HTTP_NOT_FOUND
:
915 _cupsSetError(IPP_NOT_FOUND
, httpStatus(status
));
918 case HTTP_UNAUTHORIZED
:
919 _cupsSetError(IPP_NOT_AUTHORIZED
, httpStatus(status
));
923 DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n",
925 _cupsSetError(IPP_SERVICE_UNAVAILABLE
, httpStatus(status
));
929 unlink(cg
->ppd_filename
);
935 * Return the PPD file...
938 return (cg
->ppd_filename
);
943 * 'cupsGetPrinters()' - Get a list of printers from the default server.
945 * This function is deprecated - use cupsGetDests() instead.
950 int /* O - Number of printers */
951 cupsGetPrinters(char ***printers
) /* O - Printers */
953 int n
; /* Number of printers */
954 ipp_t
*request
, /* IPP Request */
955 *response
; /* IPP Response */
956 ipp_attribute_t
*attr
; /* Current attribute */
957 cups_lang_t
*language
; /* Default language */
958 char **temp
; /* Temporary pointer */
959 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
962 if (printers
== NULL
)
964 _cupsSetError(IPP_INTERNAL_ERROR
, NULL
);
970 * Try to connect to the server...
973 if (!cups_connect("default", NULL
, NULL
))
975 DEBUG_puts("Unable to connect to server!");
981 * Build a CUPS_GET_PRINTERS request, which requires the following
985 * attributes-natural-language
986 * requested-attributes
991 request
->request
.op
.operation_id
= CUPS_GET_PRINTERS
;
992 request
->request
.op
.request_id
= 1;
994 language
= cupsLangDefault();
996 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
997 "attributes-charset", NULL
, cupsLangEncoding(language
));
999 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1000 "attributes-natural-language", NULL
, language
->language
);
1002 cupsLangFree(language
);
1004 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1005 "requested-attributes", NULL
, "printer-name");
1007 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1010 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1011 "printer-type-mask", CUPS_PRINTER_CLASS
);
1014 * Do the request and get back a response...
1020 if ((response
= cupsDoRequest(cg
->http
, request
, "/")) != NULL
)
1022 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
1023 if (attr
->name
!= NULL
&&
1024 strcasecmp(attr
->name
, "printer-name") == 0 &&
1025 attr
->value_tag
== IPP_TAG_NAME
)
1028 temp
= malloc(sizeof(char *));
1030 temp
= realloc(*printers
, sizeof(char *) * (n
+ 1));
1035 * Ran out of memory!
1041 free((*printers
)[n
]);
1045 ippDelete(response
);
1050 temp
[n
] = strdup(attr
->values
[0].string
.text
);
1054 ippDelete(response
);
1062 * 'cupsLastError()' - Return the last IPP status code.
1065 ipp_status_t
/* O - IPP status code from last request */
1068 return (_cupsGlobals()->last_error
);
1073 * 'cupsLastErrorString()' - Return the last IPP status-message.
1078 const char * /* O - status-message text from last request */
1079 cupsLastErrorString(void)
1081 return (_cupsGlobals()->last_status_message
);
1086 * 'cupsPrintFile()' - Print a file to a printer or class on the default server.
1089 int /* O - Job ID */
1090 cupsPrintFile(const char *name
, /* I - Printer or class name */
1091 const char *filename
, /* I - File to print */
1092 const char *title
, /* I - Title of job */
1093 int num_options
,/* I - Number of options */
1094 cups_option_t
*options
) /* I - Options */
1096 DEBUG_printf(("cupsPrintFile(name=\"%s\", filename=\"%s\", "
1097 "title=\"%s\", num_options=%d, options=%p)\n",
1098 name
, filename
, title
, num_options
, options
));
1100 return (cupsPrintFiles(name
, 1, &filename
, title
, num_options
, options
));
1105 * 'cupsPrintFile2()' - Print a file to a printer or class on the specified server.
1107 * @since CUPS 1.1.21@
1110 int /* O - Job ID */
1111 cupsPrintFile2(http_t
*http
, /* I - HTTP connection */
1112 const char *name
, /* I - Printer or class name */
1113 const char *filename
, /* I - File to print */
1114 const char *title
, /* I - Title of job */
1116 /* I - Number of options */
1117 cups_option_t
*options
) /* I - Options */
1119 DEBUG_printf(("cupsPrintFile2(http=%p, name=\"%s\", filename=\"%s\", "
1120 "title=\"%s\", num_options=%d, options=%p)\n",
1121 http
, name
, filename
, title
, num_options
, options
));
1123 return (cupsPrintFiles2(http
, name
, 1, &filename
, title
, num_options
, options
));
1128 * 'cupsPrintFiles()' - Print one or more files to a printer or class on the
1132 int /* O - Job ID */
1133 cupsPrintFiles(const char *name
, /* I - Printer or class name */
1134 int num_files
, /* I - Number of files */
1135 const char **files
, /* I - File(s) to print */
1136 const char *title
, /* I - Title of job */
1138 /* I - Number of options */
1139 cups_option_t
*options
) /* I - Options */
1141 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
1143 DEBUG_printf(("cupsPrintFiles(name=\"%s\", num_files=%d, "
1144 "files=%p, title=\"%s\", num_options=%d, options=%p)\n",
1145 name
, num_files
, files
, title
, num_options
, options
));
1149 * Setup a connection and request data...
1152 if (!cups_connect(name
, NULL
, NULL
))
1154 DEBUG_printf(("cupsPrintFiles: Unable to open connection - %s.\n",
1156 DEBUG_puts("Unable to connect to server!");
1162 * Print the file(s)...
1165 return (cupsPrintFiles2(cg
->http
, name
, num_files
, files
, title
,
1166 num_options
, options
));
1172 * 'cupsPrintFiles2()' - Print one or more files to a printer or class on the
1175 * @since CUPS 1.1.21@
1178 int /* O - Job ID */
1179 cupsPrintFiles2(http_t
*http
, /* I - HTTP connection */
1180 const char *name
, /* I - Printer or class name */
1181 int num_files
,/* I - Number of files */
1182 const char **files
, /* I - File(s) to print */
1183 const char *title
, /* I - Title of job */
1185 /* I - Number of options */
1186 cups_option_t
*options
) /* I - Options */
1188 int i
; /* Looping var */
1189 const char *val
; /* Pointer to option value */
1190 ipp_t
*request
; /* IPP request */
1191 ipp_t
*response
; /* IPP response */
1192 ipp_attribute_t
*attr
; /* IPP job-id attribute */
1193 char uri
[HTTP_MAX_URI
]; /* Printer URI */
1194 cups_lang_t
*language
; /* Language to use */
1195 int jobid
; /* New job ID */
1196 const char *base
; /* Basename of current filename */
1199 DEBUG_printf(("cupsPrintFiles(http=%p, name=\"%s\", num_files=%d, "
1200 "files=%p, title=\"%s\", num_options=%d, options=%p)\n",
1201 http
, name
, num_files
, files
, title
, num_options
, options
));
1204 * Range check input...
1207 if (!http
|| !name
|| num_files
< 1 || files
== NULL
)
1209 _cupsSetError(IPP_INTERNAL_ERROR
, NULL
);
1215 * Setup the printer URI...
1218 if (httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1219 "localhost", 0, "/printers/%s", name
) != HTTP_URI_OK
)
1221 _cupsSetError(IPP_INTERNAL_ERROR
, NULL
);
1227 * Setup the request data...
1230 language
= cupsLangDefault();
1233 * Build a standard CUPS URI for the printer and fill the standard IPP
1237 if ((request
= ippNew()) == NULL
)
1239 _cupsSetError(IPP_INTERNAL_ERROR
, NULL
);
1244 request
->request
.op
.operation_id
= num_files
== 1 ? IPP_PRINT_JOB
:
1246 request
->request
.op
.request_id
= 1;
1248 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1249 "attributes-charset", NULL
, cupsLangEncoding(language
));
1251 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1252 "attributes-natural-language", NULL
,
1253 language
!= NULL
? language
->language
: "C");
1255 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1258 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1262 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "job-name", NULL
,
1266 * Then add all options...
1269 cupsEncodeOptions(request
, num_options
, options
);
1275 snprintf(uri
, sizeof(uri
), "/printers/%s", name
);
1278 response
= cupsDoFileRequest(http
, request
, uri
, *files
);
1280 response
= cupsDoRequest(http
, request
, uri
);
1282 if (response
== NULL
)
1284 else if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
1286 DEBUG_printf(("IPP response code was 0x%x!\n",
1287 response
->request
.status
.status_code
));
1290 else if ((attr
= ippFindAttribute(response
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
1292 DEBUG_puts("No job ID!");
1294 _cupsSetError(IPP_INTERNAL_ERROR
, NULL
);
1299 jobid
= attr
->values
[0].integer
;
1301 if (response
!= NULL
)
1302 ippDelete(response
);
1305 * Handle multiple file jobs if the create-job operation worked...
1308 if (jobid
> 0 && num_files
> 1)
1309 for (i
= 0; i
< num_files
; i
++)
1312 * Build a standard CUPS URI for the job and fill the standard IPP
1316 if ((request
= ippNew()) == NULL
)
1319 request
->request
.op
.operation_id
= IPP_SEND_DOCUMENT
;
1320 request
->request
.op
.request_id
= 1;
1322 snprintf(uri
, sizeof(uri
), "ipp://localhost/jobs/%d", jobid
);
1324 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1325 "attributes-charset", NULL
, cupsLangEncoding(language
));
1327 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1328 "attributes-natural-language", NULL
,
1329 language
!= NULL
? language
->language
: "C");
1331 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
1335 * Handle raw print files...
1338 if (cupsGetOption("raw", num_options
, options
))
1339 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_MIMETYPE
,
1340 "document-format", NULL
, "application/vnd.cups-raw");
1341 else if ((val
= cupsGetOption("document-format", num_options
,
1343 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_MIMETYPE
,
1344 "document-format", NULL
, val
);
1346 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_MIMETYPE
,
1347 "document-format", NULL
, "application/octet-stream");
1349 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1350 "requesting-user-name", NULL
, cupsUser());
1353 * Add the original document filename...
1356 if ((base
= strrchr(files
[i
], '/')) != NULL
)
1361 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "document-name",
1365 * Is this the last document?
1368 if (i
== (num_files
- 1))
1369 ippAddBoolean(request
, IPP_TAG_OPERATION
, "last-document", 1);
1375 snprintf(uri
, sizeof(uri
), "/printers/%s", name
);
1377 if ((response
= cupsDoFileRequest(http
, request
, uri
,
1379 ippDelete(response
);
1382 cupsLangFree(language
);
1389 * 'cups_connect()' - Connect to the specified host...
1392 static char * /* I - Printer name or NULL */
1393 cups_connect(const char *name
, /* I - Destination (printer[@host]) */
1394 char *printer
, /* O - Printer name [HTTP_MAX_URI] */
1395 char *hostname
) /* O - Hostname [HTTP_MAX_URI] */
1397 char hostbuf
[HTTP_MAX_URI
]; /* Name of host */
1398 _cups_globals_t
*cg
= _cupsGlobals();/* Pointer to library globals */
1401 DEBUG_printf(("cups_connect(\"%s\", %p, %p)\n", name
, printer
, hostname
));
1405 _cupsSetError(IPP_BAD_REQUEST
, NULL
);
1411 * All jobs are now queued to cupsServer() to avoid hostname
1412 * resolution problems and to ensure that the user sees all
1413 * locally queued jobs locally.
1416 strlcpy(hostbuf
, cupsServer(), sizeof(hostbuf
));
1418 if (hostname
!= NULL
)
1419 strlcpy(hostname
, hostbuf
, HTTP_MAX_URI
);
1423 if (printer
!= NULL
)
1424 strlcpy(printer
, name
, HTTP_MAX_URI
);
1426 printer
= (char *)name
;
1428 if (cg
->http
!= NULL
)
1430 if (!strcasecmp(cg
->http
->hostname
, hostname
))
1433 httpClose(cg
->http
);
1436 DEBUG_printf(("connecting to %s on port %d...\n", hostname
, ippPort()));
1438 if ((cg
->http
= httpConnectEncrypt(hostname
, ippPort(),
1439 cupsEncryption())) == NULL
)
1441 DEBUG_puts("Unable to connect to server!");
1443 _cupsSetError(IPP_SERVICE_UNAVAILABLE
, strerror(errno
));
1453 * 'cups_get_printer_uri()' - Get the printer-uri-supported attribute for the first printer in a class.
1456 static int /* O - 1 on success, 0 on failure */
1457 cups_get_printer_uri(
1458 http_t
*http
, /* I - HTTP connection */
1459 const char *name
, /* I - Name of printer or class */
1460 char *host
, /* I - Hostname buffer */
1461 int hostsize
, /* I - Size of hostname buffer */
1462 int *port
, /* O - Port number */
1463 char *resource
, /* I - Resource buffer */
1464 int resourcesize
, /* I - Size of resource buffer */
1465 int depth
) /* I - Depth of query */
1467 int i
; /* Looping var */
1468 int http_port
; /* Port number */
1469 http_t
*http2
; /* Alternate HTTP connection */
1470 ipp_t
*request
, /* IPP request */
1471 *response
; /* IPP response */
1472 ipp_attribute_t
*attr
; /* Current attribute */
1473 char uri
[HTTP_MAX_URI
], /* printer-uri attribute */
1474 scheme
[HTTP_MAX_URI
], /* Scheme name */
1475 username
[HTTP_MAX_URI
], /* Username:password */
1476 classname
[255]; /* Temporary class name */
1477 static const char * const requested_attrs
[] =
1478 { /* Requested attributes */
1479 "printer-uri-supported",
1485 DEBUG_printf(("cups_get_printer_uri(http=%p, name=\"%s\", host=%p, "
1486 "hostsize=%d, resource=%p, resourcesize=%d, depth=%d)\n",
1487 http
, name
? name
: "(null)", host
, hostsize
,
1488 resource
, resourcesize
, depth
));
1491 * Setup the printer URI...
1494 if (httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1495 "localhost", 0, "/printers/%s", name
) != HTTP_URI_OK
)
1497 _cupsSetError(IPP_INTERNAL_ERROR
, "Unable to create printer-uri!");
1505 DEBUG_printf(("cups_get_printer_uri: printer-uri=\"%s\"\n", uri
));
1508 * Get the port number we are connected to...
1512 if (http
->hostaddr
->addr
.sa_family
== AF_INET6
)
1513 http_port
= ntohs(http
->hostaddr
->ipv6
.sin6_port
);
1515 #endif /* AF_INET6 */
1516 if (http
->hostaddr
->addr
.sa_family
== AF_INET
)
1517 http_port
= ntohs(http
->hostaddr
->ipv4
.sin_port
);
1519 http_port
= ippPort();
1522 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
1525 * attributes-charset
1526 * attributes-natural-language
1528 * requested-attributes
1531 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
1533 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1536 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1537 "requested-attributes",
1538 sizeof(requested_attrs
) / sizeof(requested_attrs
[0]),
1539 NULL
, requested_attrs
);
1542 * Do the request and get back a response...
1545 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1547 if ((attr
= ippFindAttribute(response
, "member-uris", IPP_TAG_URI
)) != NULL
)
1550 * Get the first actual printer name in the class...
1553 for (i
= 0; i
< attr
->num_values
; i
++)
1555 httpSeparateURI(HTTP_URI_CODING_ALL
, attr
->values
[i
].string
.text
,
1556 scheme
, sizeof(scheme
), username
, sizeof(username
),
1557 host
, hostsize
, port
, resource
, resourcesize
);
1558 if (!strncmp(resource
, "/printers/", 10))
1564 ippDelete(response
);
1571 * No printers in this class - try recursively looking for a printer,
1572 * but not more than 3 levels deep...
1577 for (i
= 0; i
< attr
->num_values
; i
++)
1579 httpSeparateURI(HTTP_URI_CODING_ALL
, attr
->values
[i
].string
.text
,
1580 scheme
, sizeof(scheme
), username
, sizeof(username
),
1581 host
, hostsize
, port
, resource
, resourcesize
);
1582 if (!strncmp(resource
, "/classes/", 9))
1585 * Found a class! Connect to the right server...
1588 if (!strcasecmp(http
->hostname
, host
) && *port
== http_port
)
1590 else if ((http2
= httpConnectEncrypt(host
, *port
,
1591 cupsEncryption())) == NULL
)
1593 DEBUG_puts("Unable to connect to server!");
1599 * Look up printers on that server...
1602 strlcpy(classname
, resource
+ 9, sizeof(classname
));
1604 cups_get_printer_uri(http2
, classname
, host
, hostsize
, port
,
1605 resource
, resourcesize
, depth
+ 1);
1608 * Close the connection as needed...
1620 else if ((attr
= ippFindAttribute(response
, "printer-uri-supported",
1621 IPP_TAG_URI
)) != NULL
)
1623 httpSeparateURI(HTTP_URI_CODING_ALL
, attr
->values
[0].string
.text
,
1624 scheme
, sizeof(scheme
), username
, sizeof(username
),
1625 host
, hostsize
, port
, resource
, resourcesize
);
1626 ippDelete(response
);
1631 ippDelete(response
);
1634 _cupsSetError(IPP_INTERNAL_ERROR
, "No printer-uri found!");
1644 * End of "$Id: util.c 5235 2006-03-06 13:02:23Z mike $".