## Introduction

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.

## General Usage

The <cups/backend.h> and <cups/cups.h> header files must be included to use the `CUPS_BACKEND_` constants and `cupsBackChannel` functions, respectively.

The <cups/sidechannel.h> header file must be included to use the `CUPS_SC_` constants and `cupsSideChannel` functions.

Programs using these functions must be linked to the CUPS library: libcups.a, libcups.so.2, libcups.2.dylib, libcups_s.a, or libcups2.lib depending on the platform. The following command compiles myprogram.c using GCC and the CUPS library:

    gcc -o myprogram myprogram.c -lcups

## Compatibility

The `cupsBackChannel` functions require CUPS 1.2 or higher. The `cupsSideChannel` functions require CUPS 1.3 or higher.

## Using the cupsBackChannel APIs

The `cupsBackChannel` APIs allow your filters, drivers, and port monitors to read data back from a printer and your backends to send data from a printer to the filters, drivers, and port monitors associated with the current job. Back-channel data is normally sent by the printer in response to a command sent from your program to the printer via `stdout`.

The `cupsBackChannelRead()` function reads data from the printer via the backend. You provide a timeout in seconds along with a buffer pointer and the size of that buffer. It returns the number of bytes or -1 if there was an error. The following code example shows how to poll for back-channel data in your program:

    #include <cups/cups.h>

    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);

If you are writing a backend, the `cupsBackChannelWrite()` function sends any back-channel data you have received from the printer to upstream filters in the print filter chain. We recommend using a timeout of 1.0 seconds:

    #include <cups/cups.h>

    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);

## Using the cupsSideChannel APIs

The `cupsSideChannel` APIs allow your filters, drivers, port monitors, and backend to send and receive the following out-of-band commands:

- `CUPS_SC_CMD_SOFT_RESET` - Do a soft reset
- `CUPS_SC_CMD_DRAIN_OUTPUT` - Drain all pending output
- `CUPS_SC_CMD_GET_BIDI` - Return bidirectional capabilities
- `CUPS_SC_CMD_GET_DEVICE_ID` - Return the IEEE-1284 device ID
- `CUPS_SC_CMD_GET_STATE` - Return the device state

### Sending Commands from a Filter, Driver, or Port Monitor

The `cupsSideChannelDoRequest()` function is used by filters, drivers, and port monitors to send a command to the backend and read back a response:

    cups_sc_status_t cupsSideChannelDoRequest(cups_sc_command_t command,
                                              char *data, int *datalen,
                                              double timeout);

The `CUPS_SC_CMD_SOFT_RESET` and `CUPS_SC_CMD_DRAIN_OUTPUT` commands do not return any data values, while the others return one or more bytes. The `timeout` parameter allows your program to poll or wait for the command to complete - use a timeout of 30 seconds for `CUPS_SC_CMD_SOFT_RESET` and `CUPS_SC_CMD_DRAIN_OUTPUT` and a timeout of 1 second for all other commands.

`CUPS_SC_CMD_GET_BIDI` returns a single `char` value that tells you whether the backend supports bidirectional communications:

    #include <cups/sidechannel.h>

    char data;
    int datalen;
    cups_sc_bidi_t bidi;
    cups_sc_status_t status;

    /* Tell cupsSideChannelDoRequest() how big our buffer is... */
    datalen = 1;

    /* Get the bidirectional capabilities, waiting for up to 1 second */
    status  = cupsSideChannelDoRequest(CUPS_SC_CMD_GET_BIDI, &data, &datalen, 1.0);

    /* Use the returned value if OK was returned and the length is still 1 */
    if (status == CUPS_SC_STATUS_OK && datalen == 1)
      bidi = (cups_sc_bidi_t)data;
    else
      bidi = CUPS_SC_BIDI_NOT_SUPPORTED;

`CUPS_SC_CMD_GET_DEVICE_ID` returns a string of characters containing the IEEE-1284 device ID for the connected printer:

    #include <cups/sidechannel.h>

    char data[2049];
    int datalen;
    cups_sc_status_t 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  = cupsSideChannelDoRequest(CUPS_SC_CMD_GET_DEVICE_ID, data, &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';

`CUPS_SC_CMD_GET_STATE` returns a single `char` value that tells you the current device state:

    #include <cups/sidechannel.h>

    char data;
    int datalen;
    cups_sc_state_t state;
    cups_sc_status_t status;

    /* Tell cupsSideChannelDoRequest() how big our buffer is... */
    datalen = 1;

    /* Get the bidirectional capabilities, waiting for up to 1 second */
    status  = cupsSideChannelDoRequest(CUPS_SC_CMD_GET_STATE, &data, &datalen, 1.0);

    /* Use the returned value if OK was returned and the length is still 1 */
    if (status == CUPS_SC_STATUS_OK && datalen == 1)
      state = (cups_sc_state_t)data;
    else
      state = CUPS_SC_STATE_OFFLINE;

### Handling Commands in your Backend

The `cupsSideChannelRead()` function is used by backends to read a command from a filter, driver, or port monitor:

    int cupsSideChannelRead(cups_sc_command_t &command,
                            cups_sc_status_t  &status,
                            char *data, int *datalen, double timeout);

Backends can either poll for commands using a `timeout` of 0.0, wait indefinitely for commands using a `timeout` of -1.0 (probably in a separate thread for that purpose), or use `select()` or `poll()` on the `CUPS_SC_FD` file descriptor (4) to handle input and output on several file descriptors at the same time. Backends can pass `NULL` for the `data` and `datalen` parameters, since none of the commands sent by upstream filters contain any data at this time.

Once a command is processed, the backend uses the `cupsSideChannelWrite()` function to send its response:

    #include <cups/sidechannel.h>

    cups_sc_command_t command;
    cups_sc_status_t status;

    /* Poll for a command... */
    if (!cupsSideChannelRead(&command, &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... */
      cupsSideChannelWrite(command, status, data, datalen, 1.0);
    }