]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/api-filter.shtml
Merge CUPS 1.4svn-r7319.
[thirdparty/cups.git] / cups / api-filter.shtml
index 16361025f3c1f5db15e372408b858f92531bcba1..f5b6b8cf2c622ebbfa5450b3363e6f7d39204229 100644 (file)
 <!--
-  "$Id: api-filter.shtml 177 2006-06-21 00:20:03Z jlovell $"
+  "$Id: api-filter.shtml 6649 2007-07-11 21:46:42Z mike $"
 
-  Filter and backend API introduction for the Common UNIX Printing System (CUPS).
+  Filter and backend programming introduction for the Common UNIX Printing
+  System (CUPS).
 
-  Copyright 1997-2006 by Easy Software Products.
+  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 Easy Software Products 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 missing or damaged please contact Easy Software Products
-  at:
-
-      Attn: CUPS Licensing Information
-      Easy Software Products
-      44141 Airport View Drive, Suite 204
-      Hollywood, Maryland 20636 USA
-
-      Voice: (301) 373-9600
-      EMail: cups-info@cups.org
-       WWW: http://www.cups.org
+  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'>Introduction</h2>
+<h2 class='title'><a name="OVERVIEW">Overview</a></h2>
 
-<p>The CUPS filter and backend APIs define standard exit codes
-and provide access to the backchannel data stream. They are only
-used when writing backends, filters, and port monitors.</p>
+<p>Filters, printer drivers, port monitors, and backends use a common interface
+for processing print jobs and communicating status information to the scheduler.
+Each filter is run with a standard set of command-line arguments:<p>
 
-<h2 class='title'>General Usage</h2>
+<dl class="code">
 
-<p>The <var>&lt;cups/backend.h&gt;</var> and
-<var>&lt;cups/cups.h&gt;</var> header files must be included to
-use the <tt>CUPS_BACKEND_</tt> constants and
-<tt>cupsBackChannel</tt> functions, respectively.</p>
+       <dt>argv[1]</dt>
+       <dd>The job ID</dd>
 
-<p>Programs using these functions must be linked to the CUPS
-library: <var>libcups.a</var>, <var>libcups.so.2</var>,
-<var>libcups.2.dylib</var>, <var>libcups_s.a</var>, or
-<var>libcups2.lib</var> depending on the platform. The following
-command compiles <var>myprogram.c</var> using GCC and the CUPS
-library:</p>
+       <dt>argv[2]</dt>
+       <dd>The user printing the job</dd>
 
-<pre class='command'>
-<kbd>gcc -o myprogram myprogram.c -lcups</kbd>
+       <dt>argv[3]</dt>
+       <dd>The job name/title</dd>
+
+       <dt>argv[4]</dt>
+       <dd>The number of copies to print</dd>
+
+       <dt>argv[5]</dt>
+       <dd>The options that were provided when the job was submitted</dd>
+
+       <dt>argv[6]</dt>
+       <dd>The file to print (first filter only)</dd>
+</dl>
+
+<p>The scheduler runs one or more of these programs to print any given job. The
+first filter reads from the print file and writes to the standard output, while
+the remaining filters read from the standard input and write to the standard
+output. The backend is the last filter in the chain and writes to the
+device.</p>
+
+<h3><a name="SECURITY">Security Considerations</a></h3>
+
+<p>It is always important to use security programming practices. Filters and
+most backends are run as a non-priviledged user, so the major security
+consideration is resource utilization - filters should not depend on unlimited
+amounts of CPU, memory, or disk space, and should protect against conditions
+that could lead to excess usage of any resource like infinite loops and
+unbounded recursion. In addition, filters must <em>never</em> allow the user to
+specify an arbitrary file path to a separator page, template, or other file
+used by the filter since that can lead to an unauthorized disclosure of
+information. <em>Always</em> treat input as suspect and validate it!</p>
+
+<p>If you are developing a backend that runs as root, make sure to check for
+potential buffer overflows, integer under/overflow conditions, and file
+accesses since these can lead to privilege escalations. When writing files,
+always validate the file path and <em>never</em> allow a user to determine
+where to store a file.</p>
+
+<blockquote><b>Note:</b>
+
+<p><em>Never</em> write files to a user's home directory. Aside from the
+security implications, CUPS is a network print service and as such the network
+user may not be the same as the local user and/or there may not be a local home
+directory to write to.</p>
+
+<p>In addition, some operating systems provide additional security mechanisms
+that further limit file system access, even for backends running as root.  On
+Mac OS X, for example, no backend may write to a user's home directory.</p>
+</blockquote>
+
+<h3><a name="TEMPFILES">Temporary Files</a></h3>
+
+<p>Temporary files should be created in the directory specified by the
+"TMPDIR" environment variable. The
+<a href="#cupsTempFile2"><code>cupsTempFile2</code></a> function can be
+used to safely create temporary files in this directory.</p>
+
+<h3><a name="COPIES">Copy Generation</a></h3>
+
+<p>The <code>argv[4]</code> argument specifies the number of copies to produce
+of the input file. In general, you should only generate copies if the
+<em>filename</em> argument is supplied. The only exception to this are
+filters that produce device-independent PostScript output, since the PostScript
+filter <var>pstops</var> is responsible for generating copies of PostScript
+files.</p>
+
+<h3><a name="EXITCODES">Exit Codes</a></h3>
+
+<p>Filters must exit with status 0 when they successfully generate print data
+or 1 when they encounter an error. Backends can return any of the
+<a href="#cups_backend_t"><code>cups_backend_t</code></a> constants.</p>
+
+<h3><a name="ENVIRONMENT">Environment Variables</a></h3>
+
+<p>The following environment variables are defined by the printing system:</p>
+
+<dl class="code">
+
+       <dt>APPLE_LANGUAGES</dt>
+       <dd>The Apple language identifier associated with the job
+       (Mac OS X only).</dd>
+
+       <dt>CHARSET</dt>
+       <dd>The job character set, typically "utf-8".</dd>
+
+       <dt>CLASS</dt>
+       <dd>When a job is submitted to a printer class, contains the name of
+       the destination printer class. Otherwise this environment
+       variable will not be set.</dd>
+
+       <dt>CONTENT_TYPE</dt>
+       <dd>The MIME type associated with the file (e.g.
+       application/postscript).</dd>
+
+       <dt>CUPS_CACHEDIR</dt>
+       <dd>The directory where cache files can be stored.</dd>
+
+       <dt>CUPS_DATADIR</dt>
+       <dd>The directory where data files can be found.</dd>
+
+       <dt>CUPS_SERVERROOT</dt>
+       <dd>The root directory of the server.</dd>
+
+       <dt>DEVICE_URI</dt>
+       <dd>The device-uri associated with the printer.</dd>
+
+       <dt>FINAL_CONTENT_TYPE</dt>
+       <dd>The MIME type associated with the printer (e.g.
+       application/vnd.cups-postscript).</dd>
+
+       <dt>LANG</dt>
+       <dd>The language locale associated with the job.</dd>
+
+       <dt>PPD</dt>
+       <dd>The full pathname of the PostScript Printer Description (PPD)
+       file for this printer.</dd>
+
+       <dt>PRINTER</dt>
+       <dd>The name of the printer.</dd>
+
+       <dt>RIP_CACHE</dt>
+       <dd>The recommended amount of memory to use for Raster Image
+       Processors (RIPs).</dd>
+
+</dl>
+
+<h3><a name="MESSAGES">Communicating with the Scheduler</a></h3>
+
+<p>Filters and backends communicate wih the scheduler by writing messages
+to the standard error file. For example, the following code sets the current
+printer state message to "Printing page 5":</p>
+
+<pre class="example">
+int page = 5;
+
+fprintf(stderr, "INFO: Printing page %d\n", page);
+</pre>
+
+<p>Each message is a single line of text starting with one of the following
+prefix strings:</p>
+
+<dl class="code">
+
+       <dt>ALERT: message</dt>
+       <dd>Sets the printer-state-message attribute and adds the specified
+       message to the current error log file using the "alert" log level.</dd>
+
+       <dt>ATTR: attribute=value [attribute=value]</dt>
+       <dd>Sets the named printer or job attribute(s). Typically this is used
+       to set the <code>marker-colors</code>, <code>marker-levels</code>,
+       <code>marker-names</code>, <code>marker-types</code>,
+       <code>printer-alert</code>, and <code>printer-alert-description</code>
+       printer attributes.</dd>
+
+       <dt>CRIT: message</dt>
+       <dd>Sets the printer-state-message attribute and adds the specified
+       message to the current error log file using the "critical" log
+       level.</dd>
+
+       <dt>DEBUG: message</dt>
+       <dd>Sets the printer-state-message attribute and adds the specified
+       message to the current error log file using the "debug" log level.</dd>
+
+       <dt>DEBUG2: message</dt>
+       <dd>Sets the printer-state-message attribute and adds the specified
+       message to the current error log file using the "debug2" log level.</dd>
+
+       <dt>EMERG: message</dt>
+       <dd>Sets the printer-state-message attribute and adds the specified
+       message to the current error log file using the "emergency" log
+       level.</dd>
+
+       <dt>ERROR: message</dt>
+       <dd>Sets the printer-state-message attribute and adds the specified
+       message to the current error log file using the "error" log level.</dd>
+
+       <dt>INFO: message</dt>
+       <dd>Sets the printer-state-message attribute. If the current log level
+       is set to "debug2", also adds the specified message to the current error
+       log file using the "info" log level.</dd>
+
+       <dt>NOTICE: message</dt>
+       <dd>Sets the printer-state-message attribute and adds the specified
+       message to the current error log file using the "notice" log level.</dd>
+
+       <dt>PAGE: page-number #-copies</dt>
+       <dt>PAGE: total #-pages</dt>
+       <dd>Adds an entry to the current page log file. The first form adds
+       #-copies to the job-media-sheets-completed attribute. The second
+       form sets the job-media-sheets-completed attribute to #-pages.</dd>
+
+       <dt>STATE: printer-state-reason [printer-state-reason ...]</dt>
+       <dt>STATE: + printer-state-reason [printer-state-reason ...]</dt>
+       <dt>STATE: - printer-state-reason [printer-state-reason ...]</dt>
+       <dd>Sets, adds, or removes printer-state-reason keywords to the
+       current queue. Typically this is used to indicate media, ink, and
+       toner conditions on a printer.</dd>
+
+       <dt>WARNING: message</dt>
+       <dd>Sets the printer-state-message attribute and adds the specified
+       message to the current error log file using the "warning" log
+       level.</dd>
+
+</dl>
+
+<p>Messages without one of these prefixes are treated as if they began with
+the "DEBUG:" prefix string.</p>
+
+<h3><a name="COMMUNICATING">Communicating with the Backend</a></h3>
+
+<p>Filters can communicate with the backend via the
+<a href="#cupsBackChannelRead"><code>cupsBackChannelRead</code></a> and
+<a href="#cupsSideChannelDoRequest"><code>cupsSideChannelDoRequest</code></a>
+functions. The 
+<a href="#cupsBackChannelRead"><code>cupsBackChannelRead</code></a> function
+reads data that has been sent back from the device and is typically used to
+obtain status and configuration information. For example, the following code
+polls the backend for back-channel data:</p>
+
+<pre class="example">
+#include &lt;cups/cups.h&gt;
+
+char buffer[8192];
+ssize_t bytes;
+
+/* Use a timeout of 0.0 seconds to poll for back-channel data */
+bytes = cupsBackChannelRead(buffer, sizeof(buffer), 0.0);
+</pre>
+
+The
+<a href="#cupsSideChannelDoRequest"><code>cupsSideChannelDoRequest</code></a>
+function allows you to get out-of-band status information and do synchronization
+with the device. For example, the following code gets the current IEEE-1284
+device ID string from the backend:</p>
+
+<pre class="example">
+#include &lt;cups/sidechannel.h&gt;
+
+char data[2049];
+int datalen;
+<a href="#cups_sc_status_t">cups_sc_status_t</a> status;
+
+/* Tell cupsSideChannelDoRequest() how big our buffer is, less 1 byte for nul-termination... */
+datalen = sizeof(data) - 1;
+
+/* Get the IEEE-1284 device ID, waiting for up to 1 second */
+status = <a href="#cupsSideChannelDoRequest">cupsSideChannelDoRequest</a>(CUPS_SC_CMD_GET_DEVICE_ID, data, &amp;datalen, 1.0);
+
+/* Use the returned value if OK was returned and the length is non-zero */
+if (status == CUPS_SC_STATUS_OK && datalen > 0)
+  data[datalen] = '\0';
+else
+  data[0] = '\0';
+</pre>
+
+<p>Backends communicate with filters using the reciprocal functions
+<a href="#cupsBackChannelWrite"><code>cupsBackChannelWrite</code></a>,
+<a href="#cupsSideChannelRead"><code>cupsSideChannelRead</code></a>, and
+<a href="#cupsSideChannelWrite"><code>cupsSideChannelWrite</code></a>. We
+recommend writing back-channel data using a timeout of 1.0 seconds:</p>
+
+<pre class="example">
+#include &lt;cups/cups.h&gt;
+
+char buffer[8192];
+ssize_t bytes;
+
+/* Use a timeout of 1.0 seconds to give filters a chance to read */
+cupsBackChannelWrite(buffer, bytes, 1.0);
+</pre>
+
+<p>The <a href="#cupsSideChannelRead"><code>cupsSideChannelRead</code></a>
+function reads a side-channel command from a filter, driver, or port monitor.
+Backends can either poll for commands using a <code>timeout</code> of 0.0, wait
+indefinitely for commands using a <code>timeout</code> of -1.0 (probably in a
+separate thread for that purpose), or use <code>select</code> or
+<code>poll</code> on the <code>CUPS_SC_FD</code> file descriptor (4) to handle
+input and output on several file descriptors at the same time. Backends can pass
+<code>NULL</code> for the <code>data</code> and <code>datalen</code> parameters
+since none of the commands sent by upstream filters contain any data at this
+time.</p>
+
+<p>Once a command is processed, the backend uses the
+<a href="#cupsSideChannelWrite"><code>cupsSideChannelWrite</code></a> function
+to send its response. For example, the following code shows how to poll for a
+side-channel command and respond to it:</p>
+
+<pre class="example">
+#include &lt;cups/sidechannel.h&gt;
+
+<a href="#cups_sc_command_t">cups_sc_command_t</a> command;
+<a href="#cups_sc_status_t">cups_sc_status_t</a> status;
+
+/* Poll for a command... */
+if (!<a href="#cupsSideChannelRead">cupsSideChannelRead</a>(&amp;command, &amp;status, NULL, NULL, 0.0))
+{
+  char data[2048];
+  int datalen;
+
+  switch (command)
+  {
+    /* handle supported commands, file data/datalen/status with values as needed */
+
+    default :
+        status  = CUPS_SC_STATUS_NOT_IMPLEMENTED;
+       datalen = 0;
+       break;
+  }
+
+  /* Send a response... */
+  <a href="#cupsSideChannelWrite">cupsSideChannelWrite</a>(command, status, data, datalen, 1.0);
+}
+</pre>
+
+<h3><a name="SNMP">Doing SNMP Queries with Network Printers</a></h3>
+
+<p>The Simple Network Management Protocol (SNMP) allows you to get the current
+status, page counter, and supply levels from most network printers. Every
+piece of information is associated with an Object Identifier (OID), and
+every printer has a <em>community</em> name associated with it. OIDs can be
+queried directly or by "walking" over a range of OIDs with a common prefix.</p>
+
+<p>The CUPS SNMP functions provide a simple API for querying network printers.
+Queries are made using a datagram socket that is created using
+<a href="#cupsSNMPOpen"><code>cupsSNMPOpen</code></a> and destroyed using
+<a href="#cupsSNMPClose"><code>cupsSNMPClose</code></a>:</p>
+
+<pre class="example">
+#include &lt;cups/snmp.h&gt;
+
+int snmp = <a href="#cupsSNMPOpen">cupsSNMPOpen</a>(AF_INET);
+
+/* do some queries */
+
+<a href="#cupsSNMPClose">cupsSNMPClose</a>(snmp);
 </pre>
 
-<h2 class='title'>Compatibility</h2>
+<p>OIDs are simple C arrays of integers, terminated by a value of -1. For
+example, the page counter OID .1.3.6.1.2.1.43.10.2.1.4.1.1 would be:</p>
 
-<p>All of these functions require CUPS 1.2 or higher.</p>
+<pre class="example">
+int page_counter_oid[] = { 1, 3, 6, 1, 2, 1, 43, 10, 2, 1, 4, 1, 1, -1 };
+</pre>
+
+<p>You send a query using
+<a href="#cupsSNMPWrite"><code>cupsSNMPWrite</code></a> and read the value back
+using <a href="#cupsSNMPRead"><code>cupsSNMPRead</code></a>. The value is read
+into a structure called <a href="#cups_snmp_t"><code>cups_snmp_t</code></a>:</p>
+
+<pre class="example">
+#include &lt;cups/snmp.h&gt;
+
+int page_counter_oid[] = { 1, 3, 6, 1, 2, 1, 43, 10, 2, 1, 4, 1, 1, -1 };
+http_addrlist_t *host = httpAddrGetList("myprinter", AF_UNSPEC, "161");
+int snmp = <a href="#cupsSNMPOpen">cupsSNMPOpen</a>(host->addr.addr.sa_family);
+<a href="#cups_snmp_t">cups_snmp_t</a> packet;
+
+<a href="#cupsSNMPWrite">cupsSNMPWrite</a>(snmp, &amp;(host->addr), CUPS_SNMP_VERSION_1,
+                <a href="#cupsSNMPDefaultCommunity">cupsSNMPDefaultCommunity</a>(), CUPS_ASN1_GET_REQUEST, 1,
+                page_counter_oid);
+if (<a href="#cupsSNMPRead">cupsSNMPRead</a>(snmp, &amp;packet, 5000))
+{
+  /* Do something with the value */
+  printf("Page counter is: %d\n", packet.object_value.integer);
+}
+</pre>
+
+<p>The <a href="#cupsSNMPWalk"><code>cupsSNMPWalk</code></a> function allows you
+to query a whole group of OIDs, calling a function of your choice for each OID
+that is found:</p>
+
+<pre class="example">
+#include &lt;cups/snmp.h&gt;
+
+void
+my_callback(<a href="#cups_snmp_t">cups_snmp_t</a> *packet, void *data)
+{
+  /* Do something with the value */
+}
+
+int printer_mib_oid[] = { 1, 3, 6, 1, 2, 1, 43, -1 };
+http_addrlist_t *host = httpAddrGetList("myprinter", AF_UNSPEC, "161");
+int snmp = <a href="#cupsSNMPOpen">cupsSNMPOpen</a>(host->addr.addr.sa_family);
+void *my_data;
+
+<a href="#cupsSNMPWalk">cupsSNMPWalk</a>(snmp, &amp;(host->addr), CUPS_SNMP_VERSION_1,
+               <a href="#cupsSNMPDefaultCommunity">cupsSNMPDefaultCommunity</a>(), printer_mib_oid, my_callback, my_data);
+</pre>