| <!-- |
| "$Id: api-cups.shtml 6649 2007-07-11 21:46:42Z mike $" |
| |
| CUPS API introduction for the Common UNIX Printing System (CUPS). |
| |
| Copyright 2007-2008 by Apple Inc. |
| Copyright 1997-2006 by Easy Software Products, all rights reserved. |
| |
| These coded instructions, statements, and computer programs are the |
| property of Apple Inc. and are protected by Federal copyright |
| law. Distribution and use rights are outlined in the file "LICENSE.txt" |
| which should have been included with this file. If this file is |
| file is missing or damaged, see the license at "http://www.cups.org/". |
| --> |
| |
| <h2 class='title'><a name='OVERVIEW'>Overview</a></h2> |
| |
| <p>The CUPS API provides the convenience functions needed to support |
| applications, filters, printer drivers, and backends that need to interface |
| with the CUPS scheduler.</p> |
| |
| <h3><a name='CLIENTS_AND_SERVERS'>Clients and Servers</a></h3> |
| |
| <p>CUPS is based on the Internet Printing Protocol ("IPP"), which allows |
| clients (applications) to communicate with a server (the scheduler) to get a |
| list of printers, send print jobs, and so forth. You identify which server |
| you want to communicate with using a pointer to the opaque structure |
| <code>http_t</code>. All of the examples in this document use the |
| <code>CUPS_HTTP_DEFAULT</code> constant, referring to the default connection |
| to the scheduler. The <a href='api-httpipp.html' target='_top'>HTTP and IPP |
| APIs</a> document provides more information on server connections.</p> |
| |
| <h3><a name='PRINTERS_AND_CLASSES'>Printers and Classes</a></h3> |
| |
| <p>Printers and classes (collections of printers) are accessed through |
| the <a href="#cups_dest_t"><code>cups_dest_t</code></a> structure which |
| includes the name (<code>name</code>), instance (<code>instance</code> - |
| a way of selecting certain saved options/settings), and the options and |
| attributes associated with that destination (<code>num_options</code> and |
| <code>options</code>). Destinations are created using the |
| <a href="#cupsGetDests"><code>cupsGetDests</code></a> function and freed |
| using the <a href='#cupsFreeDests'><code>cupsFreeDests</code></a> function. |
| The <a href='#cupsGetDest'><code>cupsGetDest</code></a> function finds a |
| specific destination for printing:</p> |
| |
| <pre class='example'> |
| #include <cups/cups.h> |
| |
| <a href='#cups_dest_t'>cups_dest_t</a> *dests; |
| int num_dests = <a href='#cupsGetDests'>cupsGetDests</a>(&dests); |
| <a href='#cups_dest_t'>cups_dest_t</a> *dest = <a href='#cupsGetDest'>cupsGetDest</a>("name", NULL, num_dests, dests); |
| |
| /* do something wiith dest */ |
| |
| <a href='#cupsFreeDests'>cupsFreeDests</a>(num_dests, dests); |
| </pre> |
| |
| <p>Passing <code>NULL</code> to |
| <a href='#cupsGetDest'><code>cupsGetDest</code></a> for the destination name |
| will return the default destination. Similarly, passing a <code>NULL</code> |
| instance will return the default instance for that destination.</p> |
| |
| <div class='table'><table summary='Table 1: Printer Attributes' width='80%'> |
| <caption>Table 1: <a name='TABLE1'>Printer Attributes</a></caption> |
| <thead> |
| <tr> |
| <th>Attribute Name</th> |
| <th>Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td>"auth-info-required"</td> |
| <td>The type of authentication required for printing to this |
| destination: "none", "username,password", "domain,username,password", |
| or "negotiate" (Kerberos)</td> |
| </tr> |
| <tr> |
| <td>"printer-info"</td> |
| <td>The human-readable description of the destination such as "My |
| Laser Printer".</td> |
| </tr> |
| <tr> |
| <td>"printer-is-accepting-jobs"</td> |
| <td>"1" if the destination is accepting new jobs, "0" if not.</td> |
| </tr> |
| <tr> |
| <td>"printer-is-shared"</td> |
| <td>"1" if the destination is being shared with other computers, "0" if |
| not.</td> |
| </tr> |
| <tr> |
| <td>"printer-location"</td> |
| <td>The human-readable location of the destination such as "Lab 4".</td> |
| </tr> |
| <tr> |
| <td>"printer-make-and-model"</td> |
| <td>The human-readable make and model of the destination such as "HP |
| LaserJet 4000 Series".</td> |
| </tr> |
| <tr> |
| <td>"printer-state"</td> |
| <td>"3" if the destination is idle, "4" if the destination is printing |
| a job, and "5" if the destination is stopped.</td> |
| </tr> |
| <tr> |
| <td>"printer-state-change-time"</td> |
| <td>The UNIX time when the destination entered the current state.</td> |
| </tr> |
| <tr> |
| <td>"printer-state-reasons"</td> |
| <td>Additional comma-delimited state keywords for the destination |
| such as "media-tray-empty-error" and "toner-low-warning".</td> |
| </tr> |
| <tr> |
| <td>"printer-type"</td> |
| <td>The <a href='#cups_printer_t'><code>cups_printer_t</code></a> |
| value associated with the destination.</td> |
| </tr> |
| </tbody> |
| </table></div> |
| |
| <h3><a name='OPTIONS'>Options</a></h3> |
| |
| <p>Options are stored in arrays of |
| <a href='#cups_option_t'><code>cups_option_t</code></a> structures. Each |
| option has a name (<code>name</code>) and value (<code>value</code>) |
| associated with it. The <a href='#cups_dest_t'><code>cups_dest_t</code></a> |
| <code>num_options</code> and <code>options</code> members contain the |
| default options for a particular destination, along with several informational |
| attributes about the destination as shown in <a href='#TABLE1'>Table 1</a>. |
| The <a href='#cupsGetOption'><code>cupsGetOption</code></a> function gets |
| the value for the named option. For example, the following code lists the |
| available destinations and their human-readable descriptions:</p> |
| |
| <pre class='example'> |
| #include <cups/cups.h> |
| |
| <a href='#cups_dest_t'>cups_dest_t</a> *dests; |
| int num_dests = <a href='#cupsGetDests'>cupsGetDests</a>(&dests); |
| <a href='#cups_dest_t'>cups_dest_t</a> *dest; |
| int i; |
| const char *value; |
| |
| for (i = num_dests, dest = dests; i > 0; i --, dest ++) |
| if (dest->instance == NULL) |
| { |
| value = <a href='#cupsGetOption'>cupsGetOption</a>("printer-info", dest->num_options, dest->options); |
| printf("%s (%s)\n", dest->name, value ? value : "no description"); |
| } |
| |
| <a href='#cupsFreeDests'>cupsFreeDests</a>(num_dests, dests); |
| </pre> |
| |
| <p>You can create your own option arrays using the |
| <a href='#cupsAddOption'><code>cupsAddOption</code></a> function, which |
| adds a single named option to an array:</p> |
| |
| <pre class='example'> |
| #include <cups/cups.h> |
| |
| int num_options = 0; |
| <a href='#cups_option_t'>cups_option_t</a> *options = NULL; |
| |
| /* The returned num_options value is updated as needed */ |
| num_options = <a href='#cupsAddOption'>cupsAddOption</a>("first", "value", num_options, &options); |
| |
| /* This adds a second option value */ |
| num_options = <a href='#cupsAddOption'>cupsAddOption</a>("second", "value", num_options, &options); |
| |
| /* This replaces the first option we added */ |
| num_options = <a href='#cupsAddOption'>cupsAddOption</a>("first", "new value", num_options, &options); |
| </pre> |
| |
| <p>Use a <code>for</code> loop to copy the options from a destination:</p> |
| |
| <pre class='example'> |
| #include <cups/cups.h> |
| |
| int i; |
| int num_options = 0; |
| <a href='#cups_option_t'>cups_option_t</a> *options = NULL; |
| <a href='#cups_dest_t'>cups_dest_t</a> *dest; |
| |
| for (i = 0; i < dest->num_options; i ++) |
| num_options = <a href='#cupsAddOption'>cupsAddOption</a>(dest->options[i].name, dest->options[i].value, |
| num_options, &options); |
| </pre> |
| |
| <p>Use the <a href='#cupsFreeOptions'><code>cupsFreeOptions</code></a> |
| function to free the options array when you are done using it:</p> |
| |
| <pre class='example'> |
| <a href='#cupsFreeOptions'>cupsFreeOptions</a>(num_options, options); |
| </pre> |
| |
| <h3><a name='PRINT_JOBS'>Print Jobs</a></h3> |
| |
| <p>Print jobs are identified by a locally-unique job ID number from 1 to |
| 2<sup>31</sup>-1 and have options and one or more files for printing to a |
| single destination. The <a href='#cupsPrintFile'><code>cupsPrintFile</code></a> |
| function creates a new job with one file. The following code prints the CUPS |
| test page file:</p> |
| |
| <pre class='example'> |
| #include <cups/cups.h> |
| |
| <a href='#cups_dest_t'>cups_dest_t</a> *dest; |
| int num_options; |
| <a href='#cups_option_t'>cups_option_t</a> *options; |
| int job_id; |
| |
| /* Print a single file */ |
| job_id = <a href='#cupsPrintFile'>cupsPrintFile</a>(dest->name, "/usr/share/cups/data/testprint.ps", |
| "Test Print", num_options, options); |
| </pre> |
| |
| <p>The <a href='#cupsPrintFiles'><code>cupsPrintFiles</code></a> function |
| creates a job with multiple files. The files are provided in a |
| <code>char *</code> array:</p> |
| |
| <pre class='example'> |
| #include <cups/cups.h> |
| |
| <a href='#cups_dest_t'>cups_dest_t</a> *dest; |
| int num_options; |
| <a href='#cups_option_t'>cups_option_t</a> *options; |
| int job_id; |
| char *files[3] = { "file1.pdf", "file2.pdf", "file3.pdf" }; |
| |
| /* Print three files */ |
| job_id = <a href='#cupsPrintFiles'>cupsPrintFiles</a>(dest->name, 3, files, "Test Print", num_options, options); |
| </pre> |
| |
| <p>Finally, the <a href='#cupsCreateJob'><code>cupsCreateJob</code></a> |
| function creates a new job with no files in it. Files are added using the |
| <a href='#cupsStartDocument'><code>cupsStartDocument</code></a>, |
| <a href='api-httpipp.html#cupsWriteRequestData'><code>cupsWriteRequestData</code></a>, |
| and <a href='#cupsFinishDocument'><code>cupsFinishDocument</code></a> functions. |
| The following example creates a job with 10 text files for printing:</p> |
| |
| <pre class='example'> |
| #include <cups/cups.h> |
| |
| <a href='#cups_dest_t'>cups_dest_t</a> *dest; |
| int num_options; |
| <a href='#cups_option_t'>cups_option_t</a> *options; |
| int job_id; |
| int i; |
| char buffer[1024]; |
| |
| /* Create the job */ |
| job_id = <a href='#cupsCreateJob'>cupsCreateJob</a>(CUPS_HTTP_DEFAULT, dest->name, "10 Text Files", |
| num_options, options); |
| |
| /* If the job is created, add 10 files */ |
| if (job_id > 0) |
| { |
| for (i = 1; i <= 10; i ++) |
| { |
| snprintf(buffer, sizeof(buffer), "file%d.txt", i); |
| |
| <a href='#cupsStartDocument'>cupsStartDocument</a>(CUPS_HTTP_DEFAULT, dest->name, job_id, buffer, |
| CUPS_FORMAT_TEXT, i == 10); |
| |
| snprintf(buffer, sizeof(buffer), |
| "File %d\n" |
| "\n" |
| "One fish,\n" |
| "Two fish,\n |
| "Red fish,\n |
| "Blue fish\n", i); |
| |
| /* cupsWriteRequestData can be called as many times as needed */ |
| <a href='#cupsWriteRequestData'>cupsWriteRequestData</a>(CUPS_HTTP_DEFAULT, buffer, strlen(buffer)); |
| |
| <a href='#cupsFinishDocument'>cupsFinishDocument</a>(CUPS_HTTP_DEFAULT, dest->name); |
| } |
| } |
| </pre> |
| |
| <p>Once you have created a job, you can monitor its status using the |
| <a href='#cupsGetJobs'><code>cupsGetJobs</code></a> function, which returns |
| an array of <a href='#cups_job_t'><code>cups_job_t</code></a> structures. |
| Each contains the job ID (<code>id</code>), destination name |
| (<code>dest</code>), title (<code>title</code>), and other information |
| associated with the job. The job array is freed using the |
| <a href='#cupsFreeJobs'><code>cupsFreeJobs</code></a> function. The following |
| example monitors a specific job ID, showing the current job state once every |
| 5 seconds until the job is completed:</p> |
| |
| <pre class='example'> |
| #include <cups/cups.h> |
| |
| <a href='#cups_dest_t'>cups_dest_t</a> *dest; |
| int job_id; |
| int num_jobs; |
| <a href='#cups_job_t'>cups_job_t</a> *jobs; |
| int i; |
| ipp_jstate_t job_state = IPP_JOB_PENDING; |
| |
| while (job_state < IPP_JOB_STOPPED) |
| { |
| /* Get my jobs (1) with any state (-1) */ |
| num_jobs = <a href='#cupsGetJobs'>cupsGetJobs</a>(&jobs, dest->name, 1, -1); |
| |
| /* Loop to find my job */ |
| job_state = IPP_JOB_COMPLETED; |
| |
| for (i = 0; i < num_jobs; i ++) |
| if (jobs[i].id == job_id) |
| { |
| job_state = jobs[i].state; |
| break; |
| } |
| |
| /* Free the job array */ |
| <a href='#cupsFreeJobs'>cupsFreeJobs</a>(num_jobs, jobs); |
| |
| /* Show the current state */ |
| switch (job_state) |
| { |
| case IPP_JOB_PENDING : |
| printf("Job %d is pending.\n", job_id); |
| break; |
| case IPP_JOB_HELD : |
| printf("Job %d is held.\n", job_id); |
| break; |
| case IPP_JOB_PROCESSING : |
| printf("Job %d is processing.\n", job_id); |
| break; |
| case IPP_JOB_STOPPED : |
| printf("Job %d is stopped.\n", job_id); |
| break; |
| case IPP_JOB_CANCELED : |
| printf("Job %d is canceled.\n", job_id); |
| break; |
| case IPP_JOB_ABORTED : |
| printf("Job %d is aborted.\n", job_id); |
| break; |
| case IPP_JOB_COMPLETED : |
| printf("Job %d is completed.\n", job_id); |
| break; |
| } |
| |
| /* Sleep if the job is not finished */ |
| if (job_state < IPP_JOB_STOPPED) |
| sleep(5); |
| } |
| </pre> |
| |
| <p>To cancel a job, use the |
| <a href='#cupsCancelJob'><code>cupsCancelJob</code></a> function with the |
| job ID:</p> |
| |
| <pre class='example'> |
| #include <cups/cups.h> |
| |
| <a href='#cups_dest_t'>cups_dest_t</a> *dest; |
| int job_id; |
| |
| <a href='#cupsCancelJob'>cupsCancelJob</a>(dest->name, job_id); |
| </pre> |
| |
| <h3><a name='ERROR_HANDLING'>Error Handling</a></h3> |
| |
| <p>If any of the CUPS API printing functions returns an error, the reason for |
| that error can be found by calling the |
| <a href='#cupsLastError'><code>cupsLastError</code></a> and |
| <a href='#cupsLastErrorString'><code>cupsLastErrorString</code></a> functions. |
| <a href='#cupsLastError'><code>cupsLastError</code></a> returns the last IPP |
| error code |
| (<a href='api-httpipp.html#ipp_status_t'><code>ipp_status_t</code></a>) |
| that was encountered, while |
| <a href='#cupsLastErrorString'><code>cupsLastErrorString</code></a> returns |
| a (localized) human-readable string that can be shown to the user. For example, |
| if any of the job creation functions returns a job ID of 0, you can use |
| <a href='#cupsLastErrorString'><code>cupsLastErrorString</code></a> to show |
| the reason why the job could not be created:</p> |
| |
| <pre class='example'> |
| #include <cups/cups.h> |
| |
| int job_id; |
| |
| if (job_id == 0) |
| puts(cupsLastErrorString()); |
| </pre> |
| |
| <h3><a name='PASSWORDS_AND_AUTHENTICATION'>Passwords and Authentication</a></h3> |
| |
| <p>CUPS supports authentication of any request, including submission of print |
| jobs. The default mechanism for getting the username and password is to use the |
| login user and a password from the console.</p> |
| |
| <p>To support other types of applications, in particular Graphical User |
| Interfaces ("GUIs"), the CUPS API provides functions to set the default |
| username and to register a callback function that returns a password string.</p> |
| |
| <p>The <a href="#cupsSetPasswordCB"><code>cupsSetPasswordCB</code></a> |
| function is used to set a password callback in your program. Only one |
| function can be used at any time.</p> |
| |
| <p>The <a href="#cupsSetUser"><code>cupsSetUser</code></a> function sets the |
| current username for authentication. This function can be called by your |
| password callback function to change the current username as needed.</p> |
| |
| <p>The following example shows a simple password callback that gets a |
| username and password from the user:</p> |
| |
| <pre class='example'> |
| #include <cups/cups.h> |
| |
| const char * |
| my_password_cb(const char *prompt) |
| { |
| char user[65]; |
| |
| |
| puts(prompt); |
| |
| /* Get a username from the user */ |
| printf("Username: "); |
| if (fgets(user, sizeof(user), stdin) == NULL) |
| return (NULL); |
| |
| /* Strip the newline from the string and set the user */ |
| user[strlen(user) - 1] = '\0'; |
| |
| <a href='#cupsSetUser'>cupsSetUser</a>(user); |
| |
| /* Use getpass() to ask for the password... */ |
| return (getpass("Password: ")); |
| } |
| |
| <a href='#cupsSetPasswordCB'>cupsSetPasswordCB</a>(my_password_cb); |
| </pre> |
| |
| <p>Similarly, a GUI could display the prompt string in a window with input |
| fields for the username and password. The username should default to the |
| string returned by the <a href="#cupsUser"><code>cupsUser</code></a> |
| function.</p> |