4 * Printing utilities for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2005 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.
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...
48 * Include necessary headers...
57 #if defined(WIN32) || defined(__EMX__)
61 #endif /* WIN32 || __EMX__ */
68 static char *cups_connect(const char *name
, char *printer
, char *hostname
);
72 * 'cupsCancelJob()' - Cancel a print job.
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 */
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 */
89 * See if we can connect to the server...
92 if (!cups_connect(name
, printer
, hostname
))
94 DEBUG_puts("Unable to connect to server!");
95 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
100 * Build an IPP_CANCEL_JOB request, which requires the following
104 * attributes-natural-language
107 * [requesting-user-name]
112 request
->request
.op
.operation_id
= IPP_CANCEL_JOB
;
113 request
->request
.op
.request_id
= 1;
115 language
= cupsLangDefault();
117 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
118 "attributes-charset", NULL
, cupsLangEncoding(language
));
120 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
121 "attributes-natural-language", NULL
,
122 language
!= NULL
? language
->language
: "C");
124 cupsLangFree(language
);
126 snprintf(uri
, sizeof(uri
), "ipp://%s:%d/printers/%s", hostname
, ippPort(), printer
);
127 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
130 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
, "job-id", job
);
132 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
139 if ((response
= cupsDoRequest(cg
->http
, request
, "/jobs/")) != NULL
)
142 return (cg
->last_error
< IPP_REDIRECTION_OTHER_SITE
);
147 * 'cupsDoFileRequest()' - Do an IPP request...
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 */
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 */
166 DEBUG_printf(("cupsDoFileRequest(%p, %p, \'%s\', \'%s\')\n",
167 http
, request
, resource
? resource
: "(null)",
168 filename
? filename
: "(null)"));
170 if (http
== NULL
|| request
== NULL
|| resource
== NULL
)
175 cg
->last_error
= IPP_INTERNAL_ERROR
;
180 * See if we have a file to send...
183 if (filename
!= NULL
)
185 if (stat(filename
, &fileinfo
))
188 * Can't get file information!
192 cg
->last_error
= IPP_NOT_FOUND
;
197 if (fileinfo
.st_mode
& _S_IFDIR
)
199 if (S_ISDIR(fileinfo
.st_mode
))
203 * Can't send a directory...
207 cg
->last_error
= IPP_NOT_POSSIBLE
;
211 if ((file
= fopen(filename
, "rb")) == NULL
)
218 cg
->last_error
= IPP_NOT_FOUND
;
226 * Loop until we can send the request without authorization problems.
232 while (response
== NULL
)
234 DEBUG_puts("cupsDoFileRequest: setup...");
237 * Setup the HTTP variables needed...
240 length
= ippLength(request
);
242 length
+= fileinfo
.st_size
;
244 httpClearFields(http
);
245 httpSetLength(http
, length
);
246 httpSetField(http
, HTTP_FIELD_CONTENT_TYPE
, "application/ipp");
247 httpSetField(http
, HTTP_FIELD_AUTHORIZATION
, http
->authstring
);
249 DEBUG_printf(("cupsDoFileRequest: authstring=\"%s\"\n", http
->authstring
));
255 DEBUG_puts("cupsDoFileRequest: post...");
257 if (httpPost(http
, resource
))
259 if (httpReconnect(http
))
269 * Send the IPP data and wait for the response...
272 DEBUG_puts("cupsDoFileRequest: ipp write...");
274 request
->state
= IPP_IDLE
;
275 status
= HTTP_CONTINUE
;
277 if (ippWrite(http
, request
) != IPP_ERROR
)
278 if (filename
!= NULL
)
280 DEBUG_puts("cupsDoFileRequest: file write...");
288 while ((bytes
= fread(buffer
, 1, sizeof(buffer
), file
)) > 0)
292 if ((status
= httpUpdate(http
)) != HTTP_CONTINUE
)
296 if (httpWrite(http
, buffer
, bytes
) < bytes
)
302 * Get the server's return status...
305 DEBUG_puts("cupsDoFileRequest: update...");
307 while (status
== HTTP_CONTINUE
)
308 status
= httpUpdate(http
);
310 DEBUG_printf(("cupsDoFileRequest: status = %d\n", status
));
312 if (status
== HTTP_UNAUTHORIZED
)
314 DEBUG_puts("cupsDoFileRequest: unauthorized...");
317 * Flush any error message...
323 * See if we can do authentication...
326 if (cupsDoAuthentication(http
, "POST", resource
))
333 else if (status
== HTTP_ERROR
)
336 if (http
->error
!= WSAENETDOWN
&& http
->error
!= WSAENETUNREACH
)
338 if (http
->error
!= ENETDOWN
&& http
->error
!= ENETUNREACH
)
345 else if (status
== HTTP_UPGRADE_REQUIRED
)
347 /* Flush any error message... */
351 if (httpReconnect(http
))
357 /* Upgrade with encryption... */
358 httpEncryption(http
, HTTP_ENCRYPT_REQUIRED
);
360 /* Try again, this time with encryption enabled... */
363 #endif /* HAVE_SSL */
364 else if (status
!= HTTP_OK
)
366 DEBUG_printf(("cupsDoFileRequest: error %d...\n", status
));
369 * Flush any error message...
378 * Read the response...
381 DEBUG_puts("cupsDoFileRequest: response...");
385 if (ippRead(http
, response
) == IPP_ERROR
)
388 * Delete the response...
391 DEBUG_puts("IPP read error!");
395 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
402 * Close the file if needed...
405 if (filename
!= NULL
)
409 * Flush any remaining data...
415 * Delete the original request and return the response...
421 cg
->last_error
= response
->request
.status
.status_code
;
422 else if (status
!= HTTP_OK
)
426 case HTTP_NOT_FOUND
:
427 cg
->last_error
= IPP_NOT_FOUND
;
430 case HTTP_UNAUTHORIZED
:
431 cg
->last_error
= IPP_NOT_AUTHORIZED
;
434 case HTTP_FORBIDDEN
:
435 cg
->last_error
= IPP_FORBIDDEN
;
438 case HTTP_BAD_REQUEST
:
439 cg
->last_error
= IPP_BAD_REQUEST
;
442 case HTTP_REQUEST_TOO_LARGE
:
443 cg
->last_error
= IPP_REQUEST_VALUE
;
446 case HTTP_NOT_IMPLEMENTED
:
447 cg
->last_error
= IPP_OPERATION_NOT_SUPPORTED
;
450 case HTTP_NOT_SUPPORTED
:
451 cg
->last_error
= IPP_VERSION_NOT_SUPPORTED
;
455 DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n",
457 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
467 * 'cupsFreeJobs()' - Free memory used by job data.
471 cupsFreeJobs(int num_jobs
, /* I - Number of jobs */
472 cups_job_t
*jobs
) /* I - Jobs */
474 int i
; /* Looping var */
477 if (num_jobs
<= 0 || jobs
== NULL
)
480 for (i
= 0; i
< num_jobs
; i
++)
484 free(jobs
[i
].format
);
493 * 'cupsGetClasses()' - Get a list of printer classes.
496 int /* O - Number of classes */
497 cupsGetClasses(char ***classes
) /* O - Classes */
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 */
510 cg
->last_error
= IPP_INTERNAL_ERROR
;
515 * Try to connect to the server...
518 if (!cups_connect("default", NULL
, NULL
))
520 DEBUG_puts("Unable to connect to server!");
521 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
526 * Build a CUPS_GET_CLASSES request, which requires the following
530 * attributes-natural-language
531 * requested-attributes
536 request
->request
.op
.operation_id
= CUPS_GET_CLASSES
;
537 request
->request
.op
.request_id
= 1;
539 language
= cupsLangDefault();
541 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
542 "attributes-charset", NULL
, cupsLangEncoding(language
));
544 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
545 "attributes-natural-language", NULL
, language
->language
);
547 cupsLangFree(language
);
549 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
550 "requested-attributes", NULL
, "printer-name");
553 * Do the request and get back a response...
559 if ((response
= cupsDoRequest(cg
->http
, request
, "/")) != NULL
)
561 cg
->last_error
= response
->request
.status
.status_code
;
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
)
569 temp
= malloc(sizeof(char *));
571 temp
= realloc(*classes
, sizeof(char *) * (n
+ 1));
591 temp
[n
] = strdup(attr
->values
[0].string
.text
);
598 cg
->last_error
= IPP_BAD_REQUEST
;
605 * 'cupsGetDefault()' - Get the default printer or class.
608 const char * /* O - Default printer or NULL */
611 const char *var
; /* Environment variable */
612 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
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"...
622 if ((var
= getenv("LPDEST")) != NULL
)
624 else if ((var
= getenv("PRINTER")) != NULL
&& strcmp(var
, "lp") != 0)
628 * Try to connect to the server...
631 if (!cups_connect("default", NULL
, NULL
))
633 DEBUG_puts("Unable to connect to server!");
634 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
639 * Return the default printer...
642 return (cupsGetDefault2(cg
->http
));
647 * 'cupsGetDefault2()' - Get the default printer or class.
650 const char * /* O - Default printer or NULL */
651 cupsGetDefault2(http_t
*http
) /* I - HTTP connection */
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 */
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"...
668 if ((var
= getenv("LPDEST")) != NULL
)
670 else if ((var
= getenv("PRINTER")) != NULL
&& strcmp(var
, "lp") != 0)
674 * Range check input...
681 * Build a CUPS_GET_DEFAULT request, which requires the following
685 * attributes-natural-language
690 request
->request
.op
.operation_id
= CUPS_GET_DEFAULT
;
691 request
->request
.op
.request_id
= 1;
693 language
= cupsLangDefault();
695 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
696 "attributes-charset", NULL
, cupsLangEncoding(language
));
698 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
699 "attributes-natural-language", NULL
, language
->language
);
701 cupsLangFree(language
);
704 * Do the request and get back a response...
707 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
709 cg
->last_error
= response
->request
.status
.status_code
;
711 if ((attr
= ippFindAttribute(response
, "printer-name", IPP_TAG_NAME
)) != NULL
)
713 strlcpy(cg
->def_printer
, attr
->values
[0].string
.text
, sizeof(cg
->def_printer
));
715 return (cg
->def_printer
);
721 cg
->last_error
= IPP_BAD_REQUEST
;
728 * 'cupsGetJobs()' - Get the jobs from the server.
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? */
737 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
740 * Try to connect to the server...
743 if (!cups_connect("default", NULL
, NULL
))
745 DEBUG_puts("Unable to connect to server!");
746 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
754 return (cupsGetJobs2(cg
->http
, jobs
, mydest
, myjobs
, completed
));
760 * 'cupsGetJobs2()' - Get the jobs from the server.
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? */
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 */
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 */
797 "time-at-processing",
801 "job-originating-user-name"
807 cg
->last_error
= IPP_INTERNAL_ERROR
;
812 * Build an IPP_GET_JOBS request, which requires the following
816 * attributes-natural-language
818 * requesting-user-name
821 * requested-attributes
826 request
->request
.op
.operation_id
= IPP_GET_JOBS
;
827 request
->request
.op
.request_id
= 1;
829 language
= cupsLangDefault();
831 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
832 "attributes-charset", NULL
, cupsLangEncoding(language
));
834 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
835 "attributes-natural-language", NULL
, language
->language
);
837 cupsLangFree(language
);
840 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s", mydest
);
842 strcpy(uri
, "ipp://localhost/jobs");
844 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
845 "printer-uri", NULL
, uri
);
847 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
848 "requesting-user-name", NULL
, cupsUser());
851 ippAddBoolean(request
, IPP_TAG_OPERATION
, "my-jobs", 1);
854 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
855 "which-jobs", NULL
, "completed");
857 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
858 "requested-attributes", sizeof(attrs
) / sizeof(attrs
[0]),
862 * Do the request and get back a response...
868 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
870 cg
->last_error
= response
->request
.status
.status_code
;
872 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
875 * Skip leading attributes until we hit a job...
878 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_JOB
)
885 * Pull the needed attributes from this job...
891 state
= IPP_JOB_PENDING
;
894 format
= "application/octet-stream";
900 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_JOB
)
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
)
926 if ((dest
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
)
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
;
944 * See if we have everything needed...
947 if (dest
== NULL
|| id
== 0)
956 * Allocate memory for the job...
960 temp
= malloc(sizeof(cups_job_t
));
962 temp
= realloc(*jobs
, sizeof(cups_job_t
) * (n
+ 1));
970 cupsFreeJobs(n
, *jobs
);
982 * Copy the data over...
985 temp
->dest
= strdup(dest
);
986 temp
->user
= strdup(user
);
987 temp
->format
= strdup(format
);
988 temp
->title
= strdup(title
);
990 temp
->priority
= priority
;
993 temp
->completed_time
= completed_time
;
994 temp
->creation_time
= creation_time
;
995 temp
->processing_time
= processing_time
;
1001 ippDelete(response
);
1004 cg
->last_error
= IPP_BAD_REQUEST
;
1006 if (n
== 0 && cg
->last_error
>= IPP_BAD_REQUEST
)
1014 * 'cupsGetPPD()' - Get the PPD file for a printer.
1017 const char * /* O - Filename for PPD file */
1018 cupsGetPPD(const char *name
) /* I - Printer name */
1020 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
1023 * See if we can connect to the server...
1026 if (!cups_connect(name
, NULL
, NULL
))
1028 DEBUG_puts("Unable to connect to server!");
1029 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
1034 * Return the PPD file...
1037 return (cupsGetPPD2(cg
->http
, name
));
1042 * 'cupsGetPPD2()' - Get the PPD file for a printer.
1045 const char * /* O - Filename for PPD file */
1046 cupsGetPPD2(http_t
*http
, /* I - HTTP connection */
1047 const char *name
) /* I - Printer name */
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",
1075 * Range check input...
1078 DEBUG_printf(("cupsGetPPD2(http=%p, name=\"%s\")\n", http
,
1079 name
? name
: "(null)"));
1083 cg
->last_error
= IPP_INTERNAL_ERROR
;
1088 * Get the port number we are connect to...
1092 if (http
->hostaddr
.addr
.sa_family
== AF_INET6
)
1093 http_port
= ntohs(http
->hostaddr
.ipv6
.sin6_port
);
1095 #endif /* AF_INET6 */
1096 if (http
->hostaddr
.addr
.sa_family
== AF_INET
)
1097 http_port
= ntohs(http
->hostaddr
.ipv4
.sin_port
);
1099 http_port
= ippPort();
1104 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
1107 * attributes-charset
1108 * attributes-natural-language
1110 * requested-attributes
1115 request
->request
.op
.operation_id
= IPP_GET_PRINTER_ATTRIBUTES
;
1116 request
->request
.op
.request_id
= 1;
1118 language
= cupsLangDefault();
1120 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1121 "attributes-charset", NULL
, cupsLangEncoding(language
));
1123 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1124 "attributes-natural-language", NULL
, language
->language
);
1126 cupsLangFree(language
);
1128 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s", name
);
1129 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1130 "printer-uri", NULL
, uri
);
1132 DEBUG_printf(("cupsGetPPD2: printer-uri=\"%s\"\n", uri
));
1134 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1135 "requested-attributes",
1136 sizeof(requested_attrs
) / sizeof(requested_attrs
[0]),
1137 NULL
, requested_attrs
);
1140 * Do the request and get back a response...
1143 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1145 cg
->last_error
= response
->request
.status
.status_code
;
1149 if ((attr
= ippFindAttribute(response
, "member-uris", IPP_TAG_URI
)) != NULL
)
1152 * Get the first actual server and printer name in the class...
1155 for (i
= 0; i
< attr
->num_values
; i
++)
1157 httpSeparate(attr
->values
[0].string
.text
, method
, username
, hostname
,
1159 if (!strncmp(resource
, "/printers/", 10))
1165 strlcpy(printer
, resource
+ 10, sizeof(printer
));
1170 else if ((attr
= ippFindAttribute(response
, "printer-uri-supported",
1171 IPP_TAG_URI
)) != NULL
)
1174 * Get the actual server and printer names...
1177 httpSeparate(attr
->values
[0].string
.text
, method
, username
, hostname
,
1179 strlcpy(printer
, strrchr(resource
, '/') + 1, sizeof(printer
));
1182 ippDelete(response
);
1185 * Remap local hostname to localhost...
1188 httpGetHostname(uri
, sizeof(uri
));
1190 if (!strcasecmp(uri
, hostname
))
1191 strcpy(hostname
, "localhost");
1196 cg
->last_error
= IPP_NOT_FOUND
;
1201 * Reconnect to the correct server as needed...
1204 if (!strcasecmp(http
->hostname
, hostname
) && port
== http_port
)
1206 else if ((http2
= httpConnectEncrypt(hostname
, port
,
1207 cupsEncryption())) == NULL
)
1209 DEBUG_puts("Unable to connect to server!");
1210 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
1215 * Get a temp file...
1218 if ((fd
= cupsTempFd(cg
->ppd_filename
, sizeof(cg
->ppd_filename
))) < 0)
1221 * Can't open file; close the server connection and return NULL...
1224 cg
->last_error
= IPP_INTERNAL_ERROR
;
1233 * And send a request to the HTTP server...
1236 snprintf(resource
, sizeof(resource
), "/printers/%s.ppd", printer
);
1238 status
= cupsGetFd(http2
, resource
, fd
);
1246 * See if we actually got the file or an error...
1249 if (status
!= HTTP_OK
)
1253 case HTTP_NOT_FOUND
:
1254 cg
->last_error
= IPP_NOT_FOUND
;
1257 DEBUG_puts("Mapping HTTP error to IPP_ERROR");
1258 cg
->last_error
= IPP_ERROR
;
1260 case HTTP_UNAUTHORIZED
:
1261 cg
->last_error
= IPP_NOT_AUTHORIZED
;
1264 cg
->last_error
= IPP_INTERNAL_ERROR
;
1268 unlink(cg
->ppd_filename
);
1274 * Return the PPD file...
1277 return (cg
->ppd_filename
);
1282 * 'cupsGetPrinters()' - Get a list of printers.
1285 int /* O - Number of printers */
1286 cupsGetPrinters(char ***printers
) /* O - Printers */
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 */
1297 if (printers
== NULL
)
1299 cg
->last_error
= IPP_INTERNAL_ERROR
;
1304 * Try to connect to the server...
1307 if (!cups_connect("default", NULL
, NULL
))
1309 DEBUG_puts("Unable to connect to server!");
1310 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
1315 * Build a CUPS_GET_PRINTERS request, which requires the following
1318 * attributes-charset
1319 * attributes-natural-language
1320 * requested-attributes
1325 request
->request
.op
.operation_id
= CUPS_GET_PRINTERS
;
1326 request
->request
.op
.request_id
= 1;
1328 language
= cupsLangDefault();
1330 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1331 "attributes-charset", NULL
, cupsLangEncoding(language
));
1333 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1334 "attributes-natural-language", NULL
, language
->language
);
1336 cupsLangFree(language
);
1338 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1339 "requested-attributes", NULL
, "printer-name");
1342 * Do the request and get back a response...
1348 if ((response
= cupsDoRequest(cg
->http
, request
, "/")) != NULL
)
1350 cg
->last_error
= response
->request
.status
.status_code
;
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
)
1358 temp
= malloc(sizeof(char *));
1360 temp
= realloc(*printers
, sizeof(char *) * (n
+ 1));
1365 * Ran out of memory!
1371 free((*printers
)[n
]);
1375 ippDelete(response
);
1380 temp
[n
] = strdup(attr
->values
[0].string
.text
);
1384 ippDelete(response
);
1387 cg
->last_error
= IPP_BAD_REQUEST
;
1394 * 'cupsLastError()' - Return the last IPP error that occurred.
1397 ipp_status_t
/* O - IPP error code */
1400 return (_cupsGlobals()->last_error
);
1405 * 'cupsPrintFile()' - Print a file to a printer or class.
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 */
1415 DEBUG_printf(("cupsPrintFile(name=\"%s\", filename=\"%s\", "
1416 "title=\"%s\", num_options=%d, options=%p)\n",
1417 name
, filename
, title
, num_options
, options
));
1419 return (cupsPrintFiles(name
, 1, &filename
, title
, num_options
, options
));
1424 * 'cupsPrintFile2()' - Print a file to a printer or class.
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 */
1433 /* I - Number of options */
1434 cups_option_t
*options
) /* I - Options */
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
));
1440 return (cupsPrintFiles2(http
, name
, 1, &filename
, title
, num_options
, options
));
1445 * 'cupsPrintFiles()' - Print one or more files to a printer or class.
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 */
1454 /* I - Number of options */
1455 cups_option_t
*options
) /* I - Options */
1457 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
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
));
1465 * Setup a connection and request data...
1468 if (!cups_connect(name
, NULL
, NULL
))
1470 DEBUG_printf(("cupsPrintFiles: Unable to open connection - %s.\n",
1472 DEBUG_puts("Unable to connect to server!");
1473 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
1478 * Print the file(s)...
1481 return (cupsPrintFiles2(cg
->http
, name
, num_files
, files
, title
,
1482 num_options
, options
));
1488 * 'cupsPrintFiles2()' - Print one or more files to a printer or class.
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 */
1498 /* I - Number of options */
1499 cups_option_t
*options
) /* I - Options */
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 */
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
));
1517 * Range check input...
1520 if (!http
|| !name
|| num_files
< 1 || files
== NULL
)
1524 * Setup the request data...
1527 language
= cupsLangDefault();
1530 * Build a standard CUPS URI for the printer and fill the standard IPP
1534 if ((request
= ippNew()) == NULL
)
1537 request
->request
.op
.operation_id
= num_files
== 1 ? IPP_PRINT_JOB
:
1539 request
->request
.op
.request_id
= 1;
1541 snprintf(uri
, sizeof(uri
), "ipp://%s:%d/printers/%s", http
->hostname
,
1544 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1545 "attributes-charset", NULL
, cupsLangEncoding(language
));
1547 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1548 "attributes-natural-language", NULL
,
1549 language
!= NULL
? language
->language
: "C");
1551 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1554 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1558 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "job-name", NULL
,
1562 * Then add all options...
1565 cupsEncodeOptions(request
, num_options
, options
);
1571 snprintf(uri
, sizeof(uri
), "/printers/%s", name
);
1574 response
= cupsDoFileRequest(http
, request
, uri
, *files
);
1576 response
= cupsDoRequest(http
, request
, uri
);
1578 if (response
== NULL
)
1580 else if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
1582 DEBUG_printf(("IPP response code was 0x%x!\n",
1583 response
->request
.status
.status_code
));
1586 else if ((attr
= ippFindAttribute(response
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
1588 DEBUG_puts("No job ID!");
1590 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
1595 jobid
= attr
->values
[0].integer
;
1597 if (response
!= NULL
)
1598 ippDelete(response
);
1601 * Handle multiple file jobs if the create-job operation worked...
1604 if (jobid
> 0 && num_files
> 1)
1605 for (i
= 0; i
< num_files
; i
++)
1608 * Build a standard CUPS URI for the job and fill the standard IPP
1612 if ((request
= ippNew()) == NULL
)
1615 request
->request
.op
.operation_id
= IPP_SEND_DOCUMENT
;
1616 request
->request
.op
.request_id
= 1;
1618 snprintf(uri
, sizeof(uri
), "ipp://%s:%d/jobs/%d", http
->hostname
,
1621 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1622 "attributes-charset", NULL
, cupsLangEncoding(language
));
1624 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1625 "attributes-natural-language", NULL
,
1626 language
!= NULL
? language
->language
: "C");
1628 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
1632 * Handle raw print files...
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",
1642 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_MIMETYPE
, "document-format",
1643 NULL
, "application/octet-stream");
1645 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1649 * Is this the last document?
1652 if (i
== (num_files
- 1))
1653 ippAddBoolean(request
, IPP_TAG_OPERATION
, "last-document", 1);
1659 snprintf(uri
, sizeof(uri
), "/printers/%s", name
);
1661 if ((response
= cupsDoFileRequest(http
, request
, uri
,
1663 ippDelete(response
);
1666 cupsLangFree(language
);
1673 * 'cups_connect()' - Connect to the specified host...
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] */
1681 char hostbuf
[HTTP_MAX_URI
]; /* Name of host */
1682 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
1685 DEBUG_printf(("cups_connect(\"%s\", %p, %p)\n", name
, printer
, hostname
));
1689 cg
->last_error
= IPP_BAD_REQUEST
;
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.
1699 strlcpy(hostbuf
, cupsServer(), sizeof(hostbuf
));
1701 if (hostname
!= NULL
)
1702 strlcpy(hostname
, hostbuf
, HTTP_MAX_URI
);
1706 if (printer
!= NULL
)
1707 strlcpy(printer
, name
, HTTP_MAX_URI
);
1709 printer
= (char *)name
;
1711 if (cg
->http
!= NULL
)
1713 if (strcasecmp(cg
->http
->hostname
, hostname
) == 0)
1716 httpClose(cg
->http
);
1719 DEBUG_printf(("connecting to %s on port %d...\n", hostname
, ippPort()));
1721 if ((cg
->http
= httpConnectEncrypt(hostname
, ippPort(),
1722 cupsEncryption())) == NULL
)
1724 DEBUG_puts("Unable to connect to server!");
1725 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;