pappl-device(3)
π pappl-device β the pappl device functions (it's pappl-device(3) bestie) π
okay so. sit down, grab a snack, because we're about to talk about talking to printers. no literally. this is the whole page about how your app actually reaches out and touches a device. it's giving "backend of the backend" and honestly? iconic.
π LIBRARY
Printer Application Framework (libpappl, "pkg-config --cflags --libs pappl")
lowkey the vibe check for linking this thing is right there in the quotes. use it. π«Ά
β¨ SYNOPSIS β¨
#include <pappl/pappl.h>
typedef struct _pappl_device_s pappl_device_t;
void
papplDeviceAddScheme(const char *scheme, pappl_dtype_t dtype,
pappl_devlist_cb_t list_cb, pappl_devopen_cb_t open_cb,
pappl_devclose_cb_t close_cb, pappl_devread_cb_t read_cb,
pappl_devwrite_cb_t write_cb, pappl_devstatus_cb_t status_cb);
void
papplDeviceClose(pappl_device_t *device);
void
papplDeviceError(pappl_device_t *device, const char *message, ...);
void
papplDeviceFlush(pappl_device_t *device);
void *
papplDeviceGetData(pappl_device_t *device);
pappl_dmetrics_t *
papplDeviceGetMetrics(pappl_device_t *device, pappl_dmetrics_t
*metrics);
pappl_preason_t
papplDeviceGetStatus(pappl_device_t *device);
bool
papplDeviceList(pappl_dtype_t types, pappl_device_cb_t cb, void *data,
pappl_deverror_cb_t err_cb, void *err_data);
pappl_device_t *
papplDeviceOpen(const char *device_uri, const char *name,
pappl_deverror_cb_t err_cb, void *err_data);
int
papplDeviceParse1284ID(const char *device_id, cups_option_t **pairs);
ssize_t
papplDevicePrintf(pappl_device_t *device, const char *format, ...);
ssize_t
papplDevicePuts(pappl_device_t *device, const char *s);
ssize_t
papplDeviceRead(pappl_device_t *device, void *buffer, size_t bytes);
void
papplDeviceSetData(pappl_device_t *device, void *data);
ssize_t
papplDeviceWrite(pappl_device_t *device, const void *buffer, size_t
bytes);
look at all those functions. main character energy for real. π
πΈ DESCRIPTION πΈ
so the PAPPL device functions are your whole little toolkit for connecting to output devices and for listing which output devices even exist. that's it, that's the job, and they ate.
you reach devices through Uniform Resource Identifier (URI) strings, like:
"file:///path/to/file-or-directory""socket://11.22.33.44""usb://make/model?serial=number"
see the pattern? yeah. uris. we love a consistent interface.
The papplDeviceList function lists available output devices, and it hands each one off to the callback function you supply. important caveat though: the list only contains devices whose URI scheme supports discovery, and at present that means USB printers and network printers that advertise themselves using DNS-SD/mDNS and/or SNMPv1. if your device doesn't shout about itself, it's not showing up. π
The papplDeviceOpen function opens a connection to an output device using its URI. and then The papplDeviceClose function closes the connection. open, close. balanced. as all things should be.
The papplDevicePrintf, papplDevicePuts, and papplDeviceWrite functions send data to the device, while the papplDeviceRead function reads data from the device. out goes data, in comes data.
The papplDeviceGetMetrics function gets statistical information about all communications with the device while it has been open, while the papplDeviceGetStatus function gets the hardware status of a device and maps it to the pappl_preason_t bitfield.
π’ ENUMERATIONS
pappl_devtype_e
Device type bit values β¨ (yes bestie, they're bits, so they combine. it's giving bitfield.)
PAPPL_DEVTYPE_ALLβ All printersPAPPL_DEVTYPE_CUSTOM_LOCALβ Local printer using a custom interface or protocolPAPPL_DEVTYPE_CUSTOM_NETWORKβ Network printer using a custom interface or protocolPAPPL_DEVTYPE_DNS_SDβ Network printers discovered via DNS-SD/mDNSPAPPL_DEVTYPE_FILEβ Local file/directoryPAPPL_DEVTYPE_LOCALβ All local printersPAPPL_DEVTYPE_NETWORKβ All network printersPAPPL_DEVTYPE_SNMPβ Network printers discovered via SNMPPAPPL_DEVTYPE_SOCKETβ Network printers using raw socketPAPPL_DEVTYPE_USBβ USB printers
π οΈ FUNCTIONS
papplDeviceAddScheme
Add a device URI scheme. π
void papplDeviceAddScheme (
const char *scheme,
pappl_devtype_t dtype,
pappl_devlist_cb_t list_cb,
pappl_devopen_cb_t open_cb,
pappl_devclose_cb_t close_cb,
pappl_devread_cb_t read_cb,
pappl_devwrite_cb_t write_cb,
pappl_devstatus_cb_t status_cb,
pappl_devid_cb_t id_cb
);
This function registers a device URI scheme with PAPPL, so that devices using the named scheme can receive print data, report status information, and so forth. like, you're teaching PAPPL a new dialect of uri. slay.
PAPPL already includes support for these URI schemes:
dnssd: Network printers discovered using DNS-SD.file: Character device files, plain files, and directories.snmp: Network printers discovered using SNMPv1.socket: Network printers using a hostname or numeric IP address.usb: Class 1 (unidirectional) or 2 (bidirectional) USB printers.
The "scheme" parameter specifies the URI scheme and must consist of lowercase letters, digits, "-", "_", and/or ".", for example "x-foo" or "com.example.bar". no uppercase, no chaos. (well. only the allowed kind of chaos.)
The "dtype" parameter specifies the device type and should be PAPPL_DTYPE_CUSTOM_LOCAL for locally connected printers and PAPPL_DTYPE_CUSTOM_NETWORK for network printers.
Each of the callbacks corresponds to one of the papplDevice functions:
"list_cb": Implements discovery of devices (optional)"open_cb": Opens communication with a device and allocates any device-specific data as needed"close_cb": Closes communication with a device and frees any device-specific data as needed"read_cb": Reads data from a device"write_cb": Write data to a device"status_cb": Gets basic printer state information from a device (optional)"id_cb": Gets the current IEEE-1284 device ID from a device (optional)
The "open_cb" callback typically calls papplDeviceSetData to store a pointer to contextual information for the connection, while the "close_cb", "id_cb", "read_cb", "write_cb", and "status_cb" callbacks typically call papplDeviceGetData to retrieve it. so open_cb stashes the lore, everyone else reads the lore. π§
papplDeviceAddScheme2
Add a device URI scheme with supply-level queries. π§
void papplDeviceAddScheme2 (
const char *scheme,
pappl_devtype_t dtype,
pappl_devlist_cb_t list_cb,
pappl_devopen_cb_t open_cb,
pappl_devclose_cb_t close_cb,
pappl_devread_cb_t read_cb,
pappl_devwrite_cb_t write_cb,
pappl_devstatus_cb_t status_cb,
pappl_devsupplies_cb_t supplies_cb,
pappl_devid_cb_t id_cb
);
This function registers a device URI scheme with PAPPL, so that devices using the named scheme can receive print data, report status information, and so forth. (yes it's the same opening as the other one β it's the sequel, and sequels recap. it's fine.)
PAPPL includes support for the following URI schemes:
dnssd: Network printers discovered using DNS-SD.file: Character device files, plain files, and directories.snmp: Network printers discovered using SNMPv1.socket: Network printers using a hostname or numeric IP address.usb: Class 1 (unidirectional) or 2 (bidirectional) USB printers.
The "scheme" parameter specifies the URI scheme and must consist of lowercase letters, digits, "-", "_", and/or ".", for example "x-foo" or "com.example.bar".
The "dtype" parameter specifies the device type and should be PAPPL_DTYPE_CUSTOM_LOCAL for locally connected printers and PAPPL_DTYPE_CUSTOM_NETWORK for network printers.
Each of the callbacks corresponds to one of the papplDevice functions:
"list_cb": Implements discovery of devices (optional)"open_cb": Opens communication with a device and allocates any device-specific data as needed"close_cb": Closes communication with a device and frees any device-specific data as needed"read_cb": Reads data from a device"write_cb": Write data to a device"status_cb": Gets basic printer state information from a device (optional)"supplies_cb": Gets supply level information from a device (optional)"id_cb": Gets the current IEEE-1284 device ID from a device (optional)
The "open_cb" callback typically calls papplDeviceSetData to store a pointer to contextual information for the connection, while the "close_cb", "id_cb", "read_cb", "write_cb", "status_cb", and "supplies_cb" callbacks typically call papplDeviceGetData to retrieve it. π«Ά
papplDeviceClose
Close a device connection. π
void papplDeviceClose (
pappl_device_t *device
);
This function flushes any pending write data and closes the connection to a device. bye bestie, all your writes made it out first, we promise.
papplDeviceError
Report an error on a device. π
void papplDeviceError (
pappl_device_t *device,
const char *message,
...
);
This function reports an error on a device using the client-supplied callback function. it's normally called from any custom device URI scheme callbacks you implement β so like, your code calls this when your scheme goes sideways.
papplDeviceFlush
Flush any buffered data to the device. π½ (no bestie not like that)
void papplDeviceFlush (
pappl_device_t *device
);
This function flushes any pending write data sent using the papplDevicePrintf, papplDevicePuts, or papplDeviceWrite functions to the device. basically "hey. everything you've been holding? send it. now."
papplDeviceGetData
Get device-specific data. π
void * papplDeviceGetData (
pappl_device_t *device
);
This function returns any device-specific data that has been set by the device open callback. it's normally only called from any custom device URI scheme callbacks you implement. so this is the "read the lore back out" function, and it's for your callbacks, not the general public.
papplDeviceGetID
Get the IEEE-1284 device ID. π·οΈ
char * papplDeviceGetID (
pappl_device_t *device,
char *buffer,
size_t bufsize
);
This function queries the IEEE-1284 device ID from the device and copies it to the provided buffer. The buffer must be at least 64 bytes and should be at least 1024 bytes in length. like, 64 is the floor, not the goal. aim higher.
β οΈ Note: This function can block for up to several seconds depending on the type of connection.
several. seconds. so don't call it in a tight loop and then act surprised, okay? it's not being dramatic, that's just the connection being the connection. π
papplDeviceGetMetrics
Get the device metrics. π
pappl_devmetrics_t * papplDeviceGetMetrics (
pappl_device_t *device,
pappl_devmetrics_t *metrics
);
This function returns a copy of the device metrics data, which includes the number, length (in bytes), and duration (in milliseconds) of read, status, and write requests for the current session. so: how many, how big, how long. the whole receipts.
This information is normally used for performance measurement and optimization during development of a printer application. It can also be useful diagnostic information. iykyk. β¨
papplDeviceGetStatus
Get the printer status bits. π₯
pappl_preason_t papplDeviceGetStatus (
pappl_device_t *device
);
This function returns the current printer status bits, as applicable to the current device.
The status bits for USB devices come from the original Centronics parallel printer "standard" which was later formally standardized in IEEE 1284-1984 and the USB Device Class Definition for Printing Devices. Some vendor extensions are also supported. history lesson AND a status code, we contain multitudes. π
okay so real talk β network device status bits are NOT vibes-based, they come straight from the hrPrinterDetectedErrorState property that's defined in the SNMP Printer MIB v2 (RFC 3805). so like, that's where the tea comes from π΅
This function hands you back a pappl_preason_t bitfield that you can pass straight into the papplPrinterSetReasons function. When you do that, use the PAPPL_PREASON_DEVICE_STATUS value as the value of the "remove" argument. π
β οΈ Note: This function can block for several seconds while getting the status information. like, it will just sit there. do not panic. do not spam it.
papplDeviceGetSupplies
Get the current printer supplies. π
int papplDeviceGetSupplies (
pappl_device_t *device,
int max_supplies,
pappl_supply_t *supplies
);
This function returns the number, type, and level of current printer supply levels, as applicable to the current device.
The supply levels for network devices come from the prtSupplyTable and prtMarkerColorantTable properties that are defined in the SNMP Printer MIB v2 (RFC 3805). it's giving very standardized, very demure β¨
The supply levels for other devices are not standardized and must be queried using other methods. so for those ones, bestie, you're on your own β bring your own method.
β οΈ Note: This function can block for several seconds while getting the supply information.
papplDeviceIsSupported
Determine whether a given URI is supported. π
bool papplDeviceIsSupported (
const char *uri
);
This function determines whether a given URI or URI scheme is supported as a device. quick little vibe check on your URI, basically.
papplDeviceList
List available devices. π¦
bool papplDeviceList (
pappl_devtype_t types,
pappl_device_cb_t cb,
void *data,
pappl_deverror_cb_t err_cb,
void *err_data
);
This function lists the available devices, calling the "cb" function once per device that is discovered/listed. The callback function receives the device URI, IEEE-1284 device ID (if any), and "data" pointer, and returns true to stop listing devices and false to continue. so like β true means "okay I'm done, stop", false means "keep going queen" π
The "types" argument determines which devices are listed, for example PAPPL_DEVTYPE_ALL will list all types of devices while PAPPL_DEVTYPE_USB only lists USB printers.
Any errors are reported using the supplied "err_cb" function. If you specify NULL for this argument, errors are sent to stderr. no cap, NULL means it just yells into your terminal instead.
β οΈ Note: This function will block (not return) until each of the device URI schemes has reported all of the devices or the supplied callback function returns true. it is NOT coming back early. it is committed. main character energy fr fr.
papplDeviceOpen
Open a connection to a device. π₯
pappl_device_t * papplDeviceOpen (
const char *device_uri,
const char *name,
pappl_deverror_cb_t err_cb,
void *err_data
);
This function opens a connection to the specified device URI. The "name" argument provides textual context for the connection and is usually the name (title) of the print job. so like, it's the little name tag the connection wears at the party π
Any errors are reported using the supplied "err_cb" function. If you specify NULL for this argument, errors are sent to stderr.
papplDeviceParseID
Parse an IEEE-1284 device ID string. π§
int papplDeviceParseID (
const char *device_id,
cups_option_t **pairs
);
This function parses an IEEE-1284 device ID string and returns an array of key/value pairs as a cups_option_t array.
π Heads up bestie: the returned array must be freed using the cupsFreeOptions function. if you don't free it, that's a leak and we don't do leaks in this house.
papplDevicePrintf
Write a formatted string. β¨
ssize_t papplDevicePrintf (
pappl_device_t *device,
const char *format,
...
);
This function buffers a formatted string that will be sent to the device. The "format" argument accepts all printf format specifiers and behaves identically to that function. same energy, same specifiers, no notes.
Call the papplDeviceFlush function to ensure that the formatted string is immediately sent to the device. because buffered means it's waiting, not sent. huge difference.
papplDevicePuts
Write a literal string. πΈ
ssize_t papplDevicePuts (
pappl_device_t *device,
const char *s
);
This function buffers a literal string that will be sent to the device. Call the papplDeviceFlush function to ensure that the literal string is immediately sent to the device. same deal β buffer first, flush to actually yeet it over there.
papplDeviceRead
Read from a device. π
ssize_t papplDeviceRead (
pappl_device_t *device,
void *buffer,
size_t bytes
);
This function reads data from the device. Depending on the device, this function may block indefinitely. INDEFINITELY. like, it could just never come back. plan accordingly.
papplDeviceRemoveScheme
Remove the named device URI scheme. π
void papplDeviceRemoveScheme (
const char *scheme
);
This function removes support for the named device URI scheme. Use only when you want to disable a URI scheme for security or functional reasons, for example to disable the file URI scheme. this is a big-girl move β you're literally taking a whole scheme off the menu.
papplDeviceRemoveTypes
Remove device URI schemes of the specified types. π₯
void papplDeviceRemoveTypes (
pappl_devtype_t types
);
This function removes device URI schemes of the specified types. Use only when you want to disable URI schemes for security or functional reasons, for example to disable all network URI schemes. same warning, same energy β security and functional reasons ONLY, not because you felt like it.
papplDeviceSetData
Set device-specific data. π
void papplDeviceSetData (
pappl_device_t *device,
void *data
);
This function sets any device-specific data needed to communicate with the device. It is normally only called from the open callback that was registered for the device URI scheme. so like, it lives inside the open callback. that's its home.
papplDeviceWrite
Write to a device. π
ssize_t papplDeviceWrite (
pappl_device_t *device,
const void *buffer,
size_t bytes
);
This function buffers data that will be sent to the device. Call the papplDeviceFlush function to ensure that the data is immediately sent to the device. you know the drill by now: buffer, then flush. periodt. π
ποΈ STRUCTURES ποΈ
pappl_devmetrics_s
Device metrics (the receipts π)
struct pappl_devmetrics_s
{
size_t read_bytes;
size_t read_msecs;
size_t read_requests;
size_t status_msecs;
size_t status_requests;
size_t write_bytes;
size_t write_msecs;
size_t write_requests;
};
π TYPES π
pappl_devclose_cb_t
Device close callback (saying bye to the device π)
typedef void (*pappl_devclose_cb_t)(pappl_device_t *device);
pappl_deverror_cb_t
Device error callback (the "uh oh" handler)
typedef void (*pappl_deverror_cb_t)(const char *message, void *err_data);
pappl_device_cb_t
Device callback - return true to stop, false to continue (you're literally the traffic light here π¦)
typedef bool (*pappl_device_cb_t)(const char *device_info, const char *device_uri, const char *device_id, void *data);
pappl_devid_cb_t
Device ID callback (ID check bestie πͺͺ)
typedef char * (*pappl_devid_cb_t)(pappl_device_t *device, char *buffer, size_t bufsize);
pappl_devlist_cb_t
Device list callback (rounding everyone up π¦)
typedef bool (*pappl_devlist_cb_t)(pappl_device_cb_t cb, void *data, pappl_deverror_cb_t err_cb, void *err_data);
pappl_devmetrics_t
Device metrics
typedef struct pappl_devmetrics_s pappl_devmetrics_t;
pappl_devopen_cb_t
Device open callback (cracking the door open πͺ)
typedef bool (*pappl_devopen_cb_t)(pappl_device_t *device, const char *device_uri, const char *name);
pappl_devread_cb_t
Device read callback
typedef ssize_t (*pappl_devread_cb_t)(pappl_device_t *device, void *buffer, size_t bytes);
pappl_devstatus_cb_t
Device status callback (how are we feeling today, device π )
typedef pappl_preason_t (*pappl_devstatus_cb_t)(pappl_device_t *device);
pappl_devsupplies_cb_t
Device supplies callback (ink check!! ποΈ)
typedef int (*pappl_devsupplies_cb_t)(pappl_device_t *device, int max_supplies, pappl_supply_t *supplies);
pappl_devtype_t
Device type bitfield
typedef unsigned pappl_devtype_t;
pappl_devwrite_cb_t
Device write callback
typedef ssize_t (*pappl_devwrite_cb_t)(pappl_device_t *device, const void *buffer, size_t bytes);
π SEE ALSO π
pappl(1), pappl-client(3), pappl-device(3), pappl-job(3), pappl-log(3), pappl-mainline(3), pappl-makeresheader(1), pappl-printer(3), pappl-resource(3), pappl-system(3), https://www.msweet.org/pappl
go read those too, they're all part of the same friend group π«Ά
βοΈ COPYRIGHT βοΈ
Copyright Β© 2019-2022 by Michael R. Sweet.
PAPPL is licensed under the Apache License Version 2.0 with an (optional) exception to allow linking against GPL2/LGPL2 software (like older versions of CUPS), so it can be used freely in any project you'd like. See the files LICENSE and NOTICE in the source distribution for more information. very generous, very iconic, we love to see it π
and that's the whole page bestie!! π you just read the pappl device functions β yes, the pappl-device(3) β and this edition is dated 2026-08-11. go forth and open some devices, flush your buffers, and free your cups_option_t arrays. mwah. π
β¨
π¦ where this page comes from
- arch rolling: pappl 1.4.12-1 Β· Apache-2.0 WITH LLVM-exception
- fedora 43: pappl-devel 1.4.12-1.fc43 Β· Apache-2.0 WITH LLVM-exception
- fedora 43: pappl-devel 1.4.12-1.fc43 Β· Apache-2.0 WITH LLVM-exception
- fedora 44: pappl-devel 1.4.12-1.fc44 Β· Apache-2.0 WITH LLVM-exception
- fedora 44: pappl-devel 1.4.12-1.fc44 Β· Apache-2.0 WITH LLVM-exception
- nixpkgs unstable: pappl 1.4.12
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms