X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=cups%2Fapi-httpipp.shtml;h=cd0fd53b5b134d49f3a122b546e4938f158c692f;hb=076239869a921fff635f11ef9d459eea9a4d8b9f;hp=9b860bfd30adff53f48518c3c4b7b9d930c80854;hpb=ecdc06282a65bd04f801c877d2ceb83106d737e1;p=thirdparty%2Fcups.git diff --git a/cups/api-httpipp.shtml b/cups/api-httpipp.shtml index 9b860bfd3..cd0fd53b5 100644 --- a/cups/api-httpipp.shtml +++ b/cups/api-httpipp.shtml @@ -1,52 +1,317 @@ -
The CUPS HTTP and IPP APIs provide low-level access to the -HTTP and IPP protocols and CUPS scheduler. They are typically -used by monitoring and administration programs to perform -specific functions not supported by the high-level CUPS API -functions.
+The CUPS HTTP and IPP APIs provide low-level access to the HTTP and IPP +protocols and CUPS scheduler. They are typically used by monitoring and +administration programs to perform specific functions not supported by the +high-level CUPS API functions.
-The HTTP APIs use an opaque structure called
+http_t
to manage connections to
+a particular HTTP or IPP server. The
+httpConnectEncrypt
function is
+used to create an instance of this structure for a particular server.
+The constant CUPS_HTTP_DEFAULT
can be used with all of the
+cups
functions to refer to the default CUPS server - the functions
+create a per-thread http_t
as needed.
The <cups/cups.h> header file must be included to -use the HTTP and IPP functions.
+The IPP APIs use two opaque structures for requests (messages sent to the CUPS scheduler) and responses (messages sent back to your application from the scheduler). The ipp_t
type holds a complete request or response and is allocated using the ippNew
or ippNewRequest
functions and freed using the ippDelete
function.
Programs using these functions must be linked to the CUPS -library: libcups.a, libcups.so.2, -libcups.2.dylib, libcups_s.a, or -libcups2.lib depending on the platform. The following -command compiles myprogram.c using GCC and the CUPS -library:
+The second opaque structure is called ipp_attribute_t
and holds a single IPP attribute which consists of a group tag (ippGetGroupTag
), a value type tag (ippGetValueTag
), the attribute name (ippGetName
), and 1 or more values (ippGetCount
, ippGetBoolean
, ippGetCollection
, ippGetDate
, ippGetInteger
, ippGetRange
, ippGetResolution
, and ippGetString
). Attributes are added to an ipp_t
pointer using one of the ippAdd
functions. For example, use ippAddString
to add the "printer-uri" and "requesting-user-name" string attributes to a request:
-gcc -o myprogram myprogram.c -lcups ++ipp_t *request = ippNewRequest(IPP_GET_JOBS); + +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, "ipp://localhost/printers/"); +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, cupsUser()); ++ +Once you have created an IPP request, use the
+ +cups
functions to send the request to and read the response from the server. For example, thecupsDoRequest
function can be used for simple query operations that do not involve files:+#include <cups/cups.h> + + +ipp_t *get_jobs(void) +{ + ipp_t *request = ippNewRequest(IPP_GET_JOBS); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, "ipp://localhost/printers/"); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, cupsUser()); + + return (cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")); +} ++ +The
+ +cupsDoRequest
function frees the request and returns an IPP response orNULL
pointer if the request could not be sent to the server. Once you have a response from the server, you can either use theippFindAttribute
andippFindNextAttribute
functions to find specific attributes, for example:+ipp_t *response; +ipp_attribute_t *attr; + +attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM); ++ +You can also walk the list of attributes with a simple
+ +for
loop like this:+ipp_t *response; +ipp_attribute_t *attr; + +for (attr = ippFirstAttribute(response); attr != NULL; attr = ippNextAttribute(response)) + if (ippGetName(attr) == NULL) + puts("--SEPARATOR--"); + else + puts(ippGetName(attr)); ++ +The
+ +for
loop approach is normally used when collecting attributes for multiple objects (jobs, printers, etc.) in a response. Attributes withNULL
names indicate a separator between the attributes of each object. For example, the following code will list the jobs returned from our previousget_jobs
example code:+ipp_t *response = get_jobs(); + +if (response != NULL) +{ + ipp_attribute_t *attr; + const char *attrname; + int job_id = 0; + const char *job_name = NULL; + const char *job_originating_user_name = NULL; + + puts("Job ID Owner Title"); + puts("------ ---------------- ---------------------------------"); + + for (attr = ippFirstAttribute(response); attr != NULL; attr = ippNextAttribute(response)) + { + /* Attributes without names are separators between jobs */ + attrname = ippGetName(attr); + if (attrname == NULL) + { + if (job_id > 0) + { + if (job_name == NULL) + job_name = "(withheld)"; + + if (job_originating_user_name == NULL) + job_originating_user_name = "(withheld)"; + + printf("%5d %-16s %s\n", job_id, job_originating_user_name, job_name); + } + + job_id = 0; + job_name = NULL; + job_originating_user_name = NULL; + continue; + } + else if (!strcmp(attrname, "job-id") && ippGetValueTag(attr) == IPP_TAG_INTEGER) + job_id = ippGetInteger(attr, 0); + else if (!strcmp(attrname, "job-name") && ippGetValueTag(attr) == IPP_TAG_NAME) + job_name = ippGetString(attr, 0, NULL); + else if (!strcmp(attrname, "job-originating-user-name") && + ippGetValueTag(attr) == IPP_TAG_NAME) + job_originating_user_name = ippGetString(attr, 0, NULL); + } + + if (job_id > 0) + { + if (job_name == NULL) + job_name = "(withheld)"; + + if (job_originating_user_name == NULL) + job_originating_user_name = "(withheld)"; + + printf("%5d %-16s %s\n", job_id, job_originating_user_name, job_name); + } +} ++ +Creating URI Strings
+ +To ensure proper encoding, the +
+ +httpAssembleURIf
function must be +used to format a "printer-uri" string for all printer-based requests:+const char *name = "Foo"; +char uri[1024]; +ipp_t *request; + +httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, cupsServer(), + ippPort(), "/printers/%s", name); +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);-Compatibility
+Sending Requests with Files
+ +The
-cupsDoFileRequest
and +cupsDoIORequest
functions are +used for requests involving files. The +cupsDoFileRequest
function +attaches the named file to a request and is typically used when sending a print +file or changing a printer's PPD file:Unless otherwise specified, the HTTP and IPP API functions -require CUPS 1.1 or higher.
++const char *filename = "/usr/share/cups/data/testprint.ps"; +const char *name = "Foo"; +char uri[1024]; +char resource[1024]; +ipp_t *request = ippNewRequest(IPP_PRINT_JOB); +ipp_t *response; + +/* Use httpAssembleURIf for the printer-uri string */ +httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, cupsServer(), + ippPort(), "/printers/%s", name); +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, cupsUser()); +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", + NULL, "testprint.ps"); + +/* Use snprintf for the resource path */ +snprintf(resource, sizeof(resource), "/printers/%s", name); + +response = cupsDoFileRequest(CUPS_HTTP_DEFAULT, request, resource, filename); ++ +The
+ +cupsDoIORequest
function +optionally attaches a file to the request and optionally saves a file in the +response from the server. It is used when using a pipe for the request +attachment or when using a request that returns a file, currently only +CUPS_GET_DOCUMENT
andCUPS_GET_PPD
. For example, +the following code will download the PPD file for the sample HP LaserJet +printer driver:+char tempfile[1024]; +int tempfd; +ipp_t *request = ippNewRequest(CUPS_GET_PPD); +ipp_t *response; + +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name", + NULL, "laserjet.ppd"); + +tempfd = cupsTempFd(tempfile, sizeof(tempfile)); + +response = cupsDoIORequest(CUPS_HTTP_DEFAULT, request, "/", -1, tempfd); ++ +The example passes
+ +-1
for the input file descriptor to specify +that no file is to be attached to the request. The PPD file attached to the +response is written to the temporary file descriptor we created using the +cupsTempFd
function.Asynchronous Request Processing
+ +The
+ +cupsSendRequest
and +cupsGetResponse
support +asynchronous communications with the server. Unlike the other request +functions, the IPP request is not automatically freed, so remember to +free your request with theippDelete
+function.File data is attached to the request using the +
+ +cupsWriteRequestData
+function, while file data returned from the server is read using the +cupsReadResponseData
+function. We can rewrite the previousCUPS_GET_PPD
example +to use the asynchronous functions quite easily:+char tempfile[1024]; +int tempfd; +ipp_t *request = ippNewRequest(CUPS_GET_PPD); +ipp_t *response; + +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name", + NULL, "laserjet.ppd"); + +tempfd = cupsTempFd(tempfile, sizeof(tempfile)); + +if (cupsSendRequest(CUPS_HTTP_DEFAULT, request, "/") == HTTP_CONTINUE) +{ + response = cupsGetResponse(CUPS_HTTP_DEFAULT, "/"); + + if (response != NULL) + { + ssize_t bytes; + char buffer[8192]; + + while ((bytes = cupsReadResponseData(CUPS_HTTP_DEFAULT, buffer, sizeof(buffer))) > 0) + write(tempfd, buffer, bytes); + } +} + +/* Free the request! */ +ippDelete(request); ++ +The
+ +cupsSendRequest
function +returns the initial HTTP request status, typically either +HTTP_CONTINUE
orHTTP_UNAUTHORIZED
. The latter status +is returned when the request requires authentication of some sort. The +cupsDoAuthentication
function +must be called when your seeHTTP_UNAUTHORIZED
and the request +re-sent. We can add authentication support to our example code by using a +do ... while
loop:+char tempfile[1024]; +int tempfd; +ipp_t *request = ippNewRequest(CUPS_GET_PPD); +ipp_t *response; +http_status_t status; + +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name", + NULL, "laserjet.ppd"); + +tempfd = cupsTempFd(tempfile, sizeof(tempfile)); + +/* Loop for authentication */ +do +{ + status = cupsSendRequest(CUPS_HTTP_DEFAULT, request, "/"); + + if (status == HTTP_UNAUTHORIZED) + { + /* Try to authenticate, break out of the loop if that fails */ + if (cupsDoAuthentication(CUPS_HTTP_DEFAULT, "POST", "/")) + break; + } +} +while (status != HTTP_CONTINUE && status != HTTP_UNAUTHORIZED); + +if (status == HTTP_CONTINUE) +{ + response = cupsGetResponse(CUPS_HTTP_DEFAULT, "/"); + + if (response != NULL) + { + ssize_t bytes; + char buffer[8192]; + + while ((bytes = cupsReadResponseData(CUPS_HTTP_DEFAULT, buffer, sizeof(buffer))) > 0) + write(tempfd, buffer, bytes); + } +} + +/* Free the request! */ +ippDelete(request); +