1--- 2title: CUPS Programming Manual 3author: Michael R Sweet 4copyright: Copyright © 2007-2022 by Apple Inc. All Rights Reserved. 5version: 2.3.6 6... 7 8> Please [file issues on Github](https://github.com/apple/cups/issues) to 9> provide feedback on this document. 10 11 12# Introduction 13 14CUPS provides the "cups" library to talk to the different parts of CUPS and with 15Internet Printing Protocol (IPP) printers. The "cups" library functions are 16accessed by including the `<cups/cups.h>` header. 17 18CUPS is based on the Internet Printing Protocol ("IPP"), which allows clients 19(applications) to communicate with a server (the scheduler, printers, etc.) to 20get a list of destinations, send print jobs, and so forth. You identify which 21server 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 23the CUPS scheduler. 24 25 26## Guidelines 27 28When writing software (other than printer drivers) that uses the "cups" library: 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 35CUPS is designed to insulate users and developers from the implementation 36details of printers and file formats. The goal is to allow an application to 37supply a print file in a standard format with the user intent ("print four 38copies, two-sided on A4 media, and staple each copy") and have the printing 39system manage the printer communication and format conversion needed. 40 41Similarly, printer and job management applications can use standard query 42operations to obtain the status information in a common, generic form and use 43standard management operations to control the state of those printers and jobs. 44 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 52 53## Terms Used in This Document 54 55A *Destination* is a printer or print queue that accepts print jobs. A 56*Print Job* is a collection of one or more documents that are processed by a 57destination using options supplied when creating the job. A *Document* is a 58file (JPEG image, PDF file, etc.) suitable for printing. An *Option* controls 59some aspect of printing, such as the media used. *Media* is the sheets or roll 60that is printed on. An *Attribute* is an option encoded for an Internet 61Printing Protocol (IPP) request. 62 63 64## Compiling Programs That Use the CUPS API 65 66The CUPS libraries can be used from any C, C++, or Objective C program. 67The method of compiling against the libraries varies depending on the 68operating system and installation of CUPS. The following sections show how 69to compile a simple program (shown below) in two common environments. 70 71The 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 96In Xcode, choose *New Project...* from the *File* menu (or press SHIFT+CMD+N), 97then select the *Command Line Tool* under the macOS Application project type. 98Click *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 101In the project window, click on the *Build Phases* group and expand the 102*Link Binary with Libraries* section. Click *+*, type "libcups" to show the 103library, and then double-click on `libcups.tbd`. 104 105Finally, click on the `main.c` file in the sidebar and copy the example program 106to the file. Build and run (CMD+R) to see the list of destinations. 107 108 109### Compiling with GCC 110 111From the command-line, create a file called `simple.c` using your favorite 112editor, copy the example to this file, and save. Then run the following command 113to compile it with GCC and run it: 114 115 gcc -o simple `cups-config --cflags` simple.c `cups-config --libs` 116 ./simple 117 118The `cups-config` command provides the compiler flags (`cups-config --cflags`) 119and libraries (`cups-config --libs`) needed for the local system. 120 121 122# Working with Destinations 123 124Destinations, which in CUPS represent individual printers or classes 125(collections or pools) of printers, are represented by the `cups_dest_t` 126structure which includes the name \(`name`), instance \(`instance`, saved 127options/settings), whether the destination is the default for the user 128\(`is_default`), and the options and basic information associated with that 129destination \(`num_options` and `options`). 130 131Historically destinations have been manually maintained by the administrator of 132a system or network, but CUPS also supports dynamic discovery of destinations on 133the current network. 134 135 136## Finding Available Destinations 137 138The `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 145The `flags` argument specifies enumeration options, which at present must be 146`CUPS_DEST_FLAGS_NONE`. 147 148The `msec` argument specifies the maximum amount of time that should be used for 149enumeration in milliseconds - interactive applications should keep this value to 1505000 or less when run on the main thread. 151 152The `cancel` argument points to an integer variable that, when set to a non-zero 153value, will cause enumeration to stop as soon as possible. It can be `NULL` if 154not needed. 155 156The `type` and `mask` arguments are bitfields that allow the caller to filter 157the 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` 159value when filtering. For example, to only enumerate destinations that are 160hosted on the local system, pass `CUPS_PRINTER_LOCAL` for the `type` argument 161and `CUPS_PRINTER_DISCOVERED` for the `mask` argument. The following constants 162can be used for filtering: 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 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. 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 186The `cb` argument specifies a function to call for every destination that is 187found: 188 189 typedef int (*cups_dest_cb_t)(void *user_data, 190 unsigned flags, 191 cups_dest_t *dest); 192 193The callback function receives a copy of the `user_data` argument along with a 194bitfield \(`flags`) and the destination that was found. The `flags` argument 195can 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 203The callback function returns 0 to stop enumeration or 1 to continue. 204 205> **Note:** 206> 207> The callback function will likely be called multiple times for the 208> same destination, so it is up to the caller to suppress any duplicate 209> destinations. 210 211The following example shows how to use `cupsEnumDests` to get a filtered array 212of destinations: 213 214 typedef struct 215 { 216 int num_dests; 217 cups_dest_t *dests; 218 } my_user_data_t; 219 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 */ 240 241 user_data->num_dests = 242 cupsCopyDest(dest, user_data->num_dests, 243 &(user_data->dests)); 244 } 245 246 return (1); 247 } 248 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 }; 254 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 */ 263 264 cupsFreeDests(user_data.num_dests, user_dasta.dests); 265 266 *dests = NULL; 267 268 return (0); 269 } 270 271 /* 272 * Return the destination array... 273 */ 274 275 *dests = user_data.dests; 276 277 return (user_data.num_dests); 278 } 279 280 281## Basic Destination Information 282 283The `num_options` and `options` members of the `cups_dest_t` structure provide 284basic attributes about the destination in addition to the user default options 285and values for that destination. The following names are predefined for various 286destination 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. 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. 310 311Use the `cupsGetOption` function to retrieve the value. For example, the 312following 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 318 319## Detailed Destination Information 320 321Once a destination has been chosen, the `cupsCopyDestInfo` function can be used 322to gather detailed information about the destination: 323 324 cups_dinfo_t * 325 cupsCopyDestInfo(http_t *http, cups_dest_t *dest); 326 327The `http` argument specifies a connection to the CUPS scheduler and is 328typically the constant `CUPS_HTTP_DEFAULT`. The `dest` argument specifies the 329destination to query. 330 331The `cups_dinfo_t` structure that is returned contains a snapshot of the 332supported options and their supported, ready, and default values. It also can 333report constraints between different options and values, and recommend changes 334to resolve those constraints. 335 336 337### Getting Supported Options and Values 338 339The `cupsCheckDestSupported` function can be used to test whether a particular 340option 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 348The `option` argument specifies the name of the option to check. The following 349constants 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 384If the `value` argument is `NULL`, the `cupsCheckDestSupported` function returns 385whether the option is supported by the destination. Otherwise, the function 386returns whether the specified value of the option is supported. 387 388The `cupsFindDestSupported` function returns the IPP attribute containing the 389supported 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 396For example, the following code prints the supported finishing processes for a 397destination, 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."); 416 417The "job-creation-attributes" option can be queried to get a list of supported 418options. For example, the following code prints the list of supported options 419to the standard output: 420 421 ipp_attribute_t *attrs = 422 cupsFindDestSupported(CUPS_HTTP_DEFAULT, dest, info, 423 "job-creation-attributes"); 424 int i, count = ippGetCount(attrs); 425 426 for (i = 0; i < count; i ++) 427 puts(ippGetString(attrs, i, NULL)); 428 429 430### Getting Default Values 431 432There 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 434destination defaults that available via the `cups_dinfo_t` structure and the 435`cupsFindDestDefault` function which returns the IPP attribute containing the 436default value(s) for a given option: 437 438 ipp_attribute_t * 439 cupsFindDestDefault(http_t *http, cups_dest_t *dest, 440 cups_dinfo_t *dinfo, 441 const char *option); 442 443The user defaults from `cupsGetOption` should always take preference over the 444destination defaults. For example, the following code prints the default 445finishings value(s) to the standard output: 446 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); 453 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); 461 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 } 468 469 470### Getting Ready (Loaded) Values 471 472The finishings and media options also support queries for the ready, or loaded, 473values. For example, a printer may have punch and staple finishers installed 474but be out of staples - the supported values will list both punch and staple 475finishing processes but the ready values will only list the punch processes. 476Similarly, a printer may support hundreds of different sizes of media but only 477have a single size loaded at any given time - the ready values are limited to 478the media that is actually in the printer. 479 480The `cupsFindDestReady` function finds the IPP attribute containing the ready 481values for a given option: 482 483 ipp_attribute_t * 484 cupsFindDestReady(http_t *http, cups_dest_t *dest, 485 cups_dinfo_t *dinfo, const char *option); 486 487For example, the following code lists the ready finishing processes: 488 489 ipp_attribute_t *ready_finishings = 490 cupsFindDestReady(CUPS_HTTP_DEFAULT, dest, info, 491 CUPS_FINISHINGS); 492 493 if (ready_finishings != NULL) 494 { 495 int i, count = ippGetCount(ready_finishings); 496 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."); 503 504 505### Media Size Options 506 507CUPS provides functions for querying the dimensions and margins for each of the 508supported media size options. The `cups_size_t` structure is used to describe a 509media size: 510 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 518The `width` and `length` members specify the dimensions of the media in 519hundredths of millimeters (1/2540th of an inch). The `bottom`, `left`, `right`, 520and `top` members specify the margins of the printable area, also in hundredths 521of millimeters. 522 523The `cupsGetDestMediaByName` and `cupsGetDestMediaBySize` functions lookup the 524media size information using a standard media size name or dimensions in 525hundredths 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 539The `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 550If a matching size is found for the destination, the size information is stored 551in the structure pointed to by the `size` argument and 1 is returned. Otherwise 5520 is returned. 553 554For example, the following code prints the margins for two-sided printing on US 555Letter 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)) 562 { 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); 568 } 569 else 570 puts("Margins for duplex US Letter are not available."); 571 572You can also enumerate all of the sizes that match a given `flags` value using 573the `cupsGetDestMediaByIndex` and `cupsGetDestMediaCount` functions: 574 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); 579 580 int 581 cupsGetDestMediaCount(http_t *http, cups_dest_t *dest, 582 cups_dinfo_t *dinfo, unsigned flags); 583 584For example, the following code prints the list of ready media and corresponding 585margins: 586 587 cups_size_t size; 588 int i; 589 int count = cupsGetDestMediaCount(CUPS_HTTP_DEFAULT, 590 dest, info, 591 CUPS_MEDIA_FLAGS_READY); 592 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 } 608 609Finally, the `cupsGetDestMediaDefault` function returns the default media size: 610 611 int 612 cupsGetDestMediaDefault(http_t *http, cups_dest_t *dest, 613 cups_dinfo_t *dinfo, unsigned flags, 614 cups_size_t *size); 615 616 617### Localizing Options and Values 618 619CUPS provides three functions to get localized, human-readable strings in the 620user's current locale for options and values: `cupsLocalizeDestMedia`, 621`cupsLocalizeDestOption`, and `cupsLocalizeDestValue`: 622 623 const char * 624 cupsLocalizeDestMedia(http_t *http, cups_dest_t *dest, 625 cups_dinfo_t *info, unsigned flags, 626 cups_size_t *size); 627 628 const char * 629 cupsLocalizeDestOption(http_t *http, cups_dest_t *dest, 630 cups_dinfo_t *info, 631 const char *option); 632 633 const char * 634 cupsLocalizeDestValue(http_t *http, cups_dest_t *dest, 635 cups_dinfo_t *info, 636 const char *option, const char *value); 637 638 639## Submitting a Print Job 640 641Once 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 650The `title` argument specifies a name for the print job such as "My Document". 651The `num_options` and `options` arguments specify the options for the print 652job which are allocated using the `cupsAddOption` function. 653 654When successful, the job's numeric identifier is stored in the integer pointed 655to by the `job_id` argument and `IPP_STATUS_OK` is returned. Otherwise, an IPP 656error status is returned. 657 658For example, the following code creates a new job that will print 42 copies of a 659two-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 681Once the job is created, you submit documents for the job using the 682`cupsStartDestDocument`, `cupsWriteRequestData`, and `cupsFinishDestDocument` 683functions: 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 702The `docname` argument specifies the name of the document, typically the 703original filename. The `format` argument specifies the MIME media type of the 704document, 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 711The `num_options` and `options` arguments specify per-document print options, 712which at present must be 0 and `NULL`. The `last_document` argument specifies 713whether this is the last document in the job. 714 715For example, the following code submits a PDF file to the job that was just 716created: 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) 725 { 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()); 737 } 738 739 fclose(fp); 740 741 742# Sending IPP Requests 743 744CUPS provides a rich API for sending IPP requests to the scheduler or printers, 745typically from management or utility applications whose primary purpose is not 746to send print jobs. 747 748 749## Connecting to the Scheduler or Printer 750 751The connection to the scheduler or printer is represented by the HTTP connection 752type `http_t`. The `cupsConnectDest` function connects to the scheduler or 753printer 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 761The `dest` argument specifies the destination to connect to. 762 763The `flags` argument specifies whether you want to connect to the scheduler 764(`CUPS_DEST_FLAGS_NONE`) or device/printer (`CUPS_DEST_FLAGS_DEVICE`) associated 765with the destination. 766 767The `msec` argument specifies how long you are willing to wait for the 768connection to be established in milliseconds. Specify a value of `-1` to wait 769indefinitely. 770 771The `cancel` argument specifies the address of an integer variable that can be 772set to a non-zero value to cancel the connection. Specify a value of `NULL` 773to not provide a cancel variable. 774 775The `resource` and `resourcesize` arguments specify the address and size of a 776character string array to hold the path to use when sending an IPP request. 777 778The `cb` and `user_data` arguments specify a destination callback function that 779returns 1 to continue connecting or 0 to stop. The destination callback work 780the same way as the one used for the `cupsEnumDests` function. 781 782On success, a HTTP connection is returned that can be used to send IPP requests 783and get IPP responses. 784 785For example, the following code connects to the printer associated with a 786destination 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); 792 793 794## Creating an IPP Request 795 796IPP requests are represented by the IPP message type `ipp_t` and each IPP 797attribute in the request is representing using the type `ipp_attribute_t`. Each 798IPP request includes an operation code (`IPP_OP_CREATE_JOB`, 799`IPP_OP_GET_PRINTER_ATTRIBUTES`, etc.) and a 32-bit integer identifier. 800 801The `ippNewRequest` function creates a new IPP request: 802 803 ipp_t * 804 ippNewRequest(ipp_op_t op); 805 806The `op` argument specifies the IPP operation code for the request. For 807example, the following code creates an IPP Get-Printer-Attributes request: 808 809 ipp_t *request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); 810 811The request identifier is automatically set to a unique value for the current 812process. 813 814Each IPP request starts with two IPP attributes, "attributes-charset" and 815"attributes-natural-language", followed by IPP attribute(s) that specify the 816target of the operation. The `ippNewRequest` automatically adds the correct 817"attributes-charset" and "attributes-natural-language" attributes, but you must 818add the target attribute(s). For example, the following code adds the 819"printer-uri" attribute to the IPP Get-Printer-Attributes request to specify 820which 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 829> **Note:** 830> 831> If we wanted to query the scheduler instead of the device, we would look 832> up the "printer-uri-supported" option instead of the "device-uri" value. 833 834The `ippAddString` function adds the "printer-uri" attribute the the IPP 835request. The `IPP_TAG_OPERATION` argument specifies that the attribute is part 836of the operation. The `IPP_TAG_URI` argument specifies that the value is a 837Universal Resource Identifier (URI) string. The `NULL` argument specifies there 838is no language (English, French, Japanese, etc.) associated with the string, and 839the `printer_uri` argument specifies the string value. 840 841The IPP Get-Printer-Attributes request also supports an IPP attribute called 842"requested-attributes" that lists the attributes and values you are interested 843in. 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 856The `ippAddStrings` function adds an attribute with one or more strings, in this 857case three. The `IPP_TAG_KEYWORD` argument specifies that the strings are 858keyword values, which are used for attribute names. All strings use the same 859language (`NULL`), and the attribute will contain the three strings in the 860array `requested_attributes`. 861 862CUPS 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 887## Sending the IPP Request 888 889Once you have created the IPP request, you can send it using the 890`cupsDoRequest` function. For example, the following code sends the IPP 891Get-Printer-Attributes request to the destination and saves the response: 892 893 ipp_t *response = cupsDoRequest(http, request, resource); 894 895For requests like Send-Document that include a file, the `cupsDoFileRequest` 896function should be used: 897 898 ipp_t *response = cupsDoFileRequest(http, request, resource, 899 filename); 900 901Both `cupsDoRequest` and `cupsDoFileRequest` free the IPP request. If a valid 902IPP response is received, it is stored in a new IPP message (`ipp_t`) and 903returned to the caller. Otherwise `NULL` is returned. 904 905The status from the most recent request can be queried using the `cupsLastError` 906function, for example: 907 908 if (cupsLastError() >= IPP_STATUS_ERROR_BAD_REQUEST) 909 { 910 /* request failed */ 911 } 912 913A human-readable error message is also available using the `cupsLastErrorString` 914function: 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 925Each response to an IPP request is also an IPP message (`ipp_t`) with its own 926IPP 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 928identifier from the request. 929 930For example, the following code finds the printer state attributes and prints 931their 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", 939 ippEnumString("printer-state", ippGetInteger(attr, 0))); 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 961The `ippGetCount` function returns the number of values in an attribute. 962 963The `ippGetInteger` and `ippGetString` functions return a single integer or 964string value from an attribute. 965 966The `ippEnumString` function converts a enum value to its keyword (string) 967equivalent. 968 969Once you are done using the IPP response message, free it using the `ippDelete` 970function: 971 972 ippDelete(response); 973 974 975## Authentication 976 977CUPS normally handles authentication through the console. GUI applications 978should set a password callback using the `cupsSetPasswordCB2` function: 979 980 void 981 cupsSetPasswordCB2(cups_password_cb2_t cb, void *user_data); 982 983The password callback will be called when needed and is responsible for setting 984the 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 991The `prompt` argument is a string from CUPS that should be displayed to the 992user. 993 994The `http` argument is the connection hosting the request that is being 995authenticated. The password callback can call the `httpGetField` and 996`httpGetSubField` functions to look for additional details concerning the 997authentication challenge. 998 999The `method` argument specifies the HTTP method used for the request and is 1000typically "POST". 1001 1002The `resource` argument specifies the path used for the request. 1003 1004The `user_data` argument provides the user data pointer from the 1005`cupsSetPasswordCB2` call. 1006