title: CUPS Programming Manual author: Michael R Sweet copyright: Copyright © 2007-2019 by Apple Inc. All Rights Reserved. version: 2.3.3 ...
Please file issues on Github to provide feedback on this document.
CUPS provides the “cups” library to talk to the different parts of CUPS and with Internet Printing Protocol (IPP) printers. The “cups” library functions are accessed by including the <cups/cups.h>
header.
CUPS is based on the Internet Printing Protocol (“IPP”), which allows clients (applications) to communicate with a server (the scheduler, printers, etc.) to get a list of destinations, send print jobs, and so forth. You identify which server you want to communicate with using a pointer to the opaque structure http_t
. The CUPS_HTTP_DEFAULT
constant can be used when you want to talk to the CUPS scheduler.
When writing software (other than printer drivers) that uses the “cups” library:
CUPS is designed to insulate users and developers from the implementation details of printers and file formats. The goal is to allow an application to supply a print file in a standard format with the user intent (“print four copies, two-sided on A4 media, and staple each copy”) and have the printing system manage the printer communication and format conversion needed.
Similarly, printer and job management applications can use standard query operations to obtain the status information in a common, generic form and use standard management operations to control the state of those printers and jobs.
Note:
CUPS printer drivers necessarily depend on specific file formats and certain implementation details of the CUPS software. Please consult the Postscript and raster printer driver developer documentation on CUPS.org for more information.
A Destination is a printer or print queue that accepts print jobs. A Print Job is a collection of one or more documents that are processed by a destination using options supplied when creating the job. A Document is a file (JPEG image, PDF file, etc.) suitable for printing. An Option controls some aspect of printing, such as the media used. Media is the sheets or roll that is printed on. An Attribute is an option encoded for an Internet Printing Protocol (IPP) request.
The CUPS libraries can be used from any C, C++, or Objective C program. The method of compiling against the libraries varies depending on the operating system and installation of CUPS. The following sections show how to compile a simple program (shown below) in two common environments.
The following simple program lists the available destinations:
#include <stdio.h> #include <cups/cups.h> int print_dest(void *user_data, unsigned flags, cups_dest_t *dest) { if (dest->instance) printf("%s/%s\n", dest->name, dest->instance); else puts(dest->name); return (1); } int main(void) { cupsEnumDests(CUPS_DEST_FLAGS_NONE, 1000, NULL, 0, 0, print_dest, NULL); return (0); }
In Xcode, choose New Project... from the File menu (or press SHIFT+CMD+N), then select the Command Line Tool under the macOS Application project type. Click Next and enter a name for the project, for example “firstcups”. Click Next and choose a project directory. The click Next to create the project.
In the project window, click on the Build Phases group and expand the Link Binary with Libraries section. Click +, type “libcups” to show the library, and then double-click on libcups.tbd
.
Finally, click on the main.c
file in the sidebar and copy the example program to the file. Build and run (CMD+R) to see the list of destinations.
From the command-line, create a file called simple.c
using your favorite editor, copy the example to this file, and save. Then run the following command to compile it with GCC and run it:
gcc -o simple `cups-config --cflags` simple.c `cups-config --libs` ./simple
The cups-config
command provides the compiler flags (cups-config --cflags
) and libraries (cups-config --libs
) needed for the local system.
Destinations, which in CUPS represent individual printers or classes (collections or pools) of printers, are represented by the cups_dest_t
structure which includes the name (name
), instance (instance
, saved options/settings), whether the destination is the default for the user (is_default
), and the options and basic information associated with that destination (num_options
and options
).
Historically destinations have been manually maintained by the administrator of a system or network, but CUPS also supports dynamic discovery of destinations on the current network.
The cupsEnumDests
function finds all of the available destinations:
int cupsEnumDests(unsigned flags, int msec, int *cancel, cups_ptype_t type, cups_ptype_t mask, cups_dest_cb_t cb, void *user_data)
The flags
argument specifies enumeration options, which at present must be CUPS_DEST_FLAGS_NONE
.
The msec
argument specifies the maximum amount of time that should be used for enumeration in milliseconds - interactive applications should keep this value to 5000 or less when run on the main thread.
The cancel
argument points to an integer variable that, when set to a non-zero value, will cause enumeration to stop as soon as possible. It can be NULL
if not needed.
The type
and mask
arguments are bitfields that allow the caller to filter the destinations based on categories and/or capabilities. The destination's “printer-type” value is masked by the mask
value and compared to the type
value when filtering. For example, to only enumerate destinations that are hosted on the local system, pass CUPS_PRINTER_LOCAL
for the type
argument and CUPS_PRINTER_DISCOVERED
for the mask
argument. The following constants can be used for filtering:
CUPS_PRINTER_CLASS
: A collection of destinations.CUPS_PRINTER_FAX
: A facsimile device.CUPS_PRINTER_LOCAL
: A local printer or class. This constant has the value 0 (no bits set) and is only used for the type
argument and is paired with the CUPS_PRINTER_REMOTE
or CUPS_PRINTER_DISCOVERED
constant passed in the mask
argument.CUPS_PRINTER_REMOTE
: A remote (shared) printer or class.CUPS_PRINTER_DISCOVERED
: An available network printer or class.CUPS_PRINTER_BW
: Can do B&W printing.CUPS_PRINTER_COLOR
: Can do color printing.CUPS_PRINTER_DUPLEX
: Can do two-sided printing.CUPS_PRINTER_STAPLE
: Can staple output.CUPS_PRINTER_COLLATE
: Can quickly collate copies.CUPS_PRINTER_PUNCH
: Can punch output.CUPS_PRINTER_COVER
: Can cover output.CUPS_PRINTER_BIND
: Can bind output.CUPS_PRINTER_SORT
: Can sort output (mailboxes, etc.)CUPS_PRINTER_SMALL
: Can print on Letter/Legal/A4-size media.CUPS_PRINTER_MEDIUM
: Can print on Tabloid/B/C/A3/A2-size media.CUPS_PRINTER_LARGE
: Can print on D/E/A1/A0-size media.CUPS_PRINTER_VARIABLE
: Can print on rolls and custom-size media.The cb
argument specifies a function to call for every destination that is found:
typedef int (*cups_dest_cb_t)(void *user_data, unsigned flags, cups_dest_t *dest);
The callback function receives a copy of the user_data
argument along with a bitfield (flags
) and the destination that was found. The flags
argument can have any of the following constant (bit) values set:
CUPS_DEST_FLAGS_MORE
: There are more destinations coming.CUPS_DEST_FLAGS_REMOVED
: The destination has gone away and should be removed from the list of destinations a user can select.CUPS_DEST_FLAGS_ERROR
: An error occurred. The reason for the error can be found by calling the cupsLastError
and/or cupsLastErrorString
functions.The callback function returns 0 to stop enumeration or 1 to continue.
Note:
The callback function will likely be called multiple times for the same destination, so it is up to the caller to suppress any duplicate destinations.
The following example shows how to use cupsEnumDests
to get a filtered array of destinations:
typedef struct { int num_dests; cups_dest_t *dests; } my_user_data_t; int my_dest_cb(my_user_data_t *user_data, unsigned flags, cups_dest_t *dest) { if (flags & CUPS_DEST_FLAGS_REMOVED) { /* * Remove destination from array... */ user_data->num_dests = cupsRemoveDest(dest->name, dest->instance, user_data->num_dests, &(user_data->dests)); } else { /* * Add destination to array... */ user_data->num_dests = cupsCopyDest(dest, user_data->num_dests, &(user_data->dests)); } return (1); } int my_get_dests(cups_ptype_t type, cups_ptype_t mask, cups_dest_t **dests) { my_user_data_t user_data = { 0, NULL }; if (!cupsEnumDests(CUPS_DEST_FLAGS_NONE, 1000, NULL, type, mask, (cups_dest_cb_t)my_dest_cb, &user_data)) { /* * An error occurred, free all of the destinations and * return... */ cupsFreeDests(user_data.num_dests, user_dasta.dests); *dests = NULL; return (0); } /* * Return the destination array... */ *dests = user_data.dests; return (user_data.num_dests); }
The num_options
and options
members of the cups_dest_t
structure provide basic attributes about the destination in addition to the user default options and values for that destination. The following names are predefined for various destination attributes:
cups_ptype_t
value associated with the destination.Use the cupsGetOption
function to retrieve the value. For example, the following code gets the make and model of a destination:
const char *model = cupsGetOption("printer-make-and-model", dest->num_options, dest->options);
Once a destination has been chosen, the cupsCopyDestInfo
function can be used to gather detailed information about the destination:
cups_dinfo_t * cupsCopyDestInfo(http_t *http, cups_dest_t *dest);
The http
argument specifies a connection to the CUPS scheduler and is typically the constant CUPS_HTTP_DEFAULT
. The dest
argument specifies the destination to query.
The cups_dinfo_t
structure that is returned contains a snapshot of the supported options and their supported, ready, and default values. It also can report constraints between different options and values, and recommend changes to resolve those constraints.
The cupsCheckDestSupported
function can be used to test whether a particular option or option and value is supported:
int cupsCheckDestSupported(http_t *http, cups_dest_t *dest, cups_dinfo_t *info, const char *option, const char *value);
The option
argument specifies the name of the option to check. The following constants can be used to check the various standard options:
CUPS_COPIES
: Controls the number of copies that are produced.CUPS_FINISHINGS
: A comma-delimited list of integer constants that control the finishing processes that are applied to the job, including stapling, punching, and folding.CUPS_MEDIA
: Controls the media size that is used, typically one of the following: CUPS_MEDIA_3X5
, CUPS_MEDIA_4X6
, CUPS_MEDIA_5X7
, CUPS_MEDIA_8X10
, CUPS_MEDIA_A3
, CUPS_MEDIA_A4
, CUPS_MEDIA_A5
, CUPS_MEDIA_A6
, CUPS_MEDIA_ENV10
, CUPS_MEDIA_ENVDL
, CUPS_MEDIA_LEGAL
, CUPS_MEDIA_LETTER
, CUPS_MEDIA_PHOTO_L
, CUPS_MEDIA_SUPERBA3
, or CUPS_MEDIA_TABLOID
.CUPS_MEDIA_SOURCE
: Controls where the media is pulled from, typically either CUPS_MEDIA_SOURCE_AUTO
or CUPS_MEDIA_SOURCE_MANUAL
.CUPS_MEDIA_TYPE
: Controls the type of media that is used, typically one of the following: CUPS_MEDIA_TYPE_AUTO
, CUPS_MEDIA_TYPE_ENVELOPE
, CUPS_MEDIA_TYPE_LABELS
, CUPS_MEDIA_TYPE_LETTERHEAD
, CUPS_MEDIA_TYPE_PHOTO
, CUPS_MEDIA_TYPE_PHOTO_GLOSSY
, CUPS_MEDIA_TYPE_PHOTO_MATTE
, CUPS_MEDIA_TYPE_PLAIN
, or CUPS_MEDIA_TYPE_TRANSPARENCY
.CUPS_NUMBER_UP
: Controls the number of document pages that are placed on each media side.CUPS_ORIENTATION
: Controls the orientation of document pages placed on the media: CUPS_ORIENTATION_PORTRAIT
or CUPS_ORIENTATION_LANDSCAPE
.CUPS_PRINT_COLOR_MODE
: Controls whether the output is in color (CUPS_PRINT_COLOR_MODE_COLOR
), grayscale (CUPS_PRINT_COLOR_MODE_MONOCHROME
), or either (CUPS_PRINT_COLOR_MODE_AUTO
).CUPS_PRINT_QUALITY
: Controls the generate quality of the output: CUPS_PRINT_QUALITY_DRAFT
, CUPS_PRINT_QUALITY_NORMAL
, or CUPS_PRINT_QUALITY_HIGH
.CUPS_SIDES
: Controls whether prints are placed on one or both sides of the media: CUPS_SIDES_ONE_SIDED
, CUPS_SIDES_TWO_SIDED_PORTRAIT
, or CUPS_SIDES_TWO_SIDED_LANDSCAPE
.If the value
argument is NULL
, the cupsCheckDestSupported
function returns whether the option is supported by the destination. Otherwise, the function returns whether the specified value of the option is supported.
The cupsFindDestSupported
function returns the IPP attribute containing the supported values for a given option:
ipp_attribute_t * cupsFindDestSupported(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option);
For example, the following code prints the supported finishing processes for a destination, if any, to the standard output:
cups_dinfo_t *info = cupsCopyDestInfo(CUPS_HTTP_DEFAULT, dest); if (cupsCheckDestSupported(CUPS_HTTP_DEFAULT, dest, info, CUPS_FINISHINGS, NULL)) { ipp_attribute_t *finishings = cupsFindDestSupported(CUPS_HTTP_DEFAULT, dest, info, CUPS_FINISHINGS); int i, count = ippGetCount(finishings); puts("finishings supported:"); for (i = 0; i < count; i ++) printf(" %d\n", ippGetInteger(finishings, i)); } else puts("finishings not supported.");
The “job-creation-attributes” option can be queried to get a list of supported options. For example, the following code prints the list of supported options to the standard output:
ipp_attribute_t *attrs = cupsFindDestSupported(CUPS_HTTP_DEFAULT, dest, info, "job-creation-attributes"); int i, count = ippGetCount(attrs); for (i = 0; i < count; i ++) puts(ippGetString(attrs, i, NULL));
There are two sets of default values - user defaults that are available via the num_options
and options
members of the cups_dest_t
structure, and destination defaults that available via the cups_dinfo_t
structure and the cupsFindDestDefault
function which returns the IPP attribute containing the default value(s) for a given option:
ipp_attribute_t * cupsFindDestDefault(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option);
The user defaults from cupsGetOption
should always take preference over the destination defaults. For example, the following code prints the default finishings value(s) to the standard output:
const char *def_value = cupsGetOption(CUPS_FINISHINGS, dest->num_options, dest->options); ipp_attribute_t *def_attr = cupsFindDestDefault(CUPS_HTTP_DEFAULT, dest, info, CUPS_FINISHINGS); if (def_value != NULL) { printf("Default finishings: %s\n", def_value); } else { int i, count = ippGetCount(def_attr); printf("Default finishings: %d", ippGetInteger(def_attr, 0)); for (i = 1; i < count; i ++) printf(",%d", ippGetInteger(def_attr, i)); putchar('\n'); }
The finishings and media options also support queries for the ready, or loaded, values. For example, a printer may have punch and staple finishers installed but be out of staples - the supported values will list both punch and staple finishing processes but the ready values will only list the punch processes. Similarly, a printer may support hundreds of different sizes of media but only have a single size loaded at any given time - the ready values are limited to the media that is actually in the printer.
The cupsFindDestReady
function finds the IPP attribute containing the ready values for a given option:
ipp_attribute_t * cupsFindDestReady(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option);
For example, the following code lists the ready finishing processes:
ipp_attribute_t *ready_finishings = cupsFindDestReady(CUPS_HTTP_DEFAULT, dest, info, CUPS_FINISHINGS); if (ready_finishings != NULL) { int i, count = ippGetCount(ready_finishings); puts("finishings ready:"); for (i = 0; i < count; i ++) printf(" %d\n", ippGetInteger(ready_finishings, i)); } else puts("no finishings are ready.");
CUPS provides functions for querying the dimensions and margins for each of the supported media size options. The cups_size_t
structure is used to describe a media size:
typedef struct cups_size_s { char media[128]; int width, length; int bottom, left, right, top; } cups_size_t;
The width
and length
members specify the dimensions of the media in hundredths of millimeters (1/2540th of an inch). The bottom
, left
, right
, and top
members specify the margins of the printable area, also in hundredths of millimeters.
The cupsGetDestMediaByName
and cupsGetDestMediaBySize
functions lookup the media size information using a standard media size name or dimensions in hundredths of millimeters:
int cupsGetDestMediaByName(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *media, unsigned flags, cups_size_t *size); int cupsGetDestMediaBySize(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, int width, int length, unsigned flags, cups_size_t *size);
The media
, width
, and length
arguments specify the size to lookup. The flags
argument specifies a bitfield controlling various lookup options:
CUPS_MEDIA_FLAGS_DEFAULT
: Find the closest size supported by the printer.CUPS_MEDIA_FLAGS_BORDERLESS
: Find a borderless size.CUPS_MEDIA_FLAGS_DUPLEX
: Find a size compatible with two-sided printing.CUPS_MEDIA_FLAGS_EXACT
: Find an exact match for the size.CUPS_MEDIA_FLAGS_READY
: If the printer supports media sensing or configuration of the media in each tray/source, find the size amongst the “ready” media.If a matching size is found for the destination, the size information is stored in the structure pointed to by the size
argument and 1 is returned. Otherwise 0 is returned.
For example, the following code prints the margins for two-sided printing on US Letter media:
cups_size_t size; if (cupsGetDestMediaByName(CUPS_HTTP_DEFAULT, dest, info, CUPS_MEDIA_LETTER, CUPS_MEDIA_FLAGS_DUPLEX, &size)) { puts("Margins for duplex US Letter:"); printf(" Bottom: %.2fin\n", size.bottom / 2540.0); printf(" Left: %.2fin\n", size.left / 2540.0); printf(" Right: %.2fin\n", size.right / 2540.0); printf(" Top: %.2fin\n", size.top / 2540.0); } else puts("Margins for duplex US Letter are not available.");
You can also enumerate all of the sizes that match a given flags
value using the cupsGetDestMediaByIndex
and cupsGetDestMediaCount
functions:
int cupsGetDestMediaByIndex(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, int n, unsigned flags, cups_size_t *size); int cupsGetDestMediaCount(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, unsigned flags);
For example, the following code prints the list of ready media and corresponding margins:
cups_size_t size; int i; int count = cupsGetDestMediaCount(CUPS_HTTP_DEFAULT, dest, info, CUPS_MEDIA_FLAGS_READY); for (i = 0; i < count; i ++) { if (cupsGetDestMediaByIndex(CUPS_HTTP_DEFAULT, dest, info, i, CUPS_MEDIA_FLAGS_READY, &size)) { printf("%s:\n", size.name); printf(" Width: %.2fin\n", size.width / 2540.0); printf(" Length: %.2fin\n", size.length / 2540.0); printf(" Bottom: %.2fin\n", size.bottom / 2540.0); printf(" Left: %.2fin\n", size.left / 2540.0); printf(" Right: %.2fin\n", size.right / 2540.0); printf(" Top: %.2fin\n", size.top / 2540.0); } }
Finally, the cupsGetDestMediaDefault
function returns the default media size:
int cupsGetDestMediaDefault(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, unsigned flags, cups_size_t *size);
CUPS provides three functions to get localized, human-readable strings in the user's current locale for options and values: cupsLocalizeDestMedia
, cupsLocalizeDestOption
, and cupsLocalizeDestValue
:
const char * cupsLocalizeDestMedia(http_t *http, cups_dest_t *dest, cups_dinfo_t *info, unsigned flags, cups_size_t *size); const char * cupsLocalizeDestOption(http_t *http, cups_dest_t *dest, cups_dinfo_t *info, const char *option); const char * cupsLocalizeDestValue(http_t *http, cups_dest_t *dest, cups_dinfo_t *info, const char *option, const char *value);
Once you are ready to submit a print job, you create a job using the cupsCreateDestJob
function:
ipp_status_t cupsCreateDestJob(http_t *http, cups_dest_t *dest, cups_dinfo_t *info, int *job_id, const char *title, int num_options, cups_option_t *options);
The title
argument specifies a name for the print job such as “My Document”. The num_options
and options
arguments specify the options for the print job which are allocated using the cupsAddOption
function.
When successful, the job's numeric identifier is stored in the integer pointed to by the job_id
argument and IPP_STATUS_OK
is returned. Otherwise, an IPP error status is returned.
For example, the following code creates a new job that will print 42 copies of a two-sided US Letter document:
int job_id = 0; int num_options = 0; cups_option_t *options = NULL; num_options = cupsAddOption(CUPS_COPIES, "42", num_options, &options); num_options = cupsAddOption(CUPS_MEDIA, CUPS_MEDIA_LETTER, num_options, &options); num_options = cupsAddOption(CUPS_SIDES, CUPS_SIDES_TWO_SIDED_PORTRAIT, num_options, &options); if (cupsCreateDestJob(CUPS_HTTP_DEFAULT, dest, info, &job_id, "My Document", num_options, options) == IPP_STATUS_OK) printf("Created job: %d\n", job_id); else printf("Unable to create job: %s\n", cupsLastErrorString());
Once the job is created, you submit documents for the job using the cupsStartDestDocument
, cupsWriteRequestData
, and cupsFinishDestDocument
functions:
http_status_t cupsStartDestDocument(http_t *http, cups_dest_t *dest, cups_dinfo_t *info, int job_id, const char *docname, const char *format, int num_options, cups_option_t *options, int last_document); http_status_t cupsWriteRequestData(http_t *http, const char *buffer, size_t length); ipp_status_t cupsFinishDestDocument(http_t *http, cups_dest_t *dest, cups_dinfo_t *info);
The docname
argument specifies the name of the document, typically the original filename. The format
argument specifies the MIME media type of the document, including the following constants:
CUPS_FORMAT_JPEG
: “image/jpeg”CUPS_FORMAT_PDF
: “application/pdf”CUPS_FORMAT_POSTSCRIPT
: “application/postscript”CUPS_FORMAT_TEXT
: “text/plain”The num_options
and options
arguments specify per-document print options, which at present must be 0 and NULL
. The last_document
argument specifies whether this is the last document in the job.
For example, the following code submits a PDF file to the job that was just created:
FILE *fp = fopen("filename.pdf", "rb"); size_t bytes; char buffer[65536]; if (cupsStartDestDocument(CUPS_HTTP_DEFAULT, dest, info, job_id, "filename.pdf", 0, NULL, 1) == HTTP_STATUS_CONTINUE) { while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) if (cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, bytes) != HTTP_STATUS_CONTINUE) break; if (cupsFinishDestDocument(CUPS_HTTP_DEFAULT, dest, info) == IPP_STATUS_OK) puts("Document send succeeded."); else printf("Document send failed: %s\n", cupsLastErrorString()); } fclose(fp);
CUPS provides a rich API for sending IPP requests to the scheduler or printers, typically from management or utility applications whose primary purpose is not to send print jobs.
The connection to the scheduler or printer is represented by the HTTP connection type http_t
. The cupsConnectDest
function connects to the scheduler or printer associated with the destination:
http_t * cupsConnectDest(cups_dest_t *dest, unsigned flags, int msec, int *cancel, char *resource, size_t resourcesize, cups_dest_cb_t cb, void *user_data);
The dest
argument specifies the destination to connect to.
The flags
argument specifies whether you want to connect to the scheduler (CUPS_DEST_FLAGS_NONE
) or device/printer (CUPS_DEST_FLAGS_DEVICE
) associated with the destination.
The msec
argument specifies how long you are willing to wait for the connection to be established in milliseconds. Specify a value of -1
to wait indefinitely.
The cancel
argument specifies the address of an integer variable that can be set to a non-zero value to cancel the connection. Specify a value of NULL
to not provide a cancel variable.
The resource
and resourcesize
arguments specify the address and size of a character string array to hold the path to use when sending an IPP request.
The cb
and user_data
arguments specify a destination callback function that returns 1 to continue connecting or 0 to stop. The destination callback work the same way as the one used for the cupsEnumDests
function.
On success, a HTTP connection is returned that can be used to send IPP requests and get IPP responses.
For example, the following code connects to the printer associated with a destination with a 30 second timeout:
char resource[256]; http_t *http = cupsConnectDest(dest, CUPS_DEST_FLAGS_DEVICE, 30000, NULL, resource, sizeof(resource), NULL, NULL);
IPP requests are represented by the IPP message type ipp_t
and each IPP attribute in the request is representing using the type ipp_attribute_t
. Each IPP request includes an operation code (IPP_OP_CREATE_JOB
, IPP_OP_GET_PRINTER_ATTRIBUTES
, etc.) and a 32-bit integer identifier.
The ippNewRequest
function creates a new IPP request:
ipp_t * ippNewRequest(ipp_op_t op);
The op
argument specifies the IPP operation code for the request. For example, the following code creates an IPP Get-Printer-Attributes request:
ipp_t *request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
The request identifier is automatically set to a unique value for the current process.
Each IPP request starts with two IPP attributes, “attributes-charset” and “attributes-natural-language”, followed by IPP attribute(s) that specify the target of the operation. The ippNewRequest
automatically adds the correct “attributes-charset” and “attributes-natural-language” attributes, but you must add the target attribute(s). For example, the following code adds the “printer-uri” attribute to the IPP Get-Printer-Attributes request to specify which printer is being queried:
const char *printer_uri = cupsGetOption("device-uri", dest->num_options, dest->options); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer_uri);
Note:
If we wanted to query the scheduler instead of the device, we would look up the “printer-uri-supported” option instead of the “device-uri” value.
The ippAddString
function adds the “printer-uri” attribute the the IPP request. The IPP_TAG_OPERATION
argument specifies that the attribute is part of the operation. The IPP_TAG_URI
argument specifies that the value is a Universal Resource Identifier (URI) string. The NULL
argument specifies there is no language (English, French, Japanese, etc.) associated with the string, and the printer_uri
argument specifies the string value.
The IPP Get-Printer-Attributes request also supports an IPP attribute called “requested-attributes” that lists the attributes and values you are interested in. For example, the following code requests the printer state attributes:
static const char * const requested_attributes[] = { "printer-state", "printer-state-message", "printer-state-reasons" }; ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", 3, NULL, requested_attributes);
The ippAddStrings
function adds an attribute with one or more strings, in this case three. The IPP_TAG_KEYWORD
argument specifies that the strings are keyword values, which are used for attribute names. All strings use the same language (NULL
), and the attribute will contain the three strings in the array requested_attributes
.
CUPS provides many functions to adding attributes of different types:
ippAddBoolean
adds a boolean (IPP_TAG_BOOLEAN
) attribute with one value.ippAddInteger
adds an enum (IPP_TAG_ENUM
) or integer (IPP_TAG_INTEGER
) attribute with one value.ippAddIntegers
adds an enum or integer attribute with one or more values.ippAddOctetString
adds an octetString attribute with one value.ippAddOutOfBand
adds a admin-defined (IPP_TAG_ADMINDEFINE
), default (IPP_TAG_DEFAULT
), delete-attribute (IPP_TAG_DELETEATTR
), no-value (IPP_TAG_NOVALUE
), not-settable (IPP_TAG_NOTSETTABLE
), unknown (IPP_TAG_UNKNOWN
), or unsupported (IPP_TAG_UNSUPPORTED_VALUE
) out-of-band attribute.ippAddRange
adds a rangeOfInteger attribute with one range.ippAddRanges
adds a rangeOfInteger attribute with one or more ranges.ippAddResolution
adds a resolution attribute with one resolution.ippAddResolutions
adds a resolution attribute with one or more resolutions.ippAddString
adds a charset (IPP_TAG_CHARSET
), keyword (IPP_TAG_KEYWORD
), mimeMediaType (IPP_TAG_MIMETYPE
), name (IPP_TAG_NAME
and IPP_TAG_NAMELANG
), naturalLanguage (IPP_TAG_NATURAL_LANGUAGE
), text (IPP_TAG_TEXT
and IPP_TAG_TEXTLANG
), uri (IPP_TAG_URI
), or uriScheme (IPP_TAG_URISCHEME
) attribute with one value.ippAddStrings
adds a charset, keyword, mimeMediaType, name, naturalLanguage, text, uri, or uriScheme attribute with one or more values.Once you have created the IPP request, you can send it using the cupsDoRequest
function. For example, the following code sends the IPP Get-Printer-Attributes request to the destination and saves the response:
ipp_t *response = cupsDoRequest(http, request, resource);
For requests like Send-Document that include a file, the cupsDoFileRequest
function should be used:
ipp_t *response = cupsDoFileRequest(http, request, resource, filename);
Both cupsDoRequest
and cupsDoFileRequest
free the IPP request. If a valid IPP response is received, it is stored in a new IPP message (ipp_t
) and returned to the caller. Otherwise NULL
is returned.
The status from the most recent request can be queried using the cupsLastError
function, for example:
if (cupsLastError() >= IPP_STATUS_ERROR_BAD_REQUEST) { /* request failed */ }
A human-readable error message is also available using the cupsLastErrorString
function:
if (cupsLastError() >= IPP_STATUS_ERROR_BAD_REQUEST) { /* request failed */ printf("Request failed: %s\n", cupsLastErrorString()); }
Each response to an IPP request is also an IPP message (ipp_t
) with its own IPP attributes (ipp_attribute_t
) that includes a status code (IPP_STATUS_OK
, IPP_STATUS_ERROR_BAD_REQUEST
, etc.) and the corresponding 32-bit integer identifier from the request.
For example, the following code finds the printer state attributes and prints their values:
ipp_attribute_t *attr; if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) { printf("printer-state=%s\n", ippEnumString("printer-state", ippGetInteger(attr, 0))); } else puts("printer-state=unknown"); if ((attr = ippFindAttribute(response, "printer-state-message", IPP_TAG_TEXT)) != NULL) { printf("printer-state-message=\"%s\"\n", ippGetString(attr, 0, NULL))); } if ((attr = ippFindAttribute(response, "printer-state-reasons", IPP_TAG_KEYWORD)) != NULL) { int i, count = ippGetCount(attr); puts("printer-state-reasons="); for (i = 0; i < count; i ++) printf(" %s\n", ippGetString(attr, i, NULL))); }
The ippGetCount
function returns the number of values in an attribute.
The ippGetInteger
and ippGetString
functions return a single integer or string value from an attribute.
The ippEnumString
function converts a enum value to its keyword (string) equivalent.
Once you are done using the IPP response message, free it using the ippDelete
function:
ippDelete(response);
CUPS normally handles authentication through the console. GUI applications should set a password callback using the cupsSetPasswordCB2
function:
void cupsSetPasswordCB2(cups_password_cb2_t cb, void *user_data);
The password callback will be called when needed and is responsible for setting the current user name using cupsSetUser
and returning a string:
const char * cups_password_cb2(const char *prompt, http_t *http, const char *method, const char *resource, void *user_data);
The prompt
argument is a string from CUPS that should be displayed to the user.
The http
argument is the connection hosting the request that is being authenticated. The password callback can call the httpGetField
and httpGetSubField
functions to look for additional details concerning the authentication challenge.
The method
argument specifies the HTTP method used for the request and is typically “POST”.
The resource
argument specifies the path used for the request.
The user_data
argument provides the user data pointer from the cupsSetPasswordCB2
call.