You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
441 lines
15 KiB
441 lines
15 KiB
<!-- |
|
API introduction for CUPS. |
|
|
|
Copyright 2007-2013 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 with 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>"true" if the destination is accepting new jobs, "false" if |
|
not.</td> |
|
</tr> |
|
<tr> |
|
<td>"printer-is-shared"</td> |
|
<td>"true" if the destination is being shared with other computers, |
|
"false" 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>
|
|
|