]>
Commit | Line | Data |
---|---|---|
abacc52b MS |
1 | --- |
2 | title: CUPS Programming Manual | |
3 | author: Michael R Sweet | |
73721e3e | 4 | copyright: Copyright © 2007-2019 by Apple Inc. All Rights Reserved. |
ddf2ec73 | 5 | version: 2.3.0 |
abacc52b MS |
6 | ... |
7 | ||
1da024d1 MS |
8 | > Please [file issues on Github](https://github.com/apple/cups/issues) to |
9 | > provide feedback on this document. | |
798d6e29 MS |
10 | |
11 | ||
abacc52b MS |
12 | # Introduction |
13 | ||
14 | CUPS provides the "cups" library to talk to the different parts of CUPS and with | |
15 | Internet Printing Protocol (IPP) printers. The "cups" library functions are | |
16 | accessed by including the `<cups/cups.h>` header. | |
17 | ||
18 | CUPS is based on the Internet Printing Protocol ("IPP"), which allows clients | |
19 | (applications) to communicate with a server (the scheduler, printers, etc.) to | |
20 | get a list of destinations, send print jobs, and so forth. You identify which | |
21 | server you want to communicate with using a pointer to the opaque structure | |
22 | `http_t`. The `CUPS_HTTP_DEFAULT` constant can be used when you want to talk to | |
23 | the CUPS scheduler. | |
24 | ||
25 | ||
26 | ## Guidelines | |
27 | ||
73721e3e | 28 | When writing software (other than printer drivers) that uses the "cups" library: |
abacc52b MS |
29 | |
30 | - Do not use undocumented or deprecated APIs, | |
31 | - Do not rely on pre-configured printers, | |
32 | - Do not assume that printers support specific features or formats, and | |
33 | - Do not rely on implementation details (PPDs, etc.) | |
34 | ||
35 | CUPS is designed to insulate users and developers from the implementation | |
36 | details of printers and file formats. The goal is to allow an application to | |
37 | supply a print file in a standard format with the user intent ("print four | |
38 | copies, two-sided on A4 media, and staple each copy") and have the printing | |
39 | system manage the printer communication and format conversion needed. | |
40 | ||
41 | Similarly, printer and job management applications can use standard query | |
42 | operations to obtain the status information in a common, generic form and use | |
43 | standard management operations to control the state of those printers and jobs. | |
44 | ||
73721e3e MS |
45 | > **Note:** |
46 | > | |
47 | > CUPS printer drivers necessarily depend on specific file formats and certain | |
48 | > implementation details of the CUPS software. Please consult the Postscript | |
49 | > and raster printer driver developer documentation on | |
50 | > [CUPS.org](https://www.cups.org/documentation.html) for more information. | |
51 | ||
abacc52b MS |
52 | |
53 | ## Terms Used in This Document | |
54 | ||
55 | A *Destination* is a printer or print queue that accepts print jobs. A | |
73721e3e MS |
56 | *Print Job* is a collection of one or more documents that are processed by a |
57 | destination using options supplied when creating the job. A *Document* is a | |
58 | file (JPEG image, PDF file, etc.) suitable for printing. An *Option* controls | |
59 | some aspect of printing, such as the media used. *Media* is the sheets or roll | |
60 | that is printed on. An *Attribute* is an option encoded for an Internet | |
61 | Printing Protocol (IPP) request. | |
abacc52b MS |
62 | |
63 | ||
64 | ## Compiling Programs That Use the CUPS API | |
65 | ||
66 | The CUPS libraries can be used from any C, C++, or Objective C program. | |
67 | The method of compiling against the libraries varies depending on the | |
68 | operating system and installation of CUPS. The following sections show how | |
69 | to compile a simple program (shown below) in two common environments. | |
70 | ||
71 | The following simple program lists the available destinations: | |
72 | ||
73 | #include <stdio.h> | |
74 | #include <cups/cups.h> | |
75 | ||
76 | int print_dest(void *user_data, unsigned flags, cups_dest_t *dest) | |
77 | { | |
78 | if (dest->instance) | |
79 | printf("%s/%s\n", dest->name, dest->instance); | |
80 | else | |
81 | puts(dest->name); | |
82 | ||
83 | return (1); | |
84 | } | |
85 | ||
86 | int main(void) | |
87 | { | |
88 | cupsEnumDests(CUPS_DEST_FLAGS_NONE, 1000, NULL, 0, 0, print_dest, NULL); | |
89 | ||
90 | return (0); | |
91 | } | |
92 | ||
93 | ||
94 | ### Compiling with Xcode | |
95 | ||
96 | In Xcode, choose *New Project...* from the *File* menu (or press SHIFT+CMD+N), | |
97 | then select the *Command Line Tool* under the macOS Application project type. | |
98 | Click *Next* and enter a name for the project, for example "firstcups". Click | |
99 | *Next* and choose a project directory. The click *Next* to create the project. | |
100 | ||
101 | In the project window, click on the *Build Phases* group and expand the | |
102 | *Link Binary with Libraries* section. Click *+*, type "libcups" to show the | |
103 | library, and then double-click on `libcups.tbd`. | |
104 | ||
105 | Finally, click on the `main.c` file in the sidebar and copy the example program | |
106 | to the file. Build and run (CMD+R) to see the list of destinations. | |
107 | ||
108 | ||
109 | ### Compiling with GCC | |
110 | ||
111 | From the command-line, create a file called `sample.c` using your favorite | |
112 | editor, copy the example to this file, and save. Then run the following command | |
113 | to compile it with GCC and run it: | |
114 | ||
115 | gcc -o simple `cups-config --cflags` simple.c `cups-config --libs` | |
116 | ./simple | |
117 | ||
118 | The `cups-config` command provides the compiler flags (`cups-config --cflags`) | |
119 | and libraries (`cups-config --libs`) needed for the local system. | |
120 | ||
121 | ||
122 | # Working with Destinations | |
123 | ||
798d6e29 | 124 | Destinations, which in CUPS represent individual printers or classes |
9c44e2cb MS |
125 | (collections or pools) of printers, are represented by the `cups_dest_t` |
126 | structure which includes the name \(`name`), instance \(`instance`, saved | |
127 | options/settings), whether the destination is the default for the user | |
128 | \(`is_default`), and the options and basic information associated with that | |
129 | destination \(`num_options` and `options`). | |
abacc52b | 130 | |
798d6e29 MS |
131 | Historically destinations have been manually maintained by the administrator of |
132 | a system or network, but CUPS also supports dynamic discovery of destinations on | |
133 | the current network. | |
abacc52b | 134 | |
abacc52b | 135 | |
798d6e29 | 136 | ## Finding Available Destinations |
abacc52b | 137 | |
798d6e29 MS |
138 | The `cupsEnumDests` function finds all of the available destinations: |
139 | ||
140 | int | |
141 | cupsEnumDests(unsigned flags, int msec, int *cancel, | |
142 | cups_ptype_t type, cups_ptype_t mask, | |
143 | cups_dest_cb_t cb, void *user_data) | |
144 | ||
145 | The `flags` argument specifies enumeration options, which at present must be | |
146 | `CUPS_DEST_FLAGS_NONE`. | |
147 | ||
148 | The `msec` argument specifies the maximum amount of time that should be used for | |
149 | enumeration in milliseconds - interactive applications should keep this value to | |
150 | 5000 or less when run on the main thread. | |
151 | ||
152 | The `cancel` argument points to an integer variable that, when set to a non-zero | |
153 | value, will cause enumeration to stop as soon as possible. It can be `NULL` if | |
154 | not needed. | |
155 | ||
156 | The `type` and `mask` arguments are bitfields that allow the caller to filter | |
157 | the destinations based on categories and/or capabilities. The destination's | |
158 | "printer-type" value is masked by the `mask` value and compared to the `type` | |
159 | value when filtering. For example, to only enumerate destinations that are | |
160 | hosted on the local system, pass `CUPS_PRINTER_LOCAL` for the `type` argument | |
f50db552 MS |
161 | and `CUPS_PRINTER_DISCOVERED` for the `mask` argument. The following constants |
162 | can be used for filtering: | |
798d6e29 MS |
163 | |
164 | - `CUPS_PRINTER_CLASS`: A collection of destinations. | |
165 | - `CUPS_PRINTER_FAX`: A facsimile device. | |
166 | - `CUPS_PRINTER_LOCAL`: A local printer or class. This constant has the value 0 | |
167 | (no bits set) and is only used for the `type` argument and is paired with the | |
f50db552 MS |
168 | `CUPS_PRINTER_REMOTE` or `CUPS_PRINTER_DISCOVERED` constant passed in the |
169 | `mask` argument. | |
170 | - `CUPS_PRINTER_REMOTE`: A remote (shared) printer or class. | |
171 | - `CUPS_PRINTER_DISCOVERED`: An available network printer or class. | |
798d6e29 MS |
172 | - `CUPS_PRINTER_BW`: Can do B&W printing. |
173 | - `CUPS_PRINTER_COLOR`: Can do color printing. | |
174 | - `CUPS_PRINTER_DUPLEX`: Can do two-sided printing. | |
175 | - `CUPS_PRINTER_STAPLE`: Can staple output. | |
176 | - `CUPS_PRINTER_COLLATE`: Can quickly collate copies. | |
177 | - `CUPS_PRINTER_PUNCH`: Can punch output. | |
178 | - `CUPS_PRINTER_COVER`: Can cover output. | |
179 | - `CUPS_PRINTER_BIND`: Can bind output. | |
180 | - `CUPS_PRINTER_SORT`: Can sort output (mailboxes, etc.) | |
181 | - `CUPS_PRINTER_SMALL`: Can print on Letter/Legal/A4-size media. | |
182 | - `CUPS_PRINTER_MEDIUM`: Can print on Tabloid/B/C/A3/A2-size media. | |
183 | - `CUPS_PRINTER_LARGE`: Can print on D/E/A1/A0-size media. | |
184 | - `CUPS_PRINTER_VARIABLE`: Can print on rolls and custom-size media. | |
185 | ||
186 | The `cb` argument specifies a function to call for every destination that is | |
187 | found: | |
188 | ||
189 | typedef int (*cups_dest_cb_t)(void *user_data, | |
190 | unsigned flags, | |
191 | cups_dest_t *dest); | |
192 | ||
193 | The callback function receives a copy of the `user_data` argument along with a | |
194 | bitfield \(`flags`) and the destination that was found. The `flags` argument | |
195 | can have any of the following constant (bit) values set: | |
196 | ||
197 | - `CUPS_DEST_FLAGS_MORE`: There are more destinations coming. | |
198 | - `CUPS_DEST_FLAGS_REMOVED`: The destination has gone away and should be removed | |
199 | from the list of destinations a user can select. | |
200 | - `CUPS_DEST_FLAGS_ERROR`: An error occurred. The reason for the error can be | |
201 | found by calling the `cupsLastError` and/or `cupsLastErrorString` functions. | |
202 | ||
203 | The callback function returns 0 to stop enumeration or 1 to continue. | |
204 | ||
73721e3e MS |
205 | > **Note:** |
206 | > | |
207 | > The callback function will likely be called multiple times for the | |
500fca27 MS |
208 | > same destination, so it is up to the caller to suppress any duplicate |
209 | > destinations. | |
210 | ||
798d6e29 MS |
211 | The following example shows how to use `cupsEnumDests` to get a filtered array |
212 | of destinations: | |
213 | ||
214 | typedef struct | |
215 | { | |
216 | int num_dests; | |
217 | cups_dest_t *dests; | |
218 | } my_user_data_t; | |
abacc52b | 219 | |
798d6e29 MS |
220 | int |
221 | my_dest_cb(my_user_data_t *user_data, unsigned flags, | |
222 | cups_dest_t *dest) | |
223 | { | |
224 | if (flags & CUPS_DEST_FLAGS_REMOVED) | |
225 | { | |
226 | /* | |
227 | * Remove destination from array... | |
228 | */ | |
229 | ||
230 | user_data->num_dests = | |
231 | cupsRemoveDest(dest->name, dest->instance, | |
232 | user_data->num_dests, | |
233 | &(user_data->dests)); | |
234 | } | |
235 | else | |
236 | { | |
237 | /* | |
238 | * Add destination to array... | |
239 | */ | |
abacc52b | 240 | |
798d6e29 MS |
241 | user_data->num_dests = |
242 | cupsCopyDest(dest, user_data->num_dests, | |
243 | &(user_data->dests)); | |
244 | } | |
abacc52b | 245 | |
798d6e29 MS |
246 | return (1); |
247 | } | |
abacc52b | 248 | |
798d6e29 MS |
249 | int |
250 | my_get_dests(cups_ptype_t type, cups_ptype_t mask, | |
251 | cups_dest_t **dests) | |
252 | { | |
253 | my_user_data_t user_data = { 0, NULL }; | |
abacc52b | 254 | |
798d6e29 MS |
255 | if (!cupsEnumDests(CUPS_DEST_FLAGS_NONE, 1000, NULL, type, |
256 | mask, (cups_dest_cb_t)my_dest_cb, | |
257 | &user_data)) | |
258 | { | |
259 | /* | |
260 | * An error occurred, free all of the destinations and | |
261 | * return... | |
262 | */ | |
abacc52b | 263 | |
798d6e29 | 264 | cupsFreeDests(user_data.num_dests, user_dasta.dests); |
abacc52b | 265 | |
798d6e29 | 266 | *dests = NULL; |
abacc52b | 267 | |
798d6e29 MS |
268 | return (0); |
269 | } | |
abacc52b | 270 | |
798d6e29 MS |
271 | /* |
272 | * Return the destination array... | |
273 | */ | |
abacc52b | 274 | |
798d6e29 | 275 | *dests = user_data.dests; |
abacc52b | 276 | |
798d6e29 MS |
277 | return (user_data.num_dests); |
278 | } | |
abacc52b | 279 | |
abacc52b | 280 | |
798d6e29 MS |
281 | ## Basic Destination Information |
282 | ||
283 | The `num_options` and `options` members of the `cups_dest_t` structure provide | |
284 | basic attributes about the destination in addition to the user default options | |
285 | and values for that destination. The following names are predefined for various | |
286 | destination attributes: | |
287 | ||
288 | - "auth-info-required": The type of authentication required for printing to this | |
289 | destination: "none", "username,password", "domain,username,password", or | |
290 | "negotiate" (Kerberos). | |
291 | - "printer-info": The human-readable description of the destination such as "My | |
292 | Laser Printer". | |
293 | - "printer-is-accepting-jobs": "true" if the destination is accepting new jobs, | |
294 | "false" otherwise. | |
295 | - "printer-is-shared": "true" if the destination is being shared with other | |
296 | computers, "false" otherwise. | |
297 | - "printer-location": The human-readable location of the destination such as | |
298 | "Lab 4". | |
299 | - "printer-make-and-model": The human-readable make and model of the destination | |
300 | such as "ExampleCorp LaserPrinter 4000 Series". | |
301 | - "printer-state": "3" if the destination is idle, "4" if the destination is | |
302 | printing a job, and "5" if the destination is stopped. | |
303 | - "printer-state-change-time": The UNIX time when the destination entered the | |
304 | current state. | |
305 | - "printer-state-reasons": Additional comma-delimited state keywords for the | |
306 | destination such as "media-tray-empty-error" and "toner-low-warning". | |
307 | - "printer-type": The `cups_ptype_t` value associated with the destination. | |
53af7f21 MS |
308 | - "printer-uri-supported": The URI associated with the destination; if not set, |
309 | this destination was discovered but is not yet setup as a local printer. | |
798d6e29 MS |
310 | |
311 | Use the `cupsGetOption` function to retrieve the value. For example, the | |
312 | following code gets the make and model of a destination: | |
313 | ||
314 | const char *model = cupsGetOption("printer-make-and-model", | |
315 | dest->num_options, | |
316 | dest->options); | |
317 | ||
53af7f21 | 318 | |
798d6e29 MS |
319 | ## Detailed Destination Information |
320 | ||
321 | Once a destination has been chosen, the `cupsCopyDestInfo` function can be used | |
322 | to gather detailed information about the destination: | |
323 | ||
324 | cups_dinfo_t * | |
325 | cupsCopyDestInfo(http_t *http, cups_dest_t *dest); | |
326 | ||
327 | The `http` argument specifies a connection to the CUPS scheduler and is | |
328 | typically the constant `CUPS_HTTP_DEFAULT`. The `dest` argument specifies the | |
329 | destination to query. | |
330 | ||
331 | The `cups_dinfo_t` structure that is returned contains a snapshot of the | |
332 | supported options and their supported, ready, and default values. It also can | |
333 | report constraints between different options and values, and recommend changes | |
334 | to resolve those constraints. | |
abacc52b | 335 | |
53af7f21 | 336 | |
798d6e29 | 337 | ### Getting Supported Options and Values |
abacc52b | 338 | |
798d6e29 MS |
339 | The `cupsCheckDestSupported` function can be used to test whether a particular |
340 | option or option and value is supported: | |
341 | ||
342 | int | |
343 | cupsCheckDestSupported(http_t *http, cups_dest_t *dest, | |
344 | cups_dinfo_t *info, | |
345 | const char *option, | |
346 | const char *value); | |
347 | ||
348 | The `option` argument specifies the name of the option to check. The following | |
349 | constants can be used to check the various standard options: | |
350 | ||
351 | - `CUPS_COPIES`: Controls the number of copies that are produced. | |
352 | - `CUPS_FINISHINGS`: A comma-delimited list of integer constants that control | |
353 | the finishing processes that are applied to the job, including stapling, | |
354 | punching, and folding. | |
355 | - `CUPS_MEDIA`: Controls the media size that is used, typically one of the | |
356 | following: `CUPS_MEDIA_3X5`, `CUPS_MEDIA_4X6`, `CUPS_MEDIA_5X7`, | |
357 | `CUPS_MEDIA_8X10`, `CUPS_MEDIA_A3`, `CUPS_MEDIA_A4`, `CUPS_MEDIA_A5`, | |
358 | `CUPS_MEDIA_A6`, `CUPS_MEDIA_ENV10`, `CUPS_MEDIA_ENVDL`, `CUPS_MEDIA_LEGAL`, | |
359 | `CUPS_MEDIA_LETTER`, `CUPS_MEDIA_PHOTO_L`, `CUPS_MEDIA_SUPERBA3`, or | |
360 | `CUPS_MEDIA_TABLOID`. | |
361 | - `CUPS_MEDIA_SOURCE`: Controls where the media is pulled from, typically either | |
362 | `CUPS_MEDIA_SOURCE_AUTO` or `CUPS_MEDIA_SOURCE_MANUAL`. | |
363 | - `CUPS_MEDIA_TYPE`: Controls the type of media that is used, typically one of | |
364 | the following: `CUPS_MEDIA_TYPE_AUTO`, `CUPS_MEDIA_TYPE_ENVELOPE`, | |
365 | `CUPS_MEDIA_TYPE_LABELS`, `CUPS_MEDIA_TYPE_LETTERHEAD`, | |
366 | `CUPS_MEDIA_TYPE_PHOTO`, `CUPS_MEDIA_TYPE_PHOTO_GLOSSY`, | |
367 | `CUPS_MEDIA_TYPE_PHOTO_MATTE`, `CUPS_MEDIA_TYPE_PLAIN`, or | |
368 | `CUPS_MEDIA_TYPE_TRANSPARENCY`. | |
369 | - `CUPS_NUMBER_UP`: Controls the number of document pages that are placed on | |
370 | each media side. | |
371 | - `CUPS_ORIENTATION`: Controls the orientation of document pages placed on the | |
372 | media: `CUPS_ORIENTATION_PORTRAIT` or `CUPS_ORIENTATION_LANDSCAPE`. | |
373 | - `CUPS_PRINT_COLOR_MODE`: Controls whether the output is in color | |
374 | \(`CUPS_PRINT_COLOR_MODE_COLOR`), grayscale | |
375 | \(`CUPS_PRINT_COLOR_MODE_MONOCHROME`), or either | |
376 | \(`CUPS_PRINT_COLOR_MODE_AUTO`). | |
377 | - `CUPS_PRINT_QUALITY`: Controls the generate quality of the output: | |
378 | `CUPS_PRINT_QUALITY_DRAFT`, `CUPS_PRINT_QUALITY_NORMAL`, or | |
379 | `CUPS_PRINT_QUALITY_HIGH`. | |
380 | - `CUPS_SIDES`: Controls whether prints are placed on one or both sides of the | |
381 | media: `CUPS_SIDES_ONE_SIDED`, `CUPS_SIDES_TWO_SIDED_PORTRAIT`, or | |
382 | `CUPS_SIDES_TWO_SIDED_LANDSCAPE`. | |
383 | ||
384 | If the `value` argument is `NULL`, the `cupsCheckDestSupported` function returns | |
385 | whether the option is supported by the destination. Otherwise, the function | |
386 | returns whether the specified value of the option is supported. | |
387 | ||
388 | The `cupsFindDestSupported` function returns the IPP attribute containing the | |
389 | supported values for a given option: | |
390 | ||
391 | ipp_attribute_t * | |
392 | cupsFindDestSupported(http_t *http, cups_dest_t *dest, | |
393 | cups_dinfo_t *dinfo, | |
394 | const char *option); | |
395 | ||
396 | For example, the following code prints the supported finishing processes for a | |
397 | destination, if any, to the standard output: | |
398 | ||
399 | cups_dinfo_t *info = cupsCopyDestInfo(CUPS_HTTP_DEFAULT, | |
400 | dest); | |
401 | ||
402 | if (cupsCheckDestSupported(CUPS_HTTP_DEFAULT, dest, info, | |
403 | CUPS_FINISHINGS, NULL)) | |
404 | { | |
405 | ipp_attribute_t *finishings = | |
406 | cupsFindDestSupported(CUPS_HTTP_DEFAULT, dest, info, | |
407 | CUPS_FINISHINGS); | |
408 | int i, count = ippGetCount(finishings); | |
409 | ||
410 | puts("finishings supported:"); | |
411 | for (i = 0; i < count; i ++) | |
412 | printf(" %d\n", ippGetInteger(finishings, i)); | |
413 | } | |
414 | else | |
415 | puts("finishings not supported."); | |
abacc52b | 416 | |
798d6e29 MS |
417 | The "job-creation-attributes" option can be queried to get a list of supported |
418 | options. For example, the following code prints the list of supported options | |
419 | to the standard output: | |
abacc52b | 420 | |
798d6e29 MS |
421 | ipp_attribute_t *attrs = |
422 | cupsFindDestSupported(CUPS_HTTP_DEFAULT, dest, info, | |
423 | "job-creation-attributes"); | |
424 | int i, count = ippGetCount(attrs); | |
abacc52b | 425 | |
798d6e29 MS |
426 | for (i = 0; i < count; i ++) |
427 | puts(ippGetString(attrs, i, NULL)); | |
abacc52b MS |
428 | |
429 | ||
798d6e29 | 430 | ### Getting Default Values |
abacc52b | 431 | |
798d6e29 MS |
432 | There are two sets of default values - user defaults that are available via the |
433 | `num_options` and `options` members of the `cups_dest_t` structure, and | |
434 | destination defaults that available via the `cups_dinfo_t` structure and the | |
435 | `cupsFindDestDefault` function which returns the IPP attribute containing the | |
436 | default value(s) for a given option: | |
abacc52b | 437 | |
798d6e29 MS |
438 | ipp_attribute_t * |
439 | cupsFindDestDefault(http_t *http, cups_dest_t *dest, | |
440 | cups_dinfo_t *dinfo, | |
441 | const char *option); | |
abacc52b | 442 | |
798d6e29 MS |
443 | The user defaults from `cupsGetOption` should always take preference over the |
444 | destination defaults. For example, the following code prints the default | |
445 | finishings value(s) to the standard output: | |
abacc52b | 446 | |
798d6e29 MS |
447 | const char *def_value = |
448 | cupsGetOption(CUPS_FINISHINGS, dest->num_options, | |
449 | dest->options); | |
450 | ipp_attribute_t *def_attr = | |
451 | cupsFindDestDefault(CUPS_HTTP_DEFAULT, dest, info, | |
452 | CUPS_FINISHINGS); | |
abacc52b | 453 | |
798d6e29 MS |
454 | if (def_value != NULL) |
455 | { | |
456 | printf("Default finishings: %s\n", def_value); | |
457 | } | |
458 | else | |
459 | { | |
460 | int i, count = ippGetCount(def_attr); | |
abacc52b | 461 | |
798d6e29 MS |
462 | printf("Default finishings: %d", |
463 | ippGetInteger(def_attr, 0)); | |
464 | for (i = 1; i < count; i ++) | |
465 | printf(",%d", ippGetInteger(def_attr, i)); | |
466 | putchar('\n'); | |
467 | } | |
abacc52b MS |
468 | |
469 | ||
798d6e29 | 470 | ### Getting Ready (Loaded) Values |
abacc52b | 471 | |
798d6e29 MS |
472 | The finishings and media options also support queries for the ready, or loaded, |
473 | values. For example, a printer may have punch and staple finishers installed | |
474 | but be out of staples - the supported values will list both punch and staple | |
475 | finishing processes but the ready values will only list the punch processes. | |
476 | Similarly, a printer may support hundreds of different sizes of media but only | |
477 | have a single size loaded at any given time - the ready values are limited to | |
478 | the media that is actually in the printer. | |
abacc52b | 479 | |
798d6e29 MS |
480 | The `cupsFindDestReady` function finds the IPP attribute containing the ready |
481 | values for a given option: | |
abacc52b | 482 | |
798d6e29 MS |
483 | ipp_attribute_t * |
484 | cupsFindDestReady(http_t *http, cups_dest_t *dest, | |
485 | cups_dinfo_t *dinfo, const char *option); | |
abacc52b | 486 | |
798d6e29 | 487 | For example, the following code lists the ready finishing processes: |
abacc52b | 488 | |
798d6e29 MS |
489 | ipp_attribute_t *ready_finishings = |
490 | cupsFindDestReady(CUPS_HTTP_DEFAULT, dest, info, | |
491 | CUPS_FINISHINGS); | |
abacc52b | 492 | |
798d6e29 MS |
493 | if (ready_finishings != NULL) |
494 | { | |
495 | int i, count = ippGetCount(ready_finishings); | |
abacc52b | 496 | |
798d6e29 MS |
497 | puts("finishings ready:"); |
498 | for (i = 0; i < count; i ++) | |
499 | printf(" %d\n", ippGetInteger(ready_finishings, i)); | |
500 | } | |
501 | else | |
502 | puts("no finishings are ready."); | |
abacc52b | 503 | |
abacc52b | 504 | |
798d6e29 | 505 | ### Media Size Options |
abacc52b | 506 | |
798d6e29 MS |
507 | CUPS provides functions for querying the dimensions and margins for each of the |
508 | supported media size options. The `cups_size_t` structure is used to describe a | |
509 | media size: | |
abacc52b | 510 | |
798d6e29 MS |
511 | typedef struct cups_size_s |
512 | { | |
513 | char media[128]; | |
514 | int width, length; | |
515 | int bottom, left, right, top; | |
516 | } cups_size_t; | |
517 | ||
518 | The `width` and `length` members specify the dimensions of the media in | |
519 | hundredths of millimeters (1/2540th of an inch). The `bottom`, `left`, `right`, | |
520 | and `top` members specify the margins of the printable area, also in hundredths | |
521 | of millimeters. | |
522 | ||
523 | The `cupsGetDestMediaByName` and `cupsGetDestMediaBySize` functions lookup the | |
524 | media size information using a standard media size name or dimensions in | |
525 | hundredths of millimeters: | |
526 | ||
527 | int | |
528 | cupsGetDestMediaByName(http_t *http, cups_dest_t *dest, | |
529 | cups_dinfo_t *dinfo, | |
530 | const char *media, | |
531 | unsigned flags, cups_size_t *size); | |
532 | ||
533 | int | |
534 | cupsGetDestMediaBySize(http_t *http, cups_dest_t *dest, | |
535 | cups_dinfo_t *dinfo, | |
536 | int width, int length, | |
537 | unsigned flags, cups_size_t *size); | |
538 | ||
539 | The `media`, `width`, and `length` arguments specify the size to lookup. The | |
540 | `flags` argument specifies a bitfield controlling various lookup options: | |
541 | ||
542 | - `CUPS_MEDIA_FLAGS_DEFAULT`: Find the closest size supported by the printer. | |
543 | - `CUPS_MEDIA_FLAGS_BORDERLESS`: Find a borderless size. | |
544 | - `CUPS_MEDIA_FLAGS_DUPLEX`: Find a size compatible with two-sided printing. | |
545 | - `CUPS_MEDIA_FLAGS_EXACT`: Find an exact match for the size. | |
546 | - `CUPS_MEDIA_FLAGS_READY`: If the printer supports media sensing or | |
547 | configuration of the media in each tray/source, find the size amongst the | |
548 | "ready" media. | |
549 | ||
550 | If a matching size is found for the destination, the size information is stored | |
551 | in the structure pointed to by the `size` argument and 1 is returned. Otherwise | |
552 | 0 is returned. | |
553 | ||
554 | For example, the following code prints the margins for two-sided printing on US | |
555 | Letter media: | |
556 | ||
557 | cups_size_t size; | |
558 | ||
559 | if (cupsGetDestMediaByName(CUPS_HTTP_DEFAULT, dest, info, | |
560 | CUPS_MEDIA_LETTER, | |
561 | CUPS_MEDIA_FLAGS_DUPLEX, &size)) | |
abacc52b | 562 | { |
798d6e29 MS |
563 | puts("Margins for duplex US Letter:"); |
564 | printf(" Bottom: %.2fin\n", size.bottom / 2540.0); | |
565 | printf(" Left: %.2fin\n", size.left / 2540.0); | |
566 | printf(" Right: %.2fin\n", size.right / 2540.0); | |
567 | printf(" Top: %.2fin\n", size.top / 2540.0); | |
abacc52b | 568 | } |
798d6e29 MS |
569 | else |
570 | puts("Margins for duplex US Letter are not available."); | |
abacc52b | 571 | |
798d6e29 MS |
572 | You can also enumerate all of the sizes that match a given `flags` value using |
573 | the `cupsGetDestMediaByIndex` and `cupsGetDestMediaCount` functions: | |
abacc52b | 574 | |
798d6e29 MS |
575 | int |
576 | cupsGetDestMediaByIndex(http_t *http, cups_dest_t *dest, | |
577 | cups_dinfo_t *dinfo, int n, | |
578 | unsigned flags, cups_size_t *size); | |
abacc52b | 579 | |
798d6e29 MS |
580 | int |
581 | cupsGetDestMediaCount(http_t *http, cups_dest_t *dest, | |
582 | cups_dinfo_t *dinfo, unsigned flags); | |
abacc52b | 583 | |
798d6e29 MS |
584 | For example, the following code prints the list of ready media and corresponding |
585 | margins: | |
abacc52b | 586 | |
798d6e29 MS |
587 | cups_size_t size; |
588 | int i; | |
589 | int count = cupsGetDestMediaCount(CUPS_HTTP_DEFAULT, | |
590 | dest, info, | |
591 | CUPS_MEDIA_FLAGS_READY); | |
abacc52b | 592 | |
798d6e29 MS |
593 | for (i = 0; i < count; i ++) |
594 | { | |
595 | if (cupsGetDestMediaByIndex(CUPS_HTTP_DEFAULT, dest, info, | |
596 | i, CUPS_MEDIA_FLAGS_READY, | |
597 | &size)) | |
598 | { | |
599 | printf("%s:\n", size.name); | |
600 | printf(" Width: %.2fin\n", size.width / 2540.0); | |
601 | printf(" Length: %.2fin\n", size.length / 2540.0); | |
602 | printf(" Bottom: %.2fin\n", size.bottom / 2540.0); | |
603 | printf(" Left: %.2fin\n", size.left / 2540.0); | |
604 | printf(" Right: %.2fin\n", size.right / 2540.0); | |
605 | printf(" Top: %.2fin\n", size.top / 2540.0); | |
606 | } | |
607 | } | |
abacc52b | 608 | |
798d6e29 | 609 | Finally, the `cupsGetDestMediaDefault` function returns the default media size: |
abacc52b | 610 | |
798d6e29 MS |
611 | int |
612 | cupsGetDestMediaDefault(http_t *http, cups_dest_t *dest, | |
613 | cups_dinfo_t *dinfo, unsigned flags, | |
614 | cups_size_t *size); | |
abacc52b | 615 | |
abacc52b | 616 | |
798d6e29 | 617 | ### Localizing Options and Values |
abacc52b | 618 | |
6ad44eeb MS |
619 | CUPS provides three functions to get localized, human-readable strings in the |
620 | user's current locale for options and values: `cupsLocalizeDestMedia`, | |
621 | `cupsLocalizeDestOption`, and `cupsLocalizeDestValue`: | |
abacc52b | 622 | |
798d6e29 MS |
623 | const char * |
624 | cupsLocalizeDestMedia(http_t *http, cups_dest_t *dest, | |
625 | cups_dinfo_t *info, unsigned flags, | |
626 | cups_size_t *size); | |
abacc52b | 627 | |
798d6e29 MS |
628 | const char * |
629 | cupsLocalizeDestOption(http_t *http, cups_dest_t *dest, | |
630 | cups_dinfo_t *info, | |
631 | const char *option); | |
abacc52b | 632 | |
798d6e29 MS |
633 | const char * |
634 | cupsLocalizeDestValue(http_t *http, cups_dest_t *dest, | |
635 | cups_dinfo_t *info, | |
636 | const char *option, const char *value); | |
abacc52b | 637 | |
abacc52b | 638 | |
798d6e29 | 639 | ## Submitting a Print Job |
abacc52b | 640 | |
798d6e29 MS |
641 | Once you are ready to submit a print job, you create a job using the |
642 | `cupsCreateDestJob` function: | |
643 | ||
644 | ipp_status_t | |
645 | cupsCreateDestJob(http_t *http, cups_dest_t *dest, | |
646 | cups_dinfo_t *info, int *job_id, | |
647 | const char *title, int num_options, | |
648 | cups_option_t *options); | |
649 | ||
650 | The `title` argument specifies a name for the print job such as "My Document". | |
651 | The `num_options` and `options` arguments specify the options for the print | |
652 | job which are allocated using the `cupsAddOption` function. | |
653 | ||
654 | When successful, the job's numeric identifier is stored in the integer pointed | |
655 | to by the `job_id` argument and `IPP_STATUS_OK` is returned. Otherwise, an IPP | |
656 | error status is returned. | |
657 | ||
658 | For example, the following code creates a new job that will print 42 copies of a | |
659 | two-sided US Letter document: | |
660 | ||
661 | int job_id = 0; | |
662 | int num_options = 0; | |
663 | cups_option_t *options = NULL; | |
664 | ||
665 | num_options = cupsAddOption(CUPS_COPIES, "42", | |
666 | num_options, &options); | |
667 | num_options = cupsAddOption(CUPS_MEDIA, CUPS_MEDIA_LETTER, | |
668 | num_options, &options); | |
669 | num_options = cupsAddOption(CUPS_SIDES, | |
670 | CUPS_SIDES_TWO_SIDED_PORTRAIT, | |
671 | num_options, &options); | |
672 | ||
673 | if (cupsCreateDestJob(CUPS_HTTP_DEFAULT, dest, info, | |
674 | &job_id, "My Document", num_options, | |
675 | options) == IPP_STATUS_OK) | |
676 | printf("Created job: %d\n", job_id); | |
677 | else | |
678 | printf("Unable to create job: %s\n", | |
679 | cupsLastErrorString()); | |
680 | ||
681 | Once the job is created, you submit documents for the job using the | |
682 | `cupsStartDestDocument`, `cupsWriteRequestData`, and `cupsFinishDestDocument` | |
683 | functions: | |
684 | ||
685 | http_status_t | |
686 | cupsStartDestDocument(http_t *http, cups_dest_t *dest, | |
687 | cups_dinfo_t *info, int job_id, | |
688 | const char *docname, | |
689 | const char *format, | |
690 | int num_options, | |
691 | cups_option_t *options, | |
692 | int last_document); | |
693 | ||
694 | http_status_t | |
695 | cupsWriteRequestData(http_t *http, const char *buffer, | |
696 | size_t length); | |
697 | ||
698 | ipp_status_t | |
699 | cupsFinishDestDocument(http_t *http, cups_dest_t *dest, | |
700 | cups_dinfo_t *info); | |
701 | ||
702 | The `docname` argument specifies the name of the document, typically the | |
703 | original filename. The `format` argument specifies the MIME media type of the | |
704 | document, including the following constants: | |
705 | ||
706 | - `CUPS_FORMAT_JPEG`: "image/jpeg" | |
707 | - `CUPS_FORMAT_PDF`: "application/pdf" | |
708 | - `CUPS_FORMAT_POSTSCRIPT`: "application/postscript" | |
709 | - `CUPS_FORMAT_TEXT`: "text/plain" | |
710 | ||
711 | The `num_options` and `options` arguments specify per-document print options, | |
712 | which at present must be 0 and `NULL`. The `last_document` argument specifies | |
713 | whether this is the last document in the job. | |
714 | ||
715 | For example, the following code submits a PDF file to the job that was just | |
716 | created: | |
717 | ||
718 | FILE *fp = fopen("filename.pdf", "rb"); | |
719 | size_t bytes; | |
720 | char buffer[65536]; | |
721 | ||
722 | if (cupsStartDestDocument(CUPS_HTTP_DEFAULT, dest, info, | |
723 | job_id, "filename.pdf", 0, NULL, | |
724 | 1) == HTTP_STATUS_CONTINUE) | |
abacc52b | 725 | { |
798d6e29 MS |
726 | while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) |
727 | if (cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, | |
728 | bytes) != HTTP_STATUS_CONTINUE) | |
729 | break; | |
730 | ||
731 | if (cupsFinishDestDocument(CUPS_HTTP_DEFAULT, dest, | |
732 | info) == IPP_STATUS_OK) | |
733 | puts("Document send succeeded."); | |
734 | else | |
735 | printf("Document send failed: %s\n", | |
736 | cupsLastErrorString()); | |
abacc52b | 737 | } |
798d6e29 MS |
738 | |
739 | fclose(fp); | |
65bebeac MS |
740 | |
741 | ||
742 | # Sending IPP Requests | |
743 | ||
b0fb2d75 MS |
744 | CUPS provides a rich API for sending IPP requests to the scheduler or printers, |
745 | typically from management or utility applications whose primary purpose is not | |
746 | to send print jobs. | |
747 | ||
748 | ||
65bebeac MS |
749 | ## Connecting to the Scheduler or Printer |
750 | ||
b0fb2d75 MS |
751 | The connection to the scheduler or printer is represented by the HTTP connection |
752 | type `http_t`. The `cupsConnectDest` function connects to the scheduler or | |
753 | printer associated with the destination: | |
754 | ||
755 | http_t * | |
756 | cupsConnectDest(cups_dest_t *dest, unsigned flags, int msec, | |
757 | int *cancel, char *resource, | |
758 | size_t resourcesize, cups_dest_cb_t cb, | |
759 | void *user_data); | |
760 | ||
761 | The `dest` argument specifies the destination to connect to. | |
762 | ||
763 | The `flags` argument specifies whether you want to connect to the scheduler | |
764 | (`CUPS_DEST_FLAGS_NONE`) or device/printer (`CUPS_DEST_FLAGS_DEVICE`) associated | |
765 | with the destination. | |
766 | ||
767 | The `msec` argument specifies how long you are willing to wait for the | |
768 | connection to be established in milliseconds. Specify a value of `-1` to wait | |
769 | indefinitely. | |
770 | ||
771 | The `cancel` argument specifies the address of an integer variable that can be | |
772 | set to a non-zero value to cancel the connection. Specify a value of `NULL` | |
773 | to not provide a cancel variable. | |
774 | ||
775 | The `resource` and `resourcesize` arguments specify the address and size of a | |
776 | character string array to hold the path to use when sending an IPP request. | |
777 | ||
778 | The `cb` and `user_data` arguments specify a destination callback function that | |
779 | returns 1 to continue connecting or 0 to stop. The destination callback work | |
780 | the same way as the one used for the `cupsEnumDests` function. | |
65bebeac | 781 | |
b0fb2d75 MS |
782 | On success, a HTTP connection is returned that can be used to send IPP requests |
783 | and get IPP responses. | |
784 | ||
785 | For example, the following code connects to the printer associated with a | |
786 | destination with a 30 second timeout: | |
787 | ||
788 | char resource[256]; | |
789 | http_t *http = cupsConnectDest(dest, CUPS_DEST_FLAGS_DEVICE, | |
790 | 30000, NULL, resource, | |
791 | sizeof(resource), NULL, NULL); | |
65bebeac MS |
792 | |
793 | ||
794 | ## Creating an IPP Request | |
795 | ||
b0fb2d75 MS |
796 | IPP requests are represented by the IPP message type `ipp_t` and each IPP |
797 | attribute in the request is representing using the type `ipp_attribute_t`. Each | |
798 | IPP request includes an operation code (`IPP_OP_CREATE_JOB`, | |
799 | `IPP_OP_GET_PRINTER_ATTRIBUTES`, etc.) and a 32-bit integer identifier. | |
800 | ||
801 | The `ippNewRequest` function creates a new IPP request: | |
802 | ||
803 | ipp_t * | |
804 | ippNewRequest(ipp_op_t op); | |
805 | ||
806 | The `op` argument specifies the IPP operation code for the request. For | |
807 | example, the following code creates an IPP Get-Printer-Attributes request: | |
808 | ||
809 | ipp_t *request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); | |
810 | ||
811 | The request identifier is automatically set to a unique value for the current | |
812 | process. | |
813 | ||
814 | Each IPP request starts with two IPP attributes, "attributes-charset" and | |
815 | "attributes-natural-language", followed by IPP attribute(s) that specify the | |
816 | target of the operation. The `ippNewRequest` automatically adds the correct | |
817 | "attributes-charset" and "attributes-natural-language" attributes, but you must | |
818 | add the target attribute(s). For example, the following code adds the | |
819 | "printer-uri" attribute to the IPP Get-Printer-Attributes request to specify | |
820 | which printer is being queried: | |
821 | ||
822 | const char *printer_uri = cupsGetOption("device-uri", | |
823 | dest->num_options, | |
824 | dest->options); | |
825 | ||
826 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, | |
827 | "printer-uri", NULL, printer_uri); | |
828 | ||
73721e3e MS |
829 | > **Note:** |
830 | > | |
831 | > If we wanted to query the scheduler instead of the device, we would look | |
b0fb2d75 MS |
832 | > up the "printer-uri-supported" option instead of the "device-uri" value. |
833 | ||
834 | The `ippAddString` function adds the "printer-uri" attribute the the IPP | |
835 | request. The `IPP_TAG_OPERATION` argument specifies that the attribute is part | |
836 | of the operation. The `IPP_TAG_URI` argument specifies that the value is a | |
837 | Universal Resource Identifier (URI) string. The `NULL` argument specifies there | |
838 | is no language (English, French, Japanese, etc.) associated with the string, and | |
839 | the `printer_uri` argument specifies the string value. | |
840 | ||
841 | The IPP Get-Printer-Attributes request also supports an IPP attribute called | |
842 | "requested-attributes" that lists the attributes and values you are interested | |
843 | in. For example, the following code requests the printer state attributes: | |
844 | ||
845 | static const char * const requested_attributes[] = | |
846 | { | |
847 | "printer-state", | |
848 | "printer-state-message", | |
849 | "printer-state-reasons" | |
850 | }; | |
851 | ||
852 | ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, | |
853 | "requested-attributes", 3, NULL, | |
854 | requested_attributes); | |
855 | ||
856 | The `ippAddStrings` function adds an attribute with one or more strings, in this | |
857 | case three. The `IPP_TAG_KEYWORD` argument specifies that the strings are | |
858 | keyword values, which are used for attribute names. All strings use the same | |
859 | language (`NULL`), and the attribute will contain the three strings in the | |
860 | array `requested_attributes`. | |
861 | ||
862 | CUPS provides many functions to adding attributes of different types: | |
863 | ||
864 | - `ippAddBoolean` adds a boolean (`IPP_TAG_BOOLEAN`) attribute with one value. | |
865 | - `ippAddInteger` adds an enum (`IPP_TAG_ENUM`) or integer (`IPP_TAG_INTEGER`) | |
866 | attribute with one value. | |
867 | - `ippAddIntegers` adds an enum or integer attribute with one or more values. | |
868 | - `ippAddOctetString` adds an octetString attribute with one value. | |
869 | - `ippAddOutOfBand` adds a admin-defined (`IPP_TAG_ADMINDEFINE`), default | |
870 | (`IPP_TAG_DEFAULT`), delete-attribute (`IPP_TAG_DELETEATTR`), no-value | |
871 | (`IPP_TAG_NOVALUE`), not-settable (`IPP_TAG_NOTSETTABLE`), unknown | |
872 | (`IPP_TAG_UNKNOWN`), or unsupported (`IPP_TAG_UNSUPPORTED_VALUE`) out-of-band | |
873 | attribute. | |
874 | - `ippAddRange` adds a rangeOfInteger attribute with one range. | |
875 | - `ippAddRanges` adds a rangeOfInteger attribute with one or more ranges. | |
876 | - `ippAddResolution` adds a resolution attribute with one resolution. | |
877 | - `ippAddResolutions` adds a resolution attribute with one or more resolutions. | |
878 | - `ippAddString` adds a charset (`IPP_TAG_CHARSET`), keyword (`IPP_TAG_KEYWORD`), | |
879 | mimeMediaType (`IPP_TAG_MIMETYPE`), name (`IPP_TAG_NAME` and | |
880 | `IPP_TAG_NAMELANG`), naturalLanguage (`IPP_TAG_NATURAL_LANGUAGE`), text | |
881 | (`IPP_TAG_TEXT` and `IPP_TAG_TEXTLANG`), uri (`IPP_TAG_URI`), or uriScheme | |
882 | (`IPP_TAG_URISCHEME`) attribute with one value. | |
883 | - `ippAddStrings` adds a charset, keyword, mimeMediaType, name, naturalLanguage, | |
884 | text, uri, or uriScheme attribute with one or more values. | |
885 | ||
886 | ||
65bebeac MS |
887 | ## Sending the IPP Request |
888 | ||
b0fb2d75 MS |
889 | Once you have created the IPP request, you can send it using the |
890 | `cupsDoRequest` function. For example, the following code sends the IPP | |
891 | Get-Printer-Attributes request to the destination and saves the response: | |
892 | ||
893 | ipp_t *response = cupsDoRequest(http, request, resource); | |
894 | ||
895 | For requests like Send-Document that include a file, the `cupsDoFileRequest` | |
896 | function should be used: | |
897 | ||
898 | ipp_t *response = cupsDoFileRequest(http, request, resource, | |
899 | filename); | |
900 | ||
901 | Both `cupsDoRequest` and `cupsDoFileRequest` free the IPP request. If a valid | |
902 | IPP response is received, it is stored in a new IPP message (`ipp_t`) and | |
903 | returned to the caller. Otherwise `NULL` is returned. | |
904 | ||
905 | The status from the most recent request can be queried using the `cupsLastError` | |
906 | function, for example: | |
907 | ||
908 | if (cupsLastError() >= IPP_STATUS_ERROR_BAD_REQUEST) | |
909 | { | |
910 | /* request failed */ | |
911 | } | |
912 | ||
913 | A human-readable error message is also available using the `cupsLastErrorString` | |
914 | function: | |
915 | ||
916 | if (cupsLastError() >= IPP_STATUS_ERROR_BAD_REQUEST) | |
917 | { | |
918 | /* request failed */ | |
919 | printf("Request failed: %s\n", cupsLastErrorString()); | |
920 | } | |
921 | ||
922 | ||
923 | ## Processing the IPP Response | |
924 | ||
925 | Each response to an IPP request is also an IPP message (`ipp_t`) with its own | |
926 | IPP attributes (`ipp_attribute_t`) that includes a status code (`IPP_STATUS_OK`, | |
927 | `IPP_STATUS_ERROR_BAD_REQUEST`, etc.) and the corresponding 32-bit integer | |
928 | identifier from the request. | |
929 | ||
930 | For example, the following code finds the printer state attributes and prints | |
931 | their values: | |
932 | ||
933 | ipp_attribute_t *attr; | |
934 | ||
935 | if ((attr = ippFindAttribute(response, "printer-state", | |
936 | IPP_TAG_ENUM)) != NULL) | |
937 | { | |
938 | printf("printer-state=%s\n", | |
db5424ea | 939 | ippEnumString("printer-state", ippGetInteger(attr, 0))); |
b0fb2d75 MS |
940 | } |
941 | else | |
942 | puts("printer-state=unknown"); | |
943 | ||
944 | if ((attr = ippFindAttribute(response, "printer-state-message", | |
945 | IPP_TAG_TEXT)) != NULL) | |
946 | { | |
947 | printf("printer-state-message=\"%s\"\n", | |
948 | ippGetString(attr, 0, NULL))); | |
949 | } | |
950 | ||
951 | if ((attr = ippFindAttribute(response, "printer-state-reasons", | |
952 | IPP_TAG_KEYWORD)) != NULL) | |
953 | { | |
954 | int i, count = ippGetCount(attr); | |
955 | ||
956 | puts("printer-state-reasons="); | |
957 | for (i = 0; i < count; i ++) | |
958 | printf(" %s\n", ippGetString(attr, i, NULL))); | |
959 | } | |
960 | ||
961 | The `ippGetCount` function returns the number of values in an attribute. | |
962 | ||
963 | The `ippGetInteger` and `ippGetString` functions return a single integer or | |
964 | string value from an attribute. | |
965 | ||
db5424ea | 966 | The `ippEnumString` function converts a enum value to its keyword (string) |
b0fb2d75 MS |
967 | equivalent. |
968 | ||
969 | Once you are done using the IPP response message, free it using the `ippDelete` | |
970 | function: | |
971 | ||
972 | ippDelete(response); | |
973 | ||
65bebeac MS |
974 | |
975 | ## Authentication | |
b0fb2d75 MS |
976 | |
977 | CUPS normally handles authentication through the console. GUI applications | |
978 | should set a password callback using the `cupsSetPasswordCB2` function: | |
979 | ||
980 | void | |
981 | cupsSetPasswordCB2(cups_password_cb2_t cb, void *user_data); | |
982 | ||
983 | The password callback will be called when needed and is responsible for setting | |
984 | the current user name using `cupsSetUser` and returning a string: | |
985 | ||
986 | const char * | |
987 | cups_password_cb2(const char *prompt, http_t *http, | |
988 | const char *method, const char *resource, | |
989 | void *user_data); | |
990 | ||
991 | The `prompt` argument is a string from CUPS that should be displayed to the | |
992 | user. | |
993 | ||
994 | The `http` argument is the connection hosting the request that is being | |
995 | authenticated. The password callback can call the `httpGetField` and | |
996 | `httpGetSubField` functions to look for additional details concerning the | |
997 | authentication challenge. | |
998 | ||
999 | The `method` argument specifies the HTTP method used for the request and is | |
1000 | typically "POST". | |
1001 | ||
1002 | The `resource` argument specifies the path used for the request. | |
1003 | ||
1004 | The `user_data` argument provides the user data pointer from the | |
1005 | `cupsSetPasswordCB2` call. |