1<!-- 2 API introduction for CUPS. 3 4 Copyright 2007-2013 by Apple Inc. 5 Copyright 1997-2006 by Easy Software Products, all rights reserved. 6 7 These coded instructions, statements, and computer programs are the 8 property of Apple Inc. and are protected by Federal copyright 9 law. Distribution and use rights are outlined in the file "LICENSE.txt" 10 which should have been included with this file. If this file is 11 file is missing or damaged, see the license at "http://www.cups.org/". 12--> 13 14<h2 class='title'><a name='OVERVIEW'>Overview</a></h2> 15 16<p>The CUPS API provides the convenience functions needed to support 17applications, filters, printer drivers, and backends that need to interface 18with the CUPS scheduler.</p> 19 20<h3><a name='CLIENTS_AND_SERVERS'>Clients and Servers</a></h3> 21 22<p>CUPS is based on the Internet Printing Protocol ("IPP"), which allows 23clients (applications) to communicate with a server (the scheduler) to get a 24list of printers, send print jobs, and so forth. You identify which server 25you want to communicate with using a pointer to the opaque structure 26<code>http_t</code>. All of the examples in this document use the 27<code>CUPS_HTTP_DEFAULT</code> constant, referring to the default connection 28to the scheduler. The <a href='api-httpipp.html' target='_top'>HTTP and IPP 29APIs</a> document provides more information on server connections.</p> 30 31<h3><a name='PRINTERS_AND_CLASSES'>Printers and Classes</a></h3> 32 33<p>Printers and classes (collections of printers) are accessed through 34the <a href="#cups_dest_t"><code>cups_dest_t</code></a> structure which 35includes the name (<code>name</code>), instance (<code>instance</code> - 36a way of selecting certain saved options/settings), and the options and 37attributes associated with that destination (<code>num_options</code> and 38<code>options</code>). Destinations are created using the 39<a href="#cupsGetDests"><code>cupsGetDests</code></a> function and freed 40using the <a href='#cupsFreeDests'><code>cupsFreeDests</code></a> function. 41The <a href='#cupsGetDest'><code>cupsGetDest</code></a> function finds a 42specific destination for printing:</p> 43 44<pre class='example'> 45#include <cups/cups.h> 46 47<a href='#cups_dest_t'>cups_dest_t</a> *dests; 48int num_dests = <a href='#cupsGetDests'>cupsGetDests</a>(&dests); 49<a href='#cups_dest_t'>cups_dest_t</a> *dest = <a href='#cupsGetDest'>cupsGetDest</a>("name", NULL, num_dests, dests); 50 51/* do something with dest */ 52 53<a href='#cupsFreeDests'>cupsFreeDests</a>(num_dests, dests); 54</pre> 55 56<p>Passing <code>NULL</code> to 57<a href='#cupsGetDest'><code>cupsGetDest</code></a> for the destination name 58will return the default destination. Similarly, passing a <code>NULL</code> 59instance will return the default instance for that destination.</p> 60 61<div class='table'><table summary='Table 1: Printer Attributes' width='80%'> 62<caption>Table 1: <a name='TABLE1'>Printer Attributes</a></caption> 63<thead> 64<tr> 65 <th>Attribute Name</th> 66 <th>Description</th> 67</tr> 68</thead> 69<tbody> 70<tr> 71 <td>"auth-info-required"</td> 72 <td>The type of authentication required for printing to this 73 destination: "none", "username,password", "domain,username,password", 74 or "negotiate" (Kerberos)</td> 75</tr> 76<tr> 77 <td>"printer-info"</td> 78 <td>The human-readable description of the destination such as "My 79 Laser Printer".</td> 80</tr> 81<tr> 82 <td>"printer-is-accepting-jobs"</td> 83 <td>"true" if the destination is accepting new jobs, "false" if 84 not.</td> 85</tr> 86<tr> 87 <td>"printer-is-shared"</td> 88 <td>"true" if the destination is being shared with other computers, 89 "false" if not.</td> 90</tr> 91<tr> 92 <td>"printer-location"</td> 93 <td>The human-readable location of the destination such as "Lab 4".</td> 94</tr> 95<tr> 96 <td>"printer-make-and-model"</td> 97 <td>The human-readable make and model of the destination such as "HP 98 LaserJet 4000 Series".</td> 99</tr> 100<tr> 101 <td>"printer-state"</td> 102 <td>"3" if the destination is idle, "4" if the destination is printing 103 a job, and "5" if the destination is stopped.</td> 104</tr> 105<tr> 106 <td>"printer-state-change-time"</td> 107 <td>The UNIX time when the destination entered the current state.</td> 108</tr> 109<tr> 110 <td>"printer-state-reasons"</td> 111 <td>Additional comma-delimited state keywords for the destination 112 such as "media-tray-empty-error" and "toner-low-warning".</td> 113</tr> 114<tr> 115 <td>"printer-type"</td> 116 <td>The <a href='#cups_printer_t'><code>cups_printer_t</code></a> 117 value associated with the destination.</td> 118</tr> 119</tbody> 120</table></div> 121 122<h3><a name='OPTIONS'>Options</a></h3> 123 124<p>Options are stored in arrays of 125<a href='#cups_option_t'><code>cups_option_t</code></a> structures. Each 126option has a name (<code>name</code>) and value (<code>value</code>) 127associated with it. The <a href='#cups_dest_t'><code>cups_dest_t</code></a> 128<code>num_options</code> and <code>options</code> members contain the 129default options for a particular destination, along with several informational 130attributes about the destination as shown in <a href='#TABLE1'>Table 1</a>. 131The <a href='#cupsGetOption'><code>cupsGetOption</code></a> function gets 132the value for the named option. For example, the following code lists the 133available destinations and their human-readable descriptions:</p> 134 135<pre class='example'> 136#include <cups/cups.h> 137 138<a href='#cups_dest_t'>cups_dest_t</a> *dests; 139int num_dests = <a href='#cupsGetDests'>cupsGetDests</a>(&dests); 140<a href='#cups_dest_t'>cups_dest_t</a> *dest; 141int i; 142const char *value; 143 144for (i = num_dests, dest = dests; i > 0; i --, dest ++) 145 if (dest->instance == NULL) 146 { 147 value = <a href='#cupsGetOption'>cupsGetOption</a>("printer-info", dest->num_options, dest->options); 148 printf("%s (%s)\n", dest->name, value ? value : "no description"); 149 } 150 151<a href='#cupsFreeDests'>cupsFreeDests</a>(num_dests, dests); 152</pre> 153 154<p>You can create your own option arrays using the 155<a href='#cupsAddOption'><code>cupsAddOption</code></a> function, which 156adds a single named option to an array:</p> 157 158<pre class='example'> 159#include <cups/cups.h> 160 161int num_options = 0; 162<a href='#cups_option_t'>cups_option_t</a> *options = NULL; 163 164/* The returned num_options value is updated as needed */ 165num_options = <a href='#cupsAddOption'>cupsAddOption</a>("first", "value", num_options, &options); 166 167/* This adds a second option value */ 168num_options = <a href='#cupsAddOption'>cupsAddOption</a>("second", "value", num_options, &options); 169 170/* This replaces the first option we added */ 171num_options = <a href='#cupsAddOption'>cupsAddOption</a>("first", "new value", num_options, &options); 172</pre> 173 174<p>Use a <code>for</code> loop to copy the options from a destination:</p> 175 176<pre class='example'> 177#include <cups/cups.h> 178 179int i; 180int num_options = 0; 181<a href='#cups_option_t'>cups_option_t</a> *options = NULL; 182<a href='#cups_dest_t'>cups_dest_t</a> *dest; 183 184for (i = 0; i < dest->num_options; i ++) 185 num_options = <a href='#cupsAddOption'>cupsAddOption</a>(dest->options[i].name, dest->options[i].value, 186 num_options, &options); 187</pre> 188 189<p>Use the <a href='#cupsFreeOptions'><code>cupsFreeOptions</code></a> 190function to free the options array when you are done using it:</p> 191 192<pre class='example'> 193<a href='#cupsFreeOptions'>cupsFreeOptions</a>(num_options, options); 194</pre> 195 196<h3><a name='PRINT_JOBS'>Print Jobs</a></h3> 197 198<p>Print jobs are identified by a locally-unique job ID number from 1 to 1992<sup>31</sup>-1 and have options and one or more files for printing to a 200single destination. The <a href='#cupsPrintFile'><code>cupsPrintFile</code></a> 201function creates a new job with one file. The following code prints the CUPS 202test page file:</p> 203 204<pre class='example'> 205#include <cups/cups.h> 206 207<a href='#cups_dest_t'>cups_dest_t</a> *dest; 208int num_options; 209<a href='#cups_option_t'>cups_option_t</a> *options; 210int job_id; 211 212/* Print a single file */ 213job_id = <a href='#cupsPrintFile'>cupsPrintFile</a>(dest->name, "/usr/share/cups/data/testprint.ps", 214 "Test Print", num_options, options); 215</pre> 216 217<p>The <a href='#cupsPrintFiles'><code>cupsPrintFiles</code></a> function 218creates a job with multiple files. The files are provided in a 219<code>char *</code> array:</p> 220 221<pre class='example'> 222#include <cups/cups.h> 223 224<a href='#cups_dest_t'>cups_dest_t</a> *dest; 225int num_options; 226<a href='#cups_option_t'>cups_option_t</a> *options; 227int job_id; 228char *files[3] = { "file1.pdf", "file2.pdf", "file3.pdf" }; 229 230/* Print three files */ 231job_id = <a href='#cupsPrintFiles'>cupsPrintFiles</a>(dest->name, 3, files, "Test Print", num_options, options); 232</pre> 233 234<p>Finally, the <a href='#cupsCreateJob'><code>cupsCreateJob</code></a> 235function creates a new job with no files in it. Files are added using the 236<a href='#cupsStartDocument'><code>cupsStartDocument</code></a>, 237<a href='api-httpipp.html#cupsWriteRequestData'><code>cupsWriteRequestData</code></a>, 238and <a href='#cupsFinishDocument'><code>cupsFinishDocument</code></a> functions. 239The following example creates a job with 10 text files for printing:</p> 240 241<pre class='example'> 242#include <cups/cups.h> 243 244<a href='#cups_dest_t'>cups_dest_t</a> *dest; 245int num_options; 246<a href='#cups_option_t'>cups_option_t</a> *options; 247int job_id; 248int i; 249char buffer[1024]; 250 251/* Create the job */ 252job_id = <a href='#cupsCreateJob'>cupsCreateJob</a>(CUPS_HTTP_DEFAULT, dest->name, "10 Text Files", 253 num_options, options); 254 255/* If the job is created, add 10 files */ 256if (job_id > 0) 257{ 258 for (i = 1; i <= 10; i ++) 259 { 260 snprintf(buffer, sizeof(buffer), "file%d.txt", i); 261 262 <a href='#cupsStartDocument'>cupsStartDocument</a>(CUPS_HTTP_DEFAULT, dest->name, job_id, buffer, 263 CUPS_FORMAT_TEXT, i == 10); 264 265 snprintf(buffer, sizeof(buffer), 266 "File %d\n" 267 "\n" 268 "One fish,\n" 269 "Two fish,\n 270 "Red fish,\n 271 "Blue fish\n", i); 272 273 /* cupsWriteRequestData can be called as many times as needed */ 274 <a href='#cupsWriteRequestData'>cupsWriteRequestData</a>(CUPS_HTTP_DEFAULT, buffer, strlen(buffer)); 275 276 <a href='#cupsFinishDocument'>cupsFinishDocument</a>(CUPS_HTTP_DEFAULT, dest->name); 277 } 278} 279</pre> 280 281<p>Once you have created a job, you can monitor its status using the 282<a href='#cupsGetJobs'><code>cupsGetJobs</code></a> function, which returns 283an array of <a href='#cups_job_t'><code>cups_job_t</code></a> structures. 284Each contains the job ID (<code>id</code>), destination name 285(<code>dest</code>), title (<code>title</code>), and other information 286associated with the job. The job array is freed using the 287<a href='#cupsFreeJobs'><code>cupsFreeJobs</code></a> function. The following 288example monitors a specific job ID, showing the current job state once every 2895 seconds until the job is completed:</p> 290 291<pre class='example'> 292#include <cups/cups.h> 293 294<a href='#cups_dest_t'>cups_dest_t</a> *dest; 295int job_id; 296int num_jobs; 297<a href='#cups_job_t'>cups_job_t</a> *jobs; 298int i; 299ipp_jstate_t job_state = IPP_JOB_PENDING; 300 301while (job_state < IPP_JOB_STOPPED) 302{ 303 /* Get my jobs (1) with any state (-1) */ 304 num_jobs = <a href='#cupsGetJobs'>cupsGetJobs</a>(&jobs, dest->name, 1, -1); 305 306 /* Loop to find my job */ 307 job_state = IPP_JOB_COMPLETED; 308 309 for (i = 0; i < num_jobs; i ++) 310 if (jobs[i].id == job_id) 311 { 312 job_state = jobs[i].state; 313 break; 314 } 315 316 /* Free the job array */ 317 <a href='#cupsFreeJobs'>cupsFreeJobs</a>(num_jobs, jobs); 318 319 /* Show the current state */ 320 switch (job_state) 321 { 322 case IPP_JOB_PENDING : 323 printf("Job %d is pending.\n", job_id); 324 break; 325 case IPP_JOB_HELD : 326 printf("Job %d is held.\n", job_id); 327 break; 328 case IPP_JOB_PROCESSING : 329 printf("Job %d is processing.\n", job_id); 330 break; 331 case IPP_JOB_STOPPED : 332 printf("Job %d is stopped.\n", job_id); 333 break; 334 case IPP_JOB_CANCELED : 335 printf("Job %d is canceled.\n", job_id); 336 break; 337 case IPP_JOB_ABORTED : 338 printf("Job %d is aborted.\n", job_id); 339 break; 340 case IPP_JOB_COMPLETED : 341 printf("Job %d is completed.\n", job_id); 342 break; 343 } 344 345 /* Sleep if the job is not finished */ 346 if (job_state < IPP_JOB_STOPPED) 347 sleep(5); 348} 349</pre> 350 351<p>To cancel a job, use the 352<a href='#cupsCancelJob'><code>cupsCancelJob</code></a> function with the 353job ID:</p> 354 355<pre class='example'> 356#include <cups/cups.h> 357 358<a href='#cups_dest_t'>cups_dest_t</a> *dest; 359int job_id; 360 361<a href='#cupsCancelJob'>cupsCancelJob</a>(dest->name, job_id); 362</pre> 363 364<h3><a name='ERROR_HANDLING'>Error Handling</a></h3> 365 366<p>If any of the CUPS API printing functions returns an error, the reason for 367that error can be found by calling the 368<a href='#cupsLastError'><code>cupsLastError</code></a> and 369<a href='#cupsLastErrorString'><code>cupsLastErrorString</code></a> functions. 370<a href='#cupsLastError'><code>cupsLastError</code></a> returns the last IPP 371error code 372(<a href='api-httpipp.html#ipp_status_t'><code>ipp_status_t</code></a>) 373that was encountered, while 374<a href='#cupsLastErrorString'><code>cupsLastErrorString</code></a> returns 375a (localized) human-readable string that can be shown to the user. For example, 376if any of the job creation functions returns a job ID of 0, you can use 377<a href='#cupsLastErrorString'><code>cupsLastErrorString</code></a> to show 378the reason why the job could not be created:</p> 379 380<pre class='example'> 381#include <cups/cups.h> 382 383int job_id; 384 385if (job_id == 0) 386 puts(cupsLastErrorString()); 387</pre> 388 389<h3><a name='PASSWORDS_AND_AUTHENTICATION'>Passwords and Authentication</a></h3> 390 391<p>CUPS supports authentication of any request, including submission of print 392jobs. The default mechanism for getting the username and password is to use the 393login user and a password from the console.</p> 394 395<p>To support other types of applications, in particular Graphical User 396Interfaces ("GUIs"), the CUPS API provides functions to set the default 397username and to register a callback function that returns a password string.</p> 398 399<p>The <a href="#cupsSetPasswordCB"><code>cupsSetPasswordCB</code></a> 400function is used to set a password callback in your program. Only one 401function can be used at any time.</p> 402 403<p>The <a href="#cupsSetUser"><code>cupsSetUser</code></a> function sets the 404current username for authentication. This function can be called by your 405password callback function to change the current username as needed.</p> 406 407<p>The following example shows a simple password callback that gets a 408username and password from the user:</p> 409 410<pre class='example'> 411#include <cups/cups.h> 412 413const char * 414my_password_cb(const char *prompt) 415{ 416 char user[65]; 417 418 419 puts(prompt); 420 421 /* Get a username from the user */ 422 printf("Username: "); 423 if (fgets(user, sizeof(user), stdin) == NULL) 424 return (NULL); 425 426 /* Strip the newline from the string and set the user */ 427 user[strlen(user) - 1] = '\0'; 428 429 <a href='#cupsSetUser'>cupsSetUser</a>(user); 430 431 /* Use getpass() to ask for the password... */ 432 return (getpass("Password: ")); 433} 434 435<a href='#cupsSetPasswordCB'>cupsSetPasswordCB</a>(my_password_cb); 436</pre> 437 438<p>Similarly, a GUI could display the prompt string in a window with input 439fields for the username and password. The username should default to the 440string returned by the <a href="#cupsUser"><code>cupsUser</code></a> 441function.</p> 442