From 7190a0bc2ba9e9bd771dba9499a78a6845aae17e Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Sat, 9 Mar 2024 20:43:09 +0000 Subject: [PATCH 01/26] Update scanner header files --- pappl/scanner-private.h | 119 ++++++++++++++++++++++++ pappl/scanner.h | 198 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 317 insertions(+) create mode 100644 pappl/scanner-private.h create mode 100644 pappl/scanner.h diff --git a/pappl/scanner-private.h b/pappl/scanner-private.h new file mode 100644 index 00000000..42ca56ac --- /dev/null +++ b/pappl/scanner-private.h @@ -0,0 +1,119 @@ +// +// Private scanner header file for the Scanner Application Framework +// +// Copyright © 2019-2024 by Michael R Sweet. +// Copyright © 2010-2019 by Apple Inc. +// +// Licensed under Apache License v2.0. See the file "LICENSE" for more +// information. +// + +#ifndef _PAPPL_SCANNER_PRIVATE_H_ +# define _PAPPL_SCANNER_PRIVATE_H_ +# include "dnssd-private.h" +# include "scanner.h" // Changed to Scanner.h +# include "printer.h" // Check later +# include "log.h" +# ifdef __APPLE__ +# include +# include +# elif !_WIN32 +# include +# endif // __APPLE__ +# ifdef HAVE_SYS_RANDOM_H +# include +# endif // HAVE_SYS_RANDOM_H +# ifdef HAVE_GNUTLS_RND +# include +# include +# endif // HAVE_GNUTLS_RND +# include "base-private.h" +# include "device.h" + +// +// Types and structures... +// + +struct _pappl_scanner_s // Scanner data +{ + pthread_rwlock_t rwlock; // Reader/writer lock + pappl_system_t *system; // Containing system + int scanner_id; // "scanner-id" value + char *name, // "scanner-name" value + *dns_sd_name, // "scanner-dns-sd-name" value + *location, // "scanner-location" value + *geo_location, // "scanner-geo-location" value (geo: URI) + *organization, // "scanner-organization" value + *org_unit; // "scanner-organizational-unit" value + + pappl_contact_t contact; // "scanner-contact" value + char *resource; // Resource path of scanner + size_t resourcelen; // Length of resource path + char *uriname; // Name for URLs + escl_sstate_t state; // "scanner-state" value --> Replacement for ipp_pstate_t + pappl_sreason_t state_reasons; // "scanner-state-reasons" values --> Replacement for pappl_preason_t + time_t state_time; // "scanner-state-change-time" value + bool is_accepting, // Are we accepting scan jobs? + is_stopped, // Are we stopping this scanner? + is_deleted; // Has this scanner been deleted? + + char *device_id, // "scanner-device-id" value + *device_uri; // Device URI + pappl_device_t *device; // Current connection to device (if any) + bool device_in_use; // Is the device in use? + char *driver_name; // Driver name + pappl_sc_driver_data_t *driver_data; // Driver data + + time_t start_time; // Startup time + time_t config_time; // "scanner-config-change-time" value + time_t status_time; // Last time status was updated + + pappl_job_t *processing_job; // Current scanning job, if any + bool hold_new_jobs; // Hold new scan jobs + int next_job_id; // Next "job-id" value + + cups_array_t *links; // Web navigation links + # ifdef HAVE_MDNSRESPONDER + _pappl_srv_t dns_sd_http_ref, // DNS-SD HTTP service + + DNSRecordRef dns_sd_escl_loc_ref, // DNS-SD LOC record for ESCL service + dns_sd_escl_loc_ref; // DNS-SD LOC record for ESCL service + # elif defined(HAVE_AVAHI) + _pappl_srv_t dns_sd_ref; // DNS-SD services + # endif // HAVE_MDNSRESPONDER + unsigned char dns_sd_loc[16]; // DNS-SD LOC record data + bool dns_sd_collision; // Was there a name collision? + int dns_sd_serial; // DNS-SD serial number (for collisions) + +}; + +// +// Functions... +// +extern void _papplScannerCheckJobsNoLock(pappl_scanner_t *scanner) _PAPPL_PRIVATE; +extern void _papplScannerCleanJobsNoLock(pappl_scanner_t *scanner) _PAPPL_PRIVATE; +extern void _papplScannerCopyAttributesNoLock(pappl_scanner_t *scanner, pappl_client_t *client, cups_array_t *ra, const char *format) _PAPPL_PRIVATE; + +extern void _papplScannerDelete(pappl_scanner_t *scanner) _PAPPL_PRIVATE; +extern void _papplScannerInitDriverData(pappl_sc_driver_data_t *d) _PAPPL_PRIVATE; +extern bool _papplScannerIsAuthorized(pappl_client_t *client) _PAPPL_PRIVATE; +extern void _papplScannerProcessESCL(pappl_client_t *client) _PAPPL_PRIVATE; +extern bool _papplScannerRegisterDNSSDNoLock(pappl_scanner_t *scanner) _PAPPL_PRIVATE; +extern bool _papplScannerSetAttributes(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; +extern void _papplScannerUnregisterDNSSDNoLock(pappl_scanner_t *scanner) _PAPPL_PRIVATE; + +extern void _papplScannerWebCancelAllJobs(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; +extern void _papplScannerWebConfig(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; + +extern void _papplScannerWebConfigFinalize(pappl_scanner_t *scanner, cups_len_t num_form, cups_option_t *form) _PAPPL_PRIVATE; +extern void _papplScannerWebDefaults(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; +extern void _papplScannerWebDelete(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; +extern void _papplScannerWebHome(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; +extern void _papplSannerWebIteratorCallback(pappl_scanner_t *scanner, pappl_client_t *client) _PAPPL_PRIVATE; +extern void _papplScannerWebJobs(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; +extern void _papplScannerWebMedia(pappl_client_t *client, pappl_scanner_t *printer) _PAPPL_PRIVATE; + +extern const char *_papplScannerReasonString(pappl_sreason_t value) _PAPPL_PRIVATE; +extern pappl_sreason_t _papplScannerReasonValue(const char *value) _PAPPL_PRIVATE; + +#endif // !_PAPPL_SCANNER_PRIVATE_H_ \ No newline at end of file diff --git a/pappl/scanner.h b/pappl/scanner.h new file mode 100644 index 00000000..e6b68698 --- /dev/null +++ b/pappl/scanner.h @@ -0,0 +1,198 @@ +// +// Public scanner header file for the Scanner Application Framework +// +// Copyright © 2019-2022 by Michael R Sweet. +// +// Licensed under Apache License v2.0. See the file "LICENSE" for more +// information. +// + +#ifndef _PAPPL_SCANNER_H_ +# define _PAPPL_SCANNER_H_ +# include "base.h" +# ifdef __cplusplus +extern "C" { +# endif // __cplusplus + + +// +// Limits... +// +#define PAPPL_MAX_FORMATS 5 // Most scanners support up to 5 different document formats +#define PAPPL_MAX_COLOR_MODES 3 // Most scanners support a few color modes: Black and White, Grayscale, Color +#define PAPPL_MAX_SOURCES 2 // MOST scanners offer two input sources: Flatbed and ADF +#define PAPPL_MAX_COLOR_SPACES 2 // Common color spaces like sRGB and AdobeRGB +#define PAPPL_MAX_MEDIA_TYPES 5 // Various media types like Plain, Photo, Card, etc. + +// +// Constants... +// + +typedef enum +{ + PAPPL_SSTATE_IDLE, // Scanner is idle + PAPPL_SSTATE_PROCESSING, // Scanner is busy with some job or activity + PAPPL_SSTATE_TESTING, // Scanner is calibrating, preparing the unit + PAPPL_SSTATE_STOPPED, // Scanner stopped due to an error condition + PAPPL_SSTATE_DOWN // Scanner is unavailable +} escl_sstate_t; + +enum pappl_sreason_t +{ + PAPPL_SREASON_NONE = 0x0000, // 'none', no error, scanner is ready + PAPPL_SREASON_IDLE = 0x0001, // 'idle', scanner is idle + PAPPL_SREASON_PROCESSING = 0x0002, // 'processing', scanner is currently processing a job + PAPPL_SREASON_TESTING = 0x0004, // 'testing', scanner is in calibration or preparation mode + PAPPL_SREASON_STOPPED = 0x0008, // 'stopped', an error has occurred and the scanner has stopped + PAPPL_SREASON_DOWN = 0x0010, // 'down', the scanner is unavailable +}; + +// Define color modes supported by the scanner +typedef enum { + BLACKANDWHITE1, // For black and white scans + GRAYSCALE8, // For grayscale scans + RGB24 // For full color scans +} pappl_sc_color_mode_t; + +// Define input sources for the scanner +typedef enum { + FLATBED, // For flatbed scanners + ADF, // For automatic dopappl_sc_input_source_t;cument feeder +} + +// +// Callback functions... +// +typedef void (*pappl_sc_capabilities_cb_t)(pappl_scanner_t *scanner, pappl_sc_driver_data_t *data); // Callback for getting scanner capabilities +typedef void (*pappl_sc_job_create_cb_t)(pappl_job_t *job, pappl_sc_options_t *options, pappl_device_t *device); // Callback for creating a scan job +typedef void (*pappl_sc_job_delete_cb_t)(pappl_job_t *job); // Callback for deleting a scan job +typedef bool (*pappl_sc_data_cb_t)(pappl_job_t *job, pappl_device_t *device, void *buffer, size_t bufsize); // Callback for getting scan data +typedef void (*pappl_sc_status_cb_t)(pappl_scanner_t *scanner, pappl_sc_driver_data_t *data); // Callback for getting scanner status +typedef bool (*pappl_sc_job_cancel_cb_t)(pappl_job_t *job); // Callback for cancelling a scan job +typedef void (*pappl_sc_buffer_info_cb_t)(pappl_job_t *job, pappl_sc_options_t *options, pappl_device_t *device); // Callback for getting buffer information +typedef void (*pappl_sc_image_info_cb_t)(pappl_job_t *job, pappl_device_t *device, void *data); // Callback for getting image information + +// +// Structures +// + +typedef struct pappl_sc_options_s // Combined scan job options +{ + char document_format[64]; // Desired output format (JPEG, PDF, TIFF) + pappl_sc_color_mode_t color_mode; // Color mode for the scan + int resolution; // Scanning resolution in DPI + pappl_sc_input_source_t input_source; // Selected input source + bool duplex; // Duplex scanning option + struct { + int width; // Width of the scan area + int height; // Height of the scan area + int x_offset; // X offset for the scan area + int y_offset; // Y offset for the scan area + } scan_area; + struct { + int brightness; // Brightness adjustment + int contrast; // Contrast adjustment + int gamma; // Gamma adjustment + int threshold; // Threshold for black/white scans + } adjustments; + bool blank_page_removal; // Automatically detect and remove blank pages + unsigned num_pages; // Number of pages to scan (for ADF) +} pappl_sc_options_t; + +typedef struct pappl_sc_driver_data_s +{ + pappl_sc_capabilities_cb_t capabilities_cb; // Callback for getting scanner capabilities + pappl_sc_job_create_cb_t job_create_cb; // Callback for creating a scan job + pappl_sc_job_delete_cb_t job_delete_cb; // Callback for deleting a scan job + pappl_sc_data_cb_t data_cb; // Callback for getting scan data + pappl_sc_status_cb_t status_cb; // Callback for getting scanner status + pappl_sc_job_cancel_cb_t job_cancel_cb; // Callback for cancelling a scan job + pappl_sc_buffer_info_cb_t buffer_info_cb; // Callback for getting buffer information + pappl_sc_image_info_cb_t image_info_cb; // Callback for getting image information + + char make_and_model[128]; // Make and model of the scanner + const char *document_formats_supported[PAPPL_MAX_FORMATS]; // Supported document formats (JPEG, PDF, TIFF) + pappl_sc_color_mode_t color_modes_supported[PAPPL_MAX_COLOR_MODES]; // Supported color modes (BlackAndWhite1, Grayscale8, RGB24) + int max_resolution; // Maximum optical resolution in DPI + pappl_sc_input_source_t input_sources_supported[PAPPL_MAX_SOURCES]; // Supported input sources (Platen, Feeder) + bool duplex_supported; // Duplex (double-sided) scanning support + const char *color_spaces_supported[PAPPL_MAX_COLOR_SPACES]; // Supported color spaces (sRGB, AdobeRGB) + int max_scan_area[2]; // Maximum scan area size (width, height) + const char *media_type_supported[PAPPL_MAX_MEDIA_TYPES]; // Types of media that can be scanned (Plain, Photo, Card) +} pappl_sc_driver_data_t; + +// +// Functions... +// + +extern void papplScannerAddLink(pappl_scanner_t *scanner, const char *label, const char *path_or_url, pappl_loptions_t options) _PAPPL_PUBLIC; + +extern void papplScannerCancelAllJobs(pappl_scanner_t *scanner) _PAPPL_PUBLIC; + +extern void papplScannerCloseDevice(pappl_scanner_t *scanner) _PAPPL_PUBLIC; + +extern pappl_scanner_t *papplScannerCreate(pappl_system_t *system, int scanner_id, const char *scanner_name, const char *driver_name, const char *device_id, const char *device_uri) _PAPPL_PUBLIC; +extern void papplScannerDelete(pappl_Scanner_t *scanner) _PAPPL_PUBLIC; +extern void papplScannerDisable(pappl_scanner_t *scanner) _PAPPL_PUBLIC; +extern void papplScannerEnable(pappl_scanner_t *scanner) _PAPPL_PUBLIC; + +extern pappl_job_t *papplScannerFindJob(pappl_scanner_t *scanner, int job_id) _PAPPL_PUBLIC; + +extern pappl_contact_t *papplScannerGetContact(pappl_scanner_t *scanner, pappl_contact_t *contact) _PAPPL_PUBLIC; +extern const char *papplScannerGetDeviceID(pappl_scanner_t *scanner) _PAPPL_PUBLIC; +extern const char *papplScannerGetDeviceURI(pappl_scanner_t *scanner) _PAPPL_PUBLIC; +extern char *papplScannerGetDNSSDName(pappl_scanner_t *scanner, char *buffer, size_t bufsize) _PAPPL_PUBLIC; + +extern pappl_sc_driver_data_t *papplScannerGetDriverData(pappl_scanner_t *scanner, pappl_sc_driver_data_t *data) _PAPPL_PUBLIC; +extern const char *papplScannerGetDriverName(pappl_scanner_t *scanner) _PAPPL_PUBLIC; +extern char *papplScannerGetGeoLocation(pappl_scanner_t *scanner, char *buffer, size_t bufsize) _PAPPL_PUBLIC; +extern int papplScannerGetID(pappl_scanner_t *scanner) _PAPPL_PUBLIC; +extern char *papplScannerGetLocation(pappl_scanner_t *scanner, char *buffer, size_t bufsize) _PAPPL_PUBLIC; + +extern const char *papplScannerGetName(pappl_scanner_t *scanner) _PAPPL_PUBLIC; +extern int papplScannerGetNextJobID(pappl_scanner_t *scanner) _PAPPL_PUBLIC; + +extern char *papplScannerGetOrganization(pappl_scanner_t *scanner, char *buffer, size_t bufsize) _PAPPL_PUBLIC; +extern char *papplScannerGetOrganizationalUnit(pappl_scanner_t *scanner, char *buffer, size_t bufsize) _PAPPL_PUBLIC; + +extern char *papplScannerGetPath(pappl_scanner_t *scanner, const char *subpath, char *buffer, size_t bufsize) _PAPPL_PUBLIC; + +extern pappl_sreason_t papplScannerGetReasons(pappl_printer_t *printer) _PAPPL_PUBLIC; +extern escl_sstate_t papplScannerGetState(pappl_printer_t *printer) _PAPPL_PUBLIC; + +extern pappl_system_t *papplScannerGetSystem(pappl_scanner_t *scanner) _PAPPL_PUBLIC; + +extern void papplScannerHTMLFooter(pappl_client_t *client) _PAPPL_PUBLIC; +extern void papplScannerHTMLHeader(pappl_client_t *client, const char *title, int refresh) _PAPPL_PUBLIC; + +extern bool papplScannerIsAcceptingJobs(pappl_scanner_t *scanner) _PAPPL_PUBLIC; +extern bool papplScannerIsDeleted(pappl_scanner_t *scanner) _PAPPL_PUBLIC; + +extern bool papplScannerIsHoldingNewJobs(pappl_scanner_t *printer) _PAPPL_PUBLIC; + +extern pappl_device_t *papplScannerOpenDevice(pappl_scanner_t *scanner) _PAPPL_PUBLIC; +extern int papplScannerOpenFile(pappl_scanner_t *scanner, char *fname, size_t fnamesize, const char *directory, const char *resname, const char *ext, const char *mode) _PAPPL_PUBLIC; + +extern void papplScannerPause(pappl_scanner_t *printer) _PAPPL_PUBLIC; +extern void papplScannerRemoveLink(pappl_scanner_t *scanner, const char *label) _PAPPL_PUBLIC; +extern void papplScannerResume(pappl_scanner_t *scanner) _PAPPL_PUBLIC; + + +extern void papplScannerSetContact(pappl_scanner_t *scanner, pappl_contact_t *contact) _PAPPL_PUBLIC; +extern void papplScannerSetDNSSDName(pappl_scanner_t *scanner, const char *value) _PAPPL_PUBLIC; + +extern bool papplScannerSetDriverData(pappl_scanner_t *scanner, pappl_sc_driver_data_t *data) _PAPPL_PUBLIC; +extern bool papplScannerSetDriverDefaults(pappl_scanner_t *scanner, pappl_sc_driver_data_t *data) _PAPPL_PUBLIC; + +extern void papplScannerSetGeoLocation(pappl_scanner_t *scanner, const char *value) _PAPPL_PUBLIC; +extern void papplScannerSetLocation(pappl_scanner_t *scanner, const char *value) _PAPPL_PUBLIC; +extern void papplScannerSetNextJobID(pappl_scanner_t *scanner, int next_job_id) _PAPPL_PUBLIC; + +extern void papplScannerSetOrganization(pappl_scanner_t *scanner, const char *value) _PAPPL_PUBLIC; +extern void papplScannerSetOrganizationalUnit(pappl_scanner_t *scanner, const char *value) _PAPPL_PUBLIC; +extern void papplScannerSetReasons(pappl_scanner_t *scanner, pappl_sreason_t add, pappl_sreason_t remove) _PAPPL_PUBLIC; + +# ifdef __cplusplus +} +# endif // __cplusplus +#endif // !_PAPPL_SCANNER_H_ \ No newline at end of file From f6210991e9758356df4c3134d6b17c8806fb627a Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Sat, 9 Mar 2024 20:45:22 +0000 Subject: [PATCH 02/26] Add eof lines --- pappl/scanner-private.h | 2 +- pappl/scanner.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pappl/scanner-private.h b/pappl/scanner-private.h index 42ca56ac..eaca78fd 100644 --- a/pappl/scanner-private.h +++ b/pappl/scanner-private.h @@ -116,4 +116,4 @@ extern void _papplScannerWebMedia(pappl_client_t *client, pappl_scanner_t *prin extern const char *_papplScannerReasonString(pappl_sreason_t value) _PAPPL_PRIVATE; extern pappl_sreason_t _papplScannerReasonValue(const char *value) _PAPPL_PRIVATE; -#endif // !_PAPPL_SCANNER_PRIVATE_H_ \ No newline at end of file +#endif // !_PAPPL_SCANNER_PRIVATE_H_ diff --git a/pappl/scanner.h b/pappl/scanner.h index e6b68698..bd03ab05 100644 --- a/pappl/scanner.h +++ b/pappl/scanner.h @@ -195,4 +195,4 @@ extern void papplScannerSetReasons(pappl_scanner_t *scanner, pappl_sreason_t ad # ifdef __cplusplus } # endif // __cplusplus -#endif // !_PAPPL_SCANNER_H_ \ No newline at end of file +#endif // !_PAPPL_SCANNER_H_ From 05bc9639d81fe4282be0c7b34c3e1e5a3e98555f Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Thu, 21 Mar 2024 17:13:29 +0000 Subject: [PATCH 03/26] Update Scanner header files and Makefile --- pappl/Makefile | 2 ++ pappl/scanner-private.h | 17 +---------------- pappl/scanner.h | 19 ++++++------------- 3 files changed, 9 insertions(+), 29 deletions(-) diff --git a/pappl/Makefile b/pappl/Makefile index 1e41e13d..688af785 100644 --- a/pappl/Makefile +++ b/pappl/Makefile @@ -72,6 +72,8 @@ HEADERS = \ mainloop.h \ pappl.h \ printer.h \ + scanner.h \ + scanner-private.h \ subscription.h \ system.h diff --git a/pappl/scanner-private.h b/pappl/scanner-private.h index eaca78fd..6d284054 100644 --- a/pappl/scanner-private.h +++ b/pappl/scanner-private.h @@ -45,7 +45,6 @@ struct _pappl_scanner_s // Scanner data *geo_location, // "scanner-geo-location" value (geo: URI) *organization, // "scanner-organization" value *org_unit; // "scanner-organizational-unit" value - pappl_contact_t contact; // "scanner-contact" value char *resource; // Resource path of scanner size_t resourcelen; // Length of resource path @@ -56,56 +55,42 @@ struct _pappl_scanner_s // Scanner data bool is_accepting, // Are we accepting scan jobs? is_stopped, // Are we stopping this scanner? is_deleted; // Has this scanner been deleted? - char *device_id, // "scanner-device-id" value *device_uri; // Device URI pappl_device_t *device; // Current connection to device (if any) bool device_in_use; // Is the device in use? char *driver_name; // Driver name pappl_sc_driver_data_t *driver_data; // Driver data - time_t start_time; // Startup time time_t config_time; // "scanner-config-change-time" value time_t status_time; // Last time status was updated - pappl_job_t *processing_job; // Current scanning job, if any bool hold_new_jobs; // Hold new scan jobs int next_job_id; // Next "job-id" value - cups_array_t *links; // Web navigation links # ifdef HAVE_MDNSRESPONDER _pappl_srv_t dns_sd_http_ref, // DNS-SD HTTP service - DNSRecordRef dns_sd_escl_loc_ref, // DNS-SD LOC record for ESCL service - dns_sd_escl_loc_ref; // DNS-SD LOC record for ESCL service # elif defined(HAVE_AVAHI) _pappl_srv_t dns_sd_ref; // DNS-SD services # endif // HAVE_MDNSRESPONDER unsigned char dns_sd_loc[16]; // DNS-SD LOC record data bool dns_sd_collision; // Was there a name collision? int dns_sd_serial; // DNS-SD serial number (for collisions) - }; // // Functions... // -extern void _papplScannerCheckJobsNoLock(pappl_scanner_t *scanner) _PAPPL_PRIVATE; -extern void _papplScannerCleanJobsNoLock(pappl_scanner_t *scanner) _PAPPL_PRIVATE; -extern void _papplScannerCopyAttributesNoLock(pappl_scanner_t *scanner, pappl_client_t *client, cups_array_t *ra, const char *format) _PAPPL_PRIVATE; extern void _papplScannerDelete(pappl_scanner_t *scanner) _PAPPL_PRIVATE; extern void _papplScannerInitDriverData(pappl_sc_driver_data_t *d) _PAPPL_PRIVATE; extern bool _papplScannerIsAuthorized(pappl_client_t *client) _PAPPL_PRIVATE; extern void _papplScannerProcessESCL(pappl_client_t *client) _PAPPL_PRIVATE; extern bool _papplScannerRegisterDNSSDNoLock(pappl_scanner_t *scanner) _PAPPL_PRIVATE; -extern bool _papplScannerSetAttributes(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; extern void _papplScannerUnregisterDNSSDNoLock(pappl_scanner_t *scanner) _PAPPL_PRIVATE; - -extern void _papplScannerWebCancelAllJobs(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; extern void _papplScannerWebConfig(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; - -extern void _papplScannerWebConfigFinalize(pappl_scanner_t *scanner, cups_len_t num_form, cups_option_t *form) _PAPPL_PRIVATE; +extern void _papplScannerWebConfigFinalize(pappl_scanner_t *scanner, cups_len_t num_form, cups_option_t *form) _PAPPL_PRIVATE; extern void _papplScannerWebDefaults(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; extern void _papplScannerWebDelete(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; extern void _papplScannerWebHome(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; diff --git a/pappl/scanner.h b/pappl/scanner.h index bd03ab05..811d1510 100644 --- a/pappl/scanner.h +++ b/pappl/scanner.h @@ -49,16 +49,16 @@ enum pappl_sreason_t // Define color modes supported by the scanner typedef enum { - BLACKANDWHITE1, // For black and white scans - GRAYSCALE8, // For grayscale scans - RGB24 // For full color scans + PAPPL_BLACKANDWHITE1, // For black and white scans + PAPPL_GRAYSCALE8, // For grayscale scans + PAPPL_RGB24 // For full color scans } pappl_sc_color_mode_t; // Define input sources for the scanner typedef enum { - FLATBED, // For flatbed scanners - ADF, // For automatic dopappl_sc_input_source_t;cument feeder -} + PAPPL_FLATBED, // For flatbed scanners + PAPPL_ADF, // For automatic dopappl_sc_input_source_t;cument feeder +} pappl_sc_input_source_t; // // Callback functions... @@ -127,8 +127,6 @@ typedef struct pappl_sc_driver_data_s extern void papplScannerAddLink(pappl_scanner_t *scanner, const char *label, const char *path_or_url, pappl_loptions_t options) _PAPPL_PUBLIC; -extern void papplScannerCancelAllJobs(pappl_scanner_t *scanner) _PAPPL_PUBLIC; - extern void papplScannerCloseDevice(pappl_scanner_t *scanner) _PAPPL_PUBLIC; extern pappl_scanner_t *papplScannerCreate(pappl_system_t *system, int scanner_id, const char *scanner_name, const char *driver_name, const char *device_id, const char *device_uri) _PAPPL_PUBLIC; @@ -136,8 +134,6 @@ extern void papplScannerDelete(pappl_Scanner_t *scanner) _PAPPL_PUBLIC; extern void papplScannerDisable(pappl_scanner_t *scanner) _PAPPL_PUBLIC; extern void papplScannerEnable(pappl_scanner_t *scanner) _PAPPL_PUBLIC; -extern pappl_job_t *papplScannerFindJob(pappl_scanner_t *scanner, int job_id) _PAPPL_PUBLIC; - extern pappl_contact_t *papplScannerGetContact(pappl_scanner_t *scanner, pappl_contact_t *contact) _PAPPL_PUBLIC; extern const char *papplScannerGetDeviceID(pappl_scanner_t *scanner) _PAPPL_PUBLIC; extern const char *papplScannerGetDeviceURI(pappl_scanner_t *scanner) _PAPPL_PUBLIC; @@ -168,8 +164,6 @@ extern void papplScannerHTMLHeader(pappl_client_t *client, const char *title, i extern bool papplScannerIsAcceptingJobs(pappl_scanner_t *scanner) _PAPPL_PUBLIC; extern bool papplScannerIsDeleted(pappl_scanner_t *scanner) _PAPPL_PUBLIC; -extern bool papplScannerIsHoldingNewJobs(pappl_scanner_t *printer) _PAPPL_PUBLIC; - extern pappl_device_t *papplScannerOpenDevice(pappl_scanner_t *scanner) _PAPPL_PUBLIC; extern int papplScannerOpenFile(pappl_scanner_t *scanner, char *fname, size_t fnamesize, const char *directory, const char *resname, const char *ext, const char *mode) _PAPPL_PUBLIC; @@ -177,7 +171,6 @@ extern void papplScannerPause(pappl_scanner_t *printer) _PAPPL_PUBLIC; extern void papplScannerRemoveLink(pappl_scanner_t *scanner, const char *label) _PAPPL_PUBLIC; extern void papplScannerResume(pappl_scanner_t *scanner) _PAPPL_PUBLIC; - extern void papplScannerSetContact(pappl_scanner_t *scanner, pappl_contact_t *contact) _PAPPL_PUBLIC; extern void papplScannerSetDNSSDName(pappl_scanner_t *scanner, const char *value) _PAPPL_PUBLIC; From f050217e785ff100c1e1b472c452a2ab807548f1 Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Thu, 21 Mar 2024 18:33:17 +0000 Subject: [PATCH 04/26] Update indents --- pappl/scanner-private.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pappl/scanner-private.h b/pappl/scanner-private.h index 6d284054..a6a6f16e 100644 --- a/pappl/scanner-private.h +++ b/pappl/scanner-private.h @@ -40,11 +40,11 @@ struct _pappl_scanner_s // Scanner data pappl_system_t *system; // Containing system int scanner_id; // "scanner-id" value char *name, // "scanner-name" value - *dns_sd_name, // "scanner-dns-sd-name" value - *location, // "scanner-location" value - *geo_location, // "scanner-geo-location" value (geo: URI) - *organization, // "scanner-organization" value - *org_unit; // "scanner-organizational-unit" value + *dns_sd_name, // "scanner-dns-sd-name" value + *location, // "scanner-location" value + *geo_location, // "scanner-geo-location" value (geo: URI) + *organization, // "scanner-organization" value + *org_unit; // "scanner-organizational-unit" value pappl_contact_t contact; // "scanner-contact" value char *resource; // Resource path of scanner size_t resourcelen; // Length of resource path @@ -53,10 +53,10 @@ struct _pappl_scanner_s // Scanner data pappl_sreason_t state_reasons; // "scanner-state-reasons" values --> Replacement for pappl_preason_t time_t state_time; // "scanner-state-change-time" value bool is_accepting, // Are we accepting scan jobs? - is_stopped, // Are we stopping this scanner? - is_deleted; // Has this scanner been deleted? + is_stopped, // Are we stopping this scanner? + is_deleted; // Has this scanner been deleted? char *device_id, // "scanner-device-id" value - *device_uri; // Device URI + *device_uri; // Device URI pappl_device_t *device; // Current connection to device (if any) bool device_in_use; // Is the device in use? char *driver_name; // Driver name From 8c6e185a41ac1362f5056f9d27075d870e0470dc Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Fri, 22 Mar 2024 18:00:33 +0000 Subject: [PATCH 05/26] Update scanner header files --- pappl/scanner-private.h | 3 +-- pappl/scanner.h | 12 ++++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/pappl/scanner-private.h b/pappl/scanner-private.h index a6a6f16e..6ac78660 100644 --- a/pappl/scanner-private.h +++ b/pappl/scanner-private.h @@ -60,12 +60,11 @@ struct _pappl_scanner_s // Scanner data pappl_device_t *device; // Current connection to device (if any) bool device_in_use; // Is the device in use? char *driver_name; // Driver name - pappl_sc_driver_data_t *driver_data; // Driver data + pappl_sc_driver_data_t driver_data; // Driver data time_t start_time; // Startup time time_t config_time; // "scanner-config-change-time" value time_t status_time; // Last time status was updated pappl_job_t *processing_job; // Current scanning job, if any - bool hold_new_jobs; // Hold new scan jobs int next_job_id; // Next "job-id" value cups_array_t *links; // Web navigation links # ifdef HAVE_MDNSRESPONDER diff --git a/pappl/scanner.h b/pappl/scanner.h index 811d1510..fda853ba 100644 --- a/pappl/scanner.h +++ b/pappl/scanner.h @@ -37,7 +37,7 @@ typedef enum PAPPL_SSTATE_DOWN // Scanner is unavailable } escl_sstate_t; -enum pappl_sreason_t +typedef enum { PAPPL_SREASON_NONE = 0x0000, // 'none', no error, scanner is ready PAPPL_SREASON_IDLE = 0x0001, // 'idle', scanner is idle @@ -45,7 +45,7 @@ enum pappl_sreason_t PAPPL_SREASON_TESTING = 0x0004, // 'testing', scanner is in calibration or preparation mode PAPPL_SREASON_STOPPED = 0x0008, // 'stopped', an error has occurred and the scanner has stopped PAPPL_SREASON_DOWN = 0x0010, // 'down', the scanner is unavailable -}; +} pappl_sreason_t; // Define color modes supported by the scanner typedef enum { @@ -67,7 +67,7 @@ typedef void (*pappl_sc_capabilities_cb_t)(pappl_scanner_t *scanner, pappl_sc_dr typedef void (*pappl_sc_job_create_cb_t)(pappl_job_t *job, pappl_sc_options_t *options, pappl_device_t *device); // Callback for creating a scan job typedef void (*pappl_sc_job_delete_cb_t)(pappl_job_t *job); // Callback for deleting a scan job typedef bool (*pappl_sc_data_cb_t)(pappl_job_t *job, pappl_device_t *device, void *buffer, size_t bufsize); // Callback for getting scan data -typedef void (*pappl_sc_status_cb_t)(pappl_scanner_t *scanner, pappl_sc_driver_data_t *data); // Callback for getting scanner status +typedef bool (*pappl_sc_status_cb_t)(pappl_scanner_t *scanner); // Callback for getting scanner status typedef bool (*pappl_sc_job_cancel_cb_t)(pappl_job_t *job); // Callback for cancelling a scan job typedef void (*pappl_sc_buffer_info_cb_t)(pappl_job_t *job, pappl_sc_options_t *options, pappl_device_t *device); // Callback for getting buffer information typedef void (*pappl_sc_image_info_cb_t)(pappl_job_t *job, pappl_device_t *device, void *data); // Callback for getting image information @@ -130,7 +130,7 @@ extern void papplScannerAddLink(pappl_scanner_t *scanner, const char *label, co extern void papplScannerCloseDevice(pappl_scanner_t *scanner) _PAPPL_PUBLIC; extern pappl_scanner_t *papplScannerCreate(pappl_system_t *system, int scanner_id, const char *scanner_name, const char *driver_name, const char *device_id, const char *device_uri) _PAPPL_PUBLIC; -extern void papplScannerDelete(pappl_Scanner_t *scanner) _PAPPL_PUBLIC; +extern void papplScannerDelete(pappl_scanner_t *scanner) _PAPPL_PUBLIC; extern void papplScannerDisable(pappl_scanner_t *scanner) _PAPPL_PUBLIC; extern void papplScannerEnable(pappl_scanner_t *scanner) _PAPPL_PUBLIC; @@ -153,8 +153,8 @@ extern char *papplScannerGetOrganizationalUnit(pappl_scanner_t *scanner, char * extern char *papplScannerGetPath(pappl_scanner_t *scanner, const char *subpath, char *buffer, size_t bufsize) _PAPPL_PUBLIC; -extern pappl_sreason_t papplScannerGetReasons(pappl_printer_t *printer) _PAPPL_PUBLIC; -extern escl_sstate_t papplScannerGetState(pappl_printer_t *printer) _PAPPL_PUBLIC; +extern pappl_sreason_t papplScannerGetReasons(pappl_scanner_t *scanner) _PAPPL_PUBLIC; +extern escl_sstate_t papplScannerGetState(pappl_scanner_t *scanner) _PAPPL_PUBLIC; extern pappl_system_t *papplScannerGetSystem(pappl_scanner_t *scanner) _PAPPL_PUBLIC; From e24d9e3357f470f0cc5f6242b4d90057bbbdf3bf Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Fri, 22 Mar 2024 18:01:08 +0000 Subject: [PATCH 06/26] Add scanner object to job struct --- pappl/job-private.h | 1 + 1 file changed, 1 insertion(+) diff --git a/pappl/job-private.h b/pappl/job-private.h index 7ad6cb63..55b998c2 100644 --- a/pappl/job-private.h +++ b/pappl/job-private.h @@ -24,6 +24,7 @@ struct _pappl_job_s // Job data pthread_rwlock_t rwlock; // Reader/writer lock pappl_system_t *system; // Containing system pappl_printer_t *printer; // Containing printer + pappl_scanner_t *scanner; // Containing scanner int job_id; // "job-id" value const char *name, // "job-name" value *username, // "job-originating-user-name" value From deb4baf8976b5362d292671597c8f4afc693d16c Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Fri, 22 Mar 2024 18:01:36 +0000 Subject: [PATCH 07/26] Update info about scanner objects in base.h --- pappl/base.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pappl/base.h b/pappl/base.h index 45726aca..b2204cc3 100644 --- a/pappl/base.h +++ b/pappl/base.h @@ -102,13 +102,19 @@ typedef unsigned char pappl_dither_t[16][16]; // 16x16 dither array typedef struct pappl_pr_driver_data_s pappl_pr_driver_data_t; // Print driver data +typedef struct pappl_sc_driver_data_s pappl_sc_driver_data_t; + // Scanner driver data typedef struct _pappl_job_s pappl_job_t;// Job object typedef struct _pappl_loc_s pappl_loc_t;// Localization data typedef struct pappl_pr_options_s pappl_pr_options_t; // Combined print job options +typedef struct pappl_sc_options_s pappl_sc_options_t; + // Combined scan job options typedef unsigned int pappl_preason_t; // Bitfield for IPP "printer-state-reasons" values typedef struct _pappl_printer_s pappl_printer_t; // Printer object +typedef struct _pappl_scanner_s pappl_scanner_t; + // Scanner object typedef struct _pappl_subscription_s pappl_subscription_t; // Subscription object typedef struct _pappl_system_s pappl_system_t; From 317300f166f8fe61105cb94619dc649bb415e59f Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Fri, 22 Mar 2024 18:01:58 +0000 Subject: [PATCH 08/26] Scanner accessor functions --- pappl/scanner-accessors.c | 784 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 784 insertions(+) create mode 100644 pappl/scanner-accessors.c diff --git a/pappl/scanner-accessors.c b/pappl/scanner-accessors.c new file mode 100644 index 00000000..bbf25ea9 --- /dev/null +++ b/pappl/scanner-accessors.c @@ -0,0 +1,784 @@ +// +// Scanner accessor functions for the Scanner Application Framework +// +// Copyright © 2020-2024 by Michael R Sweet. +// +// Licensed under Apache License v2.0. See the file "LICENSE" for more +// information. +// + +#include "scanner-private.h" +#include "scanner.h" +#include "job-private.h" +#include "system-private.h" + +// +// 'papplScannerCloseDevice()' - Close the device associated with the scanner . +// +// This function closes the device for a scanner. The device must have been +// previously opened using the @link papplScannerOpenDevice@ function. +// + +void +papplScannerCloseDevice( + pappl_scanner_t *scanner) // I - Scanner +{ + if (!scanner) + return; + + _papplRWLockWrite(scanner); + if (scanner->device && scanner->device_in_use) + { + scanner->device_in_use = false; + + if (scanner->state != PAPPL_SSTATE_PROCESSING) + { + papplDeviceClose(scanner->device); + scanner->device = NULL; + } + } + + _papplRWUnlock(scanner); +} + +// +// 'papplScannerDisable()' - Stop accepting jobs on a scanner. +// +// This function stops accepting jobs on a scanner. +// + +void +papplScannerDisable( + pappl_scanner_t *scanner) // I - Scanner +{ + if (scanner) + { + scanner->is_accepting = false; + // papplSystemAddEvent(scanner->system, scanner, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, NULL); + printf("Scanner State Changed\n"); + } +} + +// +// 'papplScannerEnable()' - Start accepting jobs on a scanner. +// +// This function starts accepting jobs on a scanner. +// + +void +papplScannerEnable( + pappl_scanner_t *scanner) // I - Scanner +{ + if (scanner) + { + scanner->is_accepting = true; + // papplSystemAddEvent(scanner->system, scanner, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, NULL); + printf("Scanner State Changed\n"); + } +} + + +// +// 'papplScannerGetContact()' - Get the "scanner-contact" value. +// +// This function copies the current scanner contact information to the buffer +// pointed to by the "contact" argument. +// + +pappl_contact_t * // O - Contact +papplScannerGetContact( + pappl_scanner_t *scanner, // I - Scanner + pappl_contact_t *contact) // O - Contact +{ + if (!scanner || !contact) + { + if (contact) + memset(contact, 0, sizeof(pappl_contact_t)); + + return (contact); + } + + _papplRWLockRead(scanner); + + *contact = scanner->contact; + + _papplRWUnlock(scanner); + + return (contact); +} + + +// +// 'papplScannerGetDeviceID()' - Get the device ID of the scanner. +// +// This function returns the device ID of the scanner. +// + +const char * // O - Device ID string +papplScannerGetDeviceID( + pappl_scanner_t *scanner) // I - Scanner +{ + return (scanner ? scanner->device_id : NULL); +} + +// +// 'papplScannerGetDeviceURI()' - Get the URI of the device associated with the +// scanner. +// +// This function returns the device URI for the scanner. +// + +const char * // O - Device URI string +papplScannerGetDeviceURI( + pappl_scanner_t *scanner) // I - Scanner +{ + return (scanner ? scanner->device_uri : "file:///dev/null"); +} + + +// +// 'papplScannerGetDNSSDName()' - Get the current DNS-SD service name. +// +// This function copies the current DNS-SD service name to the buffer pointed +// to by the "buffer" argument. +// + +char * // O - DNS-SD service name or `NULL` for none +papplScannerGetDNSSDName( + pappl_scanner_t *scanner, // I - Scanner + char *buffer, // I - String buffer + size_t bufsize) // I - Size of string buffer +{ + if (!scanner || !scanner->dns_sd_name || !buffer || bufsize == 0) + { + if (buffer) + *buffer = '\0'; + + return (NULL); + } + + _papplRWLockRead(scanner); + papplCopyString(buffer, scanner->dns_sd_name, bufsize); + _papplRWUnlock(scanner); + + return (buffer); +} + +// +// 'papplScannerGetGeoLocation()' - Get the current geo-location as a "geo:" +// URI. +// +// This function copies the currently configured geographic location as a "geo:" +// URI to the buffer pointed to by the "buffer" argument. +// + +char * // O - "geo:" URI or `NULL` for unknown +papplScannerGetGeoLocation( + pappl_scanner_t *scanner, // I - Scanner + char *buffer, // I - String buffer + size_t bufsize) // I - Size of string buffer +{ + if (!scanner || !scanner->geo_location || !buffer || bufsize == 0) + { + if (buffer) + *buffer = '\0'; + + return (NULL); + } + + _papplRWLockRead(scanner); + papplCopyString(buffer, scanner->geo_location, bufsize); + _papplRWUnlock(scanner); + + return (buffer); +} + +// +// 'papplScannerGetID()' - Get the scanner ID. +// +// This function returns the scanner's unique positive integer identifier. +// + +int // O - "scanner-id" value or `0` for none +papplScannerGetID( + pappl_scanner_t *scanner) // I - Scanner +{ + return (scanner ? scanner->scanner_id : 0); +} + +// +// 'papplScannerGetLocation()' - Get the location string. +// +// This function copies the scanner's human-readable location to the buffer +// pointed to by the "buffer" argument. +// + +char * // O - Location or `NULL` for none +papplScannerGetLocation( + pappl_scanner_t *scanner, // I - Scanner + char *buffer, // I - String buffer + size_t bufsize) // I - Size of string buffer +{ + if (!scanner || !scanner->location || !buffer || bufsize == 0) + { + if (buffer) + *buffer = '\0'; + + return (NULL); + } + + _papplRWLockRead(scanner); + papplCopyString(buffer, scanner->location, bufsize); + _papplRWUnlock(scanner); + + return (buffer); +} + +// +// 'papplScannerGetName()' - Get the scanner name. +// +// This function returns the scanner's human-readable name. +// + + +const char * // O - Scanner name +papplScannerGetName( + pappl_scanner_t *scanner) // I - scanner +{ + return (scanner ? scanner->name : NULL); +} + +// +// 'papplScannerGetNextJobID()' - Get the next job ID. +// +// This function returns the positive integer identifier that will be used for +// the next job that is created. +// + +int // O - Next job ID or `0` for none +papplScannerGetNextJobID( + pappl_scanner_t *scanner) // I - Scanner +{ + return (scanner ? scanner->next_job_id : 0); +} + +// +// 'papplScannerGetOrganization()' - Get the organization name. +// +// This function copies the scanner's organization name to the buffer pointed +// to by the "buffer" argument. +// + +char * // O - Organization name or `NULL` for none +papplScannerGetOrganization( + pappl_scanner_t *scanner, // I - Scanner + char *buffer, // I - String buffer + size_t bufsize) // I - Size of string buffer +{ + if (!scanner || !scanner->organization || !buffer || bufsize == 0) + { + if (buffer) + *buffer = '\0'; + + return (NULL); + } + + _papplRWLockRead(scanner); + papplCopyString(buffer, scanner->organization, bufsize); + _papplRWUnlock(scanner); + + return (buffer); +} + +// +// 'papplScannerGetOrganizationalUnit()' - Get the organizational unit name. +// +// This function copies the scanner's organizational unit name to the buffer +// pointed to by the "buffer" argument. +// + +char * // O - Organizational unit name or `NULL` for none +papplScannerGetOrganizationalUnit( + pappl_scanner_t *scanner, // I - Scanner + char *buffer, // I - String buffer + size_t bufsize) // I - Size of string buffer +{ + if (!scanner || !scanner->org_unit || !buffer || bufsize == 0) + { + if (buffer) + *buffer = '\0'; + + return (NULL); + } + + _papplRWLockRead(scanner); + papplCopyString(buffer, scanner->org_unit, bufsize); + _papplRWUnlock(scanner); + + return (buffer); +} + +// +// 'papplScannerGetPath()' - Get the URL path for a scanner web page. +// +// This function generates and returns the URL path for the scanner's web page. +// The "subpath" argument specifies an optional sub-path for a specific printer +// web page. +// + +char * // O - URI path or `NULL` on error +papplScannerGetPath( + pappl_scanner_t *scanner, // I - Scanner + const char *subpath, // I - Sub-path or `NULL` for none + char *buffer, // I - String buffer + size_t bufsize) // I - Size of string buffer +{ + if (!scanner || !buffer || bufsize < 32) + { + if (buffer) + *buffer = '\0'; + + return (NULL); + } + + if (subpath) + snprintf(buffer, bufsize, "%s/%s", scanner->uriname, subpath); + else + papplCopyString(buffer, scanner->uriname, bufsize); + + return (buffer); +} + +// +// 'papplScannerGetReasons()' - Get the current "scanner-state-reasons" bit values. +// +// This function returns the current scanner state reasons bitfield, which can +// be updated by the scanner driver and/or by the @link papplScannerSetReasons@ +// function. +// + +pappl_sreason_t // O - "scanner-state-reasons" bit values +papplScannerGetReasons( + pappl_scanner_t *scanner) // I - Scanner +{ + pappl_sreason_t ret = PAPPL_SREASON_NONE; + // Return value + + if (scanner) + { + _papplRWLockRead(scanner); + + if (!scanner->device_in_use && !scanner->processing_job && (time(NULL) - scanner->status_time) > 1 && scanner->driver_data.status_cb) + { + // Update scanner status... + _papplRWUnlock(scanner); + (scanner->driver_data.status_cb)(scanner); + + _papplRWLockRead(scanner); + scanner->status_time = time(NULL); + } + + ret = scanner->state_reasons; + + _papplRWUnlock(scanner); + } + + return (ret); +} + +// +// 'papplScannerGetState()' - Get the current "scanner-state" value. +// +// This function returns the current scanner state as an enumeration: +// + +escl_sstate_t // O - "scanner-state" value +papplScannerGetState( + pappl_scanner_t *scanner) // I - Scanner +{ + return (scanner ? scanner->state : PAPPL_SSTATE_STOPPED); +} + + +// +// 'papplScannerGetSystem()' - Get the system associated with the scanner. +// +// This function returns a pointer to the system object that contains the +// scanner. +// + +pappl_system_t * // O - System +papplScannerGetSystem( + pappl_scanner_t *scanner) // I - Scanner +{ + return (scanner ? scanner->system : NULL); +} + +// +// 'papplScannerIsAcceptingJobs()' - Return whether the scanner is accepting jobs. +// +// This function returns a boolean value indicating whether a scanner is +// accepting jobs. +// + +bool // O - `true` if the scanner is accepting jobs, `false` otherwise +papplScannerIsAcceptingJobs( + pappl_scanner_t *scanner) // I - Scanner +{ + bool is_accepting; // Return value + + + // Range check input... + if (!scanner) + return (false); + + // Lock and grab value... + _papplRWLockRead(scanner); + is_accepting = scanner->is_accepting; + _papplRWUnlock(scanner); + + return (is_accepting); +} + +// +// 'papplScannerIsDeleted()' - Return whether a scanner is in the process of being deleted. +// +// This function returns a boolean value indicating whether a scanner is being +// deleted. +// + +bool // O - `true` is scanner is being deleted, `false` otherwise +papplScannerIsDeleted( + pappl_scanner_t *scanner) // I - Scanner +{ + bool is_deleted; // Return value + + + // Range check input... + if (!scanner) + return (false); + + // Lock and grab value... + _papplRWLockRead(scanner); + is_deleted = scanner->is_deleted; + _papplRWUnlock(scanner); + + return (is_deleted); +} + + +// +// 'papplScannerOpenDevice()' - Open the device associated with a scanner. +// +// This function opens the scanners's device. `NULL` is returned if the device +// is already in use, for example while a job is being scanned. +// +// The returned device must be closed using the @link papplScannerCloseDevice@ +// function. +// + +pappl_device_t * // O - Device or `NULL` if not possible +papplScannerOpenDevice( + pappl_scanner_t *scanner) // I - Scanner +{ + pappl_device_t *device = NULL; // Open device + + + if (!scanner) + return (NULL); + + _papplRWLockWrite(scanner); + + if (!scanner->device_in_use && !scanner->processing_job && scanner->device_uri) + { + scanner->device = device = papplDeviceOpen(scanner->device_uri, "scanner", papplLogDevice, scanner->system); + scanner->device_in_use = device != NULL; + } + + _papplRWUnlock(scanner); + + return (device); +} + +// +// 'papplScannerPause()' - Pause (stop) a scanner. +// +// This function pauses a scanner. If the scanner is currently processing +// (scanning) a job, it will be completed before the scanner is stopped. +// + +void +papplScannerPause( + pappl_scanner_t *scanner) // I - Scanner +{ + if (!scanner) + return; + + _papplRWLockWrite(scanner); + + if (scanner->processing_job) + scanner->is_stopped = true; + else + scanner->state = PAPPL_SSTATE_STOPPED; + +// _papplSystemAddEventNoLock(scanner->system, scanner, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED | PAPPL_EVENT_PRINTER_STOPPED, NULL); + printf("Scanner State Changed and Scanner Paused\n"); + + _papplRWUnlock(scanner); +} + +// +// 'papplScannerResume()' - Resume (start) a scanner. +// +// This function resumes a scanner. +// + +void +papplScannerResume( + pappl_scanner_t *scanner) // I - Scanner +{ + if (!scanner) + return; + + _papplRWLockWrite(scanner); + + scanner->is_stopped = false; + scanner->state = PAPPL_SSTATE_IDLE; + +// _papplSystemAddEventNoLock(scanner->system, scanner, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, "Resumed scanner."); + printf("Scanner State Changed and Scanner Resumed \n"); + + _papplRWUnlock(scanner); +} + +// +// 'papplScannerSetContact()' - Set the "scanner-contact" value. +// +// This function sets the scanner's contact information. +// + +void +papplScannerSetContact( + pappl_scanner_t *scanner, // I - Scanner + pappl_contact_t *contact) // I - Contact +{ + if (!scanner || !contact) + return; + + _papplRWLockWrite(scanner); + + scanner->contact = *contact; + scanner->config_time = time(NULL); + + _papplRWUnlock(scanner); + + _papplSystemConfigChanged(scanner->system); +} + +// +// 'papplScannerSetDNSSDName()' - Set the DNS-SD service name. +// +// This function sets the scanner's DNS-SD service name. If `NULL`, the scanner +// will stop advertising the scanner. +// + +void +papplScannerSetDNSSDName( + pappl_scanner_t *scanner, // I - Scanner + const char *value) // I - DNS-SD service name or `NULL` for none +{ + if (!scanner) + return; + + _papplRWLockWrite(scanner); + + free(scanner->dns_sd_name); + scanner->dns_sd_name = value ? strdup(value) : NULL; + scanner->dns_sd_collision = false; + scanner->dns_sd_serial = 0; + scanner->config_time = time(NULL); + + // TODO + if (!value) + _papplScannerUnregisterDNSSDNoLock(scanner); + else + _papplScannerRegisterDNSSDNoLock(scanner); + + _papplRWUnlock(scanner); + + _papplSystemConfigChanged(scanner->system); +} + +// +// 'papplScannerSetGeoLocation()' - Set the geo-location value as a "geo:" URI. +// +// This function sets the scanner's geographic location as a "geo:" URI. If +// `NULL`, the location is cleared to the 'unknown' value. +// + +void +papplScannerSetGeoLocation( + pappl_scanner_t *scanner, // I - Scanner + const char *value) // I - "geo:" URI or `NULL` for unknown +{ + float lat, lon; // Latitude and longitude from geo: URI + + + if (!scanner) + return; + + // Validate geo-location - must be NULL or a "geo:" URI... + if (value && *value && sscanf(value, "geo:%f,%f", &lat, &lon) != 2) + return; + + _papplRWLockWrite(scanner); + + free(scanner->geo_location); + scanner->geo_location = value && *value ? strdup(value) : NULL; + scanner->config_time = time(NULL); + + // TODO + _papplScannerRegisterDNSSDNoLock(scanner); + + _papplRWUnlock(scanner); + + _papplSystemConfigChanged(scanner->system); +} + +// +// 'papplScannerSetLocation()' - Set the location string. +// +// This function sets the scanner's human-readable location string. If `NULL`, +// the location is cleared. +// + +void +papplScannerSetLocation( + pappl_scanner_t *scanner, // I - Scanner + const char *value) // I - Location ("Bob's Office", etc.) or `NULL` for none +{ + if (!scanner) + return; + + _papplRWLockWrite(scanner); + + free(scanner->location); + scanner->location = value ? strdup(value) : NULL; + scanner->config_time = time(NULL); + + //TODO + _papplScannerRegisterDNSSDNoLock(scanner); + + _papplRWUnlock(scanner); + + _papplSystemConfigChanged(scanner->system); +} + +// +// 'papplScannerSetNextJobID()' - Set the next "job-id" value. +// +// This function sets the next unique positive integer identifier that will be +// used for a job. +// +// > Note: This function is normally only called once to restore the previous +// > state of the scanner. +// +void +papplScannerSetNextJobID( + pappl_scanner_t *scanner, // I - Scanner + int next_job_id) // I - Next "job-id" value +{ + if (!scanner || next_job_id < 1) + return; + + _papplRWLockWrite(scanner); + + scanner->next_job_id = next_job_id; + scanner->config_time = time(NULL); + + _papplRWUnlock(scanner); + + _papplSystemConfigChanged(scanner->system); +} + +// +// 'papplScannerSetOrganization()' - Set the organization name. +// +// This function sets the scanner's organization name. If `NULL` the value is +// cleared. +// + +void +papplScannerSetOrganization( + pappl_scanner_t *scanner, // I - Scanner + const char *value) // I - Organization name or `NULL` for none +{ + if (!scanner) + return; + + _papplRWLockWrite(scanner); + + free(scanner->organization); + scanner->organization = value ? strdup(value) : NULL; + scanner->config_time = time(NULL); + + _papplRWUnlock(scanner); + + _papplSystemConfigChanged(scanner->system); +} + +// +// 'papplScannerSetOrganizationalUnit()' - Set the organizational unit name. +// +// This function sets the scanner's organizational unit name. If `NULL` the +// value is cleared. +// + +void +papplScannerSetOrganizationalUnit( + pappl_scanner_t *scanner, // I - Scanner + const char *value) // I - Organizational unit name or `NULL` for none +{ + if (!scanner) + return; + + _papplRWLockWrite(scanner); + + free(scanner->org_unit); + scanner->org_unit = value ? strdup(value) : NULL; + scanner->config_time = time(NULL); + + _papplRWUnlock(scanner); + + _papplSystemConfigChanged(scanner->system); +} + + +// +// 'papplScannerSetReasons()' - Add or remove values from +// "scanner-state-reasons". +// +// This function updates the scanner state reasons bitfield by clearing any bit +// values in the "remove" argument and setting any bit values in the "add" +// argument. +// + +void +papplScannerSetReasons( + pappl_scanner_t *scanner, // I - Scanner + pappl_sreason_t add, // I - "scanner-state-reasons" bit values to add or `PAPPL_SREASON_NONE` for none + pappl_sreason_t remove) // I - "scanner-state-reasons" bit values to remove or `PAPPL_SREASON_NONE` for none +{ + if (!scanner) + return; + + _papplRWLockWrite(scanner); + + scanner->state_reasons &= ~remove; + scanner->state_reasons |= add; + scanner->state_time = scanner->status_time = time(NULL); + + _papplRWUnlock(scanner); +} + + From 8176b4fd3c8c9f43978097e273478afffe2a7565 Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Fri, 22 Mar 2024 18:02:11 +0000 Subject: [PATCH 09/26] Makefile changes --- pappl/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/pappl/Makefile b/pappl/Makefile index 688af785..6410f0fb 100644 --- a/pappl/Makefile +++ b/pappl/Makefile @@ -45,6 +45,7 @@ BASEOBJS = \ printer-usb.o \ printer-webif.o \ resource.o \ + scanner-accessors.o\ snmp.o \ subscription.o \ subscription-ipp.o \ From 4e5ef68814f1dcba134100ec2789ac5dbbfe67a5 Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Fri, 22 Mar 2024 18:04:19 +0000 Subject: [PATCH 10/26] Update indents --- pappl/scanner-accessors.c | 244 +++++++++++++++++++------------------- 1 file changed, 122 insertions(+), 122 deletions(-) diff --git a/pappl/scanner-accessors.c b/pappl/scanner-accessors.c index bbf25ea9..8f85289f 100644 --- a/pappl/scanner-accessors.c +++ b/pappl/scanner-accessors.c @@ -21,21 +21,21 @@ void papplScannerCloseDevice( - pappl_scanner_t *scanner) // I - Scanner + pappl_scanner_t *scanner) // I - Scanner { if (!scanner) - return; + return; _papplRWLockWrite(scanner); if (scanner->device && scanner->device_in_use) { - scanner->device_in_use = false; + scanner->device_in_use = false; - if (scanner->state != PAPPL_SSTATE_PROCESSING) - { - papplDeviceClose(scanner->device); - scanner->device = NULL; - } + if (scanner->state != PAPPL_SSTATE_PROCESSING) + { + papplDeviceClose(scanner->device); + scanner->device = NULL; + } } _papplRWUnlock(scanner); @@ -49,13 +49,13 @@ papplScannerCloseDevice( void papplScannerDisable( - pappl_scanner_t *scanner) // I - Scanner + pappl_scanner_t *scanner) // I - Scanner { if (scanner) { - scanner->is_accepting = false; - // papplSystemAddEvent(scanner->system, scanner, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, NULL); - printf("Scanner State Changed\n"); + scanner->is_accepting = false; + // papplSystemAddEvent(scanner->system, scanner, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, NULL); + printf("Scanner State Changed\n"); } } @@ -67,13 +67,13 @@ papplScannerDisable( void papplScannerEnable( - pappl_scanner_t *scanner) // I - Scanner + pappl_scanner_t *scanner) // I - Scanner { if (scanner) { - scanner->is_accepting = true; - // papplSystemAddEvent(scanner->system, scanner, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, NULL); - printf("Scanner State Changed\n"); + scanner->is_accepting = true; + // papplSystemAddEvent(scanner->system, scanner, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, NULL); + printf("Scanner State Changed\n"); } } @@ -87,15 +87,15 @@ papplScannerEnable( pappl_contact_t * // O - Contact papplScannerGetContact( - pappl_scanner_t *scanner, // I - Scanner - pappl_contact_t *contact) // O - Contact + pappl_scanner_t *scanner, // I - Scanner + pappl_contact_t *contact) // O - Contact { if (!scanner || !contact) { - if (contact) - memset(contact, 0, sizeof(pappl_contact_t)); + if (contact) + memset(contact, 0, sizeof(pappl_contact_t)); - return (contact); + return (contact); } _papplRWLockRead(scanner); @@ -116,7 +116,7 @@ papplScannerGetContact( const char * // O - Device ID string papplScannerGetDeviceID( - pappl_scanner_t *scanner) // I - Scanner + pappl_scanner_t *scanner) // I - Scanner { return (scanner ? scanner->device_id : NULL); } @@ -130,7 +130,7 @@ papplScannerGetDeviceID( const char * // O - Device URI string papplScannerGetDeviceURI( - pappl_scanner_t *scanner) // I - Scanner + pappl_scanner_t *scanner) // I - Scanner { return (scanner ? scanner->device_uri : "file:///dev/null"); } @@ -145,16 +145,16 @@ papplScannerGetDeviceURI( char * // O - DNS-SD service name or `NULL` for none papplScannerGetDNSSDName( - pappl_scanner_t *scanner, // I - Scanner - char *buffer, // I - String buffer - size_t bufsize) // I - Size of string buffer + pappl_scanner_t *scanner, // I - Scanner + char *buffer, // I - String buffer + size_t bufsize) // I - Size of string buffer { if (!scanner || !scanner->dns_sd_name || !buffer || bufsize == 0) { - if (buffer) - *buffer = '\0'; + if (buffer) + *buffer = '\0'; - return (NULL); + return (NULL); } _papplRWLockRead(scanner); @@ -174,16 +174,16 @@ papplScannerGetDNSSDName( char * // O - "geo:" URI or `NULL` for unknown papplScannerGetGeoLocation( - pappl_scanner_t *scanner, // I - Scanner - char *buffer, // I - String buffer - size_t bufsize) // I - Size of string buffer + pappl_scanner_t *scanner, // I - Scanner + char *buffer, // I - String buffer + size_t bufsize) // I - Size of string buffer { if (!scanner || !scanner->geo_location || !buffer || bufsize == 0) { - if (buffer) - *buffer = '\0'; + if (buffer) + *buffer = '\0'; - return (NULL); + return (NULL); } _papplRWLockRead(scanner); @@ -201,7 +201,7 @@ papplScannerGetGeoLocation( int // O - "scanner-id" value or `0` for none papplScannerGetID( - pappl_scanner_t *scanner) // I - Scanner + pappl_scanner_t *scanner) // I - Scanner { return (scanner ? scanner->scanner_id : 0); } @@ -215,16 +215,16 @@ papplScannerGetID( char * // O - Location or `NULL` for none papplScannerGetLocation( - pappl_scanner_t *scanner, // I - Scanner - char *buffer, // I - String buffer - size_t bufsize) // I - Size of string buffer + pappl_scanner_t *scanner, // I - Scanner + char *buffer, // I - String buffer + size_t bufsize) // I - Size of string buffer { if (!scanner || !scanner->location || !buffer || bufsize == 0) { - if (buffer) - *buffer = '\0'; + if (buffer) + *buffer = '\0'; - return (NULL); + return (NULL); } _papplRWLockRead(scanner); @@ -243,7 +243,7 @@ papplScannerGetLocation( const char * // O - Scanner name papplScannerGetName( - pappl_scanner_t *scanner) // I - scanner + pappl_scanner_t *scanner) // I - scanner { return (scanner ? scanner->name : NULL); } @@ -257,7 +257,7 @@ papplScannerGetName( int // O - Next job ID or `0` for none papplScannerGetNextJobID( - pappl_scanner_t *scanner) // I - Scanner + pappl_scanner_t *scanner) // I - Scanner { return (scanner ? scanner->next_job_id : 0); } @@ -271,16 +271,16 @@ papplScannerGetNextJobID( char * // O - Organization name or `NULL` for none papplScannerGetOrganization( - pappl_scanner_t *scanner, // I - Scanner - char *buffer, // I - String buffer - size_t bufsize) // I - Size of string buffer + pappl_scanner_t *scanner, // I - Scanner + char *buffer, // I - String buffer + size_t bufsize) // I - Size of string buffer { if (!scanner || !scanner->organization || !buffer || bufsize == 0) { - if (buffer) - *buffer = '\0'; + if (buffer) + *buffer = '\0'; - return (NULL); + return (NULL); } _papplRWLockRead(scanner); @@ -299,16 +299,16 @@ papplScannerGetOrganization( char * // O - Organizational unit name or `NULL` for none papplScannerGetOrganizationalUnit( - pappl_scanner_t *scanner, // I - Scanner - char *buffer, // I - String buffer - size_t bufsize) // I - Size of string buffer + pappl_scanner_t *scanner, // I - Scanner + char *buffer, // I - String buffer + size_t bufsize) // I - Size of string buffer { if (!scanner || !scanner->org_unit || !buffer || bufsize == 0) { - if (buffer) - *buffer = '\0'; + if (buffer) + *buffer = '\0'; - return (NULL); + return (NULL); } _papplRWLockRead(scanner); @@ -328,23 +328,23 @@ papplScannerGetOrganizationalUnit( char * // O - URI path or `NULL` on error papplScannerGetPath( - pappl_scanner_t *scanner, // I - Scanner - const char *subpath, // I - Sub-path or `NULL` for none - char *buffer, // I - String buffer - size_t bufsize) // I - Size of string buffer + pappl_scanner_t *scanner, // I - Scanner + const char *subpath, // I - Sub-path or `NULL` for none + char *buffer, // I - String buffer + size_t bufsize) // I - Size of string buffer { if (!scanner || !buffer || bufsize < 32) { - if (buffer) - *buffer = '\0'; + if (buffer) + *buffer = '\0'; - return (NULL); + return (NULL); } if (subpath) - snprintf(buffer, bufsize, "%s/%s", scanner->uriname, subpath); + snprintf(buffer, bufsize, "%s/%s", scanner->uriname, subpath); else - papplCopyString(buffer, scanner->uriname, bufsize); + papplCopyString(buffer, scanner->uriname, bufsize); return (buffer); } @@ -359,28 +359,28 @@ papplScannerGetPath( pappl_sreason_t // O - "scanner-state-reasons" bit values papplScannerGetReasons( - pappl_scanner_t *scanner) // I - Scanner + pappl_scanner_t *scanner) // I - Scanner { pappl_sreason_t ret = PAPPL_SREASON_NONE; - // Return value + // Return value if (scanner) { - _papplRWLockRead(scanner); + _papplRWLockRead(scanner); - if (!scanner->device_in_use && !scanner->processing_job && (time(NULL) - scanner->status_time) > 1 && scanner->driver_data.status_cb) - { - // Update scanner status... - _papplRWUnlock(scanner); - (scanner->driver_data.status_cb)(scanner); + if (!scanner->device_in_use && !scanner->processing_job && (time(NULL) - scanner->status_time) > 1 && scanner->driver_data.status_cb) + { + // Update scanner status... + _papplRWUnlock(scanner); + (scanner->driver_data.status_cb)(scanner); - _papplRWLockRead(scanner); - scanner->status_time = time(NULL); - } + _papplRWLockRead(scanner); + scanner->status_time = time(NULL); + } - ret = scanner->state_reasons; + ret = scanner->state_reasons; - _papplRWUnlock(scanner); + _papplRWUnlock(scanner); } return (ret); @@ -394,7 +394,7 @@ papplScannerGetReasons( escl_sstate_t // O - "scanner-state" value papplScannerGetState( - pappl_scanner_t *scanner) // I - Scanner + pappl_scanner_t *scanner) // I - Scanner { return (scanner ? scanner->state : PAPPL_SSTATE_STOPPED); } @@ -409,7 +409,7 @@ papplScannerGetState( pappl_system_t * // O - System papplScannerGetSystem( - pappl_scanner_t *scanner) // I - Scanner + pappl_scanner_t *scanner) // I - Scanner { return (scanner ? scanner->system : NULL); } @@ -423,14 +423,14 @@ papplScannerGetSystem( bool // O - `true` if the scanner is accepting jobs, `false` otherwise papplScannerIsAcceptingJobs( - pappl_scanner_t *scanner) // I - Scanner + pappl_scanner_t *scanner) // I - Scanner { bool is_accepting; // Return value // Range check input... if (!scanner) - return (false); + return (false); // Lock and grab value... _papplRWLockRead(scanner); @@ -449,14 +449,14 @@ papplScannerIsAcceptingJobs( bool // O - `true` is scanner is being deleted, `false` otherwise papplScannerIsDeleted( - pappl_scanner_t *scanner) // I - Scanner + pappl_scanner_t *scanner) // I - Scanner { bool is_deleted; // Return value // Range check input... if (!scanner) - return (false); + return (false); // Lock and grab value... _papplRWLockRead(scanner); @@ -479,20 +479,20 @@ papplScannerIsDeleted( pappl_device_t * // O - Device or `NULL` if not possible papplScannerOpenDevice( - pappl_scanner_t *scanner) // I - Scanner + pappl_scanner_t *scanner) // I - Scanner { pappl_device_t *device = NULL; // Open device if (!scanner) - return (NULL); + return (NULL); _papplRWLockWrite(scanner); if (!scanner->device_in_use && !scanner->processing_job && scanner->device_uri) { - scanner->device = device = papplDeviceOpen(scanner->device_uri, "scanner", papplLogDevice, scanner->system); - scanner->device_in_use = device != NULL; + scanner->device = device = papplDeviceOpen(scanner->device_uri, "scanner", papplLogDevice, scanner->system); + scanner->device_in_use = device != NULL; } _papplRWUnlock(scanner); @@ -509,17 +509,17 @@ papplScannerOpenDevice( void papplScannerPause( - pappl_scanner_t *scanner) // I - Scanner + pappl_scanner_t *scanner) // I - Scanner { if (!scanner) - return; + return; _papplRWLockWrite(scanner); if (scanner->processing_job) - scanner->is_stopped = true; + scanner->is_stopped = true; else - scanner->state = PAPPL_SSTATE_STOPPED; + scanner->state = PAPPL_SSTATE_STOPPED; // _papplSystemAddEventNoLock(scanner->system, scanner, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED | PAPPL_EVENT_PRINTER_STOPPED, NULL); printf("Scanner State Changed and Scanner Paused\n"); @@ -535,10 +535,10 @@ papplScannerPause( void papplScannerResume( - pappl_scanner_t *scanner) // I - Scanner + pappl_scanner_t *scanner) // I - Scanner { if (!scanner) - return; + return; _papplRWLockWrite(scanner); @@ -559,11 +559,11 @@ papplScannerResume( void papplScannerSetContact( - pappl_scanner_t *scanner, // I - Scanner - pappl_contact_t *contact) // I - Contact + pappl_scanner_t *scanner, // I - Scanner + pappl_contact_t *contact) // I - Contact { if (!scanner || !contact) - return; + return; _papplRWLockWrite(scanner); @@ -584,11 +584,11 @@ papplScannerSetContact( void papplScannerSetDNSSDName( - pappl_scanner_t *scanner, // I - Scanner - const char *value) // I - DNS-SD service name or `NULL` for none + pappl_scanner_t *scanner, // I - Scanner + const char *value) // I - DNS-SD service name or `NULL` for none { if (!scanner) - return; + return; _papplRWLockWrite(scanner); @@ -600,9 +600,9 @@ papplScannerSetDNSSDName( // TODO if (!value) - _papplScannerUnregisterDNSSDNoLock(scanner); + _papplScannerUnregisterDNSSDNoLock(scanner); else - _papplScannerRegisterDNSSDNoLock(scanner); + _papplScannerRegisterDNSSDNoLock(scanner); _papplRWUnlock(scanner); @@ -618,18 +618,18 @@ papplScannerSetDNSSDName( void papplScannerSetGeoLocation( - pappl_scanner_t *scanner, // I - Scanner - const char *value) // I - "geo:" URI or `NULL` for unknown + pappl_scanner_t *scanner, // I - Scanner + const char *value) // I - "geo:" URI or `NULL` for unknown { float lat, lon; // Latitude and longitude from geo: URI if (!scanner) - return; + return; // Validate geo-location - must be NULL or a "geo:" URI... if (value && *value && sscanf(value, "geo:%f,%f", &lat, &lon) != 2) - return; + return; _papplRWLockWrite(scanner); @@ -654,11 +654,11 @@ papplScannerSetGeoLocation( void papplScannerSetLocation( - pappl_scanner_t *scanner, // I - Scanner - const char *value) // I - Location ("Bob's Office", etc.) or `NULL` for none + pappl_scanner_t *scanner, // I - Scanner + const char *value) // I - Location ("Bob's Office", etc.) or `NULL` for none { if (!scanner) - return; + return; _papplRWLockWrite(scanner); @@ -685,11 +685,11 @@ papplScannerSetLocation( // void papplScannerSetNextJobID( - pappl_scanner_t *scanner, // I - Scanner - int next_job_id) // I - Next "job-id" value + pappl_scanner_t *scanner, // I - Scanner + int next_job_id) // I - Next "job-id" value { if (!scanner || next_job_id < 1) - return; + return; _papplRWLockWrite(scanner); @@ -710,11 +710,11 @@ papplScannerSetNextJobID( void papplScannerSetOrganization( - pappl_scanner_t *scanner, // I - Scanner - const char *value) // I - Organization name or `NULL` for none + pappl_scanner_t *scanner, // I - Scanner + const char *value) // I - Organization name or `NULL` for none { if (!scanner) - return; + return; _papplRWLockWrite(scanner); @@ -736,11 +736,11 @@ papplScannerSetOrganization( void papplScannerSetOrganizationalUnit( - pappl_scanner_t *scanner, // I - Scanner - const char *value) // I - Organizational unit name or `NULL` for none + pappl_scanner_t *scanner, // I - Scanner + const char *value) // I - Organizational unit name or `NULL` for none { if (!scanner) - return; + return; _papplRWLockWrite(scanner); @@ -765,12 +765,12 @@ papplScannerSetOrganizationalUnit( void papplScannerSetReasons( - pappl_scanner_t *scanner, // I - Scanner - pappl_sreason_t add, // I - "scanner-state-reasons" bit values to add or `PAPPL_SREASON_NONE` for none - pappl_sreason_t remove) // I - "scanner-state-reasons" bit values to remove or `PAPPL_SREASON_NONE` for none + pappl_scanner_t *scanner, // I - Scanner + pappl_sreason_t add, // I - "scanner-state-reasons" bit values to add or `PAPPL_SREASON_NONE` for none + pappl_sreason_t remove) // I - "scanner-state-reasons" bit values to remove or `PAPPL_SREASON_NONE` for none { if (!scanner) - return; + return; _papplRWLockWrite(scanner); From 40786982e029e9aeff4ecd7be182cc381b08503a Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Thu, 4 Jul 2024 21:33:05 +0000 Subject: [PATCH 11/26] Update: Implement scanner-driver.c for PAPPL This commit introduces a new file scanner-driver.c that contains the implementation of functions related to the scanner driver. Signed-off-by: Akarshan Kapoor --- pappl/Makefile | 3 + pappl/scanner-accessors.c | 10 +- pappl/scanner-driver.c | 206 ++++++++++++++++++++++++++++++++++++++ pappl/scanner-private.h | 17 ++-- pappl/scanner.h | 20 ++-- 5 files changed, 232 insertions(+), 24 deletions(-) create mode 100644 pappl/scanner-driver.c diff --git a/pappl/Makefile b/pappl/Makefile index 6410f0fb..4e1d23f9 100644 --- a/pappl/Makefile +++ b/pappl/Makefile @@ -9,6 +9,8 @@ include ../Makedefs +CFLAGS += $(shell pkg-config --cflags libxml-2.0) +LDFLAGS += $(shell pkg-config --libs libxml-2.0) BASEOBJS = \ client.o \ @@ -46,6 +48,7 @@ BASEOBJS = \ printer-webif.o \ resource.o \ scanner-accessors.o\ + scanner-driver.o \ snmp.o \ subscription.o \ subscription-ipp.o \ diff --git a/pappl/scanner-accessors.c b/pappl/scanner-accessors.c index 8f85289f..7a1feab5 100644 --- a/pappl/scanner-accessors.c +++ b/pappl/scanner-accessors.c @@ -31,7 +31,7 @@ papplScannerCloseDevice( { scanner->device_in_use = false; - if (scanner->state != PAPPL_SSTATE_PROCESSING) + if (scanner->state != ESCL_SSTATE_PROCESSING) { papplDeviceClose(scanner->device); scanner->device = NULL; @@ -396,7 +396,7 @@ escl_sstate_t // O - "scanner-state" value papplScannerGetState( pappl_scanner_t *scanner) // I - Scanner { - return (scanner ? scanner->state : PAPPL_SSTATE_STOPPED); + return (scanner ? scanner->state : ESCL_SSTATE_STOPPED); } @@ -519,7 +519,7 @@ papplScannerPause( if (scanner->processing_job) scanner->is_stopped = true; else - scanner->state = PAPPL_SSTATE_STOPPED; + scanner->state = ESCL_SSTATE_STOPPED; // _papplSystemAddEventNoLock(scanner->system, scanner, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED | PAPPL_EVENT_PRINTER_STOPPED, NULL); printf("Scanner State Changed and Scanner Paused\n"); @@ -543,7 +543,7 @@ papplScannerResume( _papplRWLockWrite(scanner); scanner->is_stopped = false; - scanner->state = PAPPL_SSTATE_IDLE; + scanner->state = ESCL_SSTATE_IDLE; // _papplSystemAddEventNoLock(scanner->system, scanner, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, "Resumed scanner."); printf("Scanner State Changed and Scanner Resumed \n"); @@ -780,5 +780,3 @@ papplScannerSetReasons( _papplRWUnlock(scanner); } - - diff --git a/pappl/scanner-driver.c b/pappl/scanner-driver.c new file mode 100644 index 00000000..58a47472 --- /dev/null +++ b/pappl/scanner-driver.c @@ -0,0 +1,206 @@ +// +// Printer driver functions for the Printer Application Framework +// +// Copyright © 2020-2024 by Michael R Sweet. +// +// Licensed under Apache License v2.0. See the file "LICENSE" for more +// information. +// + +#include "scanner-private.h" +#include "system-private.h" +#include +#include +// +// Local functions... +// + +// Declare the capability structure and the callback function +typedef struct { + char make_and_model[256]; + const char *document_formats_supported[PAPPL_MAX_FORMATS]; + pappl_sc_color_mode_t color_modes_supported[PAPPL_MAX_COLOR_MODES]; + int resolutions[MAX_RESOLUTIONS]; + pappl_sc_input_source_t input_sources_supported[PAPPL_MAX_SOURCES]; + bool duplex_supported; + float max_scan_area[2]; +} capability_t; + +capability_t *capability_cb(pappl_scanner_t *scanner); +const char *pappl_sc_color_mode_str(pappl_sc_color_mode_t mode); +const char *pappl_sc_input_source_str(pappl_sc_input_source_t source); + +// +// 'papplScannerGetDriverName()' - Get the driver name for a scanner. +// +// This function returns the driver name for the scanner. +// + +const char * // O - Driver name or `NULL` for none +papplScannerGetDriverName( + pappl_scanner_t *scanner) // I - Scanner +{ + return (scanner ? scanner->driver_name : NULL); +} + +// +// 'papplScannerGetDriverData()' - Get the current scan driver data. +// +// This function copies the current scan driver data. +// + +pappl_sc_driver_data_t * // O - Driver data or `NULL` if none +papplScannerGetDriverData( + pappl_scanner_t *scanner, // I - Scanner + pappl_sc_driver_data_t *data) // I - Pointer to driver data structure to fill +{ + if (!scanner || !scanner->driver_name || !data) + { + if (data) + _papplScannerInitDriverData(scanner, data); + + return (NULL); + } + memcpy(data, &scanner->driver_data, sizeof(pappl_sc_driver_data_t)); + + return (data); +} + +// +// '_papplScannerInitDriverData()' - Initialize a scan driver data structure. +// + +void +_papplScannerInitDriverData( + pappl_scanner_t *scanner, // I - Scanner + pappl_sc_driver_data_t *d) // I - Driver data +{ + capability_t *capability = capability_cb(scanner); + if (capability) + { + strncpy(d->make_and_model, capability->make_and_model, sizeof(d->make_and_model) - 1); + d->make_and_model[sizeof(d->make_and_model) - 1] = '\0'; // Ensure null-termination + + for (int i = 0; i < PAPPL_MAX_FORMATS && capability->document_formats_supported[i]; i++) + { + d->document_formats_supported[i] = capability->document_formats_supported[i]; + } + + for (int i = 0; i < PAPPL_MAX_COLOR_MODES && capability->color_modes_supported[i]; i++) + { + d->color_modes_supported[i] = capability->color_modes_supported[i]; + } + + for (int i = 0; i < MAX_RESOLUTIONS && capability->resolutions[i]; i++) + { + d->resolutions[i] = capability->resolutions[i]; + } + + for (int i = 0; i < PAPPL_MAX_SOURCES && capability->input_sources_supported[i]; i++) + { + d->input_sources_supported[i] = capability->input_sources_supported[i]; + } + + d->duplex_supported = capability->duplex_supported; + + d->max_scan_area[0] = capability->max_scan_area[0]; + d->max_scan_area[1] = capability->max_scan_area[1]; + + } +} + +// +// 'papplScannerSetDriverData()' - Set the driver data. +// +// This function validates and sets the driver data. +// +// + +bool // O - `true` on success, `false` on failure +papplScannerSetDriverData( + pappl_scanner_t *scanner, // I - Scanner + pappl_sc_driver_data_t *data) // I - Driver data +{ + if (!scanner || !data) + return (false); + + _papplRWLockWrite(scanner); + + memcpy(&scanner->driver_data, data, sizeof(scanner->driver_data)); + + _papplRWUnlock(scanner); + + return (true); +} + +xmlDocPtr make_escl_attr(pappl_scanner_t *scanner) +{ + xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); + xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST "eSCL"); + xmlDocSetRootElement(doc, root_node); + + capability_t *capability = capability_cb(scanner); + if (!capability) { + return doc; + } + + xmlNewChild(root_node, NULL, BAD_CAST "MakeAndModel", BAD_CAST capability->make_and_model); + + xmlNodePtr formats_node = xmlNewChild(root_node, NULL, BAD_CAST "DocumentFormatsSupported", NULL); + for (int i = 0; i < PAPPL_MAX_FORMATS && capability->document_formats_supported[i]; i++) { + xmlNewChild(formats_node, NULL, BAD_CAST "Format", BAD_CAST capability->document_formats_supported[i]); + } + + + xmlNodePtr color_modes_node = xmlNewChild(root_node, NULL, BAD_CAST "ColorModesSupported", NULL); + for (int i = 0; i < PAPPL_MAX_COLOR_MODES && capability->color_modes_supported[i]; i++) { + xmlNewChild(color_modes_node, NULL, BAD_CAST "ColorMode", BAD_CAST pappl_sc_color_mode_str(capability->color_modes_supported[i])); + } + + xmlNodePtr resolutions_node = xmlNewChild(root_node, NULL, BAD_CAST "Resolutions", NULL); + for (int i = 0; i < MAX_RESOLUTIONS && capability->resolutions[i]; i++) { + char resolution_str[10]; + snprintf(resolution_str, sizeof(resolution_str), "%d", capability->resolutions[i]); + xmlNewChild(resolutions_node, NULL, BAD_CAST "Resolution", BAD_CAST resolution_str); + } + + xmlNodePtr input_sources_node = xmlNewChild(root_node, NULL, BAD_CAST "InputSourcesSupported", NULL); + for (int i = 0; i < PAPPL_MAX_SOURCES && capability->input_sources_supported[i]; i++) { + xmlNewChild(input_sources_node, NULL, BAD_CAST "InputSource", BAD_CAST pappl_sc_input_source_str(capability->input_sources_supported[i])); + } + + xmlNewChild(root_node, NULL, BAD_CAST "DuplexSupported", BAD_CAST (capability->duplex_supported ? "true" : "false")); + + xmlNodePtr max_scan_area_node = xmlNewChild(root_node, NULL, BAD_CAST "MaxScanArea", NULL); + char max_scan_width[10], max_scan_height[10]; + snprintf(max_scan_width, sizeof(max_scan_width), "%.2f", capability->max_scan_area[0]); + snprintf(max_scan_height, sizeof(max_scan_height), "%.2f", capability->max_scan_area[1]); + xmlNewChild(max_scan_area_node, NULL, BAD_CAST "Width", BAD_CAST max_scan_width); + xmlNewChild(max_scan_area_node, NULL, BAD_CAST "Height", BAD_CAST max_scan_height); + + return doc; +} + +const char *pappl_sc_color_mode_str(pappl_sc_color_mode_t mode) { + switch (mode) { + case PAPPL_BLACKANDWHITE1: + return "BlackAndWhite"; + case PAPPL_GRAYSCALE8: + return "Grayscale"; + case PAPPL_RGB24: + return "RGB"; + default: + return "Unknown"; + } +} + +const char *pappl_sc_input_source_str(pappl_sc_input_source_t source) { + switch (source) { + case PAPPL_FLATBED: + return "Flatbed"; + case PAPPL_ADF: + return "ADF"; + default: + return "Unknown"; + } +} diff --git a/pappl/scanner-private.h b/pappl/scanner-private.h index 6ac78660..5abc5974 100644 --- a/pappl/scanner-private.h +++ b/pappl/scanner-private.h @@ -12,7 +12,6 @@ # define _PAPPL_SCANNER_PRIVATE_H_ # include "dnssd-private.h" # include "scanner.h" // Changed to Scanner.h -# include "printer.h" // Check later # include "log.h" # ifdef __APPLE__ # include @@ -36,19 +35,19 @@ struct _pappl_scanner_s // Scanner data { - pthread_rwlock_t rwlock; // Reader/writer lock + pthread_rwlock_t rwlock; // Reader/writer lock pappl_system_t *system; // Containing system int scanner_id; // "scanner-id" value char *name, // "scanner-name" value *dns_sd_name, // "scanner-dns-sd-name" value - *location, // "scanner-location" value - *geo_location, // "scanner-geo-location" value (geo: URI) - *organization, // "scanner-organization" value - *org_unit; // "scanner-organizational-unit" value - pappl_contact_t contact; // "scanner-contact" value + *location, // "scanner-location" value + *geo_location, // "scanner-geo-location" value (geo: URI) + *organization, // "scanner-organization" value + *org_unit; // "scanner-organizational-unit" value + pappl_contact_t contact; // "scanner-contact" value char *resource; // Resource path of scanner size_t resourcelen; // Length of resource path - char *uriname; // Name for URLs + char *uriname; // Name for URLs escl_sstate_t state; // "scanner-state" value --> Replacement for ipp_pstate_t pappl_sreason_t state_reasons; // "scanner-state-reasons" values --> Replacement for pappl_preason_t time_t state_time; // "scanner-state-change-time" value @@ -83,7 +82,7 @@ struct _pappl_scanner_s // Scanner data // extern void _papplScannerDelete(pappl_scanner_t *scanner) _PAPPL_PRIVATE; -extern void _papplScannerInitDriverData(pappl_sc_driver_data_t *d) _PAPPL_PRIVATE; +extern void _papplScannerInitDriverData(pappl_scanner_t *scanner, pappl_sc_driver_data_t *d) _PAPPL_PRIVATE; extern bool _papplScannerIsAuthorized(pappl_client_t *client) _PAPPL_PRIVATE; extern void _papplScannerProcessESCL(pappl_client_t *client) _PAPPL_PRIVATE; extern bool _papplScannerRegisterDNSSDNoLock(pappl_scanner_t *scanner) _PAPPL_PRIVATE; diff --git a/pappl/scanner.h b/pappl/scanner.h index fda853ba..a20dee8e 100644 --- a/pappl/scanner.h +++ b/pappl/scanner.h @@ -23,21 +23,23 @@ extern "C" { #define PAPPL_MAX_SOURCES 2 // MOST scanners offer two input sources: Flatbed and ADF #define PAPPL_MAX_COLOR_SPACES 2 // Common color spaces like sRGB and AdobeRGB #define PAPPL_MAX_MEDIA_TYPES 5 // Various media types like Plain, Photo, Card, etc. +#define MAX_RESOLUTIONS 5 // // Constants... // -typedef enum +typedef enum { - PAPPL_SSTATE_IDLE, // Scanner is idle - PAPPL_SSTATE_PROCESSING, // Scanner is busy with some job or activity - PAPPL_SSTATE_TESTING, // Scanner is calibrating, preparing the unit - PAPPL_SSTATE_STOPPED, // Scanner stopped due to an error condition - PAPPL_SSTATE_DOWN // Scanner is unavailable + ESCL_SSTATE_IDLE, // Scanner is idle + ESCL_SSTATE_PROCESSING, // Scanner is busy with some job or activity + ESCL_SSTATE_TESTING, // Scanner is calibrating, preparing the unit + ESCL_SSTATE_STOPPED, // Scanner stopped due to an error condition + ESCL_SSTATE_DOWN // Scanner is unavailable } escl_sstate_t; -typedef enum +// Update in the future to include more reasons +typedef enum { PAPPL_SREASON_NONE = 0x0000, // 'none', no error, scanner is ready PAPPL_SREASON_IDLE = 0x0001, // 'idle', scanner is idle @@ -63,7 +65,7 @@ typedef enum { // // Callback functions... // -typedef void (*pappl_sc_capabilities_cb_t)(pappl_scanner_t *scanner, pappl_sc_driver_data_t *data); // Callback for getting scanner capabilities +typedef void (*pappl_sc_capabilities_cb_t)(pappl_scanner_t *scanner); // Callback for getting scanner capabilities typedef void (*pappl_sc_job_create_cb_t)(pappl_job_t *job, pappl_sc_options_t *options, pappl_device_t *device); // Callback for creating a scan job typedef void (*pappl_sc_job_delete_cb_t)(pappl_job_t *job); // Callback for deleting a scan job typedef bool (*pappl_sc_data_cb_t)(pappl_job_t *job, pappl_device_t *device, void *buffer, size_t bufsize); // Callback for getting scan data @@ -113,7 +115,7 @@ typedef struct pappl_sc_driver_data_s char make_and_model[128]; // Make and model of the scanner const char *document_formats_supported[PAPPL_MAX_FORMATS]; // Supported document formats (JPEG, PDF, TIFF) pappl_sc_color_mode_t color_modes_supported[PAPPL_MAX_COLOR_MODES]; // Supported color modes (BlackAndWhite1, Grayscale8, RGB24) - int max_resolution; // Maximum optical resolution in DPI + int resolutions[MAX_RESOLUTIONS]; // All optical resolution in DPI pappl_sc_input_source_t input_sources_supported[PAPPL_MAX_SOURCES]; // Supported input sources (Platen, Feeder) bool duplex_supported; // Duplex (double-sided) scanning support const char *color_spaces_supported[PAPPL_MAX_COLOR_SPACES]; // Supported color spaces (sRGB, AdobeRGB) From 363a7fcc923893f57894a9018efe066900b95b7e Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Sun, 7 Jul 2024 12:57:24 +0000 Subject: [PATCH 12/26] Update Scanner.h to closely follow specifications This commit updates Scanner.h to closely follow the Mopria Scan specifications. We should now have a very detailed implementaion of scanner.h that closely follows the structure of printer.h while also following the Mopria Scan specifications. Signed-off-by: Akarshan Kapoor --- pappl/scanner.h | 87 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 28 deletions(-) diff --git a/pappl/scanner.h b/pappl/scanner.h index a20dee8e..36306e99 100644 --- a/pappl/scanner.h +++ b/pappl/scanner.h @@ -1,7 +1,7 @@ // // Public scanner header file for the Scanner Application Framework // -// Copyright © 2019-2022 by Michael R Sweet. +// Copyright © 2019-2024 by Michael R Sweet. // // Licensed under Apache License v2.0. See the file "LICENSE" for more // information. @@ -14,11 +14,10 @@ extern "C" { # endif // __cplusplus - // // Limits... // -#define PAPPL_MAX_FORMATS 5 // Most scanners support up to 5 different document formats +#define PAPPL_MAX_FORMATS 5 // Most scanners support a variety of document formats such as JPEG, PDF, TIFF, PNG, and BMP. #define PAPPL_MAX_COLOR_MODES 3 // Most scanners support a few color modes: Black and White, Grayscale, Color #define PAPPL_MAX_SOURCES 2 // MOST scanners offer two input sources: Flatbed and ADF #define PAPPL_MAX_COLOR_SPACES 2 // Common color spaces like sRGB and AdobeRGB @@ -29,6 +28,9 @@ extern "C" { // Constants... // +// This defines the overall state of the scanner. It describes the scanner's operational state, +// focusing on what the scanner is currently doing or its readiness to perform tasks. +// The states are mutually exclusive, meaning the scanner can be in only one of these states at a time. typedef enum { ESCL_SSTATE_IDLE, // Scanner is idle @@ -38,7 +40,9 @@ typedef enum ESCL_SSTATE_DOWN // Scanner is unavailable } escl_sstate_t; -// Update in the future to include more reasons +// This defines specific reasons for the scanner's state. These reasons can provide more detailed +// information about why the scanner is in its current state. Multiple reasons can be combined using +// bitwise operations, which means the scanner can have multiple reasons for being in a particular state at the same time. typedef enum { PAPPL_SREASON_NONE = 0x0000, // 'none', no error, scanner is ready @@ -70,57 +74,84 @@ typedef void (*pappl_sc_job_create_cb_t)(pappl_job_t *job, pappl_sc_options_t *o typedef void (*pappl_sc_job_delete_cb_t)(pappl_job_t *job); // Callback for deleting a scan job typedef bool (*pappl_sc_data_cb_t)(pappl_job_t *job, pappl_device_t *device, void *buffer, size_t bufsize); // Callback for getting scan data typedef bool (*pappl_sc_status_cb_t)(pappl_scanner_t *scanner); // Callback for getting scanner status +typedef void (*pappl_sc_job_complete_cb_t)(pappl_job_t *job); // Callback for completing a scan job typedef bool (*pappl_sc_job_cancel_cb_t)(pappl_job_t *job); // Callback for cancelling a scan job typedef void (*pappl_sc_buffer_info_cb_t)(pappl_job_t *job, pappl_sc_options_t *options, pappl_device_t *device); // Callback for getting buffer information -typedef void (*pappl_sc_image_info_cb_t)(pappl_job_t *job, pappl_device_t *device, void *data); // Callback for getting image information +typedef void (*pappl_sc_image_info_cb_t)(pappl_job_t *job, pappl_device_t *device, void *data); // Callback for getting scan image information // // Structures // -typedef struct pappl_sc_options_s // Combined scan job options +typedef struct pappl_icon_sc_s // Scanner PNG icon structure +{ + char filename[256]; // External filename, if any + const void *data; // PNG icon data, if any + size_t datalen; // Size of PNG icon data +} pappl_icon_sc_t; + +typedef struct pappl_sc_options_s // Provides scan job options for the user after we have fetched the scanner driver data { - char document_format[64]; // Desired output format (JPEG, PDF, TIFF) - pappl_sc_color_mode_t color_mode; // Color mode for the scan - int resolution; // Scanning resolution in DPI - pappl_sc_input_source_t input_source; // Selected input source - bool duplex; // Duplex scanning option + char document_format[64]; // Desired output format (JPEG, PDF, TIFF, PNG, BMP) + pappl_sc_color_mode_t color_mode; // Color mode for the scan + int resolution; // Scanning resolution in DPI + pappl_sc_input_source_t input_source; // Selected input source + bool duplex; // Duplex scanning option + char intent[64]; // Scan intent (e.g., Document, Photo, Preview, etc.) struct { - int width; // Width of the scan area - int height; // Height of the scan area - int x_offset; // X offset for the scan area - int y_offset; // Y offset for the scan area + int width; // Width of the scan area + int height; // Height of the scan area + int x_offset; // X offset for the scan area + int y_offset; // Y offset for the scan area } scan_area; struct { - int brightness; // Brightness adjustment - int contrast; // Contrast adjustment - int gamma; // Gamma adjustment - int threshold; // Threshold for black/white scans + int brightness; // Brightness adjustment + int contrast; // Contrast adjustment + int gamma; // Gamma adjustment + int threshold; // Threshold for black/white scans + int saturation; // Saturation adjustment + int sharpness; // Sharpness adjustment } adjustments; - bool blank_page_removal; // Automatically detect and remove blank pages - unsigned num_pages; // Number of pages to scan (for ADF) + bool blank_page_removal; // Automatically detect and remove blank pages + unsigned num_pages; // Number of pages to scan (for ADF) + int compression_factor; // Compression factor for the scan + bool noise_removal; // Noise removal option + bool sharpening; // Sharpening option } pappl_sc_options_t; -typedef struct pappl_sc_driver_data_s +typedef struct pappl_sc_driver_data_s // Initially polling the scanner driver for capabilities and settings { pappl_sc_capabilities_cb_t capabilities_cb; // Callback for getting scanner capabilities pappl_sc_job_create_cb_t job_create_cb; // Callback for creating a scan job pappl_sc_job_delete_cb_t job_delete_cb; // Callback for deleting a scan job pappl_sc_data_cb_t data_cb; // Callback for getting scan data pappl_sc_status_cb_t status_cb; // Callback for getting scanner status + pappl_sc_job_complete_cb_t job_complete_cb; // Callback for completing a scan job pappl_sc_job_cancel_cb_t job_cancel_cb; // Callback for cancelling a scan job pappl_sc_buffer_info_cb_t buffer_info_cb; // Callback for getting buffer information pappl_sc_image_info_cb_t image_info_cb; // Callback for getting image information - char make_and_model[128]; // Make and model of the scanner - const char *document_formats_supported[PAPPL_MAX_FORMATS]; // Supported document formats (JPEG, PDF, TIFF) + char make_and_model[128]; // Make and model of the scanner + const char *document_formats_supported[PAPPL_MAX_FORMATS]; // Supported document formats (JPEG, PDF, TIFF, PNG, BMP) pappl_sc_color_mode_t color_modes_supported[PAPPL_MAX_COLOR_MODES]; // Supported color modes (BlackAndWhite1, Grayscale8, RGB24) - int resolutions[MAX_RESOLUTIONS]; // All optical resolution in DPI - pappl_sc_input_source_t input_sources_supported[PAPPL_MAX_SOURCES]; // Supported input sources (Platen, Feeder) - bool duplex_supported; // Duplex (double-sided) scanning support + int resolutions[MAX_RESOLUTIONS]; // All optical resolutions in DPI + pappl_sc_input_source_t input_sources_supported[PAPPL_MAX_SOURCES]; // Supported input sources (Flatbed, ADF) + bool duplex_supported; // Duplex (double-sided) scanning support const char *color_spaces_supported[PAPPL_MAX_COLOR_SPACES]; // Supported color spaces (sRGB, AdobeRGB) - int max_scan_area[2]; // Maximum scan area size (width, height) + int max_scan_area[2]; // Maximum scan area size (width, height) const char *media_type_supported[PAPPL_MAX_MEDIA_TYPES]; // Types of media that can be scanned (Plain, Photo, Card) + int default_resolution; // Default scanning resolution + pappl_sc_color_mode_t default_color_mode; // Default color mode + pappl_sc_input_source_t default_input_source; // Default input source + int scan_region_supported[4]; // Supported scan regions (top, left, width, height) + const char *mandatory_intents[5]; // Mandatory intents supported by the scanner (e.g., Document, Photo, TextAndGraphic, Preview, BusinessCard) + const char *optional_intents[5]; // Optional intents supported by the scanner (e.g., Object, CustomIntent) + bool compression_supported; // Whether compression is supported + bool noise_removal_supported; // Whether noise removal is supported + bool sharpness_supported; // Whether sharpness adjustment is supported + int compression_factor_supported; // Supported compression factors + bool binary_rendering_supported; // Whether binary rendering is supported + const char *feed_direction_supported[2]; // Supported feed directions (e.g., LeftToRight, RightToLeft) } pappl_sc_driver_data_t; // From 67762688bfbe61f68fac320d4782445fb2492e72 Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Sun, 7 Jul 2024 13:31:07 +0000 Subject: [PATCH 13/26] Update scanner-private.h This commit adds some basic features to closely follow the printer-private.h file. The updated scanner-private.h should be the final version of this file (for now). Signed-off-by: Akarshan Kapoor --- pappl/scanner-private.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pappl/scanner-private.h b/pappl/scanner-private.h index 5abc5974..2be0b97e 100644 --- a/pappl/scanner-private.h +++ b/pappl/scanner-private.h @@ -33,7 +33,7 @@ // Types and structures... // -struct _pappl_scanner_s // Scanner data +struct _pappl_scanner_s // Scanner data that get configured when a scanning job is configured { pthread_rwlock_t rwlock; // Reader/writer lock pappl_system_t *system; // Containing system @@ -48,6 +48,7 @@ struct _pappl_scanner_s // Scanner data char *resource; // Resource path of scanner size_t resourcelen; // Length of resource path char *uriname; // Name for URLs + char *uuid; // UUID for the scanner escl_sstate_t state; // "scanner-state" value --> Replacement for ipp_pstate_t pappl_sreason_t state_reasons; // "scanner-state-reasons" values --> Replacement for pappl_preason_t time_t state_time; // "scanner-state-change-time" value @@ -87,6 +88,10 @@ extern bool _papplScannerIsAuthorized(pappl_client_t *client) _PAPPL_PRIVATE; extern void _papplScannerProcessESCL(pappl_client_t *client) _PAPPL_PRIVATE; extern bool _papplScannerRegisterDNSSDNoLock(pappl_scanner_t *scanner) _PAPPL_PRIVATE; extern void _papplScannerUnregisterDNSSDNoLock(pappl_scanner_t *scanner) _PAPPL_PRIVATE; + +extern const char *_papplScannerColorModeString(pappl_sc_color_mode_t value) _PAPPL_PRIVATE; +extern pappl_sc_color_mode_t _papplScannerColorModeValue(const char *value) _PAPPL_PRIVATE; + extern void _papplScannerWebConfig(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; extern void _papplScannerWebConfigFinalize(pappl_scanner_t *scanner, cups_len_t num_form, cups_option_t *form) _PAPPL_PRIVATE; extern void _papplScannerWebDefaults(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; From 7dd8e3b46210c37633c37e7aa3c2e3f6144d7e25 Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Sun, 7 Jul 2024 19:32:35 +0000 Subject: [PATCH 14/26] Update scanner-accessors.c with Proper System Call - Implemented scanner-specific event handling and introduced new events for scanner operations. - Added `scanner-escl.c` for eSCL-specific scanner state management. - Modified `job-process.c`, `job.c`, `printer-accessors.c`, and `scanner-accessors.c` to integrate scanner event functions. - Updated `system-subscription.c` to support scanner events and added `papplSystemAddScannerEvent`. - Enhanced `system-private.h` and `subscription.h` with new scanner event types and callback definitions. - Included necessary changes in `Makefile` and other system-related files for compatibility. Signed-off-by: Akarshan Kapoor --- pappl/Makefile | 1 + pappl/job-process.c | 10 +-- pappl/job.c | 6 +- pappl/printer-accessors.c | 8 +- pappl/scanner-accessors.c | 15 ++-- pappl/scanner-escl.c | 93 +++++++++++++++++++++++ pappl/scanner-private.h | 2 + pappl/subscription-private.h | 1 + pappl/subscription.h | 13 +++- pappl/system-accessors.c | 16 ++++ pappl/system-private.h | 10 ++- pappl/system-subscription.c | 140 ++++++++++++++++++++++++----------- pappl/system.h | 1 + 13 files changed, 248 insertions(+), 68 deletions(-) create mode 100644 pappl/scanner-escl.c diff --git a/pappl/Makefile b/pappl/Makefile index 4e1d23f9..288a38b8 100644 --- a/pappl/Makefile +++ b/pappl/Makefile @@ -49,6 +49,7 @@ BASEOBJS = \ resource.o \ scanner-accessors.o\ scanner-driver.o \ + scanner-escl.o \ snmp.o \ subscription.o \ subscription-ipp.o \ diff --git a/pappl/job-process.c b/pappl/job-process.c index e73b31e5..435efa0b 100644 --- a/pappl/job-process.c +++ b/pappl/job-process.c @@ -1076,7 +1076,7 @@ finish_job(pappl_job_t *job) // I - Job if (job->state >= IPP_JSTATE_CANCELED && !printer->max_preserved_jobs && !job->retain_until) _papplJobRemoveFile(job); - _papplSystemAddEventNoLock(job->system, job->printer, job, PAPPL_EVENT_JOB_COMPLETED, NULL); + _papplSystemAddEventNoLock(job->system, job->printer, NULL, job, PAPPL_EVENT_JOB_COMPLETED, NULL); if (printer->is_stopped) { @@ -1102,7 +1102,7 @@ finish_job(pappl_job_t *job) // I - Job _papplRWUnlock(job); - _papplSystemAddEventNoLock(printer->system, printer, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, NULL); + _papplSystemAddEventNoLock(printer->system, printer, NULL, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, NULL); if (printer->max_preserved_jobs > 0) _papplPrinterCleanJobsNoLock(printer); @@ -1166,7 +1166,7 @@ start_job(pappl_job_t *job) // I - Job job->processing = time(NULL); printer->processing_job = job; - _papplSystemAddEventNoLock(printer->system, printer, job, PAPPL_EVENT_JOB_STATE_CHANGED, NULL); + _papplSystemAddEventNoLock(printer->system, printer, NULL, job, PAPPL_EVENT_JOB_STATE_CHANGED, NULL); _papplRWUnlock(job); @@ -1216,7 +1216,7 @@ start_job(pappl_job_t *job) // I - Job job->state = IPP_JSTATE_PENDING; _papplRWLockRead(job); - _papplSystemAddEventNoLock(job->system, job->printer, job, PAPPL_EVENT_JOB_STATE_CHANGED, NULL); + _papplSystemAddEventNoLock(job->system, job->printer, NULL, job, PAPPL_EVENT_JOB_STATE_CHANGED, NULL); _papplRWUnlock(job); if (printer->device) @@ -1234,7 +1234,7 @@ start_job(pappl_job_t *job) // I - Job ret = true; } - _papplSystemAddEventNoLock(printer->system, printer, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, NULL); + _papplSystemAddEventNoLock(printer->system, printer, NULL, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, NULL); _papplRWUnlock(printer); diff --git a/pappl/job.c b/pappl/job.c index d943eb5c..97704911 100644 --- a/pappl/job.c +++ b/pappl/job.c @@ -408,7 +408,7 @@ _papplJobHoldNoLock( if (username) { - _papplSystemAddEventNoLock(job->system, job->printer, job, PAPPL_EVENT_JOB_STATE_CHANGED, "Job held by '%s'.", username); + _papplSystemAddEventNoLock(job->system, job->printer, NULL, job, PAPPL_EVENT_JOB_STATE_CHANGED, "Job held by '%s'.", username); } return (true); @@ -583,7 +583,7 @@ _papplJobReleaseNoLock( ippDeleteAttribute(job->attrs, attr); if (username) - _papplSystemAddEventNoLock(job->system, job->printer, job, PAPPL_EVENT_JOB_STATE_CHANGED, "Job released by '%s'.", username); + _papplSystemAddEventNoLock(job->system, job->printer, NULL, job, PAPPL_EVENT_JOB_STATE_CHANGED, "Job released by '%s'.", username); } @@ -704,7 +704,7 @@ _papplJobRetainNoLock( if (username) { - _papplSystemAddEventNoLock(job->system, job->printer, job, PAPPL_EVENT_JOB_CONFIG_CHANGED, "Job retain set by '%s'.", username); + _papplSystemAddEventNoLock(job->system, job->printer, NULL, job, PAPPL_EVENT_JOB_CONFIG_CHANGED, "Job retain set by '%s'.", username); } return (true); diff --git a/pappl/printer-accessors.c b/pappl/printer-accessors.c index d8cef8dd..6fc86ebe 100644 --- a/pappl/printer-accessors.c +++ b/pappl/printer-accessors.c @@ -649,7 +649,7 @@ papplPrinterHoldNewJobs( ret = true; // Notify of the change in state... - _papplSystemAddEventNoLock(printer->system, printer, NULL, PAPPL_EVENT_PRINTER_CONFIG_CHANGED, "Holding new jobs."); + _papplSystemAddEventNoLock(printer->system, printer, NULL, NULL, PAPPL_EVENT_PRINTER_CONFIG_CHANGED, "Holding new jobs."); } _papplRWUnlock(printer); @@ -942,7 +942,7 @@ papplPrinterPause( else printer->state = IPP_PSTATE_STOPPED; - _papplSystemAddEventNoLock(printer->system, printer, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED | PAPPL_EVENT_PRINTER_STOPPED, NULL); + _papplSystemAddEventNoLock(printer->system, printer, NULL, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED | PAPPL_EVENT_PRINTER_STOPPED, NULL); _papplRWUnlock(printer); } @@ -979,7 +979,7 @@ papplPrinterReleaseHeldNewJobs( printer->config_time = time(NULL); ret = true; - _papplSystemAddEventNoLock(printer->system, printer, NULL, PAPPL_EVENT_PRINTER_CONFIG_CHANGED, "Releasing held new jobs."); + _papplSystemAddEventNoLock(printer->system, printer, NULL, NULL, PAPPL_EVENT_PRINTER_CONFIG_CHANGED, "Releasing held new jobs."); for (job = (pappl_job_t *)cupsArrayGetFirst(printer->active_jobs); job; job = (pappl_job_t *)cupsArrayGetNext(printer->active_jobs)) { @@ -1022,7 +1022,7 @@ papplPrinterResume( printer->is_stopped = false; printer->state = IPP_PSTATE_IDLE; - _papplSystemAddEventNoLock(printer->system, printer, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, "Resumed printer."); + _papplSystemAddEventNoLock(printer->system, printer, NULL, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, "Resumed printer."); _papplPrinterCheckJobsNoLock(printer); diff --git a/pappl/scanner-accessors.c b/pappl/scanner-accessors.c index 7a1feab5..7a87c790 100644 --- a/pappl/scanner-accessors.c +++ b/pappl/scanner-accessors.c @@ -54,8 +54,7 @@ papplScannerDisable( if (scanner) { scanner->is_accepting = false; - // papplSystemAddEvent(scanner->system, scanner, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, NULL); - printf("Scanner State Changed\n"); + papplSystemAddScannerEvent(scanner->system, scanner, NULL, PAPPL_EVENT_SCANNER_STATE_CHANGED, NULL); } } @@ -72,8 +71,7 @@ papplScannerEnable( if (scanner) { scanner->is_accepting = true; - // papplSystemAddEvent(scanner->system, scanner, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, NULL); - printf("Scanner State Changed\n"); + papplSystemAddScannerEvent(scanner->system, scanner, NULL, PAPPL_EVENT_SCANNER_STATE_CHANGED, NULL); } } @@ -521,8 +519,7 @@ papplScannerPause( else scanner->state = ESCL_SSTATE_STOPPED; -// _papplSystemAddEventNoLock(scanner->system, scanner, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED | PAPPL_EVENT_PRINTER_STOPPED, NULL); - printf("Scanner State Changed and Scanner Paused\n"); + papplSystemAddScannerEvent(scanner->system, scanner, NULL, PAPPL_EVENT_SCANNER_STATE_CHANGED | PAPPL_EVENT_SCANNER_STOPPED, NULL); _papplRWUnlock(scanner); } @@ -538,19 +535,19 @@ papplScannerResume( pappl_scanner_t *scanner) // I - Scanner { if (!scanner) - return; + return; _papplRWLockWrite(scanner); scanner->is_stopped = false; scanner->state = ESCL_SSTATE_IDLE; -// _papplSystemAddEventNoLock(scanner->system, scanner, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, "Resumed scanner."); - printf("Scanner State Changed and Scanner Resumed \n"); + papplSystemAddScannerEvent(scanner->system, scanner, NULL, PAPPL_EVENT_SCANNER_STATE_CHANGED, "Resumed scanner."); _papplRWUnlock(scanner); } + // // 'papplScannerSetContact()' - Set the "scanner-contact" value. // diff --git a/pappl/scanner-escl.c b/pappl/scanner-escl.c new file mode 100644 index 00000000..c18178b2 --- /dev/null +++ b/pappl/scanner-escl.c @@ -0,0 +1,93 @@ +#include "scanner-private.h" +#include "client-private.h" +#include +#include +#include +#include +#include +#include +#include + +// _papplScannerReasonString() - Convert a scanner state reason value to a string. +const char * +_papplScannerReasonString(pappl_sreason_t reason) +{ + switch (reason) + { + case PAPPL_SREASON_NONE: + return "none"; + case PAPPL_SREASON_IDLE: + return "idle"; + case PAPPL_SREASON_PROCESSING: + return "processing"; + case PAPPL_SREASON_TESTING: + return "testing"; + case PAPPL_SREASON_STOPPED: + return "stopped"; + case PAPPL_SREASON_DOWN: + return "down"; + default: + return "unknown"; + } +} + +void +_papplScannerCopyStateNoLock( + pappl_scanner_t *scanner, // I - Scanner + ipp_tag_t group_tag, // I - Group tag + ipp_t *ipp, // I - IPP message + pappl_client_t *client, // I - Client connection + cups_array_t *ra) // I - Requested attributes +{ + if (!ra || cupsArrayFind(ra, "scanner-is-accepting-jobs")) + ippAddBoolean(ipp, group_tag, "scanner-is-accepting-jobs", scanner->is_accepting); + + if (!ra || cupsArrayFind(ra, "scanner-state")) + ippAddInteger(ipp, group_tag, IPP_TAG_ENUM, "scanner-state", (int)scanner->state); + + if (!ra || cupsArrayFind(ra, "scanner-state-message")) + { + static const char * const messages[] = { "Idle.", "Scanning.", "Stopped." }; + + ippAddString(ipp, group_tag, IPP_CONST_TAG(IPP_TAG_TEXT), "scanner-state-message", NULL, messages[scanner->state - ESCL_SSTATE_IDLE]); + } + + if (!ra || cupsArrayFind(ra, "scanner-state-reasons")) + { + ipp_attribute_t *attr = NULL; // scanner-state-reasons + + if (scanner->state_reasons == PAPPL_SREASON_NONE) + { + if (scanner->is_stopped) + attr = ippAddString(ipp, group_tag, IPP_CONST_TAG(IPP_TAG_KEYWORD), "scanner-state-reasons", NULL, "moving-to-paused"); + else if (scanner->state == ESCL_SSTATE_STOPPED) + attr = ippAddString(ipp, group_tag, IPP_CONST_TAG(IPP_TAG_KEYWORD), "scanner-state-reasons", NULL, "paused"); + + if (!attr) + ippAddString(ipp, group_tag, IPP_CONST_TAG(IPP_TAG_KEYWORD), "scanner-state-reasons", NULL, "none"); + } + else + { + pappl_sreason_t bit; // Reason bit + + for (bit = PAPPL_SREASON_IDLE; bit <= PAPPL_SREASON_DOWN; bit *= 2) + { + if (scanner->state_reasons & bit) + { + if (attr) + ippSetString(ipp, &attr, ippGetCount(attr), _papplScannerReasonString(bit)); + else + attr = ippAddString(ipp, group_tag, IPP_CONST_TAG(IPP_TAG_KEYWORD), "scanner-state-reasons", NULL, _papplScannerReasonString(bit)); + } + } + + if (scanner->is_stopped) + ippSetString(ipp, &attr, ippGetCount(attr), "moving-to-paused"); + else if (scanner->state == ESCL_SSTATE_STOPPED) + ippSetString(ipp, &attr, ippGetCount(attr), "paused"); + } + } + + ippAddInteger(ipp, group_tag, IPP_TAG_INTEGER, "scanner-state-change-time", (int)(scanner->state_time)); + ippAddInteger(ipp, group_tag, IPP_TAG_INTEGER, "scanner-up-time", (int)(time(NULL) - scanner->start_time)); +} diff --git a/pappl/scanner-private.h b/pappl/scanner-private.h index 2be0b97e..9f221386 100644 --- a/pappl/scanner-private.h +++ b/pappl/scanner-private.h @@ -81,6 +81,8 @@ struct _pappl_scanner_s // Scanner data that get configured when a scanning jo // // Functions... // +extern void _papplScannerCopyStateNoLock(pappl_scanner_t *scanner, ipp_tag_t group_tag, ipp_t *ipp, pappl_client_t *client, cups_array_t *ra) _PAPPL_PRIVATE; +extern const char *_papplScannerReasonString(pappl_sreason_t reason) _PAPPL_PRIVATE; extern void _papplScannerDelete(pappl_scanner_t *scanner) _PAPPL_PRIVATE; extern void _papplScannerInitDriverData(pappl_scanner_t *scanner, pappl_sc_driver_data_t *d) _PAPPL_PRIVATE; diff --git a/pappl/subscription-private.h b/pappl/subscription-private.h index a76b9382..855ad415 100644 --- a/pappl/subscription-private.h +++ b/pappl/subscription-private.h @@ -38,6 +38,7 @@ struct _pappl_subscription_s // Subscription data # endif // DEBUG pappl_event_t mask; // IPP "notify-events" bit field pappl_printer_t *printer; // Printer, if any + pappl_scanner_t *scanner; // Scanner, if any pappl_job_t *job; // Job, if any ipp_t *attrs; // Attributes char *language, // Language for notifications diff --git a/pappl/subscription.h b/pappl/subscription.h index 1182dd27..1312c32a 100644 --- a/pappl/subscription.h +++ b/pappl/subscription.h @@ -103,11 +103,20 @@ enum pappl_event_e // IPP "notify-events" bit values // All 'printer-xxx' configuration events PAPPL_EVENT_PRINTER_STATE_ALL = 0x001e0000, // All 'printer-xxx' state events - PAPPL_EVENT_ALL = 0x7fffffff // All events + PAPPL_EVENT_ALL = 0x7fffffff, // All events + + // New scanner-specific events + PAPPL_EVENT_SCANNER_CONFIG_CHANGED = 0x80000000, // 'scanner-config-changed' + PAPPL_EVENT_SCANNER_STATE_CHANGED = 0x100000000, // 'scanner-state-changed' + PAPPL_EVENT_SCANNER_STOPPED = 0x600000000, // 'scanner-stopped', + PAPPL_EVENT_SCANNER_ALL = 0x180000000 // All 'scanner' events + }; -typedef unsigned int pappl_event_t; // Bitfield for IPP "notify-events" attribute +typedef unsigned long long int pappl_event_t; // Bitfield for IPP/ESCL "notify-events" attribute typedef void (*pappl_event_cb_t)(pappl_system_t *system, pappl_printer_t *printer, pappl_job_t *job, pappl_event_t event, void *data); // System event callback +typedef void (*pappl_scanner_event_cb_t)(pappl_system_t *system, pappl_scanner_t *scanner, pappl_job_t *job, pappl_event_t event, void *data); + // System scanner event callback // diff --git a/pappl/system-accessors.c b/pappl/system-accessors.c index f18236f7..6d6e8c34 100644 --- a/pappl/system-accessors.c +++ b/pappl/system-accessors.c @@ -1725,6 +1725,22 @@ papplSystemSetEventCallback( } } +void +papplSystemSetScanEventCallback( + pappl_system_t *system, // I - System + pappl_scanner_event_cb_t scan_event_cb, // I - Event callback function + void *scan_event_data) // I - Event callback data +{ + if (system && scan_event_cb) + { + _papplRWLockWrite(system); + + system->scan_event_cb = scan_event_cb; + system->scan_event_data = scan_event_data; + + _papplRWUnlock(system); + } +} // // 'papplSystemSetFooterHTML()' - Set the footer HTML for the web interface. diff --git a/pappl/system-private.h b/pappl/system-private.h index e16a3b55..9bb4abd5 100644 --- a/pappl/system-private.h +++ b/pappl/system-private.h @@ -141,6 +141,12 @@ struct _pappl_system_s // System data pappl_event_cb_t event_cb; // Event callback void *event_data; // Event callback data + + pappl_scanner_event_cb_t scan_event_cb; // Scanner event callback + void *scan_event_data; // Scanner event callback data + pappl_scanner_event_cb_t systemui_scan_cb; // System UI scanner event callback + void *systemui_scan_data; // System UI scanner event callback data + pappl_event_cb_t systemui_cb; // System UI event callback void *systemui_data; // System UI event callback data size_t max_subscriptions; // Maximum number of subscriptions @@ -167,8 +173,8 @@ typedef struct _pappl_timer_s // Timer callback data // Functions... // -extern void _papplSystemAddEventNoLock(pappl_system_t *system, pappl_printer_t *printer, pappl_job_t *job, pappl_event_t event, const char *message, ...) _PAPPL_FORMAT(5, 6) _PAPPL_PRIVATE; -extern void _papplSystemAddEventNoLockv(pappl_system_t *system, pappl_printer_t *printer, pappl_job_t *job, pappl_event_t event, const char *message, va_list ap) _PAPPL_PRIVATE; +extern void _papplSystemAddEventNoLock(pappl_system_t *system, pappl_printer_t *printer, pappl_scanner_t *scanner, pappl_job_t *job, pappl_event_t event, const char *message, ...) _PAPPL_FORMAT(6, 7) _PAPPL_PRIVATE; +extern void _papplSystemAddEventNoLockv(pappl_system_t *system, pappl_printer_t *printer, pappl_scanner_t *scanner, pappl_job_t *job, pappl_event_t event, const char *message, va_list ap) _PAPPL_PRIVATE; extern void _papplSystemAddLoc(pappl_system_t *system, pappl_loc_t *loc) _PAPPL_PRIVATE; extern void _papplSystemAddPrinter(pappl_system_t *system, pappl_printer_t *printer, int printer_id) _PAPPL_PRIVATE; extern void _papplSystemAddPrinterIcons(pappl_system_t *system, pappl_printer_t *printer) _PAPPL_PRIVATE; diff --git a/pappl/system-subscription.c b/pappl/system-subscription.c index 87b455b3..69b08ce5 100644 --- a/pappl/system-subscription.c +++ b/pappl/system-subscription.c @@ -12,6 +12,8 @@ // #include "pappl-private.h" +#include "subscription.h" +#include "scanner-private.h" // @@ -27,15 +29,14 @@ static int compare_subscriptions(pappl_subscription_t *a, pappl_subscription_t * void papplSystemAddEvent( - pappl_system_t *system, // I - System - pappl_printer_t *printer, // I - Associated printer, if any - pappl_job_t *job, // I - Associated job, if any - pappl_event_t event, // I - IPP "notify-events" bit value - const char *message, // I - printf-style message string - ...) // I - Additional arguments as needed + pappl_system_t *system, // I - System + pappl_printer_t *printer, // I - Associated printer, if any + pappl_job_t *job, // I - Associated job, if any + pappl_event_t event, // I - IPP "notify-events" bit value + const char *message, // I - printf-style message string + ...) // I - Additional arguments as needed { - va_list ap; // Argument pointer - + va_list ap; // Argument pointer if (!system) return; @@ -46,7 +47,7 @@ papplSystemAddEvent( _papplRWLockRead(job); va_start(ap, message); - _papplSystemAddEventNoLockv(system, printer, job, event, message, ap); + _papplSystemAddEventNoLockv(system, printer, NULL, job, event, message, ap); va_end(ap); if (job) @@ -56,47 +57,75 @@ papplSystemAddEvent( } +void +papplSystemAddScannerEvent( + pappl_system_t *system, // I - System + pappl_scanner_t *scanner, // I - Associated scanner, if any + pappl_job_t *job, // I - Associated job, if any + pappl_event_t event, // I - IPP "notify-events" bit value + const char *message, // I - printf-style message string + ...) // I - Additional arguments as needed +{ + va_list ap; // Argument pointer + + if (!system) + return; + + if (scanner) + _papplRWLockRead(scanner); + if (job) + _papplRWLockRead(job); + + va_start(ap, message); + _papplSystemAddEventNoLockv(system, NULL, scanner, job, event, message, ap); + va_end(ap); + + if (job) + _papplRWUnlock(job); + if (scanner) + _papplRWUnlock(scanner); +} + // // '_papplSystemAddEventNoLock()' - Add a notification event (no lock). // void _papplSystemAddEventNoLock( - pappl_system_t *system, // I - System - pappl_printer_t *printer, // I - Associated printer, if any - pappl_job_t *job, // I - Associated job, if any - pappl_event_t event, // I - IPP "notify-events" bit value - const char *message, // I - printf-style message string - ...) // I - Additional arguments as needed + pappl_system_t *system, // I - System + pappl_printer_t *printer, // I - Associated printer, if any + pappl_scanner_t *scanner, // I - Associated scanner, if any + pappl_job_t *job, // I - Associated job, if any + pappl_event_t event, // I - IPP "notify-events" bit value + const char *message, // I - printf-style message string + ...) // I - Additional arguments as needed { - va_list ap; // Argument pointer - + va_list ap; // Argument pointer va_start(ap, message); - _papplSystemAddEventNoLockv(system, printer, job, event, message, ap); + _papplSystemAddEventNoLockv(system, printer, scanner, job, event, message, ap); va_end(ap); } - // // '_papplSystemAddEventNoLockv()' - Add a notification event (no lock). // void _papplSystemAddEventNoLockv( - pappl_system_t *system, // I - System - pappl_printer_t *printer, // I - Associated printer, if any - pappl_job_t *job, // I - Associated job, if any - pappl_event_t event, // I - IPP "notify-events" bit value - const char *message, // I - printf-style message string - va_list ap) // I - Pointer to additional arguments + pappl_system_t *system, // I - System + pappl_printer_t *printer, // I - Associated printer, if any + pappl_scanner_t *scanner, // I - Associated scanner, if any + pappl_job_t *job, // I - Associated job, if any + pappl_event_t event, // I - IPP "notify-events" bit value + const char *message, // I - printf-style message string + va_list ap) // I - Pointer to additional arguments { - pappl_subscription_t *sub; // Current subscription - ipp_t *n; // Notify event attributes - char uri[1024] = "", // "notify-printer/system-uri" value - text[1024]; // "notify-text" value - va_list cap; // Copy of additional arguments - + pappl_subscription_t *sub; // Current subscription + ipp_t *n; // Notify event attributes + char uri[1024] = "", // "notify-printer/scanner/system-uri" value + text[1024]; // "notify-text" value + va_list cap; // Copy of additional arguments // Loop through all of the subscriptions and deliver any events... _papplRWLockRead(system); @@ -107,15 +136,23 @@ _papplSystemAddEventNoLockv( if (system->event_cb) (system->event_cb)(system, printer, job, event, system->event_data); + // Check if scanner-specific callbacks are defined + if (system->systemui_scan_cb && system->systemui_scan_data) + (system->systemui_scan_cb)(system, scanner, job, event, system->systemui_scan_data); + + if (system->scan_event_cb && system->scan_event_data) + (system->scan_event_cb)(system, scanner, job, event, system->scan_event_data); + for (sub = (pappl_subscription_t *)cupsArrayGetFirst(system->subscriptions); sub; sub = (pappl_subscription_t *)cupsArrayGetNext(system->subscriptions)) { - if ((sub->mask & event) && (!sub->job || job == sub->job) && (!sub->printer || printer == sub->printer)) + if ((sub->mask & event) && (!sub->job || job == sub->job) && (!sub->printer || printer == sub->printer) && (!sub->scanner || scanner == sub->scanner)) { _papplRWLockWrite(sub); n = ippNew(); ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_CONST_TAG(IPP_TAG_CHARSET), "notify-charset", NULL, "utf-8"); ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_CONST_TAG(IPP_TAG_LANGUAGE), "notify-natural-language", NULL, sub->language); + if (printer) { if (!uri[0]) @@ -123,6 +160,13 @@ _papplSystemAddEventNoLockv( ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_URI, "notify-printer-uri", NULL, uri); } + else if (scanner) + { + if (!uri[0]) + httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipps", NULL, system->hostname, system->port, scanner->resource); + + ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_URI, "notify-scanner-uri", NULL, uri); + } else { if (!uri[0]) @@ -130,12 +174,15 @@ _papplSystemAddEventNoLockv( ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_URI, "notify-system-uri", NULL, uri); } + if (job) ippAddInteger(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "notify-job-id", job->job_id); + ippAddInteger(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "notify-subscription-id", sub->subscription_id); ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_CONST_TAG(IPP_TAG_URI), "notify-subscription-uuid", NULL, sub->uuid); - ippAddInteger(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "notify-sequence-number", ++ sub->last_sequence); + ippAddInteger(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "notify-sequence-number", ++sub->last_sequence); ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_CONST_TAG(IPP_TAG_KEYWORD), "notify-subscribed-event", NULL, _papplSubscriptionEventString(event)); + if (message) { va_copy(cap, ap); @@ -143,29 +190,36 @@ _papplSystemAddEventNoLockv( va_end(cap); ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_TEXT, "notify-text", NULL, text); } + if (job && (event & PAPPL_EVENT_JOB_ALL)) { _papplJobCopyStateNoLock(job, IPP_TAG_EVENT_NOTIFICATION, n, NULL); - if (event == PAPPL_EVENT_JOB_CREATED) - { - ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_NAME, "job-name", NULL, job->name); - ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_NAME, "job-originating-user-name", NULL, job->username); - } + if (event == PAPPL_EVENT_JOB_CREATED) + { + ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_NAME, "job-name", NULL, job->name); + ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_NAME, "job-originating-user-name", NULL, job->username); + } } + if (!sub->job && printer && (event & PAPPL_EVENT_PRINTER_ALL)) _papplPrinterCopyStateNoLock(printer, IPP_TAG_EVENT_NOTIFICATION, n, NULL, NULL); - // TODO: add system event notifications + + if (!sub->job && scanner && (event & PAPPL_EVENT_SCANNER_ALL)) + _papplScannerCopyStateNoLock(scanner, IPP_TAG_EVENT_NOTIFICATION, n, NULL, NULL); + if (printer) - ippAddInteger(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "printer-up-time", (int)(time(NULL) - printer->start_time)); + ippAddInteger(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "printer-up-time", (int)(time(NULL) - printer->start_time)); + else if (scanner) + ippAddInteger(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "scanner-up-time", (int)(time(NULL) - scanner->start_time)); else - ippAddInteger(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "system-up-time", (int)(time(NULL) - system->start_time)); + ippAddInteger(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "system-up-time", (int)(time(NULL) - system->start_time)); cupsArrayAdd(sub->events, n); if (cupsArrayGetCount(sub->events) > PAPPL_MAX_EVENTS) { - cupsArrayRemove(sub->events, cupsArrayGetFirst(sub->events)); - sub->first_sequence ++; + cupsArrayRemove(sub->events, cupsArrayGetFirst(sub->events)); + sub->first_sequence++; } _papplRWUnlock(sub); diff --git a/pappl/system.h b/pappl/system.h index ce83464c..c29d2343 100644 --- a/pappl/system.h +++ b/pappl/system.h @@ -140,6 +140,7 @@ typedef pappl_wifi_t *(*pappl_wifi_status_cb_t)(pappl_system_t *system, void *da // extern void papplSystemAddEvent(pappl_system_t *system, pappl_printer_t *printer, pappl_job_t *job, pappl_event_t event, const char *message, ...) _PAPPL_FORMAT(5, 6) _PAPPL_PUBLIC; +extern void papplSystemAddScannerEvent(pappl_system_t *system, pappl_scanner_t *scanner, pappl_job_t *job, pappl_event_t event, const char *message, ...) _PAPPL_PUBLIC; extern void papplSystemAddLink(pappl_system_t *system, const char *label, const char *path_or_url, pappl_loptions_t options) _PAPPL_PUBLIC; extern bool papplSystemAddListeners(pappl_system_t *system, const char *name) _PAPPL_PUBLIC; extern void papplSystemAddMIMEFilter(pappl_system_t *system, const char *srctype, const char *dsttype, pappl_mime_filter_cb_t cb, void *data) _PAPPL_PUBLIC; From 63025bf9ee6c24e4d7a2147486eb05d177dae8c1 Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Sun, 7 Jul 2024 19:41:24 +0000 Subject: [PATCH 15/26] Update Readme and Build This commit updates the Readme and Build files to include libxml2 as a dependency. Signed-off-by: Akarshan Kapoor --- BUILD.md | 5 +++-- README.md | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/BUILD.md b/BUILD.md index 422a0c18..97fc4c32 100644 --- a/BUILD.md +++ b/BUILD.md @@ -28,13 +28,13 @@ CentOS 8/Fedora 23+/RHEL 8: sudo dnf groupinstall 'Development Tools' sudo dnf install avahi-devel cups-devel libjpeg-turbo-devel \ - libpng-devel libssl-devel libusbx-devel pam-devel zlib-devel + libpng-devel libssl-devel libusbx-devel pam-devel zlib-devel libxml2 libxml2-dev Debian/Raspbian/Ubuntu: sudo apt-get install build-essential libavahi-client-dev libcups2-dev \ libcupsimage2-dev libjpeg-dev libpam-dev libpng-dev libssl-dev \ - libusb-1.0-0-dev zlib1g-dev + libusb-1.0-0-dev zlib1g-dev libxml2 libxml2-dev macOS (after installing Xcode from the AppStore): @@ -43,6 +43,7 @@ macOS (after installing Xcode from the AppStore): brew install libpng brew install libusb brew install openssl@3 + brew install libxml2 or download, build, and install libjpeg, libpng, libusb, and OpenSSL or LibreSSL from source. diff --git a/README.md b/README.md index daccf940..3a9e99d9 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ are required along with the following support libraries: - LIBUSB (1.0 or later) for USB printing support (optional) - PAM for authentication support (optional) - ZLIB (1.1 or later) for compression support +- LIBXML for xml parsing support Most development happens on Intel and Apple Silicon Macs, with testing on various Linux distributions, Windows 10+, and a [Raspberry Pi Zero W][7] to @@ -111,4 +112,3 @@ This software is based loosely on the "ippeveprinter.c" code from [CUPS][12]. [10]: https://github.com/openprinting/ps-printer-app [11]: https://hosted.weblate.org [12]: https://openprinting.github.io/cups - From 8507fb948554fe34d8442ced8fadcff2c1439456 Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Sun, 7 Jul 2024 21:34:41 +0000 Subject: [PATCH 16/26] Finalise scanner-driver.c This commit finalises the scanner-driver.c file. It includes all the functions as required for working with scanner-drivers and closely in line with the printer-driver.c file. Signed-off-by: Akarshan Kapoor --- pappl/scanner-driver.c | 309 ++++++++++++++++++++++++---------------- pappl/scanner-private.h | 2 +- pappl/scanner.h | 2 +- 3 files changed, 192 insertions(+), 121 deletions(-) diff --git a/pappl/scanner-driver.c b/pappl/scanner-driver.c index 58a47472..2a3ea4ce 100644 --- a/pappl/scanner-driver.c +++ b/pappl/scanner-driver.c @@ -11,196 +11,267 @@ #include "system-private.h" #include #include + // // Local functions... // +extern xmlDocPtr make_escl_attr(pappl_scanner_t *scanner); +extern const char *ScannerInputSourceString(pappl_sc_input_source_t value) _PAPPL_PRIVATE; +extern const char *ScannerResolutionString(int resolution) _PAPPL_PRIVATE; -// Declare the capability structure and the callback function -typedef struct { - char make_and_model[256]; - const char *document_formats_supported[PAPPL_MAX_FORMATS]; - pappl_sc_color_mode_t color_modes_supported[PAPPL_MAX_COLOR_MODES]; - int resolutions[MAX_RESOLUTIONS]; - pappl_sc_input_source_t input_sources_supported[PAPPL_MAX_SOURCES]; - bool duplex_supported; - float max_scan_area[2]; -} capability_t; - -capability_t *capability_cb(pappl_scanner_t *scanner); -const char *pappl_sc_color_mode_str(pappl_sc_color_mode_t mode); -const char *pappl_sc_input_source_str(pappl_sc_input_source_t source); // -// 'papplScannerGetDriverName()' - Get the driver name for a scanner. +// 'papplScannerGetDriverData()' - Get the current scanner driver data. // -// This function returns the driver name for the scanner. +// This function copies the current scanner driver data into the specified buffer. // -const char * // O - Driver name or `NULL` for none -papplScannerGetDriverName( - pappl_scanner_t *scanner) // I - Scanner -{ - return (scanner ? scanner->driver_name : NULL); -} - -// -// 'papplScannerGetDriverData()' - Get the current scan driver data. -// -// This function copies the current scan driver data. -// - -pappl_sc_driver_data_t * // O - Driver data or `NULL` if none +pappl_sc_driver_data_t * // O - Driver data or `NULL` if none papplScannerGetDriverData( - pappl_scanner_t *scanner, // I - Scanner - pappl_sc_driver_data_t *data) // I - Pointer to driver data structure to fill + pappl_scanner_t *scanner, // I - Scanner + pappl_sc_driver_data_t *data) // I - Pointer to driver data structure to fill { if (!scanner || !scanner->driver_name || !data) { if (data) - _papplScannerInitDriverData(scanner, data); + _papplScannerInitDriverData(scanner, data); return (NULL); } + memcpy(data, &scanner->driver_data, sizeof(pappl_sc_driver_data_t)); return (data); } + // -// '_papplScannerInitDriverData()' - Initialize a scan driver data structure. +// 'papplScannerGetDriverName()' - Get the driver name for a scanner. +// +// This function returns the driver name for the scanner. // -void -_papplScannerInitDriverData( - pappl_scanner_t *scanner, // I - Scanner - pappl_sc_driver_data_t *d) // I - Driver data +const char * // O - Driver name or `NULL` for none +papplScannerGetDriverName( + pappl_scanner_t *scanner) // I - Scanner { - capability_t *capability = capability_cb(scanner); - if (capability) - { - strncpy(d->make_and_model, capability->make_and_model, sizeof(d->make_and_model) - 1); - d->make_and_model[sizeof(d->make_and_model) - 1] = '\0'; // Ensure null-termination + return (scanner ? scanner->driver_name : NULL); +} - for (int i = 0; i < PAPPL_MAX_FORMATS && capability->document_formats_supported[i]; i++) - { - d->document_formats_supported[i] = capability->document_formats_supported[i]; - } +// +// 'papplScannerSetDriverData()' - Set the driver data. +// +// This function sets the driver data. +// - for (int i = 0; i < PAPPL_MAX_COLOR_MODES && capability->color_modes_supported[i]; i++) - { - d->color_modes_supported[i] = capability->color_modes_supported[i]; - } +bool // O - `true` on success, `false` on failure +papplScannerSetDriverData( + pappl_scanner_t *scanner, // I - Scanner + pappl_sc_driver_data_t *data) // I - Driver data +{ + if (!scanner || !data) + return (false); - for (int i = 0; i < MAX_RESOLUTIONS && capability->resolutions[i]; i++) - { - d->resolutions[i] = capability->resolutions[i]; - } + // Note: For now, we assume the data is valid. We will add validation in later versions. + + _papplRWLockWrite(scanner); - for (int i = 0; i < PAPPL_MAX_SOURCES && capability->input_sources_supported[i]; i++) - { - d->input_sources_supported[i] = capability->input_sources_supported[i]; - } + memcpy(&scanner->driver_data, data, sizeof(scanner->driver_data)); - d->duplex_supported = capability->duplex_supported; + scanner->config_time = time(NULL); - d->max_scan_area[0] = capability->max_scan_area[0]; - d->max_scan_area[1] = capability->max_scan_area[1]; + _papplRWUnlock(scanner); - } + return (true); } // -// 'papplScannerSetDriverData()' - Set the driver data. -// -// This function validates and sets the driver data. +// 'papplScannerSetDriverDefaults()' - Set the default scan option values. // +// This function validates and sets the scanner's default scan options. // -bool // O - `true` on success, `false` on failure -papplScannerSetDriverData( - pappl_scanner_t *scanner, // I - Scanner - pappl_sc_driver_data_t *data) // I - Driver data +bool // O - `true` on success, `false` on failure +papplScannerSetDriverDefaults( + pappl_scanner_t *scanner, // I - Scanner + pappl_sc_driver_data_t *data) // I - Driver data { if (!scanner || !data) return (false); + // Note: For now, we assume the data is valid. We will add validation in later versions. + _papplRWLockWrite(scanner); - memcpy(&scanner->driver_data, data, sizeof(scanner->driver_data)); + scanner->driver_data.default_color_mode = data->default_color_mode; + scanner->driver_data.default_resolution = data->default_resolution; + scanner->driver_data.default_input_source = data->default_input_source; + + scanner->config_time = time(NULL); _papplRWUnlock(scanner); return (true); } -xmlDocPtr make_escl_attr(pappl_scanner_t *scanner) +// +// _paplScannerInitDriverData() - Initialize the driver data. +// +// This function initializes the driver data through the callback function. + +void +_papplScannerInitDriverData( + pappl_scanner_t *scanner, // I - Scanner + pappl_sc_driver_data_t *d) // I - Driver data +{ + memset(d, 0, sizeof(pappl_sc_driver_data_t)); + if (scanner->driver_data.capabilities_cb) + { + // Get the driver data from the callback function + pappl_sc_driver_data_t callback_data = (scanner->driver_data.capabilities_cb)(scanner); + *d = callback_data; + } +} + +// +// 'make_escl_attr()' - Generate the scanner attributes in eSCL format. +// + +xmlDocPtr // O - XML document pointer +make_escl_attr( + pappl_scanner_t *scanner) // I - Scanner { - xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); - xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST "eSCL"); + xmlDocPtr doc = NULL; + xmlNodePtr root_node = NULL; + + doc = xmlNewDoc(BAD_CAST "1.0"); + if (!doc) + return (NULL); + + root_node = xmlNewNode(NULL, BAD_CAST "scan:ScannerCapabilities"); + if (!root_node) + { + xmlFreeDoc(doc); + return (NULL); + } xmlDocSetRootElement(doc, root_node); - capability_t *capability = capability_cb(scanner); - if (!capability) { - return doc; + xmlNsPtr ns = xmlNewNs(root_node, BAD_CAST "http://schemas.hp.com/imaging/escl/2011/05/03", BAD_CAST "scan"); + xmlSetNs(root_node, ns); + + xmlNewChild(root_node, NULL, BAD_CAST "pwg:Version", BAD_CAST "2.0"); // Example value + xmlNewChild(root_node, NULL, BAD_CAST "pwg:MakeAndModel", BAD_CAST scanner->driver_data.make_and_model); + + xmlNodePtr resolutions_node = xmlNewChild(root_node, NULL, BAD_CAST "scan:SupportedResolutions", NULL); + for (int i = 0; i < MAX_RESOLUTIONS && scanner->driver_data.resolutions[i]; i++) + { + char res_str[16]; + snprintf(res_str, sizeof(res_str), "%d", scanner->driver_data.resolutions[i]); + xmlNewChild(resolutions_node, NULL, BAD_CAST "scan:Resolution", BAD_CAST res_str); + } + + xmlNodePtr formats_node = xmlNewChild(root_node, NULL, BAD_CAST "scan:DocumentFormatsSupported", NULL); + for (int i = 0; i < PAPPL_MAX_FORMATS && scanner->driver_data.document_formats_supported[i]; i++) + { + xmlNewChild(formats_node, NULL, BAD_CAST "scan:DocumentFormat", BAD_CAST scanner->driver_data.document_formats_supported[i]); } - xmlNewChild(root_node, NULL, BAD_CAST "MakeAndModel", BAD_CAST capability->make_and_model); + xmlNodePtr color_modes_node = xmlNewChild(root_node, NULL, BAD_CAST "scan:ColorModesSupported", NULL); + for (int i = 0; i < PAPPL_MAX_COLOR_MODES && scanner->driver_data.color_modes_supported[i]; i++) + { + xmlNewChild(color_modes_node, NULL, BAD_CAST "scan:ColorMode", BAD_CAST _papplScannerColorModeString(scanner->driver_data.color_modes_supported[i])); + } - xmlNodePtr formats_node = xmlNewChild(root_node, NULL, BAD_CAST "DocumentFormatsSupported", NULL); - for (int i = 0; i < PAPPL_MAX_FORMATS && capability->document_formats_supported[i]; i++) { - xmlNewChild(formats_node, NULL, BAD_CAST "Format", BAD_CAST capability->document_formats_supported[i]); + xmlNodePtr input_sources_node = xmlNewChild(root_node, NULL, BAD_CAST "scan:InputSourcesSupported", NULL); + for (int i = 0; i < PAPPL_MAX_SOURCES && scanner->driver_data.input_sources_supported[i]; i++) + { + xmlNewChild(input_sources_node, NULL, BAD_CAST "scan:InputSource", BAD_CAST ScannerInputSourceString(scanner->driver_data.input_sources_supported[i])); } + xmlNewChild(root_node, NULL, BAD_CAST "scan:DuplexSupported", BAD_CAST (scanner->driver_data.duplex_supported ? "true" : "false")); - xmlNodePtr color_modes_node = xmlNewChild(root_node, NULL, BAD_CAST "ColorModesSupported", NULL); - for (int i = 0; i < PAPPL_MAX_COLOR_MODES && capability->color_modes_supported[i]; i++) { - xmlNewChild(color_modes_node, NULL, BAD_CAST "ColorMode", BAD_CAST pappl_sc_color_mode_str(capability->color_modes_supported[i])); + xmlNodePtr color_spaces_node = xmlNewChild(root_node, NULL, BAD_CAST "scan:ColorSpacesSupported", NULL); + for (int i = 0; i < PAPPL_MAX_COLOR_SPACES && scanner->driver_data.color_spaces_supported[i]; i++) + { + xmlNewChild(color_spaces_node, NULL, BAD_CAST "scan:ColorSpace", BAD_CAST scanner->driver_data.color_spaces_supported[i]); } - xmlNodePtr resolutions_node = xmlNewChild(root_node, NULL, BAD_CAST "Resolutions", NULL); - for (int i = 0; i < MAX_RESOLUTIONS && capability->resolutions[i]; i++) { - char resolution_str[10]; - snprintf(resolution_str, sizeof(resolution_str), "%d", capability->resolutions[i]); - xmlNewChild(resolutions_node, NULL, BAD_CAST "Resolution", BAD_CAST resolution_str); + char max_scan_area_str[64]; + snprintf(max_scan_area_str, sizeof(max_scan_area_str), "width=%d,height=%d", + scanner->driver_data.max_scan_area[0], + scanner->driver_data.max_scan_area[1]); + xmlNewChild(root_node, NULL, BAD_CAST "scan:MaxScanArea", BAD_CAST max_scan_area_str); + + xmlNodePtr media_types_node = xmlNewChild(root_node, NULL, BAD_CAST "scan:MediaTypesSupported", NULL); + for (int i = 0; i < PAPPL_MAX_MEDIA_TYPES && scanner->driver_data.media_type_supported[i]; i++) + { + xmlNewChild(media_types_node, NULL, BAD_CAST "scan:MediaType", BAD_CAST scanner->driver_data.media_type_supported[i]); + } + + xmlNodePtr defaults_node = xmlNewChild(root_node, NULL, BAD_CAST "scan:Defaults", NULL); + xmlNewChild(defaults_node, NULL, BAD_CAST "scan:DefaultResolution", BAD_CAST ScannerResolutionString(scanner->driver_data.default_resolution)); + xmlNewChild(defaults_node, NULL, BAD_CAST "scan:DefaultColorMode", BAD_CAST _papplScannerColorModeString(scanner->driver_data.default_color_mode)); + xmlNewChild(defaults_node, NULL, BAD_CAST "scan:DefaultInputSource", BAD_CAST ScannerInputSourceString(scanner->driver_data.default_input_source)); + + char scan_region_str[64]; + snprintf(scan_region_str, sizeof(scan_region_str), "top=%d,left=%d,width=%d,height=%d", + scanner->driver_data.scan_region_supported[0], + scanner->driver_data.scan_region_supported[1], + scanner->driver_data.scan_region_supported[2], + scanner->driver_data.scan_region_supported[3]); + xmlNewChild(root_node, NULL, BAD_CAST "scan:ScanRegionsSupported", BAD_CAST scan_region_str); + + xmlNodePtr mandatory_intents_node = xmlNewChild(root_node, NULL, BAD_CAST "scan:MandatoryIntents", NULL); + for (int i = 0; i < 5 && scanner->driver_data.mandatory_intents[i]; i++) + { + xmlNewChild(mandatory_intents_node, NULL, BAD_CAST "scan:Intent", BAD_CAST scanner->driver_data.mandatory_intents[i]); } - xmlNodePtr input_sources_node = xmlNewChild(root_node, NULL, BAD_CAST "InputSourcesSupported", NULL); - for (int i = 0; i < PAPPL_MAX_SOURCES && capability->input_sources_supported[i]; i++) { - xmlNewChild(input_sources_node, NULL, BAD_CAST "InputSource", BAD_CAST pappl_sc_input_source_str(capability->input_sources_supported[i])); + xmlNodePtr optional_intents_node = xmlNewChild(root_node, NULL, BAD_CAST "scan:OptionalIntents", NULL); + for (int i = 0; i < 5 && scanner->driver_data.optional_intents[i]; i++) + { + xmlNewChild(optional_intents_node, NULL, BAD_CAST "scan:Intent", BAD_CAST scanner->driver_data.optional_intents[i]); } - xmlNewChild(root_node, NULL, BAD_CAST "DuplexSupported", BAD_CAST (capability->duplex_supported ? "true" : "false")); + xmlNewChild(root_node, NULL, BAD_CAST "scan:CompressionSupported", BAD_CAST (scanner->driver_data.compression_supported ? "true" : "false")); - xmlNodePtr max_scan_area_node = xmlNewChild(root_node, NULL, BAD_CAST "MaxScanArea", NULL); - char max_scan_width[10], max_scan_height[10]; - snprintf(max_scan_width, sizeof(max_scan_width), "%.2f", capability->max_scan_area[0]); - snprintf(max_scan_height, sizeof(max_scan_height), "%.2f", capability->max_scan_area[1]); - xmlNewChild(max_scan_area_node, NULL, BAD_CAST "Width", BAD_CAST max_scan_width); - xmlNewChild(max_scan_area_node, NULL, BAD_CAST "Height", BAD_CAST max_scan_height); + xmlNewChild(root_node, NULL, BAD_CAST "scan:NoiseRemovalSupported", BAD_CAST (scanner->driver_data.noise_removal_supported ? "true" : "false")); - return doc; -} + xmlNewChild(root_node, NULL, BAD_CAST "scan:SharpnessSupported", BAD_CAST (scanner->driver_data.sharpness_supported ? "true" : "false")); + + char compression_factor_str[16]; + snprintf(compression_factor_str, sizeof(compression_factor_str), "%d", scanner->driver_data.compression_factor_supported); + xmlNewChild(root_node, NULL, BAD_CAST "scan:CompressionFactorsSupported", BAD_CAST compression_factor_str); -const char *pappl_sc_color_mode_str(pappl_sc_color_mode_t mode) { - switch (mode) { - case PAPPL_BLACKANDWHITE1: - return "BlackAndWhite"; - case PAPPL_GRAYSCALE8: - return "Grayscale"; - case PAPPL_RGB24: - return "RGB"; - default: - return "Unknown"; + xmlNewChild(root_node, NULL, BAD_CAST "scan:BinaryRenderingSupported", BAD_CAST (scanner->driver_data.binary_rendering_supported ? "true" : "false")); + + xmlNodePtr feed_directions_node = xmlNewChild(root_node, NULL, BAD_CAST "scan:FeedDirectionsSupported", NULL); + for (int i = 0; i < 2 && scanner->driver_data.feed_direction_supported[i]; i++) + { + xmlNewChild(feed_directions_node, NULL, BAD_CAST "scan:FeedDirection", BAD_CAST scanner->driver_data.feed_direction_supported[i]); } + + return (doc); } -const char *pappl_sc_input_source_str(pappl_sc_input_source_t source) { - switch (source) { - case PAPPL_FLATBED: - return "Flatbed"; - case PAPPL_ADF: - return "ADF"; - default: - return "Unknown"; +// Converts input source to string +const char *_papplScannerInputSourceString(pappl_sc_input_source_t value) +{ + switch (value) + { + case PAPPL_FLATBED: + return "Flatbed"; + case PAPPL_ADF: + return "ADF"; + default: + return "Unknown"; } } + +// Converts resolution to string +const char *_papplScannerResolutionString(int resolution) +{ + static char res_str[32]; + snprintf(res_str, sizeof(res_str), "%d DPI", resolution); + return res_str; +} diff --git a/pappl/scanner-private.h b/pappl/scanner-private.h index 9f221386..905a53bc 100644 --- a/pappl/scanner-private.h +++ b/pappl/scanner-private.h @@ -85,7 +85,7 @@ extern void _papplScannerCopyStateNoLock(pappl_scanner_t *scanner, ipp_tag_t gro extern const char *_papplScannerReasonString(pappl_sreason_t reason) _PAPPL_PRIVATE; extern void _papplScannerDelete(pappl_scanner_t *scanner) _PAPPL_PRIVATE; -extern void _papplScannerInitDriverData(pappl_scanner_t *scanner, pappl_sc_driver_data_t *d) _PAPPL_PRIVATE; +extern void _papplScannerInitDriverData(pappl_scanner_t *scanner, pappl_sc_driver_data_t *d) _PAPPL_PRIVATE; extern bool _papplScannerIsAuthorized(pappl_client_t *client) _PAPPL_PRIVATE; extern void _papplScannerProcessESCL(pappl_client_t *client) _PAPPL_PRIVATE; extern bool _papplScannerRegisterDNSSDNoLock(pappl_scanner_t *scanner) _PAPPL_PRIVATE; diff --git a/pappl/scanner.h b/pappl/scanner.h index 36306e99..6ae674a3 100644 --- a/pappl/scanner.h +++ b/pappl/scanner.h @@ -69,7 +69,7 @@ typedef enum { // // Callback functions... // -typedef void (*pappl_sc_capabilities_cb_t)(pappl_scanner_t *scanner); // Callback for getting scanner capabilities +typedef pappl_sc_driver_data_t (*pappl_sc_capabilities_cb_t)(pappl_scanner_t *scanner); // Callback for getting scanner capabilities typedef void (*pappl_sc_job_create_cb_t)(pappl_job_t *job, pappl_sc_options_t *options, pappl_device_t *device); // Callback for creating a scan job typedef void (*pappl_sc_job_delete_cb_t)(pappl_job_t *job); // Callback for deleting a scan job typedef bool (*pappl_sc_data_cb_t)(pappl_job_t *job, pappl_device_t *device, void *buffer, size_t bufsize); // Callback for getting scan data From 64f7aa48337c9376bfb9f80c6e43707a8d773b39 Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Fri, 12 Jul 2024 15:58:29 +0000 Subject: [PATCH 17/26] Finalise scanner-webif.c This commit finalises the scanner-webif.c file. It closely follows all aspects of the printer-webif.c file, but also follows the scan specific requirements. This commit finalizes the implementation of the scanner web interface functions, including the following features: - Added `_papplScannerWebConfig()` to show and handle scanner configuration settings. - Implemented `_papplScannerWebConfigFinalize()` to save changes to the scanner configuration. - Developed `_papplScannerWebDefaults()` to display and update default scanning settings. Signed-off-by: Akarshan Kapoor --- pappl/Makefile | 1 + pappl/client-private.h | 1 + pappl/client-webif.c | 124 ++++++++ pappl/client.h | 2 + pappl/pappl-private.h | 1 + pappl/scanner-driver.c | 14 +- pappl/scanner-webif.c | 636 +++++++++++++++++++++++++++++++++++++++ pappl/scanner.h | 27 +- pappl/system-accessors.c | 24 ++ pappl/system-private.h | 9 + pappl/system.h | 17 ++ 11 files changed, 847 insertions(+), 9 deletions(-) create mode 100644 pappl/scanner-webif.c diff --git a/pappl/Makefile b/pappl/Makefile index 288a38b8..6f602622 100644 --- a/pappl/Makefile +++ b/pappl/Makefile @@ -50,6 +50,7 @@ BASEOBJS = \ scanner-accessors.o\ scanner-driver.o \ scanner-escl.o \ + scanner-webif.o \ snmp.o \ subscription.o \ subscription-ipp.o \ diff --git a/pappl/client-private.h b/pappl/client-private.h index dfe30a05..93b231f1 100644 --- a/pappl/client-private.h +++ b/pappl/client-private.h @@ -40,6 +40,7 @@ struct _pappl_client_s // Client data char username[256]; // Authenticated username, if any char language[256]; // Accept-Language value, if any pappl_printer_t *printer; // Printer, if any + pappl_scanner_t *scanner; // Scanner, if any pappl_job_t *job; // Job, if any pappl_loc_t *loc; // Localization, if any int num_files; // Number of temporary files diff --git a/pappl/client-webif.c b/pappl/client-webif.c index cb42d879..7b71493d 100644 --- a/pappl/client-webif.c +++ b/pappl/client-webif.c @@ -896,6 +896,26 @@ papplClientHTMLPrinterFooter(pappl_client_t *client) // I - Client } +// +// 'papplClientHTMLScannerFooter()' - Show the web interface footer for scanners. +// +// This function sends the standard web interface footer for a scanner followed +// by a trailing 0-length chunk to finish the current HTTP response. Use the +// @link papplSystemSetFooterHTML@ function to add any custom HTML needed in +// the footer. +// + +void +papplClientHTMLScannerFooter(pappl_client_t *client) // I - Client +{ + papplClientHTMLPuts(client, + " \n" + " \n" + " \n"); + papplClientHTMLFooter(client); +} + + // // 'papplClientHTMLPrinterHeader()' - Show the web interface header and title // for printers. @@ -1015,6 +1035,110 @@ papplClientHTMLPrinterHeader( } +// +// 'papplClientHTMLScannerHeader()' - Show the web interface header and title +// for scanners. +// +// This function sends the standard web interface header and title for a +// scanner. If the "refresh" argument is greater than zero, the page will +// automatically reload after that many seconds. +// +// If "label" and "path_or_url" are non-`NULL` strings, an additional navigation +// link is included with the title header - this is typically used for an +// action button ("Change"). +// +// Use the @link papplSystemAddLink@ function to add system-wide navigation +// links to the header. Similarly, use @link papplScannerAddLink@ to add +// scanner-specific links, which will appear in the web interface scanner if +// the system is not configured to support multiple scanners +// + +// TODO : papplScannerAddLink +void +papplClientHTMLScannerHeader( + pappl_client_t *client, // I - Client + pappl_scanner_t *scanner, // I - Scanner + const char *title, // I - Title + int refresh, // I - Refresh time in seconds or 0 for none + const char *label, // I - Button label or `NULL` for none + const char *path_or_url) // I - Button path or `NULL` for none +{ + const char *header; // Header text + + if (!papplClientRespond(client, HTTP_STATUS_OK, NULL, "text/html", 0, 0)) + return; + + + // Multi-queue mode not required for scanners + + // Single queue mode - the function will automatically add the scanner name and localize the title... + papplClientHTMLHeader(client, title, refresh); + + // Generate HTML for scanners + _papplRWLockRead(scanner); + papplClientHTMLPrintf(client, + "
\n" + "
\n" + "
%s:\n", scanner->uriname, scanner->name); + _papplClientHTMLPutLinks(client, scanner->links, PAPPL_LOPTIONS_NAVIGATION); + papplClientHTMLPuts(client, + "
\n" + "
\n" + "
\n"); + _papplRWUnlock(scanner); + + // Display system version if available + if (client->system->versions[0].sversion[0]) + { + papplClientHTMLPrintf(client, + "
\n" + "
\n" + "
\n" + " Version %s\n" + "
\n" + "
\n" + "
\n", client->system->versions[0].sversion); + } + + papplClientHTMLPuts(client, "
\n"); + + if ((header = papplClientGetLocString(client, client->uri)) == client->uri) + { + size_t urilen = strlen(scanner->uriname); + // Length of scanner URI name + const char *uriptr = client->uri + urilen; + // Pointer into client URI + + if (strlen(client->uri) <= urilen || !strcmp(client->uri, "/") || (header = papplClientGetLocString(client, uriptr)) == uriptr) + header = NULL; + } + + if (header) + { + // Show header text + papplClientHTMLPuts(client, + "
\n" + "
\n"); + papplClientHTMLPuts(client, header); + papplClientHTMLPuts(client, + "\n" + "
\n" + "
\n"); + } + + if (title) + { + papplClientHTMLPrintf(client, + "
\n" + "
\n" + "

%s", papplClientGetLocString(client, title)); + if (label && path_or_url) + papplClientHTMLPrintf(client, " %s", path_or_url, papplClientGetLocString(client, label)); + papplClientHTMLPuts(client, "

\n"); + } +} + + // // 'papplClientHTMLPrintf()' - Send formatted text to the web browser client, // escaping as needed. diff --git a/pappl/client.h b/pappl/client.h index ec560379..493a8e30 100644 --- a/pappl/client.h +++ b/pappl/client.h @@ -42,6 +42,8 @@ extern bool papplClientHTMLAuthorize(pappl_client_t *client) _PAPPL_PUBLIC; extern void papplClientHTMLEscape(pappl_client_t *client, const char *s, size_t slen) _PAPPL_PUBLIC; extern void papplClientHTMLFooter(pappl_client_t *client) _PAPPL_PUBLIC; extern void papplClientHTMLHeader(pappl_client_t *client, const char *title, int refresh) _PAPPL_PUBLIC; +extern void papplClientHTMLScannerHeader(pappl_client_t *client, pappl_scanner_t *scanner, const char *title, int refresh, const char *label, const char *path_or_url)_PAPPL_PUBLIC; +extern void papplClientHTMLScannerFooter(pappl_client_t *client)_PAPPL_PUBLIC; extern void papplClientHTMLPrinterFooter(pappl_client_t *client) _PAPPL_PUBLIC; extern void papplClientHTMLPrinterHeader(pappl_client_t *client, pappl_printer_t *printer, const char *title, int refresh, const char *label, const char *path_or_url) _PAPPL_PUBLIC; extern void papplClientHTMLPrintf(pappl_client_t *client, const char *format, ...) _PAPPL_PUBLIC _PAPPL_FORMAT(2, 3); diff --git a/pappl/pappl-private.h b/pappl/pappl-private.h index 1d4f5457..88e20cb1 100644 --- a/pappl/pappl-private.h +++ b/pappl/pappl-private.h @@ -17,5 +17,6 @@ # include "log-private.h" # include "mainloop-private.h" # include "printer-private.h" +# include "scanner-private.h" # include "system-private.h" #endif // !_PAPPL_PAPPL_PRIVATE_H_ diff --git a/pappl/scanner-driver.c b/pappl/scanner-driver.c index 2a3ea4ce..e0cb1eaf 100644 --- a/pappl/scanner-driver.c +++ b/pappl/scanner-driver.c @@ -106,6 +106,10 @@ papplScannerSetDriverDefaults( scanner->driver_data.default_color_mode = data->default_color_mode; scanner->driver_data.default_resolution = data->default_resolution; scanner->driver_data.default_input_source = data->default_input_source; + scanner->driver_data.default_media_type = data->default_media_type; + scanner->driver_data.default_document_format = data->default_document_format; + scanner->driver_data.default_intent = data->default_intent; + scanner->driver_data.default_color_space = data->default_color_space; scanner->config_time = time(NULL); @@ -237,11 +241,7 @@ make_escl_attr( xmlNewChild(root_node, NULL, BAD_CAST "scan:NoiseRemovalSupported", BAD_CAST (scanner->driver_data.noise_removal_supported ? "true" : "false")); - xmlNewChild(root_node, NULL, BAD_CAST "scan:SharpnessSupported", BAD_CAST (scanner->driver_data.sharpness_supported ? "true" : "false")); - - char compression_factor_str[16]; - snprintf(compression_factor_str, sizeof(compression_factor_str), "%d", scanner->driver_data.compression_factor_supported); - xmlNewChild(root_node, NULL, BAD_CAST "scan:CompressionFactorsSupported", BAD_CAST compression_factor_str); + xmlNewChild(root_node, NULL, BAD_CAST "scan:SharpeningSupported", BAD_CAST (scanner->driver_data.sharpening_supported ? "true" : "false")); xmlNewChild(root_node, NULL, BAD_CAST "scan:BinaryRenderingSupported", BAD_CAST (scanner->driver_data.binary_rendering_supported ? "true" : "false")); @@ -255,7 +255,7 @@ make_escl_attr( } // Converts input source to string -const char *_papplScannerInputSourceString(pappl_sc_input_source_t value) +const char *ScannerInputSourceString(pappl_sc_input_source_t value) { switch (value) { @@ -269,7 +269,7 @@ const char *_papplScannerInputSourceString(pappl_sc_input_source_t value) } // Converts resolution to string -const char *_papplScannerResolutionString(int resolution) +const char *ScannerResolutionString(int resolution) { static char res_str[32]; snprintf(res_str, sizeof(res_str), "%d DPI", resolution); diff --git a/pappl/scanner-webif.c b/pappl/scanner-webif.c new file mode 100644 index 00000000..d4111f3f --- /dev/null +++ b/pappl/scanner-webif.c @@ -0,0 +1,636 @@ +// +// Scanner web interface functions for the Scanner Application Framework +// +// Copyright © 2019-2024 by Michael R Sweet. +// Copyright © 2010-2019 by Apple Inc. +// +// Licensed under Apache License v2.0. See the file "LICENSE" for more +// information. +// + +#include "pappl-private.h" + +// +// Local functions... +// + +// Duplicate of the local functions in scanner-driver.c. TODO:Remove Later +extern const char *InputSourceString(pappl_sc_input_source_t value) _PAPPL_PRIVATE; +extern const char *ResolutionString(int resolution) _PAPPL_PRIVATE; + +// Converts resolution to string +const char *ResolutionString(int resolution) +{ + static char res_str[32]; + snprintf(res_str, sizeof(res_str), "%d DPI", resolution); + return res_str; +} + +// Converts input source to string +const char *InputSourceString(pappl_sc_input_source_t value) +{ + switch (value) + { + case PAPPL_FLATBED: + return "Flatbed"; + case PAPPL_ADF: + return "ADF"; + default: + return "Unknown"; + } +} + +// +// '_papplScannerWebConfig()' - Show the scanner configuration web page. +// + +void +_papplScannerWebConfig( + pappl_client_t *client, // I - Client + pappl_scanner_t *scanner) // I - Scanner +{ + const char *status = NULL; // Status message, if any + char dns_sd_name[64], // DNS-SD name + location[128], // Location + geo_location[128], // Geo-location latitude + organization[128]; // Organization + pappl_contact_t contact; // Contact info + + + if (!papplClientHTMLAuthorize(client)) + return; + + if (client->operation == HTTP_STATE_POST) + { + cups_len_t num_form = 0; // Number of form variable + cups_option_t *form = NULL; // Form variables + + if ((num_form = (cups_len_t)papplClientGetForm(client, &form)) == 0) + { + status = _PAPPL_LOC("Invalid form data."); + } + else if (!papplClientIsValidForm(client, (int)num_form, form)) + { + status = _PAPPL_LOC("Invalid form submission."); + } + else + { + _papplScannerWebConfigFinalize(scanner, num_form, form); + status = _PAPPL_LOC("Changes saved."); + } + + cupsFreeOptions(num_form, form); + } + + papplClientHTMLScannerHeader(client, scanner, _PAPPL_LOC("Configuration"), 0, NULL, NULL); + if (status) + papplClientHTMLPrintf(client, "
%s
\n", papplClientGetLocString(client, status)); + + _papplClientHTMLInfo(client, true, papplScannerGetDNSSDName(scanner, dns_sd_name, sizeof(dns_sd_name)), papplScannerGetLocation(scanner, location, sizeof(location)), papplScannerGetGeoLocation(scanner, geo_location, sizeof(geo_location)), papplScannerGetOrganization(scanner, organization, sizeof(organization)), NULL , papplScannerGetContact(scanner, &contact)); + + papplClientHTMLScannerFooter(client); +} + + +// +// '_papplScannerWebConfigFinalize()' - Save the changes to the scanner configuration. +// + +void +_papplScannerWebConfigFinalize( + pappl_scanner_t *scanner, // I - Scanner + cups_len_t num_form, // I - Number of form variables + cups_option_t *form) // I - Form variables +{ + const char *value, // Form value + *geo_lat, // Geo-location latitude + *geo_lon, // Geo-location longitude + *contact_name, // Contact name + *contact_email, // Contact email + *contact_tel; // Contact telephone number + + + if ((value = cupsGetOption("dns_sd_name", num_form, form)) != NULL) + papplScannerSetDNSSDName(scanner, *value ? value : NULL); + + if ((value = cupsGetOption("location", num_form, form)) != NULL) + papplScannerSetLocation(scanner, *value ? value : NULL); + + geo_lat = cupsGetOption("geo_location_lat", num_form, form); + geo_lon = cupsGetOption("geo_location_lon", num_form, form); + if (geo_lat && geo_lon) + { + char uri[1024]; // "geo:" URI + + if (*geo_lat && *geo_lon) + { + snprintf(uri, sizeof(uri), "geo:%g,%g", strtod(geo_lat, NULL), strtod(geo_lon, NULL)); + papplScannerSetGeoLocation(scanner, uri); + } + else + papplScannerSetGeoLocation(scanner, NULL); + } + + if ((value = cupsGetOption("organization", num_form, form)) != NULL) + papplScannerSetOrganization(scanner, *value ? value : NULL); + + contact_name = cupsGetOption("contact_name", num_form, form); + contact_email = cupsGetOption("contact_email", num_form, form); + contact_tel = cupsGetOption("contact_telephone", num_form, form); + if (contact_name || contact_email || contact_tel) + { + pappl_contact_t contact; // Contact info + + memset(&contact, 0, sizeof(contact)); + + if (contact_name) + papplCopyString(contact.name, contact_name, sizeof(contact.name)); + if (contact_email) + papplCopyString(contact.email, contact_email, sizeof(contact.email)); + if (contact_tel) + papplCopyString(contact.telephone, contact_tel, sizeof(contact.telephone)); + + papplScannerSetContact(scanner, &contact); + } +} + +// +// '_papplScannerWebDefaults()' - Show the scanner defaults web page. +// + +void +_papplScannerWebDefaults( + pappl_client_t *client, // I - Client + pappl_scanner_t *scanner) // I - Scanner +{ + pappl_sc_driver_data_t data; + const char *status = NULL; + + if (!papplClientHTMLAuthorize(client)) + return; + + papplScannerGetDriverData(scanner, &data); + + if (client->operation == HTTP_STATE_POST) + { + cups_len_t num_form = 0; + cups_option_t *form = NULL; + int num_vendor = 0; + cups_option_t *vendor = NULL; + + if ((num_form = (cups_len_t)papplClientGetForm(client, &form)) == 0) + { + status = _PAPPL_LOC("Invalid form data."); + } + else if (!papplClientIsValidForm(client, (int)num_form, form)) + { + status = _PAPPL_LOC("Invalid form submission."); + } + else + { + const char *value; + char *end; + + if ((value = cupsGetOption("document-format", num_form, form)) != NULL) + { + strncpy((char *)data.default_document_format, value, sizeof(data.default_document_format) - 1); + } + + if ((value = cupsGetOption("color-mode", num_form, form)) != NULL) + { + data.default_color_mode = (pappl_sc_color_mode_t)_papplColorModeValue(value); + } + + if ((value = cupsGetOption("resolution", num_form, form)) != NULL) + { + data.default_resolution = (int)strtol(value, &end, 10); + + if (errno == ERANGE || *end || data.default_resolution < 0) + data.default_resolution = data.default_resolution; + } + + if ((value = cupsGetOption("input-source", num_form, form)) != NULL) + { + for (int i = 0; i < PAPPL_MAX_SOURCES; i++) + { + if (!strcmp(InputSourceString(data.input_sources_supported[i]), value)) + { + data.default_input_source = data.input_sources_supported[i]; + break; + } + } + } + + if ((value = cupsGetOption("duplex", num_form, form)) != NULL) + { + data.duplex_supported = !strcmp(value, "true"); + } + + if ((value = cupsGetOption("intent", num_form, form)) != NULL) + { + strncpy((char *)data.default_intent, value, sizeof(data.default_intent) - 1); + } + + if ((value = cupsGetOption("scan-area-width", num_form, form)) != NULL) + { + data.default_scan_area[0] = (int)strtol(value, &end, 10); + } + + if ((value = cupsGetOption("scan-area-height", num_form, form)) != NULL) + { + data.default_scan_area[1] = (int)strtol(value, &end, 10); + } + + if ((value = cupsGetOption("brightness", num_form, form)) != NULL) + { + data.adjustments.brightness = (int)strtol(value, &end, 10); + } + + if ((value = cupsGetOption("contrast", num_form, form)) != NULL) + { + data.adjustments.contrast = (int)strtol(value, &end, 10); + } + + if ((value = cupsGetOption("gamma", num_form, form)) != NULL) + { + data.adjustments.gamma = (int)strtol(value, &end, 10); + } + + if ((value = cupsGetOption("threshold", num_form, form)) != NULL) + { + data.adjustments.threshold = (int)strtol(value, &end, 10); + } + + if ((value = cupsGetOption("saturation", num_form, form)) != NULL) + { + data.adjustments.saturation = (int)strtol(value, &end, 10); + } + + if ((value = cupsGetOption("sharpness", num_form, form)) != NULL) + { + data.adjustments.sharpness = (int)strtol(value, &end, 10); + } + + if ((value = cupsGetOption("compression-supported", num_form, form)) != NULL) + { + data.compression_supported = !strcmp(value, "true"); + } + + if ((value = cupsGetOption("noise-removal-supported", num_form, form)) != NULL) + { + data.noise_removal_supported = !strcmp(value, "true"); + } + + if ((value = cupsGetOption("sharpening-supported", num_form, form)) != NULL) + { + data.sharpening_supported = !strcmp(value, "true"); + } + + if ((value = cupsGetOption("binary-rendering-supported", num_form, form)) != NULL) + { + data.binary_rendering_supported = !strcmp(value, "true"); + } + + if ((value = cupsGetOption("blank-page-removal-supported", num_form, form)) != NULL) + { + data.blank_page_removal_supported = !strcmp(value, "true"); + } + + if (papplScannerSetDriverDefaults(scanner, &data)) + status = _PAPPL_LOC("Changes saved."); + else + status = _PAPPL_LOC("Bad scanner defaults."); + + cupsFreeOptions((cups_len_t)num_vendor, vendor); + } + + cupsFreeOptions(num_form, form); + } + + papplClientHTMLScannerHeader(client, scanner, _PAPPL_LOC("Scanning Defaults"), 0, NULL, NULL); + if (status) + papplClientHTMLPrintf(client, "
%s
\n", papplClientGetLocString(client, status)); + + papplClientHTMLStartForm(client, client->uri, false); + + papplClientHTMLPuts(client, + " \n" + " \n"); + + // Document Format + papplClientHTMLPrintf(client, " \n"); + + // Resolution + papplClientHTMLPrintf(client, " \n"); + + // Color Mode + papplClientHTMLPrintf(client, " \n"); + + // Input Source + papplClientHTMLPrintf(client, " \n"); + + // Duplex + papplClientHTMLPrintf(client, " \n", + data.duplex_supported ? " checked" : ""); + + // Scan Intent + papplClientHTMLPrintf(client, " \n"); + + // Scan Area Width + papplClientHTMLPrintf(client, " \n", + data.default_scan_area[0]); + + // Scan Area Height + papplClientHTMLPrintf(client, " \n", + data.default_scan_area[1]); + + // Adjustments + papplClientHTMLPrintf(client, " \n", + data.adjustments.brightness); + + papplClientHTMLPrintf(client, " \n", + data.adjustments.contrast); + + papplClientHTMLPrintf(client, " \n", + data.adjustments.gamma); + + papplClientHTMLPrintf(client, " \n", + data.adjustments.threshold); + + papplClientHTMLPrintf(client, " \n", + data.adjustments.saturation); + + papplClientHTMLPrintf(client, " \n", + data.adjustments.sharpness); + + // Blank Page Removal + papplClientHTMLPrintf(client, " \n", + data.blank_page_removal_supported ? " checked" : ""); + + + // Noise Removal + papplClientHTMLPrintf(client, " \n", + data.noise_removal_supported ? " checked" : ""); + // Sharpening + papplClientHTMLPrintf(client, " \n", + data.sharpening_supported ? " checked" : ""); + + papplClientHTMLPuts(client, + " \n" + " \n" + "
%s:", papplClientGetLocString(client, "document-format")); + papplClientHTMLPuts(client, "
%s:", papplClientGetLocString(client, "resolution")); + papplClientHTMLPuts(client, "
%s:", papplClientGetLocString(client, "color-mode")); + papplClientHTMLPuts(client, "
%s:", papplClientGetLocString(client, "input-source")); + papplClientHTMLPuts(client, "
%s:", papplClientGetLocString(client, "duplex")); + papplClientHTMLPrintf(client, "
%s:", papplClientGetLocString(client, "intent")); + papplClientHTMLPuts(client, "
%s:", papplClientGetLocString(client, "scan-area-width")); + papplClientHTMLPrintf(client, "
%s:", papplClientGetLocString(client, "scan-area-height")); + papplClientHTMLPrintf(client, "
%s:", papplClientGetLocString(client, "brightness")); + papplClientHTMLPrintf(client, "
%s:", papplClientGetLocString(client, "contrast")); + papplClientHTMLPrintf(client, "
%s:", papplClientGetLocString(client, "gamma")); + papplClientHTMLPrintf(client, "
%s:", papplClientGetLocString(client, "threshold")); + papplClientHTMLPrintf(client, "
%s:", papplClientGetLocString(client, "saturation")); + papplClientHTMLPrintf(client, "
%s:", papplClientGetLocString(client, "sharpness")); + papplClientHTMLPrintf(client, "
%s:", papplClientGetLocString(client, "blank-page-removal")); + papplClientHTMLPrintf(client, "
%s:", papplClientGetLocString(client, "noise-removal")); + papplClientHTMLPrintf(client, "
%s:", papplClientGetLocString(client, "sharpening")); + papplClientHTMLPrintf(client, "
\n" + " \n"); + + papplClientHTMLScannerFooter(client); +} + + +// +// '_papplScannerWebDelete()' - Show the scanner delete confirmation web page. +// + +void +_papplScannerWebDelete( + pappl_client_t *client, // I - Client + pappl_scanner_t *scanner) // I - Scanner +{ + const char *status = NULL; // Status message, if any + + + if (!papplClientHTMLAuthorize(client)) + return; + + if (client->operation == HTTP_STATE_POST) + { + cups_len_t num_form = 0; // Number of form variables + cups_option_t *form = NULL; // Form variables + + if ((num_form = (cups_len_t)papplClientGetForm(client, &form)) == 0) + { + status = _PAPPL_LOC("Invalid form data."); + } + else if (!papplClientIsValidForm(client, (int)num_form, form)) + { + status = _PAPPL_LOC("Invalid form submission."); + } + else if (scanner->processing_job) + { + // Scanner is processing a job... + status = _PAPPL_LOC("Scanner is currently active."); + } + else + { + if (!papplScannerIsDeleted(scanner)) + { + papplScannerDelete(scanner); + scanner = NULL; + } + + papplClientRespondRedirect(client, HTTP_STATUS_FOUND, "/"); + cupsFreeOptions(num_form, form); + return; + } + + cupsFreeOptions(num_form, form); + } + + papplClientHTMLScannerHeader(client, scanner, _PAPPL_LOC("Delete Scanner"), 0, NULL, NULL); + + if (status) + papplClientHTMLPrintf(client, "
%s
\n", papplClientGetLocString(client, status)); + + papplClientHTMLStartForm(client, client->uri, false); + papplClientHTMLPrintf(client," ", papplClientGetLocString(client, _PAPPL_LOC("Confirm Delete Scanner"))); + + papplClientHTMLFooter(client); +} + +// +// '_papplScannerWebHome()' - Show the scanner home page. +// + +void +_papplScannerWebHome( + pappl_client_t *client, // I - Client + pappl_scanner_t *scanner) // I - Scanner +{ + const char *status = NULL; // Status text, if any + escl_sstate_t scanner_state; // Scanner state + char edit_path[1024]; // Edit configuration URL + // Job index and limit not required as of now + char dns_sd_name[64], // Scanner DNS-SD name + location[128], // Scanner location + geo_location[128], // Scanner geo-location + organization[256]; // Scanner organization + pappl_contact_t contact; // Scanner contact + + // Save current scanner state... + scanner_state = scanner->state; + + // Handle POSTs to perform scanner actions... + if (client->operation == HTTP_STATE_POST) + { + cups_len_t num_form = 0; // Number of form variables + cups_option_t *form = NULL; // Form variables + const char *action; // Form action + + if ((num_form = (cups_len_t)papplClientGetForm(client, &form)) == 0) + { + status = _PAPPL_LOC("Invalid form data."); + } + else if (!papplClientIsValidForm(client, (int)num_form, form)) + { + status = _PAPPL_LOC("Invalid form submission."); + } + else if ((action = cupsGetOption("action", num_form, form)) == NULL) + { + status = _PAPPL_LOC("Missing action."); + } + else + { + // Handle different actions (e.g., pause, resume, identify, etc.) + if (!strcmp(action, "identify-scanner")) + { + if (scanner->driver_data.identify_cb) + { + (scanner->driver_data.identify_cb)(scanner, scanner->driver_data.identify_supported, "Hello."); + status = _PAPPL_LOC("Scanner identified."); + } + else + { + status = _PAPPL_LOC("Unable to identify scanner."); + } + } + else if (!strcmp(action, "resume-scanner")) + { + papplScannerResume(scanner); + scanner->state = ESCL_SSTATE_IDLE; + status = _PAPPL_LOC("Scanner resuming."); + } + else if (!strcmp(action, "set-as-default")) + { + papplSystemSetDefaultScannerID(scanner->system, scanner->scanner_id); + status = _PAPPL_LOC("Default scanner set."); + } + else + { + status = _PAPPL_LOC("Unknown action."); + } + } + cupsFreeOptions(num_form, form); + } + + + // Show status... + papplClientHTMLScannerHeader(client, scanner, NULL, scanner_state == ESCL_SSTATE_PROCESSING ? 10 : 0, NULL, NULL); + + papplClientHTMLPuts(client, + "
\n" + "
\n"); + + + if (status) + papplClientHTMLPrintf(client, "
%s
\n", papplClientGetLocString(client, status)); + + snprintf(edit_path, sizeof(edit_path), "%s/config", scanner->uriname); + papplClientHTMLPrintf(client, "

%s %s

\n", papplClientGetLocString(client, _PAPPL_LOC("Configuration")), _papplClientGetAuthWebScheme(client), client->host_field, client->host_port, edit_path, papplClientGetLocString(client, _PAPPL_LOC("Change"))); + + // Display scanner information and links + _papplClientHTMLInfo(client, false, + papplScannerGetDNSSDName(scanner, dns_sd_name, sizeof(dns_sd_name)), + papplScannerGetLocation(scanner, location, sizeof(location)), + papplScannerGetGeoLocation(scanner, geo_location, sizeof(geo_location)), + papplScannerGetOrganization(scanner, organization, sizeof(organization)), + NULL, + papplScannerGetContact(scanner, &contact)); + + _papplClientHTMLPutLinks(client, scanner->links, PAPPL_LOPTIONS_CONFIGURATION); + + // Display scanner state + papplClientHTMLPrintf(client, + "
\n" + "
\n" + "

%s

\n", papplClientGetLocString(client, _PAPPL_LOC("Scanner Status"))); + + if (scanner->state == ESCL_SSTATE_PROCESSING) + { + papplClientHTMLPrintf(client, "

%s

\n", papplClientGetLocString(client, _PAPPL_LOC("Processing"))); + } + else + { + papplClientHTMLPrintf(client, "

%s

\n", papplClientGetLocString(client, _PAPPL_LOC("Idle"))); + } + + _papplClientHTMLPutLinks(client, scanner->links, PAPPL_LOPTIONS_JOB); + + papplClientHTMLScannerFooter(client); + + // Optional TODO: Add functions to show all completed jobs, right now we only show scanner status and configuration + +} diff --git a/pappl/scanner.h b/pappl/scanner.h index 6ae674a3..db23baf7 100644 --- a/pappl/scanner.h +++ b/pappl/scanner.h @@ -66,10 +66,13 @@ typedef enum { PAPPL_ADF, // For automatic dopappl_sc_input_source_t;cument feeder } pappl_sc_input_source_t; +typedef unsigned pappl_identify_sc_actions_t; // eSCL actions for identifying the scanner + // // Callback functions... // typedef pappl_sc_driver_data_t (*pappl_sc_capabilities_cb_t)(pappl_scanner_t *scanner); // Callback for getting scanner capabilities +typedef void (*pappl_sc_identify_cb_t)(pappl_scanner_t *scanner, pappl_identify_sc_actions_t actions, const char *message); // Callback for identifying the scanner typedef void (*pappl_sc_job_create_cb_t)(pappl_job_t *job, pappl_sc_options_t *options, pappl_device_t *device); // Callback for creating a scan job typedef void (*pappl_sc_job_delete_cb_t)(pappl_job_t *job); // Callback for deleting a scan job typedef bool (*pappl_sc_data_cb_t)(pappl_job_t *job, pappl_device_t *device, void *buffer, size_t bufsize); // Callback for getting scan data @@ -121,6 +124,7 @@ typedef struct pappl_sc_options_s // Provides scan job options for the user afte typedef struct pappl_sc_driver_data_s // Initially polling the scanner driver for capabilities and settings { + pappl_sc_identify_cb_t identify_cb; // Callback for identifying the scanner pappl_sc_capabilities_cb_t capabilities_cb; // Callback for getting scanner capabilities pappl_sc_job_create_cb_t job_create_cb; // Callback for creating a scan job pappl_sc_job_delete_cb_t job_delete_cb; // Callback for deleting a scan job @@ -131,6 +135,9 @@ typedef struct pappl_sc_driver_data_s // Initially polling the scanner driver f pappl_sc_buffer_info_cb_t buffer_info_cb; // Callback for getting buffer information pappl_sc_image_info_cb_t image_info_cb; // Callback for getting image information + pappl_identify_sc_actions_t identify_default; // "identify-actions-default" values + pappl_identify_sc_actions_t identify_supported; // "identify-actions-supported" values + char make_and_model[128]; // Make and model of the scanner const char *document_formats_supported[PAPPL_MAX_FORMATS]; // Supported document formats (JPEG, PDF, TIFF, PNG, BMP) pappl_sc_color_mode_t color_modes_supported[PAPPL_MAX_COLOR_MODES]; // Supported color modes (BlackAndWhite1, Grayscale8, RGB24) @@ -146,12 +153,28 @@ typedef struct pappl_sc_driver_data_s // Initially polling the scanner driver f int scan_region_supported[4]; // Supported scan regions (top, left, width, height) const char *mandatory_intents[5]; // Mandatory intents supported by the scanner (e.g., Document, Photo, TextAndGraphic, Preview, BusinessCard) const char *optional_intents[5]; // Optional intents supported by the scanner (e.g., Object, CustomIntent) + + struct { + int brightness; // Brightness adjustment + int contrast; // Contrast adjustment + int gamma; // Gamma adjustment + int threshold; // Threshold for black/white scans + int saturation; // Saturation adjustment + int sharpness; // Sharpness adjustment + } adjustments; + bool compression_supported; // Whether compression is supported bool noise_removal_supported; // Whether noise removal is supported - bool sharpness_supported; // Whether sharpness adjustment is supported - int compression_factor_supported; // Supported compression factors + bool sharpening_supported; // Whether sharpness adjustment is supported bool binary_rendering_supported; // Whether binary rendering is supported + bool blank_page_removal_supported; // Whether blank page removal is supported + const char *feed_direction_supported[2]; // Supported feed directions (e.g., LeftToRight, RightToLeft) + const char *default_document_format; // Default document format + const char *default_color_space; // Default color space + int default_scan_area[2]; // Default scan area (width, height) + const char *default_media_type; // Default media type + const char *default_intent; // Default intent } pappl_sc_driver_data_t; // diff --git a/pappl/system-accessors.c b/pappl/system-accessors.c index 6d6e8c34..76ea3d50 100644 --- a/pappl/system-accessors.c +++ b/pappl/system-accessors.c @@ -1639,6 +1639,30 @@ papplSystemSetDefaultPrinterID( } } +// +// 'papplSystemSetDefaultScannerID()' - Set the "default-scanner-id" value. +// +// This function sets the default scanner using its unique positive integer +// identifier. +// + +void +papplSystemSetDefaultScannerID( + pappl_system_t *system, // I - System + int default_scanner_id) // I - "default-scanner-id" value +{ + if (system) + { + _papplRWLockWrite(system); + + system->default_scanner_id = default_scanner_id; + + _papplSystemConfigChanged(system); + + _papplRWUnlock(system); + } +} + // // 'papplSystemSetDefaultPrintGroup()' - Set the default print group. diff --git a/pappl/system-private.h b/pappl/system-private.h index 9bb4abd5..9b1bb64f 100644 --- a/pappl/system-private.h +++ b/pappl/system-private.h @@ -102,9 +102,18 @@ struct _pappl_system_s // System data cups_array_t *printers; // Array of printers int default_printer_id, // Default printer-id next_printer_id; // Next printer-id + + int default_scanner_id, // Default scanner-id + next_scanner_id; // Next scanner-id char password_hash[100]; // Access password hash cups_len_t num_drivers; // Number of printer drivers pappl_pr_driver_t *drivers; // Printer drivers + + pappl_sc_driver_t *scanners; // Scanner drivers + pappl_sc_autoadd_cb_t autoadd_sc_cb; // Scanner driver auto-add callback + pappl_sc_create_cb_t create_sc_cb; // Scanner driver creation callback + pappl_sc_driver_cb_t driver_sc_cb; // Scanner driver initialization callback + pappl_pr_autoadd_cb_t autoadd_cb; // Printer driver auto-add callback pappl_pr_create_cb_t create_cb; // Printer driver creation callback pappl_pr_driver_cb_t driver_cb; // Printer driver initialization callback diff --git a/pappl/system.h b/pappl/system.h index c29d2343..7674beec 100644 --- a/pappl/system.h +++ b/pappl/system.h @@ -55,6 +55,14 @@ typedef struct pappl_pr_driver_s // Printer driver information void *extension; // Extension data pointer } pappl_pr_driver_t; +typedef struct pappl_sc_driver_s // Scanner driver information +{ + const char *name; // Driver name + const char *description; // Driver description (usually the make and model) + const char *device_id; // Device ID + void *extension; // Extension data pointer +} pappl_sc_driver_t; + enum pappl_soptions_e // System option bits { PAPPL_SOPTIONS_NONE = 0x0000, // No options @@ -109,6 +117,14 @@ typedef void (*pappl_pr_create_cb_t)(pappl_printer_t *printer, void *data); // Printer creation callback typedef bool (*pappl_pr_driver_cb_t)(pappl_system_t *system, const char *driver_name, const char *device_uri, const char *device_id, pappl_pr_driver_data_t *driver_data, ipp_t **driver_attrs, void *data); // Driver callback function + +typedef const char *(*pappl_sc_autoadd_cb_t)(const char *device_info, const char *device_uri, const char *device_id, void *data); + // Scanner Auto-add callback +typedef void (*pappl_sc_create_cb_t)(pappl_scanner_t *scanner, void *data); + // Scanner creation callback +typedef bool (*pappl_sc_driver_cb_t)(pappl_system_t *system, const char *driver_name, const char *device_uri, const char *device_id, pappl_sc_driver_data_t *driver_data, void *data); + // Scanner Driver callback function + typedef bool (*pappl_mime_filter_cb_t)(pappl_job_t *job, pappl_device_t *device, void *data); // Filter callback function typedef bool (*pappl_ipp_op_cb_t)(pappl_client_t *client, void *data); @@ -204,6 +220,7 @@ extern void papplSystemSetAdminGroup(pappl_system_t *system, const char *value) extern void papplSystemSetAuthCallback(pappl_system_t *system, const char *auth_scheme, pappl_auth_cb_t auth_cb, void *auth_cbdata) _PAPPL_PUBLIC; extern void papplSystemSetContact(pappl_system_t *system, pappl_contact_t *contact) _PAPPL_PUBLIC; extern void papplSystemSetDefaultPrinterID(pappl_system_t *system, int default_printer_id) _PAPPL_PUBLIC; +extern void papplSystemSetDefaultScannerID(pappl_system_t *system, int default_scanner_id) _PAPPL_PUBLIC; extern void papplSystemSetDefaultPrintGroup(pappl_system_t *system, const char *value) _PAPPL_PUBLIC; extern void papplSystemSetDNSSDName(pappl_system_t *system, const char *value) _PAPPL_PUBLIC; extern void papplSystemSetEventCallback(pappl_system_t *system, pappl_event_cb_t event_cb, void *event_data) _PAPPL_PUBLIC; From 3579da66e6ec550449c684557de68689c5fbabbc Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Fri, 12 Jul 2024 22:20:17 +0000 Subject: [PATCH 18/26] Finalise scanner.c This commit finalises the scanner.c file. It is closely in reference to the printer.c file, while also covering the necessary details of eSCL Scanning. Signed-off-by: Akarshan Kapoor --- pappl/Makefile | 4 +- pappl/dnssd.c | 22 +++ pappl/scanner-driver.c | 18 ++- pappl/scanner.c | 335 +++++++++++++++++++++++++++++++++++++++ pappl/scanner.h | 3 + pappl/system-accessors.c | 22 +++ pappl/system-printer.c | 158 ++++++++++++++++++ pappl/system-private.h | 6 +- pappl/system.c | 43 +++++ pappl/system.h | 3 + testsuite/Makefile | 2 + 11 files changed, 613 insertions(+), 3 deletions(-) create mode 100644 pappl/scanner.c diff --git a/pappl/Makefile b/pappl/Makefile index 6f602622..d1461190 100644 --- a/pappl/Makefile +++ b/pappl/Makefile @@ -47,6 +47,7 @@ BASEOBJS = \ printer-usb.o \ printer-webif.o \ resource.o \ + scanner.o \ scanner-accessors.o\ scanner-driver.o \ scanner-escl.o \ @@ -81,7 +82,8 @@ HEADERS = \ scanner.h \ scanner-private.h \ subscription.h \ - system.h + system.h \ + system-private.h RESOURCES = \ icon-sm.png \ diff --git a/pappl/dnssd.c b/pappl/dnssd.c index f5ba46a4..0da19ced 100644 --- a/pappl/dnssd.c +++ b/pappl/dnssd.c @@ -922,6 +922,28 @@ _papplPrinterUnregisterDNSSDNoLock( #endif // HAVE_MDNSRESPONDER } +// +// TODO : papplScannerRegisterDNSSDNoLock - Register a scanner's DNS-SD service. +// + +bool // O - `true` on success, `false` on failure +_papplScannerRegisterDNSSDNoLock( + pappl_scanner_t *scanner) // I - Scanner +{ + bool ret = true; // Sample return value + return (ret); +} + +// +// TODO: '_papplScannerUnregisterDNSSDNoLock()' - Unregister a scanners's DNS-SD service. +// + +void +_papplScannerUnregisterDNSSDNoLock( + pappl_scanner_t *scanner) // I - Scanner +{ + return ; // Sample return +} // // '_papplSystemRegisterDNSSDNoLock()' - Register a system's DNS-SD service. diff --git a/pappl/scanner-driver.c b/pappl/scanner-driver.c index e0cb1eaf..52f180ac 100644 --- a/pappl/scanner-driver.c +++ b/pappl/scanner-driver.c @@ -18,7 +18,7 @@ extern xmlDocPtr make_escl_attr(pappl_scanner_t *scanner); extern const char *ScannerInputSourceString(pappl_sc_input_source_t value) _PAPPL_PRIVATE; extern const char *ScannerResolutionString(int resolution) _PAPPL_PRIVATE; - +extern const char *_papplScannerColorModeString(pappl_sc_color_mode_t value) _PAPPL_PRIVATE; // // 'papplScannerGetDriverData()' - Get the current scanner driver data. @@ -275,3 +275,19 @@ const char *ScannerResolutionString(int resolution) snprintf(res_str, sizeof(res_str), "%d DPI", resolution); return res_str; } + +// Converts color mode to string +const char *_papplScannerColorModeString(pappl_sc_color_mode_t value) +{ + switch (value) + { + case PAPPL_BLACKANDWHITE1: + return "BlackAndWhite1"; + case PAPPL_GRAYSCALE8: + return "Grayscale8"; + case PAPPL_RGB24: + return "RGB24"; + default: + return "Unknown"; + } +} \ No newline at end of file diff --git a/pappl/scanner.c b/pappl/scanner.c new file mode 100644 index 00000000..d15c9062 --- /dev/null +++ b/pappl/scanner.c @@ -0,0 +1,335 @@ +// +// scanner object for the Scanner Application Framework +// +// Copyright © 2019-2024 by Michael R Sweet. +// Copyright © 2010-2019 by Apple Inc. +// +// Licensed under Apache License v2.0. See the file "LICENSE" for more +// information. +// + +#include "pappl-private.h" +#include "scanner-private.h" +#include "scanner.h" +#include "system-private.h" + +// +// 'papplScannerCreate()' - Create a new scanner. +// +// This function creates a new scanner (service) on the specified system. The +// "scanner_id" argument specifies a positive integer identifier that is +// unique to the system. If you specify a value of `0`, a new identifier will +// be assigned. +// +// The "scanner_name" argument specifies a human-readable name for the scanner. +// +// The "driver_name" argument specifies a named driver for the scanner. +// +// The "device_id" and "device_uri" arguments specify the device ID +// and device URI strings for the scanner. +// +// On error, this function sets the `errno` variable to one of the following +// values: +// +// - `EEXIST`: A scanner with the specified name already exists. +// - `EINVAL`: Bad values for the arguments were specified. +// - `EIO`: The driver callback failed. +// - `ENOENT`: No driver callback has been set. +// - `ENOMEM`: Ran out of memory. +// + + +pappl_scanner_t * // O - Scanner or `NULL` on error +papplScannerCreate( + pappl_system_t *system, // I - System + int scanner_id, // I - scanner-id value or `0` for new + const char *scanner_name, // I - Human-readable scanner name + const char *driver_name, // I - Driver name + const char *device_id, // I - IEEE-1284 device ID + const char *device_uri) // I - Device URI +{ + pappl_scanner_t *scanner; // Scanner + pappl_sc_driver_data_t driver_data; // Driver data + char resource[1024], // Resource path + *resptr, // Pointer into resource path + uuid[128]; // scanner-uuid + char path[256]; // Path to resource + + // Range check input... + if (!system || !scanner_name || !driver_name || !device_uri) + { + errno = EINVAL; + return (NULL); + } + + if (!system->driver_cb) + { + papplLog(system, PAPPL_LOGLEVEL_ERROR, "No driver callback set, unable to add scanner."); + errno = ENOENT; + return (NULL); + } + + // Prepare URI values for the scanner attributes... + if (system->options & PAPPL_SOPTIONS_MULTI_QUEUE) + { + // Make sure scanner names that start with a digit have a resource path + // containing an underscore... + if (isdigit(*scanner_name & 255)) + snprintf(resource, sizeof(resource), "/escl/scan/_%s", scanner_name); + else + snprintf(resource, sizeof(resource), "/escl/scan/%s", scanner_name); + + // Convert URL reserved characters to underscore... + for (resptr = resource + 11; *resptr; resptr ++) + { + if ((*resptr & 255) <= ' ' || strchr("\177/\\\'\"?#", *resptr)) + *resptr = '_'; + } + + // Eliminate duplicate and trailing underscores... + resptr = resource + 11; + while (*resptr) + { + if (resptr[0] == '_' && resptr[1] == '_') + memmove(resptr, resptr + 1, strlen(resptr)); // Duplicate underscores + else if (resptr[0] == '_' && !resptr[1]) + *resptr = '\0'; // Trailing underscore + else + resptr ++; + } + } + else + { + papplCopyString(resource, "/escl/scan", sizeof(resource)); + } + + // Make sure the scanner doesn't already exist... + if ((scanner = papplSystemFindScanner(system, resource, 0, NULL)) != NULL) + { + int n; // Current instance number + char temp[1024]; // Temporary resource path + + if (!strcmp(scanner_name, scanner->name)) + { + papplLog(system, PAPPL_LOGLEVEL_ERROR, "Scanner '%s' already exists.", scanner_name); + errno = EEXIST; + return (NULL); + } + + for (n = 2; n < 10; n ++) + { + snprintf(temp, sizeof(temp), "%s_%d", resource, n); + if (!papplSystemFindScanner(system, temp, 0, NULL)) + break; + } + + if (n >= 10) + { + papplLog(system, PAPPL_LOGLEVEL_ERROR, "Scanner '%s' name conflicts with existing scanner.", scanner_name); + errno = EEXIST; + return (NULL); + } + + papplCopyString(resource, temp, sizeof(resource)); + } + + // Allocate memory for the scanner... + if ((scanner = calloc(1, sizeof(pappl_scanner_t))) == NULL) + { + papplLog(system, PAPPL_LOGLEVEL_ERROR, "Unable to allocate memory for scanner: %s", strerror(errno)); + return (NULL); + } + + papplLog(system, PAPPL_LOGLEVEL_INFO, "Scanner '%s' at resource path '%s'.", scanner_name, resource); + + _papplSystemMakeUUID(system, scanner_name, 0, uuid, sizeof(uuid)); + + // Initialize scanner structure and attributes... + pthread_rwlock_init(&scanner->rwlock, NULL); + + scanner->system = system; + scanner->name = strdup(scanner_name); + scanner->dns_sd_name = strdup(scanner_name); + scanner->resource = strdup(resource); + scanner->resourcelen = strlen(resource); + scanner->uriname = scanner->resource + 10; // Skip "/escl/scan" in resource + scanner->device_id = device_id ? strdup(device_id) : NULL; + scanner->device_uri = strdup(device_uri); + scanner->driver_name = strdup(driver_name); + scanner->uuid = strdup(uuid); + scanner->start_time = time(NULL); + scanner->config_time = scanner->start_time; + scanner->state = ESCL_SSTATE_IDLE; + scanner->state_reasons = PAPPL_SREASON_NONE; + scanner->state_time = scanner->start_time; + scanner->is_accepting = true; + scanner->next_job_id = 1; + scanner->processing_job = NULL; // Initialize to NULL + scanner->device = NULL; // Initialize to NULL + scanner->device_in_use = false; // Initialize to false + + // Check for memory allocation failures + if (!scanner->name || !scanner->dns_sd_name || !scanner->resource || (device_id && !scanner->device_id) || !scanner->device_uri || !scanner->driver_name || !scanner->uuid) + { + // Failed to allocate one of the required members... + _papplScannerDelete(scanner); + return (NULL); + } + + // If the driver is "auto", figure out the proper driver name... + if (!strcmp(driver_name, "auto") && system->autoadd_sc_cb) + { + // If device_id is NULL, try to look it up... + if (!scanner->device_id && strncmp(device_uri, "file://", 7)) + { + pappl_device_t *device; // Connection to scanner + + if ((device = papplDeviceOpen(device_uri, "auto", papplLogDevice, system)) != NULL) + { + char new_id[1024]; // New device ID + + if (papplDeviceGetID(device, new_id, sizeof(new_id))) + scanner->device_id = strdup(new_id); + + papplDeviceClose(device); + } + } + + if ((driver_name = (system->autoadd_sc_cb)(scanner_name, device_uri, scanner->device_id, system->sc_driver_cbdata)) == NULL) + { + errno = EIO; + _papplScannerDelete(scanner); + return (NULL); + } + } + + + _papplScannerInitDriverData(scanner,&driver_data); + + if (!(system->driver_sc_cb)(system, driver_name, device_uri, device_id, &driver_data, system->sc_driver_cbdata)) + { + errno = EIO; + _papplScannerDelete(scanner); + return (NULL); + } + + papplScannerSetDriverData(scanner, &driver_data); + + // Add the scanner to the system... + _papplSystemAddScanner(system, scanner, scanner_id); + + // Do any post-creation work... + if (system->create_sc_cb) + (system->create_sc_cb)(scanner, system->sc_driver_cbdata); + + // Add icons... + _papplSystemAddScannerIcons(system, scanner); + + // Add web pages, if any... + if (system->options & PAPPL_SOPTIONS_WEB_INTERFACE) + { + snprintf(path, sizeof(path), "%s/", scanner->uriname); + papplSystemAddResourceCallback(system, path, "text/html", (pappl_resource_cb_t)_papplScannerWebHome, scanner); + + snprintf(path, sizeof(path), "%s/delete", scanner->uriname); + papplSystemAddResourceCallback(system, path, "text/html", (pappl_resource_cb_t)_papplScannerWebDelete, scanner); + + snprintf(path, sizeof(path), "%s/config", scanner->uriname); + papplSystemAddResourceCallback(system, path, "text/html", (pappl_resource_cb_t)_papplScannerWebConfig, scanner); + + snprintf(path, sizeof(path), "%s/printing", scanner->uriname); + papplSystemAddResourceCallback(system, path, "text/html", (pappl_resource_cb_t)_papplScannerWebDefaults, scanner); + + } + + _papplSystemConfigChanged(system); + + // Return it! + return (scanner); +} + +// +// '_papplScannerDelete()' - Free memory associated with a scanner. +// + +void +_papplScannerDelete( + pappl_scanner_t *scanner) // I - Scanner +{ + _pappl_resource_t *r; // Current resource + char prefix[1024]; // Prefix for scanner resources + size_t prefixlen; // Length of prefix + + + _papplRWLockWrite(scanner); + scanner->is_deleted = true; + _papplRWUnlock(scanner); + + // Remove DNS-SD registrations... + _papplScannerUnregisterDNSSDNoLock(scanner); + + // Remove scanner-specific resources... + snprintf(prefix, sizeof(prefix), "%s/", scanner->uriname); + prefixlen = strlen(prefix); + + // Note: System writer lock is already held when calling cupsArrayRemove + // for the system's scanner object, so we don't need a separate lock here + // and can safely use cupsArrayGetFirst/Next... + _papplRWLockWrite(scanner->system); + for (r = (_pappl_resource_t *)cupsArrayGetFirst(scanner->system->resources); r; r = (_pappl_resource_t *)cupsArrayGetNext(scanner->system->resources)) + { + if (r->cbdata == scanner || !strncmp(r->path, prefix, prefixlen)) + cupsArrayRemove(scanner->system->resources, r); + } + _papplRWUnlock(scanner->system); + + // If applicable, call the delete function... + if (scanner->driver_data.sc_delete_cb) + (scanner->driver_data.sc_delete_cb)(scanner, &scanner->driver_data); + + // Free memory... + free(scanner->name); + free(scanner->dns_sd_name); + free(scanner->location); + free(scanner->geo_location); + free(scanner->organization); + free(scanner->resource); + free(scanner->device_id); + free(scanner->device_uri); + free(scanner->driver_name); + free(scanner->uuid); + + cupsArrayDelete(scanner->links); + + pthread_rwlock_destroy(&scanner->rwlock); + + free(scanner); +} + + +// +// 'papplScannerDelete()' - Delete a scanner. +// +// This function deletes a scanner from a system, freeing all memory and +// canceling all jobs as needed. +// + +void +papplScannerDelete( + pappl_scanner_t *scanner) // I - Scanner +{ + pappl_system_t *system = scanner->system; + // System + + // Deliver delete event... + papplSystemAddScannerEvent(scanner->system, scanner, NULL, PAPPL_EVENT_SCANNER_STATE_CHANGED | PAPPL_EVENT_SYSTEM_CONFIG_CHANGED, NULL); + + // Remove the scanner from the system object... + _papplRWLockWrite(system); + cupsArrayRemove(system->scanners, scanner); + _papplRWUnlock(system); + + _papplScannerDelete(scanner); + + _papplSystemConfigChanged(system); +} diff --git a/pappl/scanner.h b/pappl/scanner.h index db23baf7..10eed8dc 100644 --- a/pappl/scanner.h +++ b/pappl/scanner.h @@ -73,6 +73,7 @@ typedef unsigned pappl_identify_sc_actions_t; // eSCL actions for identifying th // typedef pappl_sc_driver_data_t (*pappl_sc_capabilities_cb_t)(pappl_scanner_t *scanner); // Callback for getting scanner capabilities typedef void (*pappl_sc_identify_cb_t)(pappl_scanner_t *scanner, pappl_identify_sc_actions_t actions, const char *message); // Callback for identifying the scanner +typedef void (*pappl_sc_delete_cb_t)(pappl_scanner_t *scanner, pappl_sc_driver_data_t *data); typedef void (*pappl_sc_job_create_cb_t)(pappl_job_t *job, pappl_sc_options_t *options, pappl_device_t *device); // Callback for creating a scan job typedef void (*pappl_sc_job_delete_cb_t)(pappl_job_t *job); // Callback for deleting a scan job typedef bool (*pappl_sc_data_cb_t)(pappl_job_t *job, pappl_device_t *device, void *buffer, size_t bufsize); // Callback for getting scan data @@ -125,6 +126,7 @@ typedef struct pappl_sc_options_s // Provides scan job options for the user afte typedef struct pappl_sc_driver_data_s // Initially polling the scanner driver for capabilities and settings { pappl_sc_identify_cb_t identify_cb; // Callback for identifying the scanner + pappl_sc_delete_cb_t sc_delete_cb; // Scanner deletion callback pappl_sc_capabilities_cb_t capabilities_cb; // Callback for getting scanner capabilities pappl_sc_job_create_cb_t job_create_cb; // Callback for creating a scan job pappl_sc_job_delete_cb_t job_delete_cb; // Callback for deleting a scan job @@ -137,6 +139,7 @@ typedef struct pappl_sc_driver_data_s // Initially polling the scanner driver f pappl_identify_sc_actions_t identify_default; // "identify-actions-default" values pappl_identify_sc_actions_t identify_supported; // "identify-actions-supported" values + pappl_icon_sc_t icons[3]; // "printer-icons" values char make_and_model[128]; // Make and model of the scanner const char *document_formats_supported[PAPPL_MAX_FORMATS]; // Supported document formats (JPEG, PDF, TIFF, PNG, BMP) diff --git a/pappl/system-accessors.c b/pappl/system-accessors.c index 76ea3d50..3f404589 100644 --- a/pappl/system-accessors.c +++ b/pappl/system-accessors.c @@ -535,6 +535,28 @@ papplSystemGetDefaultPrinterID( return (ret); } +// +// 'papplSystemGetDefaultScannerID()' - Get the current "default-scanner-id" value. +// +// This function returns the positive integer identifier for the current +// default scanner or `0` if there is no default scanner. +// + +int // O - "default-scanner-id" value +papplSystemGetDefaultScannerID( + pappl_system_t *system) // I - System +{ + int ret = 0; // Return value + + if (system) + { + _papplRWLockRead(system); + ret = system->default_scanner_id; + _papplRWUnlock(system); + } + return (ret); +} + // // 'papplSystemGetDefaultPrintGroup()' - Get the default print group, if any. diff --git a/pappl/system-printer.c b/pappl/system-printer.c index eba7d1bd..f8c80c6f 100644 --- a/pappl/system-printer.c +++ b/pappl/system-printer.c @@ -19,8 +19,42 @@ // static int compare_printers(pappl_printer_t *a, pappl_printer_t *b); +static int compare_scanners(pappl_scanner_t *a, pappl_scanner_t *b); +// +// '_papplSystemAddScanner()' - Add a scanner to the system object, creating the scanners array as needed. +// + +void +_papplSystemAddScanner( + pappl_system_t *system, // I - System + pappl_scanner_t *scanner, // I - Scanner + int scanner_id) // I - Scanner ID or `0` for new +{ + // Add the scanner to the system... + _papplRWLockWrite(system); + + if (scanner_id) + scanner->scanner_id = scanner_id; + else + scanner->scanner_id = system->next_scanner_id ++; + + if (!system->scanners) + system->scanners = cupsArrayNew((cups_array_cb_t)compare_scanners, /*cb_data*/NULL, /*hash_cb*/NULL, /*hash_size*/0, /*copy_cb*/NULL, /*free_cb*/NULL); + + cupsArrayAdd(system->scanners, scanner); + + if (!system->default_scanner_id) + system->default_scanner_id = scanner->scanner_id; + + _papplRWUnlock(system); + + _papplSystemConfigChanged(system); + + papplSystemAddScannerEvent(scanner->system, scanner, NULL, PAPPL_EVENT_SCANNER_STATE_CHANGED, NULL); +} + // // '_papplSystemAddPrinter()' - Add a printer to the system object, creating the printers array as needed. // @@ -112,6 +146,62 @@ papplSystemCreatePrinters( } +// +// 'papplSystemCreateScanners()' - Create newly discovered scanners. +// +// This function lists all devices specified by "types" and attempts to add any +// new scanners that are found. The callback function "cb" is invoked for each +// scanner that is added. +// + +bool // O - `true` if printers were added, `false` otherwise +papplSystemCreateScanners( + pappl_system_t *system, // I - System + pappl_devtype_t types, // I - Device types + pappl_sc_create_cb_t cb, // I - Callback function + void *cb_data) // I - Callback data +{ + bool ret = false; // Return value + cups_array_t *devices; // Device array + _pappl_dinfo_t *d; // Current device information + + // List the devices... + devices = _papplDeviceInfoCreateArray(); + + papplDeviceList(types, (pappl_device_cb_t)_papplDeviceInfoCallback, devices, papplLogDevice, system); + + // Loop through the devices to find new stuff... + for (d = (_pappl_dinfo_t *)cupsArrayGetFirst(devices); d; d = (_pappl_dinfo_t *)cupsArrayGetNext(devices)) + { + pappl_scanner_t *scanner = NULL;// New scanner + + // See if there is already a scanner for this device URI... + if (papplSystemFindScanner(system, NULL, 0, d->device_uri)) + continue; // Scanner with this device URI exists + + // Then try creating the scanner... + if ((scanner = papplScannerCreate(system, 0, d->device_info, "auto", d->device_id, d->device_uri)) == NULL) + continue; // Scanner with this name exists + + // Register the DNS-SD service... + _papplRWLockRead(scanner->system); + _papplRWLockRead(scanner); + _papplScannerRegisterDNSSDNoLock(scanner); + _papplRWUnlock(scanner); + _papplRWUnlock(scanner->system); + + // Created, return true and invoke the callback if provided... + ret = true; + + if (cb) + (cb)(scanner, cb_data); + } + + cupsArrayDelete(devices); + + return (ret); +} + // // 'papplSystemFindPrinter()' - Find a printer by resource, ID, or device URI. // @@ -169,6 +259,63 @@ papplSystemFindPrinter( return (printer); } +// +// 'papplSystemFindScanner()' - Find a scanner by resource, ID, or device URI. +// +// This function finds a scanner contained in the system using its resource +// path, unique integer identifier, or device URI. If none of these is +// specified, the current default scanner is returned. +// + +pappl_scanner_t * // O - Scanner or `NULL` if none +papplSystemFindScanner( + pappl_system_t *system, // I - System + const char *resource, // I - Resource path or `NULL` + int scanner_id, // I - Printer ID or `0` + const char *device_uri) // I - Device URI or `NULL` +{ + cups_len_t i, // Current scanner index + count; // scanner count + pappl_scanner_t *scanner = NULL;// Matching scanner + + + // Range check input... + if (!system) + return (NULL); + + _papplRWLockRead(system); + + if (resource && (!strcmp(resource, "/") || !strcmp(resource, "/escl/scan") || (!strncmp(resource, "/escl/scan/", 11) && isdigit(resource[11] & 255)))) + { + scanner_id = system->default_scanner_id; + resource = NULL; + } + + // Loop through the scanners to find the one we want... + // + // Note: Cannot use cupsArrayGetFirst/Last since other threads might be + // enumerating the scanners array. + + for (i = 0, count = cupsArrayGetCount(system->scanners); i < count; i ++) + { + scanner = (pappl_scanner_t *)cupsArrayGetElement(system->scanners, i); + + if (resource && !strncasecmp(scanner->resource, resource, scanner->resourcelen) && (!resource[scanner->resourcelen] || resource[scanner->resourcelen] == '/')) + break; + else if (scanner->scanner_id == scanner_id) + break; + else if (device_uri && !strcmp(scanner->device_uri, device_uri)) + break; + } + + if (i >= count) + scanner = NULL; + + _papplRWUnlock(system); + + return (scanner); +} + // // 'compare_printers()' - Compare two printers. @@ -180,3 +327,14 @@ compare_printers(pappl_printer_t *a, // I - First printer { return (strcmp(a->name, b->name)); } + + +// +// 'compare_scanners())' - Compare two scanners. +// +static int // O - Result of comparison +compare_scanners(pappl_scanner_t *a, // I - First scanner + pappl_scanner_t *b) // I - Second scanner +{ + return (strcmp(a->name, b->name)); +} diff --git a/pappl/system-private.h b/pappl/system-private.h index 9b1bb64f..49f3370e 100644 --- a/pappl/system-private.h +++ b/pappl/system-private.h @@ -100,6 +100,7 @@ struct _pappl_system_s // System data cups_array_t *filters; // Array of filters int next_client; // Next client number cups_array_t *printers; // Array of printers + cups_array_t *scanners; // Array of scanners int default_printer_id, // Default printer-id next_printer_id; // Next printer-id @@ -109,7 +110,7 @@ struct _pappl_system_s // System data cups_len_t num_drivers; // Number of printer drivers pappl_pr_driver_t *drivers; // Printer drivers - pappl_sc_driver_t *scanners; // Scanner drivers + pappl_sc_driver_t *scanner_drivers; // Scanner drivers pappl_sc_autoadd_cb_t autoadd_sc_cb; // Scanner driver auto-add callback pappl_sc_create_cb_t create_sc_cb; // Scanner driver creation callback pappl_sc_driver_cb_t driver_sc_cb; // Scanner driver initialization callback @@ -118,6 +119,7 @@ struct _pappl_system_s // System data pappl_pr_create_cb_t create_cb; // Printer driver creation callback pappl_pr_driver_cb_t driver_cb; // Printer driver initialization callback void *driver_cbdata; // Printer driver callback data + void *sc_driver_cbdata; // Scanner driver callback data ipp_t *attrs; // Static attributes for system char *auth_scheme; // Authentication scheme pappl_auth_cb_t auth_cb; // Authentication callback @@ -186,7 +188,9 @@ extern void _papplSystemAddEventNoLock(pappl_system_t *system, pappl_printer_t * extern void _papplSystemAddEventNoLockv(pappl_system_t *system, pappl_printer_t *printer, pappl_scanner_t *scanner, pappl_job_t *job, pappl_event_t event, const char *message, va_list ap) _PAPPL_PRIVATE; extern void _papplSystemAddLoc(pappl_system_t *system, pappl_loc_t *loc) _PAPPL_PRIVATE; extern void _papplSystemAddPrinter(pappl_system_t *system, pappl_printer_t *printer, int printer_id) _PAPPL_PRIVATE; +extern void _papplSystemAddScanner(pappl_system_t *system, pappl_scanner_t *scanner, int scanner_id) _PAPPL_PRIVATE; extern void _papplSystemAddPrinterIcons(pappl_system_t *system, pappl_printer_t *printer) _PAPPL_PRIVATE; +extern void _papplSystemAddScannerIcons(pappl_system_t *system, pappl_scanner_t *scanner) _PAPPL_PRIVATE; extern bool _papplSystemAddSubscription(pappl_system_t *system, pappl_subscription_t *sub, int sub_id) _PAPPL_PRIVATE; extern void _papplSystemCleanSubscriptions(pappl_system_t *system, bool clean_all) _PAPPL_PRIVATE; extern void _papplSystemConfigChanged(pappl_system_t *system) _PAPPL_PRIVATE; diff --git a/pappl/system.c b/pappl/system.c index bbbdf42e..911abf06 100644 --- a/pappl/system.c +++ b/pappl/system.c @@ -73,6 +73,49 @@ _papplSystemAddPrinterIcons( } +// +// '_papplSystemAddScannerIcons()' - (Re)add scanner icon resources. +// + +void +_papplSystemAddScannerIcons( + pappl_system_t *system, // I - System + pappl_scanner_t *scanner) // I - Scanner +{ + char path[256]; // Resource path + pappl_icon_sc_t *icons = scanner->driver_data.icons; + // Scanner icons + + + snprintf(path, sizeof(path), "%s/icon-sm.png", scanner->uriname); + papplSystemRemoveResource(system, path); + if (icons[0].filename[0]) + papplSystemAddResourceFile(system, path, "image/png", icons[0].filename); + else if (icons[0].data && icons[0].datalen) + papplSystemAddResourceData(system, path, "image/png", icons[0].data, icons[0].datalen); + else + papplSystemAddResourceData(system, path, "image/png", icon_sm_png, sizeof(icon_sm_png)); + + snprintf(path, sizeof(path), "%s/icon-md.png", scanner->uriname); + papplSystemRemoveResource(system, path); + if (icons[1].filename[0]) + papplSystemAddResourceFile(system, path, "image/png", icons[1].filename); + else if (icons[1].data && icons[1].datalen) + papplSystemAddResourceData(system, path, "image/png", icons[1].data, icons[1].datalen); + else + papplSystemAddResourceData(system, path, "image/png", icon_md_png, sizeof(icon_md_png)); + + snprintf(path, sizeof(path), "%s/icon-lg.png", scanner->uriname); + papplSystemRemoveResource(system, path); + if (icons[2].filename[0]) + papplSystemAddResourceFile(system, path, "image/png", icons[2].filename); + else if (icons[2].data && icons[2].datalen) + papplSystemAddResourceData(system, path, "image/png", icons[2].data, icons[2].datalen); + else + papplSystemAddResourceData(system, path, "image/png", icon_lg_png, sizeof(icon_lg_png)); +} + + // // '_papplSystemConfigChanged()' - Mark the system configuration as changed. // diff --git a/pappl/system.h b/pappl/system.h index 7674beec..5d058086 100644 --- a/pappl/system.h +++ b/pappl/system.h @@ -171,14 +171,17 @@ extern bool papplSystemAddTimerCallback(pappl_system_t *system, time_t start, i extern void papplSystemCleanJobs(pappl_system_t *system) _PAPPL_PUBLIC; extern pappl_system_t *papplSystemCreate(pappl_soptions_t options, const char *name, int port, const char *subtypes, const char *spooldir, const char *logfile, pappl_loglevel_t loglevel, const char *auth_service, bool tls_only) _PAPPL_PUBLIC; extern bool papplSystemCreatePrinters(pappl_system_t *system, pappl_devtype_t types, pappl_pr_create_cb_t cb, void *cb_data) _PAPPL_PUBLIC; +extern bool papplSystemCreateScanners(pappl_system_t *system, pappl_devtype_t types, pappl_sc_create_cb_t cb, void *cb_data) _PAPPL_PUBLIC; extern void papplSystemDelete(pappl_system_t *system) _PAPPL_PUBLIC; extern pappl_loc_t *papplSystemFindLoc(pappl_system_t *system, const char *language) _PAPPL_PUBLIC; extern pappl_printer_t *papplSystemFindPrinter(pappl_system_t *system, const char *resource, int printer_id, const char *device_uri) _PAPPL_PUBLIC; +extern pappl_scanner_t *papplSystemFindScanner(pappl_system_t *system, const char *resource, int scanner_id, const char *device_uri) _PAPPL_PUBLIC; extern pappl_subscription_t *papplSystemFindSubscription(pappl_system_t *system, int sub_id) _PAPPL_PUBLIC; extern char *papplSystemGetAdminGroup(pappl_system_t *system, char *buffer, size_t bufsize) _PAPPL_PUBLIC; extern const char *papplSystemGetAuthService(pappl_system_t *system) _PAPPL_PUBLIC; extern pappl_contact_t *papplSystemGetContact(pappl_system_t *system, pappl_contact_t *contact) _PAPPL_PUBLIC; extern int papplSystemGetDefaultPrinterID(pappl_system_t *system) _PAPPL_PUBLIC; +extern int papplSystemGetDefaultScannerID(pappl_system_t *system) _PAPPL_PUBLIC; extern char *papplSystemGetDefaultPrintGroup(pappl_system_t *system, char *buffer, size_t bufsize) _PAPPL_PUBLIC; extern char *papplSystemGetDNSSDName(pappl_system_t *system, char *buffer, size_t bufsize) _PAPPL_PUBLIC; extern const char *papplSystemGetFooterHTML(pappl_system_t *system) _PAPPL_PUBLIC; diff --git a/testsuite/Makefile b/testsuite/Makefile index ee144072..72973fa1 100644 --- a/testsuite/Makefile +++ b/testsuite/Makefile @@ -82,3 +82,5 @@ resheader: # Dependencies include Dependencies + +LIBS=-ldl -lpthread -lcups -lavahi-common -lavahi-client -lssl -lcrypto -ljpeg -lpng16 -lz -lusb-1.0 -lpam -lxml2 From 92dcfe0e820a9e2608dda4a2942f9f3178d97e89 Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Sat, 2 Nov 2024 12:41:59 +0000 Subject: [PATCH 19/26] Minor changes to the log and scanner files Add a few comments and also add scanner_logging function to the log file. Signed-off-by: Akarshan Kapoor --- pappl/log.c | 70 +++++++++++++++++++++++++++++++++++++++++ pappl/log.h | 1 + pappl/scanner-private.h | 19 +++++------ pappl/scanner.h | 2 +- 4 files changed, 82 insertions(+), 10 deletions(-) diff --git a/pappl/log.c b/pappl/log.c index 4b4e9a2a..0d1b869d 100644 --- a/pappl/log.c +++ b/pappl/log.c @@ -11,6 +11,7 @@ #include "job-private.h" #include "log-private.h" #include "printer-private.h" +#include "scanner-private.h" #include "system-private.h" #include #if !_WIN32 @@ -423,6 +424,75 @@ papplLogPrinter( va_end(ap); } +// 'papplLogScanner()' - Log a message for a scanner. +// +// This function sends a scanner message to the system's log file. The "level" +// argument specifies the urgency of the message: +// +// - `PAPPL_LOGLEVEL_DEBUG`: A debugging message. +// - `PAPPL_LOGLEVEL_ERROR`: An error message. +// - `PAPPL_LOGLEVEL_FATAL`: A fatal error message. +// - `PAPPL_LOGLEVEL_INFO`: An informational message. +// - `PAPPL_LOGLEVEL_WARN`: A warning message. +// +// The "message" argument specifies a `printf`-style format string. Values +// logged using the "%c" and "%s" format specifiers are sanitized to not +// contain control characters. +// + +void +papplLogScanner( + pappl_scanner_t *scanner, // I - Scanner + pappl_loglevel_t level, // I - Log level + const char *message, // I - Printf-style message string + ...) // I - Additional arguments as needed +{ + char pmessage[1024], // Message with scanner prefix + *pptr, // Pointer into prefix + *nameptr; // Pointer into scanner name + va_list ap; // Pointer to arguments + pappl_system_t *system; // System + + + if (!scanner || !message) + return; + + system = scanner->system; + + if (level < papplSystemGetLogLevel(system)) + return; + + // Prefix the message with "[Printer foo]", making sure to not insert any + // printf format specifiers. + papplCopyString(pmessage, "[Scanner ", sizeof(pmessage)); + for (pptr = pmessage + 9, nameptr = scanner->name; *nameptr && pptr < (pmessage + 200); pptr ++) + { + if (*nameptr == '%') + *pptr++ = '%'; + *pptr = *nameptr++; + } + *pptr++ = ']'; + *pptr++ = ' '; + papplCopyString(pptr, message, sizeof(pmessage) - (size_t)(pptr - pmessage)); + + // Write the log message... + va_start(ap, message); + +#if !_WIN32 + if (system->log_is_syslog) + { + vsyslog(syslevels[level], pmessage, ap); + } + else +#endif // !_WIN32 + { + pthread_mutex_lock(&system->log_mutex); + write_log_no_lock(system, level, pmessage, ap); + pthread_mutex_unlock(&system->log_mutex); + } + + va_end(ap); +} // // 'rotate_log_no_lock()' - Rotate the log file... diff --git a/pappl/log.h b/pappl/log.h index d73de52b..3542bdb9 100644 --- a/pappl/log.h +++ b/pappl/log.h @@ -40,6 +40,7 @@ extern void papplLogClient(pappl_client_t *client, pappl_loglevel_t level, cons extern void papplLogDevice(const char *message, void *data) _PAPPL_PUBLIC; extern void papplLogJob(pappl_job_t *job, pappl_loglevel_t level, const char *message, ...) _PAPPL_PUBLIC _PAPPL_FORMAT(3, 4); extern void papplLogPrinter(pappl_printer_t *printer, pappl_loglevel_t level, const char *message, ...) _PAPPL_PUBLIC _PAPPL_FORMAT(3, 4); +extern void papplLogScanner(pappl_scanner_t *scanner, pappl_loglevel_t level, const char *message, ...) _PAPPL_PUBLIC _PAPPL_FORMAT(3, 4); # ifdef __cplusplus diff --git a/pappl/scanner-private.h b/pappl/scanner-private.h index 905a53bc..eba9112f 100644 --- a/pappl/scanner-private.h +++ b/pappl/scanner-private.h @@ -86,24 +86,25 @@ extern const char *_papplScannerReasonString(pappl_sreason_t reason) _PAPPL_PRIV extern void _papplScannerDelete(pappl_scanner_t *scanner) _PAPPL_PRIVATE; extern void _papplScannerInitDriverData(pappl_scanner_t *scanner, pappl_sc_driver_data_t *d) _PAPPL_PRIVATE; -extern bool _papplScannerIsAuthorized(pappl_client_t *client) _PAPPL_PRIVATE; -extern void _papplScannerProcessESCL(pappl_client_t *client) _PAPPL_PRIVATE; -extern bool _papplScannerRegisterDNSSDNoLock(pappl_scanner_t *scanner) _PAPPL_PRIVATE; -extern void _papplScannerUnregisterDNSSDNoLock(pappl_scanner_t *scanner) _PAPPL_PRIVATE; +extern bool _papplScannerIsAuthorized(pappl_client_t *client) _PAPPL_PRIVATE; // Implement in scan-escl.c +extern void _papplScannerProcessESCL(pappl_client_t *client) _PAPPL_PRIVATE;// Implement in scan-escl.c +extern bool _papplScannerRegisterDNSSDNoLock(pappl_scanner_t *scanner) _PAPPL_PRIVATE; // Implement with reference to _papplPrinterRegisterDNSSDNoLock +extern void _papplScannerUnregisterDNSSDNoLock(pappl_scanner_t *scanner) _PAPPL_PRIVATE; // Implement with reference to _papplPrinterUnregisterDNSSDNoLock extern const char *_papplScannerColorModeString(pappl_sc_color_mode_t value) _PAPPL_PRIVATE; extern pappl_sc_color_mode_t _papplScannerColorModeValue(const char *value) _PAPPL_PRIVATE; +extern const char *_papplScannerReasonString(pappl_sreason_t value) _PAPPL_PRIVATE; +extern pappl_sreason_t _papplScannerReasonValue(const char *value) _PAPPL_PRIVATE; + extern void _papplScannerWebConfig(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; extern void _papplScannerWebConfigFinalize(pappl_scanner_t *scanner, cups_len_t num_form, cups_option_t *form) _PAPPL_PRIVATE; extern void _papplScannerWebDefaults(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; extern void _papplScannerWebDelete(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; extern void _papplScannerWebHome(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; -extern void _papplSannerWebIteratorCallback(pappl_scanner_t *scanner, pappl_client_t *client) _PAPPL_PRIVATE; -extern void _papplScannerWebJobs(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; -extern void _papplScannerWebMedia(pappl_client_t *client, pappl_scanner_t *printer) _PAPPL_PRIVATE; +extern void _papplSannerWebIteratorCallback(pappl_scanner_t *scanner, pappl_client_t *client) _PAPPL_PRIVATE; // Check +extern void _papplScannerWebJobs(pappl_client_t *client, pappl_scanner_t *scanner) _PAPPL_PRIVATE; // Check +extern void _papplScannerWebMedia(pappl_client_t *client, pappl_scanner_t *printer) _PAPPL_PRIVATE; //Check -extern const char *_papplScannerReasonString(pappl_sreason_t value) _PAPPL_PRIVATE; -extern pappl_sreason_t _papplScannerReasonValue(const char *value) _PAPPL_PRIVATE; #endif // !_PAPPL_SCANNER_PRIVATE_H_ diff --git a/pappl/scanner.h b/pappl/scanner.h index 10eed8dc..dab80b9f 100644 --- a/pappl/scanner.h +++ b/pappl/scanner.h @@ -22,7 +22,7 @@ extern "C" { #define PAPPL_MAX_SOURCES 2 // MOST scanners offer two input sources: Flatbed and ADF #define PAPPL_MAX_COLOR_SPACES 2 // Common color spaces like sRGB and AdobeRGB #define PAPPL_MAX_MEDIA_TYPES 5 // Various media types like Plain, Photo, Card, etc. -#define MAX_RESOLUTIONS 5 +#define MAX_RESOLUTIONS 5 // The number of resolutions supported by the scanner // // Constants... From ea4cd3ce540c105bc0ca6ab496d5658ca615294e Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Sat, 2 Nov 2024 16:41:35 +0000 Subject: [PATCH 20/26] Add support for scanning dnssd services This commits primarily adds functions for registration and unregistration of DNSSD related to scanners. Signed-off-by: Akarshan Kapoor --- pappl/dnssd.c | 1122 +++++++++++++++++++++++++++------------ pappl/scanner-private.h | 1 + 2 files changed, 787 insertions(+), 336 deletions(-) diff --git a/pappl/dnssd.c b/pappl/dnssd.c index 03fe26da..6457ece9 100644 --- a/pappl/dnssd.c +++ b/pappl/dnssd.c @@ -10,64 +10,61 @@ #include "pappl-private.h" - // // Constants... // #ifdef HAVE_AVAHI -# define AVAHI_DNS_TYPE_LOC 29 // Per RFC 1876 -#endif // HAVE_AVAHI - +#define AVAHI_DNS_TYPE_LOC 29 // Per RFC 1876 +#endif // HAVE_AVAHI // // Local globals... // -static char pappl_dns_sd_hostname[256] = ""; - // Current DNS-SD hostname -static int pappl_dns_sd_hostname_changes = 0; - // Number of host name changes/collisions -static pthread_mutex_t pappl_dns_sd_hostname_mutex = PTHREAD_MUTEX_INITIALIZER; - // Host name mutex +static char pappl_dns_sd_hostname[256] = ""; +// Current DNS-SD hostname +static int pappl_dns_sd_hostname_changes = 0; +// Number of host name changes/collisions +static pthread_mutex_t pappl_dns_sd_hostname_mutex = PTHREAD_MUTEX_INITIALIZER; +// Host name mutex #ifdef HAVE_MDNSRESPONDER -static DNSServiceRef pappl_dns_sd_hostname_ref = NULL; - // Host name query reference +static DNSServiceRef pappl_dns_sd_hostname_ref = NULL; +// Host name query reference #endif // HAVE_MDNSRESPONDER -static _pappl_dns_sd_t pappl_dns_sd_master = NULL; - // DNS-SD master reference -static pthread_mutex_t pappl_dns_sd_mutex = PTHREAD_MUTEX_INITIALIZER; - // DNS-SD master mutex +static _pappl_dns_sd_t pappl_dns_sd_master = NULL; +// DNS-SD master reference +static pthread_mutex_t pappl_dns_sd_mutex = PTHREAD_MUTEX_INITIALIZER; +// DNS-SD master mutex #ifdef HAVE_AVAHI static AvahiThreadedPoll *pappl_dns_sd_poll = NULL; - // Avahi background thread +// Avahi background thread #endif // HAVE_AVAHI - // // Local functions... // -static void dns_sd_geo_to_loc(const char *geo, unsigned char loc[16]); +static void dns_sd_geo_to_loc(const char *geo, unsigned char loc[16]); #ifdef HAVE_MDNSRESPONDER -static void DNSSD_API dns_sd_hostname_callback(DNSServiceRef ref, DNSServiceFlags flags, uint32_t if_index, DNSServiceErrorType error, const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context); -static void DNSSD_API dns_sd_printer_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, pappl_printer_t *printer); -static void *dns_sd_run(void *data); -static void DNSSD_API dns_sd_system_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, pappl_system_t *system); +static void DNSSD_API dns_sd_hostname_callback(DNSServiceRef ref, DNSServiceFlags flags, uint32_t if_index, DNSServiceErrorType error, const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context); +static void DNSSD_API dns_sd_printer_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, pappl_printer_t *printer); +static void *dns_sd_run(void *data); +static void DNSSD_API dns_sd_system_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, pappl_system_t *system); #elif defined(HAVE_AVAHI) -static void dns_sd_client_cb(AvahiClient *c, AvahiClientState state, void *data); -static void dns_sd_printer_callback(AvahiEntryGroup *p, AvahiEntryGroupState state, pappl_printer_t *printer); -static void dns_sd_system_callback(AvahiEntryGroup *p, AvahiEntryGroupState state, pappl_system_t *system); +static void dns_sd_client_cb(AvahiClient *c, AvahiClientState state, void *data); +static void dns_sd_printer_callback(AvahiEntryGroup *p, AvahiEntryGroupState state, pappl_printer_t *printer); +static void dns_sd_scanner_callback(AvahiEntryGroup *p, AvahiEntryGroupState state, pappl_scanner_t *scanner); +static void dns_sd_system_callback(AvahiEntryGroup *p, AvahiEntryGroupState state, pappl_system_t *system); #endif // HAVE_MDNSRESPONDER - // // '_papplDNSSDCopyHostName()' - Copy the current DNS-SD hostname. // -const char * // O - Current DNS-SD hostname -_papplDNSSDCopyHostName(char *buffer, // I - Hostname buffer - size_t bufsize) // I - Size of hostname buffer +const char * // O - Current DNS-SD hostname +_papplDNSSDCopyHostName(char *buffer, // I - Hostname buffer + size_t bufsize) // I - Size of hostname buffer { pthread_mutex_lock(&pappl_dns_sd_hostname_mutex); if (pappl_dns_sd_hostname[0]) @@ -79,16 +76,14 @@ _papplDNSSDCopyHostName(char *buffer, // I - Hostname buffer return (buffer); } - // // '_papplDNSSDGetHostChanges()' - Get the number of host name changes/collisions so far. // -int // O - Number of host name changes/collisions +int // O - Number of host name changes/collisions _papplDNSSDGetHostChanges(void) { - int changes; // Return value - + int changes; // Return value pthread_mutex_lock(&pappl_dns_sd_hostname_mutex); changes = pappl_dns_sd_hostname_changes; @@ -97,19 +92,17 @@ _papplDNSSDGetHostChanges(void) return (changes); } - // // '_papplDNSSDInit()' - Initialize DNS-SD services. // -_pappl_dns_sd_t // O - DNS-SD master reference +_pappl_dns_sd_t // O - DNS-SD master reference _papplDNSSDInit( - pappl_system_t *system) // I - System + pappl_system_t *system) // I - System { #ifdef HAVE_MDNSRESPONDER - int error; // Error code, if any - pthread_t tid; // Thread ID - + int error; // Error code, if any + pthread_t tid; // Thread ID pthread_mutex_lock(&pappl_dns_sd_mutex); @@ -152,8 +145,7 @@ _papplDNSSDInit( pthread_mutex_unlock(&pappl_dns_sd_mutex); #elif defined(HAVE_AVAHI) - int error; // Error code, if any - + int error; // Error code, if any pthread_mutex_lock(&pappl_dns_sd_mutex); @@ -179,7 +171,7 @@ _papplDNSSDInit( { // Get the current mDNS hostname... const char *dns_sd_hostname = avahi_client_get_host_name_fqdn(pappl_dns_sd_master); - // mDNS hostname + // mDNS hostname if (dns_sd_hostname) papplCopyString(pappl_dns_sd_hostname, dns_sd_hostname, sizeof(pappl_dns_sd_hostname)); @@ -196,13 +188,11 @@ _papplDNSSDInit( return (pappl_dns_sd_master); } - // // '_papplDNSSDLock()' - Grab a lock to make DNS-SD changes. // -void -_papplDNSSDLock(void) +void _papplDNSSDLock(void) { #ifdef HAVE_AVAHI if (pappl_dns_sd_poll) @@ -210,116 +200,115 @@ _papplDNSSDLock(void) #endif // HAVE_AVAHI } - // // '_papplDNSSDStrError()' - Return a string for the given DNS-SD error code. // -const char * // O - Error message -_papplDNSSDStrError(int error) // I - Error code +const char * // O - Error message +_papplDNSSDStrError(int error) // I - Error code { #ifdef HAVE_MDNSRESPONDER switch (error) { - case kDNSServiceErr_NoError : - return ("No error"); + case kDNSServiceErr_NoError: + return ("No error"); - case kDNSServiceErr_Unknown : - default : - return ("Unknown error"); + case kDNSServiceErr_Unknown: + default: + return ("Unknown error"); - case kDNSServiceErr_NoSuchName : - return ("Name not found"); + case kDNSServiceErr_NoSuchName: + return ("Name not found"); - case kDNSServiceErr_NoMemory : - return ("Out of memory"); + case kDNSServiceErr_NoMemory: + return ("Out of memory"); - case kDNSServiceErr_BadParam : - return ("Bad parameter"); + case kDNSServiceErr_BadParam: + return ("Bad parameter"); - case kDNSServiceErr_BadReference : - return ("Bad service reference"); + case kDNSServiceErr_BadReference: + return ("Bad service reference"); - case kDNSServiceErr_BadState : - return ("Bad state"); + case kDNSServiceErr_BadState: + return ("Bad state"); - case kDNSServiceErr_BadFlags : - return ("Bad flags argument"); + case kDNSServiceErr_BadFlags: + return ("Bad flags argument"); - case kDNSServiceErr_Unsupported : - return ("Unsupported feature"); + case kDNSServiceErr_Unsupported: + return ("Unsupported feature"); - case kDNSServiceErr_NotInitialized : - return ("Not initialized"); + case kDNSServiceErr_NotInitialized: + return ("Not initialized"); - case kDNSServiceErr_AlreadyRegistered : - return ("Name already registered"); + case kDNSServiceErr_AlreadyRegistered: + return ("Name already registered"); - case kDNSServiceErr_NameConflict : - return ("Name conflicts"); + case kDNSServiceErr_NameConflict: + return ("Name conflicts"); - case kDNSServiceErr_Invalid : - return ("Invalid argument"); + case kDNSServiceErr_Invalid: + return ("Invalid argument"); - case kDNSServiceErr_Firewall : - return ("Firewall prevents access"); + case kDNSServiceErr_Firewall: + return ("Firewall prevents access"); - case kDNSServiceErr_Incompatible : - return ("Client library incompatible with background daemon"); + case kDNSServiceErr_Incompatible: + return ("Client library incompatible with background daemon"); - case kDNSServiceErr_BadInterfaceIndex : - return ("Bad interface index"); + case kDNSServiceErr_BadInterfaceIndex: + return ("Bad interface index"); - case kDNSServiceErr_Refused : - return ("Connection refused"); + case kDNSServiceErr_Refused: + return ("Connection refused"); - case kDNSServiceErr_NoSuchRecord : - return ("DNS record not found"); + case kDNSServiceErr_NoSuchRecord: + return ("DNS record not found"); - case kDNSServiceErr_NoAuth : - return ("No authoritative answer"); + case kDNSServiceErr_NoAuth: + return ("No authoritative answer"); - case kDNSServiceErr_NoSuchKey : - return ("TXT record key not found"); + case kDNSServiceErr_NoSuchKey: + return ("TXT record key not found"); - case kDNSServiceErr_NATTraversal : - return ("Unable to traverse via NAT"); + case kDNSServiceErr_NATTraversal: + return ("Unable to traverse via NAT"); - case kDNSServiceErr_DoubleNAT : - return ("Double NAT is in use"); + case kDNSServiceErr_DoubleNAT: + return ("Double NAT is in use"); - case kDNSServiceErr_BadTime : - return ("Bad time value"); + case kDNSServiceErr_BadTime: + return ("Bad time value"); - case kDNSServiceErr_BadSig : - return ("Bad signal"); + case kDNSServiceErr_BadSig: + return ("Bad signal"); - case kDNSServiceErr_BadKey : - return ("Bad TXT record key"); + case kDNSServiceErr_BadKey: + return ("Bad TXT record key"); - case kDNSServiceErr_Transient : - return ("Transient error"); + case kDNSServiceErr_Transient: + return ("Transient error"); - case kDNSServiceErr_ServiceNotRunning : - return ("Background daemon not running"); + case kDNSServiceErr_ServiceNotRunning: + return ("Background daemon not running"); - case kDNSServiceErr_NATPortMappingUnsupported : - return ("NAT doesn't support PCP, NAT-PMP or UPnP"); + case kDNSServiceErr_NATPortMappingUnsupported: + return ("NAT doesn't support PCP, NAT-PMP or UPnP"); - case kDNSServiceErr_NATPortMappingDisabled : - return ("NAT supports PCP, NAT-PMP or UPnP, but it's disabled by the administrator"); + case kDNSServiceErr_NATPortMappingDisabled: + return ("NAT supports PCP, NAT-PMP or UPnP, but it's disabled by the administrator"); - case kDNSServiceErr_NoRouter : - return ("No router configured, probably no network connectivity"); + case kDNSServiceErr_NoRouter: + return ("No router configured, probably no network connectivity"); - case kDNSServiceErr_PollingMode : - return ("Polling error"); + case kDNSServiceErr_PollingMode: + return ("Polling error"); - case kDNSServiceErr_Timeout : - return ("Timeout"); + case kDNSServiceErr_Timeout: + return ("Timeout"); #if !_WIN32 - case kDNSServiceErr_DefunctConnection : - return ("Connection lost"); + case kDNSServiceErr_DefunctConnection: + return ("Connection lost"); #endif // !_WIN32 } @@ -331,13 +320,11 @@ _papplDNSSDStrError(int error) // I - Error code #endif // HAVE_MDNSRESPONDER } - // // '_papplDNSSDUnlock()' - Release a lock after making DNS-SD changes. // -void -_papplDNSSDUnlock(void) +void _papplDNSSDUnlock(void) { #ifdef HAVE_AVAHI if (pappl_dns_sd_poll) @@ -345,66 +332,64 @@ _papplDNSSDUnlock(void) #endif // HAVE_AVAHI } - // // '_papplPrinterRegisterDNSSDNoLock()' - Register a printer's DNS-SD service. // -bool // O - `true` on success, `false` on failure +bool // O - `true` on success, `false` on failure _papplPrinterRegisterDNSSDNoLock( - pappl_printer_t *printer) // I - Printer + pappl_printer_t *printer) // I - Printer { - bool ret = true; // Return value + bool ret = true; // Return value #ifdef HAVE_DNSSD - pappl_system_t *system = printer->system; - // System - uint32_t if_index; // Interface index - _pappl_txt_t txt; // DNS-SD TXT record - cups_len_t i, // Looping var - count; // Number of values - ipp_attribute_t *color_supported, - *document_format_supported, - *printer_kind, - *printer_uuid, - *urf_supported; // Printer attributes - const char *value; // Value string - char adminurl[246], // Admin URL - formats[252], // List of supported formats - kind[251], // List of printer-kind values - urf[252], // List of supported URF values - *ptr; // Pointer into string - char regtype[256]; // DNS-SD service type - char product[248]; // Make and model (legacy) - int max_width; // Maximum media width (legacy) - const char *papermax; // PaperMax string value (legacy) -# ifdef HAVE_MDNSRESPONDER - DNSServiceErrorType error; // Error from mDNSResponder -# else - int error; // Error from Avahi - char fullname[256]; // Full service name -# endif // HAVE_MDNSRESPONDER - _pappl_dns_sd_t master; // DNS-SD master reference - + pappl_system_t *system = printer->system; + // System + uint32_t if_index; // Interface index + _pappl_txt_t txt; // DNS-SD TXT record + cups_len_t i, // Looping var + count; // Number of values + ipp_attribute_t *color_supported, + *document_format_supported, + *printer_kind, + *printer_uuid, + *urf_supported; // Printer attributes + const char *value; // Value string + char adminurl[246], // Admin URL + formats[252], // List of supported formats + kind[251], // List of printer-kind values + urf[252], // List of supported URF values + *ptr; // Pointer into string + char regtype[256]; // DNS-SD service type + char product[248]; // Make and model (legacy) + int max_width; // Maximum media width (legacy) + const char *papermax; // PaperMax string value (legacy) +#ifdef HAVE_MDNSRESPONDER + DNSServiceErrorType error; // Error from mDNSResponder +#else + int error; // Error from Avahi + char fullname[256]; // Full service name +#endif // HAVE_MDNSRESPONDER + _pappl_dns_sd_t master; // DNS-SD master reference if (!printer->dns_sd_name || !printer->system->is_running) return (false); papplLogPrinter(printer, PAPPL_LOGLEVEL_DEBUG, "Registering DNS-SD name '%s'.", printer->dns_sd_name); -# ifdef HAVE_MDNSRESPONDER +#ifdef HAVE_MDNSRESPONDER if_index = !strcmp(system->hostname, "localhost") ? kDNSServiceInterfaceIndexLocalOnly : kDNSServiceInterfaceIndexAny; -# else +#else if_index = !strcmp(system->hostname, "localhost") ? if_nametoindex("lo") : AVAHI_IF_UNSPEC; -# endif // HAVE_MDNSRESPONDER +#endif // HAVE_MDNSRESPONDER // Get attributes and values for the TXT record... - color_supported = ippFindAttribute(printer->driver_attrs, "color-supported", IPP_TAG_BOOLEAN); + color_supported = ippFindAttribute(printer->driver_attrs, "color-supported", IPP_TAG_BOOLEAN); document_format_supported = ippFindAttribute(printer->driver_attrs, "document-format-supported", IPP_TAG_MIMETYPE); - printer_kind = ippFindAttribute(printer->driver_attrs, "printer-kind", IPP_TAG_KEYWORD); - printer_uuid = ippFindAttribute(printer->attrs, "printer-uuid", IPP_TAG_URI); - urf_supported = ippFindAttribute(printer->driver_attrs, "urf-supported", IPP_TAG_KEYWORD); + printer_kind = ippFindAttribute(printer->driver_attrs, "printer-kind", IPP_TAG_KEYWORD); + printer_uuid = ippFindAttribute(printer->attrs, "printer-uuid", IPP_TAG_URI); + urf_supported = ippFindAttribute(printer->driver_attrs, "urf-supported", IPP_TAG_KEYWORD); - for (i = 0, count = ippGetCount(document_format_supported), ptr = formats; i < count; i ++) + for (i = 0, count = ippGetCount(document_format_supported), ptr = formats; i < count; i++) { value = ippGetString(document_format_supported, i, NULL); @@ -422,7 +407,7 @@ _papplPrinterRegisterDNSSDNoLock( } kind[0] = '\0'; - for (i = 0, count = ippGetCount(printer_kind), ptr = kind; i < count; i ++) + for (i = 0, count = ippGetCount(printer_kind), ptr = kind; i < count; i++) { value = ippGetString(printer_kind, i, NULL); @@ -438,10 +423,10 @@ _papplPrinterRegisterDNSSDNoLock( snprintf(product, sizeof(product), "(%s)", printer->driver_data.make_and_model); - for (i = 0, max_width = 0; i < (cups_len_t)printer->driver_data.num_media; i ++) + for (i = 0, max_width = 0; i < (cups_len_t)printer->driver_data.num_media; i++) { pwg_media_t *media = pwgMediaForPWG(printer->driver_data.media[i]); - // Current media size + // Current media size if (media && media->width > max_width) max_width = media->width; @@ -459,7 +444,7 @@ _papplPrinterRegisterDNSSDNoLock( papermax = ">isoC-A2"; urf[0] = '\0'; - for (i = 0, count = ippGetCount(urf_supported), ptr = urf; i < count; i ++) + for (i = 0, count = ippGetCount(urf_supported), ptr = urf; i < count; i++) { value = ippGetString(urf_supported, i, NULL); @@ -481,26 +466,26 @@ _papplPrinterRegisterDNSSDNoLock( // Rename the service as needed... if (printer->dns_sd_collision) { - char new_dns_sd_name[256]; // New DNS-SD name - const char *serial = strstr(printer->device_uri, "?serial="); - // Serial number - const char *uuid = ippGetString(printer_uuid, 0, NULL); - // "printer-uuid" value + char new_dns_sd_name[256]; // New DNS-SD name + const char *serial = strstr(printer->device_uri, "?serial="); + // Serial number + const char *uuid = ippGetString(printer_uuid, 0, NULL); + // "printer-uuid" value - printer->dns_sd_serial ++; + printer->dns_sd_serial++; if (printer->dns_sd_serial == 1) { if (printer->system->options & PAPPL_SOPTIONS_DNSSD_HOST) - snprintf(new_dns_sd_name, sizeof(new_dns_sd_name), "%s (%s)", printer->dns_sd_name, printer->system->hostname); + snprintf(new_dns_sd_name, sizeof(new_dns_sd_name), "%s (%s)", printer->dns_sd_name, printer->system->hostname); else if (serial) - snprintf(new_dns_sd_name, sizeof(new_dns_sd_name), "%s (%s)", printer->dns_sd_name, serial + 8); + snprintf(new_dns_sd_name, sizeof(new_dns_sd_name), "%s (%s)", printer->dns_sd_name, serial + 8); else - snprintf(new_dns_sd_name, sizeof(new_dns_sd_name), "%s (%c%c%c%c%c%c)", printer->dns_sd_name, toupper(uuid[39]), toupper(uuid[40]), toupper(uuid[41]), toupper(uuid[42]), toupper(uuid[43]), toupper(uuid[44])); + snprintf(new_dns_sd_name, sizeof(new_dns_sd_name), "%s (%c%c%c%c%c%c)", printer->dns_sd_name, toupper(uuid[39]), toupper(uuid[40]), toupper(uuid[41]), toupper(uuid[42]), toupper(uuid[43]), toupper(uuid[44])); } else { - char base_dns_sd_name[256]; // Base DNS-SD name + char base_dns_sd_name[256]; // Base DNS-SD name papplCopyString(base_dns_sd_name, printer->dns_sd_name, sizeof(base_dns_sd_name)); if ((ptr = strrchr(base_dns_sd_name, '(')) != NULL) @@ -566,7 +551,7 @@ _papplPrinterRegisterDNSSDNoLock( printer->dns_sd_printer_ref = master; - if ((error = DNSServiceRegister(&printer->dns_sd_printer_ref, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, if_index, printer->dns_sd_name, "_printer._tcp", NULL /* domain */, /*hostname*/NULL, 0 /* port */, 0 /* txtLen */, NULL /* txtRecord */, (DNSServiceRegisterReply)dns_sd_printer_callback, printer)) != kDNSServiceErr_NoError) + if ((error = DNSServiceRegister(&printer->dns_sd_printer_ref, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, if_index, printer->dns_sd_name, "_printer._tcp", NULL /* domain */, /*hostname*/ NULL, 0 /* port */, 0 /* txtLen */, NULL /* txtRecord */, (DNSServiceRegisterReply)dns_sd_printer_callback, printer)) != kDNSServiceErr_NoError) { papplLogPrinter(printer, PAPPL_LOGLEVEL_ERROR, "Unable to register '%s._printer._tcp': %s", printer->dns_sd_name, _papplDNSSDStrError(error)); ret = false; @@ -584,7 +569,7 @@ _papplPrinterRegisterDNSSDNoLock( else papplCopyString(regtype, "_ipp._tcp", sizeof(regtype)); - if ((error = DNSServiceRegister(&printer->dns_sd_ipp_ref, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, if_index, printer->dns_sd_name, regtype, NULL /* domain */, /*hostname*/NULL, htons(system->port), TXTRecordGetLength(&txt), TXTRecordGetBytesPtr(&txt), (DNSServiceRegisterReply)dns_sd_printer_callback, printer)) != kDNSServiceErr_NoError) + if ((error = DNSServiceRegister(&printer->dns_sd_ipp_ref, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, if_index, printer->dns_sd_name, regtype, NULL /* domain */, /*hostname*/ NULL, htons(system->port), TXTRecordGetLength(&txt), TXTRecordGetBytesPtr(&txt), (DNSServiceRegisterReply)dns_sd_printer_callback, printer)) != kDNSServiceErr_NoError) { papplLogPrinter(printer, PAPPL_LOGLEVEL_ERROR, "Unable to register '%s.%s': %s", printer->dns_sd_name, regtype, _papplDNSSDStrError(error)); ret = false; @@ -611,7 +596,7 @@ _papplPrinterRegisterDNSSDNoLock( else papplCopyString(regtype, "_ipps._tcp", sizeof(regtype)); - if ((error = DNSServiceRegister(&printer->dns_sd_ipps_ref, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, if_index, printer->dns_sd_name, regtype, NULL /* domain */, /*hostname*/NULL, htons(system->port), TXTRecordGetLength(&txt), TXTRecordGetBytesPtr(&txt), (DNSServiceRegisterReply)dns_sd_printer_callback, printer)) != kDNSServiceErr_NoError) + if ((error = DNSServiceRegister(&printer->dns_sd_ipps_ref, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, if_index, printer->dns_sd_name, regtype, NULL /* domain */, /*hostname*/ NULL, htons(system->port), TXTRecordGetLength(&txt), TXTRecordGetBytesPtr(&txt), (DNSServiceRegisterReply)dns_sd_printer_callback, printer)) != kDNSServiceErr_NoError) { papplLogPrinter(printer, PAPPL_LOGLEVEL_ERROR, "Unable to register '%s.%s': %s", printer->dns_sd_name, regtype, _papplDNSSDStrError(error)); ret = false; @@ -621,8 +606,8 @@ _papplPrinterRegisterDNSSDNoLock( { if ((error = DNSServiceAddRecord(printer->dns_sd_ipps_ref, &printer->dns_sd_ipps_loc_ref, 0, kDNSServiceType_LOC, sizeof(printer->dns_sd_loc), printer->dns_sd_loc, 0)) != kDNSServiceErr_NoError) { - papplLogPrinter(printer, PAPPL_LOGLEVEL_ERROR, "Unable to register LOC record for '%s.%s': %s", printer->dns_sd_name, regtype, _papplDNSSDStrError(error)); - ret = false; + papplLogPrinter(printer, PAPPL_LOGLEVEL_ERROR, "Unable to register LOC record for '%s.%s': %s", printer->dns_sd_name, regtype, _papplDNSSDStrError(error)); + ret = false; } } } @@ -662,7 +647,7 @@ _papplPrinterRegisterDNSSDNoLock( printer->dns_sd_pdl_ref = master; - if ((error = DNSServiceRegister(&printer->dns_sd_pdl_ref, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, if_index, printer->dns_sd_name, "_pdl-datastream._tcp", NULL /* domain */, /*hostname*/NULL, htons(9099 + printer->printer_id), TXTRecordGetLength(&txt), TXTRecordGetBytesPtr(&txt), (DNSServiceRegisterReply)dns_sd_printer_callback, printer)) != kDNSServiceErr_NoError) + if ((error = DNSServiceRegister(&printer->dns_sd_pdl_ref, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, if_index, printer->dns_sd_name, "_pdl-datastream._tcp", NULL /* domain */, /*hostname*/ NULL, htons(9099 + printer->printer_id), TXTRecordGetLength(&txt), TXTRecordGetBytesPtr(&txt), (DNSServiceRegisterReply)dns_sd_printer_callback, printer)) != kDNSServiceErr_NoError) { papplLogPrinter(printer, PAPPL_LOGLEVEL_ERROR, "Unable to register '%s.%s': %s", printer->dns_sd_name, "_pdl-datastream._tcp", _papplDNSSDStrError(error)); ret = false; @@ -683,7 +668,7 @@ _papplPrinterRegisterDNSSDNoLock( printer->dns_sd_http_ref = master; - if ((error = DNSServiceRegister(&printer->dns_sd_http_ref, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, if_index, printer->dns_sd_name, "_http._tcp,_printer", NULL /* domain */, /*hostname*/NULL, htons(system->port), TXTRecordGetLength(&txt), TXTRecordGetBytesPtr(&txt), (DNSServiceRegisterReply)dns_sd_printer_callback, printer)) != kDNSServiceErr_NoError) + if ((error = DNSServiceRegister(&printer->dns_sd_http_ref, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, if_index, printer->dns_sd_name, "_http._tcp,_printer", NULL /* domain */, /*hostname*/ NULL, htons(system->port), TXTRecordGetLength(&txt), TXTRecordGetBytesPtr(&txt), (DNSServiceRegisterReply)dns_sd_printer_callback, printer)) != kDNSServiceErr_NoError) { papplLogPrinter(printer, PAPPL_LOGLEVEL_ERROR, "Unable to register '%s.%s': %s", printer->dns_sd_name, "_http._tcp,_printer", _papplDNSSDStrError(error)); ret = false; @@ -741,7 +726,7 @@ _papplPrinterRegisterDNSSDNoLock( } // Then register the IPP/IPPS services... - if ((error = avahi_entry_group_add_service_strlst(printer->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, printer->dns_sd_name, "_ipp._tcp", NULL, /*hostname*/NULL, system->port, txt)) < 0) + if ((error = avahi_entry_group_add_service_strlst(printer->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, printer->dns_sd_name, "_ipp._tcp", NULL, /*hostname*/ NULL, system->port, txt)) < 0) { papplLogPrinter(printer, PAPPL_LOGLEVEL_ERROR, "Unable to register '%s._ipp._tcp': %s", printer->dns_sd_name, _papplDNSSDStrError(error)); ret = false; @@ -750,14 +735,14 @@ _papplPrinterRegisterDNSSDNoLock( if (system->subtypes && *system->subtypes) { char *temptypes = strdup(system->subtypes), *start, *end; - // Pointers into sub-types... + // Pointers into sub-types... for (start = temptypes; start && *start; start = end) { if ((end = strchr(start, ',')) != NULL) - *end++ = '\0'; + *end++ = '\0'; else - end = start + strlen(start); + end = start + strlen(start); snprintf(regtype, sizeof(regtype), "%s._sub._ipp._tcp", start); if ((error = avahi_entry_group_add_service_subtype(printer->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, printer->dns_sd_name, "_ipp._tcp", NULL, regtype)) < 0) @@ -772,7 +757,7 @@ _papplPrinterRegisterDNSSDNoLock( if (!(printer->system->options & PAPPL_SOPTIONS_NO_TLS)) { - if ((error = avahi_entry_group_add_service_strlst(printer->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, printer->dns_sd_name, "_ipps._tcp", NULL, /*hostname*/NULL, system->port, txt)) < 0) + if ((error = avahi_entry_group_add_service_strlst(printer->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, printer->dns_sd_name, "_ipps._tcp", NULL, /*hostname*/ NULL, system->port, txt)) < 0) { papplLogPrinter(printer, PAPPL_LOGLEVEL_ERROR, "Unable to register '%s._ipps._tcp': %s", printer->dns_sd_name, _papplDNSSDStrError(error)); ret = false; @@ -781,21 +766,21 @@ _papplPrinterRegisterDNSSDNoLock( if (system->subtypes && *system->subtypes) { char *temptypes = strdup(system->subtypes), *start, *end; - // Pointers into sub-types... + // Pointers into sub-types... for (start = temptypes; start && *start; start = end) { - if ((end = strchr(start, ',')) != NULL) - *end++ = '\0'; - else - end = start + strlen(start); - - snprintf(regtype, sizeof(regtype), "%s._sub._ipps._tcp", start); - if ((error = avahi_entry_group_add_service_subtype(printer->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, printer->dns_sd_name, "_ipps._tcp", NULL, regtype)) < 0) - { - papplLogPrinter(printer, PAPPL_LOGLEVEL_ERROR, "Unable to register '%s.%s': %s", printer->dns_sd_name, regtype, _papplDNSSDStrError(error)); - ret = false; - } + if ((end = strchr(start, ',')) != NULL) + *end++ = '\0'; + else + end = start + strlen(start); + + snprintf(regtype, sizeof(regtype), "%s._sub._ipps._tcp", start); + if ((error = avahi_entry_group_add_service_subtype(printer->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, printer->dns_sd_name, "_ipps._tcp", NULL, regtype)) < 0) + { + papplLogPrinter(printer, PAPPL_LOGLEVEL_ERROR, "Unable to register '%s.%s': %s", printer->dns_sd_name, regtype, _papplDNSSDStrError(error)); + ret = false; + } } free(temptypes); @@ -827,7 +812,7 @@ _papplPrinterRegisterDNSSDNoLock( txt = avahi_string_list_add_printf(txt, "PaperMax=%s", papermax); txt = avahi_string_list_add_printf(txt, "Scan=F"); - if ((error = avahi_entry_group_add_service_strlst(printer->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, printer->dns_sd_name, "_pdl-datastream._tcp", NULL, /*hostname*/NULL, 9099 + printer->printer_id, txt)) < 0) + if ((error = avahi_entry_group_add_service_strlst(printer->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, printer->dns_sd_name, "_pdl-datastream._tcp", NULL, /*hostname*/ NULL, 9099 + printer->printer_id, txt)) < 0) { papplLogPrinter(printer, PAPPL_LOGLEVEL_ERROR, "Unable to register '%s._pdl-datastream._tcp': %s", printer->dns_sd_name, _papplDNSSDStrError(error)); ret = false; @@ -860,7 +845,7 @@ _papplPrinterRegisterDNSSDNoLock( txt = NULL; txt = avahi_string_list_add_printf(txt, "path=%s/", printer->uriname); - avahi_entry_group_add_service_strlst(printer->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, printer->dns_sd_name, "_http._tcp", NULL, /*hostname*/NULL, system->port, txt); + avahi_entry_group_add_service_strlst(printer->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, printer->dns_sd_name, "_http._tcp", NULL, /*hostname*/ NULL, system->port, txt); avahi_entry_group_add_service_subtype(printer->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, printer->dns_sd_name, "_http._tcp", NULL, "_printer._sub._http._tcp"); avahi_string_list_free(txt); @@ -873,14 +858,12 @@ _papplPrinterRegisterDNSSDNoLock( return (ret); } - // // '_papplPrinterUnregisterDNSSDNoLock()' - Unregister a printer's DNS-SD service. // -void -_papplPrinterUnregisterDNSSDNoLock( - pappl_printer_t *printer) // I - Printer +void _papplPrinterUnregisterDNSSDNoLock( + pappl_printer_t *printer) // I - Printer { #if HAVE_MDNSRESPONDER if (printer->dns_sd_printer_ref) @@ -891,13 +874,13 @@ _papplPrinterUnregisterDNSSDNoLock( if (printer->dns_sd_ipp_ref) { DNSServiceRefDeallocate(printer->dns_sd_ipp_ref); - printer->dns_sd_ipp_ref = NULL; + printer->dns_sd_ipp_ref = NULL; printer->dns_sd_ipp_loc_ref = NULL; } if (printer->dns_sd_ipps_ref) { DNSServiceRefDeallocate(printer->dns_sd_ipps_ref); - printer->dns_sd_ipps_ref = NULL; + printer->dns_sd_ipps_ref = NULL; printer->dns_sd_ipps_loc_ref = NULL; } if (printer->dns_sd_http_ref) @@ -923,48 +906,468 @@ _papplPrinterUnregisterDNSSDNoLock( } // -// TODO : papplScannerRegisterDNSSDNoLock - Register a scanner's DNS-SD service. +// _papplScannerRegisterDNSSDNoLock - Register a scanner's DNS-SD service. // -bool // O - `true` on success, `false` on failure -_papplScannerRegisterDNSSDNoLock( - pappl_scanner_t *scanner) // I - Scanner +bool _papplScannerRegisterDNSSDNoLock( + pappl_scanner_t *scanner) // I - Scanner { - bool ret = true; // Sample return value + bool ret = true; // Return value +#ifdef HAVE_DNSSD + pappl_system_t *system = scanner->system; // System + uint32_t if_index; // Interface index + _pappl_txt_t txt; // DNS-SD TXT record + cups_len_t i, // Looping var + count; // Number of values + char adminurl[246], // Admin URL + formats[252], // List of supported formats + sources[252], // List of input sources + intents[252], // List of scanning intents + colorspaces[252], // List of color spaces + color_modes[252], // List of color modes + *ptr; // Pointer into string +#endif +#ifdef HAVE_MDNSRESPONDER + DNSServiceErrorType error; // Error from mDNSResponder +#else + int error; // Error from Avahi + char fullname[256]; // Full service name +#endif // HAVE_MDNSRESPONDER + _pappl_dns_sd_t master; // DNS-SD master reference + + if (!scanner->dns_sd_name || !scanner->system->is_running) + { + papplLogScanner(scanner, PAPPL_LOGLEVEL_DEBUG, "DNS-SD name not set or system not running."); + return (false); + } + + papplLogScanner(scanner, PAPPL_LOGLEVEL_DEBUG, "Registering DNS-SD name '%s'.", scanner->dns_sd_name); + +#ifdef HAVE_MDNSRESPONDER + if_index = !strcmp(system->hostname, "localhost") ? kDNSServiceInterfaceIndexLocalOnly : kDNSServiceInterfaceIndexAny; +#else + if_index = !strcmp(system->hostname, "localhost") ? if_nametoindex("lo") : AVAHI_IF_UNSPEC; +#endif // HAVE_MDNSRESPONDER + + // Build formats string + for (i = 0, count = 0, ptr = formats; scanner->driver_data.document_formats_supported[i] && i < PAPPL_MAX_FORMATS; i++) + { + if (count > 0 && ptr < (formats + sizeof(formats) - 1)) + *ptr++ = ','; + + papplCopyString(ptr, scanner->driver_data.document_formats_supported[i], sizeof(formats) - (size_t)(ptr - formats)); + ptr += strlen(ptr); + count++; + + if (ptr >= (formats + sizeof(formats) - 1)) + break; + } + + // Build input sources string + sources[0] = '\0'; + ptr = sources; + for (i = 0; i < PAPPL_MAX_SOURCES && scanner->driver_data.input_sources_supported[i]; i++) + { + if (i > 0) + *ptr++ = ','; + if (scanner->driver_data.input_sources_supported[i] == PAPPL_FLATBED) + ptr += snprintf(ptr, sizeof(sources) - (size_t)(ptr - sources), "platen"); + else if (scanner->driver_data.input_sources_supported[i] == PAPPL_ADF) + ptr += snprintf(ptr, sizeof(sources) - (size_t)(ptr - sources), "adf"); + } + + // Build color spaces string + for (i = 0, count = 0, ptr = colorspaces; scanner->driver_data.color_spaces_supported[i] && i < PAPPL_MAX_COLOR_SPACES; i++) + { + if (count > 0) + *ptr++ = ','; + papplCopyString(ptr, scanner->driver_data.color_spaces_supported[i], sizeof(colorspaces) - (size_t)(ptr - colorspaces)); + ptr += strlen(ptr); + count++; + } + + // Build intents string (combining mandatory and optional) + intents[0] = '\0'; + ptr = intents; + for (i = 0; i < 5 && scanner->driver_data.mandatory_intents[i]; i++) + { + if (i > 0) + *ptr++ = ','; + ptr += snprintf(ptr, sizeof(intents) - (size_t)(ptr - intents), "%s", scanner->driver_data.mandatory_intents[i]); + } + for (i = 0; i < 5 && scanner->driver_data.optional_intents[i]; i++) + { + if (ptr > intents) + *ptr++ = ','; + ptr += snprintf(ptr, sizeof(intents) - (size_t)(ptr - intents), "%s", scanner->driver_data.optional_intents[i]); + } + + httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl, sizeof(adminurl), "http", NULL, scanner->system->hostname, scanner->system->port, "%s/", scanner->uriname); + + if (scanner->geo_location) + dns_sd_geo_to_loc(scanner->geo_location, scanner->dns_sd_loc); + + // Handle name collisions + if (scanner->dns_sd_collision) + { + char new_dns_sd_name[256]; // New DNS-SD name + + scanner->dns_sd_serial++; + + if (scanner->dns_sd_serial == 1) + { + if (scanner->system->options & PAPPL_SOPTIONS_DNSSD_HOST) + snprintf(new_dns_sd_name, sizeof(new_dns_sd_name), "%s (%s)", scanner->dns_sd_name, scanner->system->hostname); + else + snprintf(new_dns_sd_name, sizeof(new_dns_sd_name), "%s (%d)", scanner->dns_sd_name, scanner->scanner_id); + } + else + { + char base_dns_sd_name[256]; // Base DNS-SD name + + papplCopyString(base_dns_sd_name, scanner->dns_sd_name, sizeof(base_dns_sd_name)); + if ((ptr = strrchr(base_dns_sd_name, '(')) != NULL) + *ptr = '\0'; + + snprintf(new_dns_sd_name, sizeof(new_dns_sd_name), "%s(%d)", base_dns_sd_name, scanner->dns_sd_serial); + } + + free(scanner->dns_sd_name); + if ((scanner->dns_sd_name = strdup(new_dns_sd_name)) != NULL) + { + papplLogScanner(scanner, PAPPL_LOGLEVEL_INFO, "DNS-SD name collision, trying new DNS-SD service name '%s'.", scanner->dns_sd_name); + scanner->dns_sd_collision = false; + } + else + { + papplLogScanner(scanner, PAPPL_LOGLEVEL_ERROR, "DNS-SD name collision, failed to allocate new DNS-SD service name."); + return (false); + } + } + + if ((master = _papplDNSSDInit(scanner->system)) == NULL) + return (false); + +#ifdef HAVE_MDNSRESPONDER + // Build the TXT record for eSCL + TXTRecordCreate(&txt, 1024, NULL); + + // Add make and model if available + if (scanner->driver_data.make_and_model[0]) + TXTRecordSetValue(&txt, "ty", (uint8_t)strlen(scanner->driver_data.make_and_model), scanner->driver_data.make_and_model); + + // Add admin URL + TXTRecordSetValue(&txt, "adminurl", (uint8_t)strlen(adminurl), adminurl); + + // Add location if available + TXTRecordSetValue(&txt, "note", (uint8_t)strlen(scanner->location ? scanner->location : ""), scanner->location ? scanner->location : ""); + + // Add supported formats + TXTRecordSetValue(&txt, "formats", (uint8_t)strlen(formats), formats); + + // Add UUID if available + if (scanner->uuid) + TXTRecordSetValue(&txt, "uuid", (uint8_t)strlen(scanner->uuid) - 9, scanner->uuid + 9); + + // Add input sources + if (sources[0]) + TXTRecordSetValue(&txt, "is", (uint8_t)strlen(sources), sources); + + // Add color spaces + if (colorspaces[0]) + TXTRecordSetValue(&txt, "cs", (uint8_t)strlen(colorspaces), colorspaces); + + // Add duplex support + TXTRecordSetValue(&txt, "duplex", 1, scanner->driver_data.duplex_supported ? "T" : "F"); + + // Add scanning intents + if (intents[0]) + TXTRecordSetValue(&txt, "intents", (uint8_t)strlen(intents), intents); + + // Add resolutions + char res_str[252] = ""; + ptr = res_str; + for (i = 0; i < MAX_RESOLUTIONS && scanner->driver_data.resolutions[i]; i++) + { + if (i > 0) + ptr += snprintf(ptr, sizeof(res_str) - (size_t)(ptr - res_str), ","); + ptr += snprintf(ptr, sizeof(res_str) - (size_t)(ptr - res_str), "%d", scanner->driver_data.resolutions[i]); + } + if (res_str[0]) + TXTRecordSetValue(&txt, "rs", (uint8_t)strlen(res_str), res_str); + + // Add scan area + char area_str[32]; + snprintf(area_str, sizeof(area_str), "%dx%d", scanner->driver_data.max_scan_area[0], scanner->driver_data.max_scan_area[1]); + TXTRecordSetValue(&txt, "area", (uint8_t)strlen(area_str), area_str); + + // Add color modes + char color_modes[252] = ""; + ptr = color_modes; + for (i = 0; i < PAPPL_MAX_COLOR_MODES && scanner->driver_data.color_modes_supported[i]; i++) + { + if (i > 0) + ptr += snprintf(ptr, sizeof(color_modes) - (size_t)(ptr - color_modes), ","); + + switch (scanner->driver_data.color_modes_supported[i]) + { + case PAPPL_BLACKANDWHITE1: + ptr += snprintf(ptr, sizeof(color_modes) - (size_t)(ptr - color_modes), "BlackAndWhite1"); + break; + case PAPPL_GRAYSCALE8: + ptr += snprintf(ptr, sizeof(color_modes) - (size_t)(ptr - color_modes), "Grayscale8"); + break; + case PAPPL_RGB24: + ptr += snprintf(ptr, sizeof(color_modes) - (size_t)(ptr - color_modes), "RGB24"); + break; + } + } + if (color_modes[0]) + TXTRecordSetValue(&txt, "modes", (uint8_t)strlen(color_modes), color_modes); + + // Add default values + char defaults[252]; + snprintf(defaults, sizeof(defaults), "dpi=%d", scanner->driver_data.default_resolution); + TXTRecordSetValue(&txt, "defaults", (uint8_t)strlen(defaults), defaults); + + // Add scan region + char region[64]; + snprintf(region, sizeof(region), "%d,%d,%d,%d", + scanner->driver_data.scan_region_supported[0], + scanner->driver_data.scan_region_supported[1], + scanner->driver_data.scan_region_supported[2], + scanner->driver_data.scan_region_supported[3]); + TXTRecordSetValue(&txt, "region", (uint8_t)strlen(region), region); + + // Add standard required fields + TXTRecordSetValue(&txt, "txtvers", 1, "1"); + TXTRecordSetValue(&txt, "TLS", 3, "1.2"); + + // Register eSCL service + if (scanner->dns_sd_escl_ref) + DNSServiceRefDeallocate(scanner->dns_sd_escl_ref); + + scanner->dns_sd_escl_ref = master; + + if ((error = DNSServiceRegister(&scanner->dns_sd_escl_ref, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, if_index, scanner->dns_sd_name, "_uscan._tcp", NULL /* domain */, /*hostname*/ NULL, htons(system->port), TXTRecordGetLength(&txt), TXTRecordGetBytesPtr(&txt), (DNSServiceRegisterReply)dns_sd_scanner_callback, scanner)) != kDNSServiceErr_NoError) + { + papplLogScanner(scanner, PAPPL_LOGLEVEL_ERROR, "Unable to register '%s._uscan._tcp': %s", scanner->dns_sd_name, _papplDNSSDStrError(error)); + ret = false; + } + + if (scanner->geo_location && ret) + { + if ((error = DNSServiceAddRecord(scanner->dns_sd_escl_ref, &scanner->dns_sd_escl_loc_ref, 0, kDNSServiceType_LOC, sizeof(scanner->dns_sd_loc), scanner->dns_sd_loc, 0)) != kDNSServiceErr_NoError) + { + papplLogScanner(scanner, PAPPL_LOGLEVEL_ERROR, "Unable to register LOC record for '%s._uscan._tcp': %s", scanner->dns_sd_name, _papplDNSSDStrError(error)); + ret = false; + } + } + + TXTRecordDeallocate(&txt); + + // Register HTTP service + if (scanner->dns_sd_http_ref) + DNSServiceRefDeallocate(scanner->dns_sd_http_ref); + + TXTRecordCreate(&txt, 1024, NULL); + snprintf(adminurl, sizeof(adminurl), "%s/", scanner->uriname); + TXTRecordSetValue(&txt, "path", (uint8_t)strlen(adminurl), adminurl); + + scanner->dns_sd_http_ref = master; + + if ((error = DNSServiceRegister(&scanner->dns_sd_http_ref, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, if_index, scanner->dns_sd_name, "_http._tcp,_scanner", NULL /* domain */, /*hostname*/ NULL, htons(system->port), TXTRecordGetLength(&txt), TXTRecordGetBytesPtr(&txt), (DNSServiceRegisterReply)dns_sd_scanner_callback, scanner)) != kDNSServiceErr_NoError) + { + papplLogScanner(scanner, PAPPL_LOGLEVEL_ERROR, "Unable to register '%s._http._tcp,_scanner': %s", scanner->dns_sd_name, _papplDNSSDStrError(error)); + ret = false; + } + + TXTRecordDeallocate(&txt); + +#elif defined(HAVE_AVAHI) + // Create the TXT record for Avahi + txt = NULL; + if (scanner->driver_data.make_and_model[0]) + txt = avahi_string_list_add_printf(txt, "ty=%s", scanner->driver_data.make_and_model); + txt = avahi_string_list_add_printf(txt, "adminurl=%s", adminurl); + txt = avahi_string_list_add_printf(txt, "note=%s", scanner->location ? scanner->location : ""); + txt = avahi_string_list_add_printf(txt, "formats=%s", formats); + if (scanner->uuid) + txt = avahi_string_list_add_printf(txt, "uuid=%s", scanner->uuid + 9); + if (sources[0]) + txt = avahi_string_list_add_printf(txt, "is=%s", sources); + if (colorspaces[0]) + txt = avahi_string_list_add_printf(txt, "cs=%s", colorspaces); + txt = avahi_string_list_add_printf(txt, "duplex=%s", scanner->driver_data.duplex_supported ? "T" : "F"); + if (intents[0]) + txt = avahi_string_list_add_printf(txt, "intents=%s", intents); + + // Add resolutions + char res_str[252] = ""; + ptr = res_str; + for (i = 0; i < MAX_RESOLUTIONS && scanner->driver_data.resolutions[i]; i++) + { + if (i > 0) + ptr += snprintf(ptr, sizeof(res_str) - (size_t)(ptr - res_str), ","); + ptr += snprintf(ptr, sizeof(res_str) - (size_t)(ptr - res_str), "%d", scanner->driver_data.resolutions[i]); + } + if (res_str[0]) + txt = avahi_string_list_add_printf(txt, "rs=%s", res_str); + + // Add scan area + txt = avahi_string_list_add_printf(txt, "area=%dx%d", scanner->driver_data.max_scan_area[0], scanner->driver_data.max_scan_area[1]); + + // Add color modes + // color_modes[252] = ""; + ptr = color_modes; + for (i = 0; i < PAPPL_MAX_COLOR_MODES && scanner->driver_data.color_modes_supported[i]; i++) + { + if (i > 0) + ptr += snprintf(ptr, sizeof(color_modes) - (size_t)(ptr - color_modes), ","); + + switch (scanner->driver_data.color_modes_supported[i]) + { + case PAPPL_BLACKANDWHITE1: + ptr += snprintf(ptr, sizeof(color_modes) - (size_t)(ptr - color_modes), "BlackAndWhite1"); + break; + case PAPPL_GRAYSCALE8: + ptr += snprintf(ptr, sizeof(color_modes) - (size_t)(ptr - color_modes), "Grayscale8"); + break; + case PAPPL_RGB24: + ptr += snprintf(ptr, sizeof(color_modes) - (size_t)(ptr - color_modes), "RGB24"); + break; + } + } + if (color_modes[0]) + txt = avahi_string_list_add_printf(txt, "modes=%s", color_modes); + + // Add default values + txt = avahi_string_list_add_printf(txt, "defaults=dpi=%d", scanner->driver_data.default_resolution); + + // Add scan region + txt = avahi_string_list_add_printf(txt, "region=%d,%d,%d,%d", + scanner->driver_data.scan_region_supported[0], + scanner->driver_data.scan_region_supported[1], + scanner->driver_data.scan_region_supported[2], + scanner->driver_data.scan_region_supported[3]); + + // Add standard required fields + txt = avahi_string_list_add_printf(txt, "txtvers=1"); + txt = avahi_string_list_add_printf(txt, "TLS=1.2"); + + _papplDNSSDLock(); + + if (scanner->dns_sd_ref) + avahi_entry_group_free(scanner->dns_sd_ref); + + if ((scanner->dns_sd_ref = avahi_entry_group_new(master, (AvahiEntryGroupCallback)dns_sd_scanner_callback, scanner)) == NULL) + { + papplLogScanner(scanner, PAPPL_LOGLEVEL_ERROR, "Unable to register scanner, is the Avahi daemon running?"); + _papplDNSSDUnlock(); + avahi_string_list_free(txt); + return (false); + } + + // Register eSCL service + if ((error = avahi_entry_group_add_service_strlst(scanner->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, scanner->dns_sd_name, "_uscan._tcp", NULL, /*hostname*/ NULL, system->port, txt)) < 0) + { + papplLogScanner(scanner, PAPPL_LOGLEVEL_ERROR, "Unable to register '%s._uscan._tcp': %s", scanner->dns_sd_name, _papplDNSSDStrError(error)); + ret = false; + } + + // Add geolocation record if available + if (scanner->geo_location && ret) + { + snprintf(fullname, sizeof(fullname), "%s._uscan._tcp.local.", scanner->dns_sd_name); + + if ((error = avahi_entry_group_add_record(scanner->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, fullname, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_LOC, 75 * 60, scanner->dns_sd_loc, sizeof(scanner->dns_sd_loc))) < 0) + { + papplLogScanner(scanner, PAPPL_LOGLEVEL_ERROR, "Unable to register LOC record for '%s': %s", fullname, _papplDNSSDStrError(error)); + ret = false; + } + } + + avahi_string_list_free(txt); + + // Register HTTP service + txt = NULL; + txt = avahi_string_list_add_printf(txt, "path=%s/", scanner->uriname); + + if ((error = avahi_entry_group_add_service_strlst(scanner->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, scanner->dns_sd_name, "_http._tcp", NULL, /*hostname*/ NULL, system->port, txt)) < 0) + { + papplLogScanner(scanner, PAPPL_LOGLEVEL_ERROR, "Unable to register '%s._http._tcp': %s", scanner->dns_sd_name, _papplDNSSDStrError(error)); + ret = false; + } + + // Add scanner subtype for HTTP service + avahi_entry_group_add_service_subtype(scanner->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, scanner->dns_sd_name, "_http._tcp", NULL, "_scanner._sub._http._tcp"); + + avahi_string_list_free(txt); + + // Commit the group + avahi_entry_group_commit(scanner->dns_sd_ref); + _papplDNSSDUnlock(); + +#endif // HAVE_MDNSRESPONDER + return (ret); } // -// TODO: '_papplScannerUnregisterDNSSDNoLock()' - Unregister a scanners's DNS-SD service. +// '_papplScannerUnregisterDNSSDNoLock()' - Unregister a scanner's DNS-SD service. // - -void -_papplScannerUnregisterDNSSDNoLock( - pappl_scanner_t *scanner) // I - Scanner +void _papplScannerUnregisterDNSSDNoLock( + pappl_scanner_t *scanner) // I - Scanner { - return ; // Sample return +#if HAVE_MDNSRESPONDER + if (scanner->dns_sd_escl_ref) + { + DNSServiceRefDeallocate(scanner->dns_sd_escl_ref); + scanner->dns_sd_escl_ref = NULL; + scanner->dns_sd_escl_loc_ref = NULL; + } + + if (scanner->dns_sd_http_ref) + { + DNSServiceRefDeallocate(scanner->dns_sd_http_ref); + scanner->dns_sd_http_ref = NULL; + } + +#elif defined(HAVE_AVAHI) + _papplDNSSDLock(); + + if (scanner->dns_sd_ref) + { + avahi_entry_group_free(scanner->dns_sd_ref); + scanner->dns_sd_ref = NULL; + } + + _papplDNSSDUnlock(); + +#else + (void)scanner; +#endif // HAVE_MDNSRESPONDER } // // '_papplSystemRegisterDNSSDNoLock()' - Register a system's DNS-SD service. // -bool // O - `true` on success, `false` on failure +bool // O - `true` on success, `false` on failure _papplSystemRegisterDNSSDNoLock( - pappl_system_t *system) // I - System + pappl_system_t *system) // I - System { - bool ret = true; // Return value + bool ret = true; // Return value #ifdef HAVE_DNSSD - _pappl_dns_sd_t master; // DNS-SD master reference - _pappl_txt_t txt; // DNS-SD TXT record - uint32_t if_index; // Interface index -# ifdef HAVE_MDNSRESPONDER - DNSServiceErrorType error; // Error from mDNSResponder -# else - int error; // Error from Avahi - char fullname[256]; // Full name of services -# endif // HAVE_MDNSRESPONDER - + _pappl_dns_sd_t master; // DNS-SD master reference + _pappl_txt_t txt; // DNS-SD TXT record + uint32_t if_index; // Interface index +#ifdef HAVE_MDNSRESPONDER + DNSServiceErrorType error; // Error from mDNSResponder +#else + int error; // Error from Avahi + char fullname[256]; // Full name of services +#endif // HAVE_MDNSRESPONDER // Make sure we have all of the necessary information to register the system... if (!system->dns_sd_name || !system->hostname || !system->uuid || !system->is_running) @@ -972,11 +1375,11 @@ _papplSystemRegisterDNSSDNoLock( papplLog(system, PAPPL_LOGLEVEL_DEBUG, "Registering DNS-SD name '%s'.", system->dns_sd_name); -# ifdef HAVE_MDNSRESPONDER +#ifdef HAVE_MDNSRESPONDER if_index = !strcmp(system->hostname, "localhost") ? kDNSServiceInterfaceIndexLocalOnly : kDNSServiceInterfaceIndexAny; -# else +#else if_index = !strcmp(system->hostname, "localhost") ? if_nametoindex("lo") : AVAHI_IF_UNSPEC; -# endif // HAVE_MDNSRESPONDER +#endif // HAVE_MDNSRESPONDER if (system->geo_location) dns_sd_geo_to_loc(system->geo_location, system->dns_sd_loc); @@ -984,21 +1387,21 @@ _papplSystemRegisterDNSSDNoLock( // Rename the service as needed... if (system->dns_sd_collision) { - char new_dns_sd_name[256]; // New DNS-SD name + char new_dns_sd_name[256]; // New DNS-SD name - system->dns_sd_serial ++; + system->dns_sd_serial++; if (system->dns_sd_serial == 1) { if (system->options & PAPPL_SOPTIONS_DNSSD_HOST) - snprintf(new_dns_sd_name, sizeof(new_dns_sd_name), "%s (%s)", system->dns_sd_name, system->hostname); + snprintf(new_dns_sd_name, sizeof(new_dns_sd_name), "%s (%s)", system->dns_sd_name, system->hostname); else - snprintf(new_dns_sd_name, sizeof(new_dns_sd_name), "%s (%c%c%c%c%c%c)", system->dns_sd_name, toupper(system->uuid[39]), toupper(system->uuid[40]), toupper(system->uuid[41]), toupper(system->uuid[42]), toupper(system->uuid[43]), toupper(system->uuid[44])); + snprintf(new_dns_sd_name, sizeof(new_dns_sd_name), "%s (%c%c%c%c%c%c)", system->dns_sd_name, toupper(system->uuid[39]), toupper(system->uuid[40]), toupper(system->uuid[41]), toupper(system->uuid[42]), toupper(system->uuid[43]), toupper(system->uuid[44])); } else { - char base_dns_sd_name[256], // Base DNS-SD name - *ptr; // Pointer into name + char base_dns_sd_name[256], // Base DNS-SD name + *ptr; // Pointer into name papplCopyString(base_dns_sd_name, system->dns_sd_name, sizeof(base_dns_sd_name)); if ((ptr = strrchr(base_dns_sd_name, '(')) != NULL) @@ -1041,7 +1444,7 @@ _papplSystemRegisterDNSSDNoLock( { system->dns_sd_ipps_ref = master; - if ((error = DNSServiceRegister(&system->dns_sd_ipps_ref, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, if_index, system->dns_sd_name, "_ipps-system._tcp", NULL /* domain */, /*hostname*/NULL, htons(system->port), TXTRecordGetLength(&txt), TXTRecordGetBytesPtr(&txt), (DNSServiceRegisterReply)dns_sd_system_callback, system)) != kDNSServiceErr_NoError) + if ((error = DNSServiceRegister(&system->dns_sd_ipps_ref, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, if_index, system->dns_sd_name, "_ipps-system._tcp", NULL /* domain */, /*hostname*/ NULL, htons(system->port), TXTRecordGetLength(&txt), TXTRecordGetBytesPtr(&txt), (DNSServiceRegisterReply)dns_sd_system_callback, system)) != kDNSServiceErr_NoError) { papplLog(system, PAPPL_LOGLEVEL_ERROR, "Unable to register '%s._ipps-system._tcp': %s", system->dns_sd_name, _papplDNSSDStrError(error)); ret = false; @@ -1053,8 +1456,8 @@ _papplSystemRegisterDNSSDNoLock( if ((error = DNSServiceAddRecord(system->dns_sd_ipps_ref, &system->dns_sd_loc_ref, 0, kDNSServiceType_LOC, sizeof(system->dns_sd_loc), system->dns_sd_loc, 0)) != kDNSServiceErr_NoError) { - papplLog(system, PAPPL_LOGLEVEL_ERROR, "Unable to register LOC record for '%s._ipps-system._tcp': %s", system->dns_sd_name, _papplDNSSDStrError(error)); - ret = false; + papplLog(system, PAPPL_LOGLEVEL_ERROR, "Unable to register LOC record for '%s._ipps-system._tcp': %s", system->dns_sd_name, _papplDNSSDStrError(error)); + ret = false; } } } @@ -1072,7 +1475,7 @@ _papplSystemRegisterDNSSDNoLock( system->dns_sd_http_ref = master; - if ((error = DNSServiceRegister(&system->dns_sd_http_ref, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, if_index, system->dns_sd_name, "_http._tcp,_printer", NULL /* domain */, /*hostname*/NULL, htons(system->port), 0 /* txtlen */, NULL /* txt */, (DNSServiceRegisterReply)dns_sd_system_callback, system)) != kDNSServiceErr_NoError) + if ((error = DNSServiceRegister(&system->dns_sd_http_ref, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, if_index, system->dns_sd_name, "_http._tcp,_printer", NULL /* domain */, /*hostname*/ NULL, htons(system->port), 0 /* txtlen */, NULL /* txt */, (DNSServiceRegisterReply)dns_sd_system_callback, system)) != kDNSServiceErr_NoError) { papplLog(system, PAPPL_LOGLEVEL_ERROR, "Unable to register '%s.%s': %s", system->dns_sd_name, "_http._tcp,_printer", _papplDNSSDStrError(error)); ret = false; @@ -1102,7 +1505,7 @@ _papplSystemRegisterDNSSDNoLock( if (!(system->options & PAPPL_SOPTIONS_NO_TLS)) { - if ((error = avahi_entry_group_add_service_strlst(system->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, system->dns_sd_name, "_ipps-system._tcp", NULL, /*hostname*/NULL, system->port, txt)) < 0) + if ((error = avahi_entry_group_add_service_strlst(system->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, system->dns_sd_name, "_ipps-system._tcp", NULL, /*hostname*/ NULL, system->port, txt)) < 0) { papplLog(system, PAPPL_LOGLEVEL_ERROR, "Unable to register '%s._ipps-system._tcp': %s", system->dns_sd_name, _papplDNSSDStrError(error)); ret = false; @@ -1117,8 +1520,8 @@ _papplSystemRegisterDNSSDNoLock( if ((error = avahi_entry_group_add_record(system->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, fullname, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_LOC, 75 * 60, system->dns_sd_loc, sizeof(system->dns_sd_loc))) < 0) { - papplLog(system, PAPPL_LOGLEVEL_ERROR, "Unable to register LOC record for '%s': %s", fullname, _papplDNSSDStrError(error)); - ret = false; + papplLog(system, PAPPL_LOGLEVEL_ERROR, "Unable to register LOC record for '%s': %s", fullname, _papplDNSSDStrError(error)); + ret = false; } } } @@ -1126,7 +1529,7 @@ _papplSystemRegisterDNSSDNoLock( // Finally _http.tcp (HTTP) for the web interface... if (system->options & PAPPL_SOPTIONS_MULTI_QUEUE) { - avahi_entry_group_add_service_strlst(system->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, system->dns_sd_name, "_http._tcp", NULL, /*hostname*/NULL, system->port, NULL); + avahi_entry_group_add_service_strlst(system->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, system->dns_sd_name, "_http._tcp", NULL, /*hostname*/ NULL, system->port, NULL); avahi_entry_group_add_service_subtype(system->dns_sd_ref, if_index, AVAHI_PROTO_UNSPEC, 0, system->dns_sd_name, "_http._tcp", NULL, "_printer._sub._http._tcp"); } @@ -1140,14 +1543,12 @@ _papplSystemRegisterDNSSDNoLock( return (ret); } - // // '_papplSystemUnregisterDNSSDNoLock()' - Unregister a printer's DNS-SD service. // -void -_papplSystemUnregisterDNSSDNoLock( - pappl_system_t *system) // I - System +void _papplSystemUnregisterDNSSDNoLock( + pappl_system_t *system) // I - System { #if HAVE_MDNSRESPONDER if (system->dns_sd_ipps_ref) @@ -1178,50 +1579,48 @@ _papplSystemUnregisterDNSSDNoLock( #endif // HAVE_MDNSRESPONDER } - // // 'dns_sd_geo_to_loc()' - Convert a "geo:" URI to a DNS LOC record. // static void -dns_sd_geo_to_loc(const char *geo, // I - "geo:" URI - unsigned char loc[16])// O - DNS LOC record +dns_sd_geo_to_loc(const char *geo, // I - "geo:" URI + unsigned char loc[16]) // O - DNS LOC record { - double lat = 0.0, lon = 0.0; // Latitude and longitude in degrees - double alt = 0.0; // Altitude in meters - unsigned int lat_ksec, lon_ksec; // Latitude and longitude in thousandths of arc seconds, biased by 2^31 - unsigned int alt_cm; // Altitude in centimeters, biased by 10,000,000cm + double lat = 0.0, lon = 0.0; // Latitude and longitude in degrees + double alt = 0.0; // Altitude in meters + unsigned int lat_ksec, lon_ksec; // Latitude and longitude in thousandths of arc seconds, biased by 2^31 + unsigned int alt_cm; // Altitude in centimeters, biased by 10,000,000cm // Pull apart the "geo:" URI and convert to the integer representation for // the LOC record... sscanf(geo, "geo:%lf,%lf,%lf", &lat, &lon, &alt); lat_ksec = (unsigned)((int)(lat * 3600000.0) + 0x40000000 + 0x40000000); lon_ksec = (unsigned)((int)(lon * 3600000.0) + 0x40000000 + 0x40000000); - alt_cm = (unsigned)((int)(alt * 100.0) + 10000000); + alt_cm = (unsigned)((int)(alt * 100.0) + 10000000); // Build the LOC record... - loc[0] = 0x00; // Version - loc[1] = 0x11; // Size (10cm) - loc[2] = 0x11; // Horizontal precision (10cm) - loc[3] = 0x11; // Vertical precision (10cm) - loc[4] = (unsigned char)(lat_ksec >> 24); - // Latitude (32-bit big-endian) - loc[5] = (unsigned char)(lat_ksec >> 16); - loc[6] = (unsigned char)(lat_ksec >> 8); - loc[7] = (unsigned char)(lat_ksec); - loc[8] = (unsigned char)(lon_ksec >> 24); - // Latitude (32-bit big-endian) - loc[9] = (unsigned char)(lon_ksec >> 16); + loc[0] = 0x00; // Version + loc[1] = 0x11; // Size (10cm) + loc[2] = 0x11; // Horizontal precision (10cm) + loc[3] = 0x11; // Vertical precision (10cm) + loc[4] = (unsigned char)(lat_ksec >> 24); + // Latitude (32-bit big-endian) + loc[5] = (unsigned char)(lat_ksec >> 16); + loc[6] = (unsigned char)(lat_ksec >> 8); + loc[7] = (unsigned char)(lat_ksec); + loc[8] = (unsigned char)(lon_ksec >> 24); + // Latitude (32-bit big-endian) + loc[9] = (unsigned char)(lon_ksec >> 16); loc[10] = (unsigned char)(lon_ksec >> 8); loc[11] = (unsigned char)(lon_ksec); loc[12] = (unsigned char)(alt_cm >> 24); - // Altitude (32-bit big-endian) + // Altitude (32-bit big-endian) loc[13] = (unsigned char)(alt_cm >> 16); loc[14] = (unsigned char)(alt_cm >> 8); loc[15] = (unsigned char)(alt_cm); } - #ifdef HAVE_MDNSRESPONDER // // 'dns_sd_hostname_callback()' - Track changes to the mDNS hostname... @@ -1229,23 +1628,22 @@ dns_sd_geo_to_loc(const char *geo, // I - "geo:" URI static void DNSSD_API dns_sd_hostname_callback( - DNSServiceRef ref, // I - Service reference (unused) - DNSServiceFlags flags, // I - Flags (unused) - uint32_t if_index, // I - Interface index (unused) - DNSServiceErrorType error, // I - Error code, if any - const char *fullname, // I - Search name (unused) - uint16_t rrtype, // I - Record type (unused) - uint16_t rrclass, // I - Record class (unused) - uint16_t rdlen, // I - Record data length - const void *rdata, // I - Record data - uint32_t ttl, // I - Time-to-live (unused) - void *context) // I - Context (unused) + DNSServiceRef ref, // I - Service reference (unused) + DNSServiceFlags flags, // I - Flags (unused) + uint32_t if_index, // I - Interface index (unused) + DNSServiceErrorType error, // I - Error code, if any + const char *fullname, // I - Search name (unused) + uint16_t rrtype, // I - Record type (unused) + uint16_t rrclass, // I - Record class (unused) + uint16_t rdlen, // I - Record data length + const void *rdata, // I - Record data + uint32_t ttl, // I - Time-to-live (unused) + void *context) // I - Context (unused) { - uint8_t *rdataptr, // Pointer into record data - lablen; // Length of current label - char temp[1024], // Temporary hostname string - *tempptr; // Pointer into temporary string - + uint8_t *rdataptr, // Pointer into record data + lablen; // Length of current label + char temp[1024], // Temporary hostname string + *tempptr; // Pointer into temporary string (void)ref; (void)flags; @@ -1264,7 +1662,7 @@ dns_sd_hostname_callback( for (rdataptr = (uint8_t *)rdata, tempptr = temp; rdlen > 0 && tempptr < (temp + sizeof(temp) - 2); rdlen -= lablen, rdataptr += lablen) { lablen = *rdataptr++; - rdlen --; + rdlen--; if (!rdlen || rdlen < lablen) break; @@ -1290,25 +1688,24 @@ dns_sd_hostname_callback( if (strcmp(temp, pappl_dns_sd_hostname)) { papplCopyString(pappl_dns_sd_hostname, temp, sizeof(pappl_dns_sd_hostname)); - pappl_dns_sd_hostname_changes ++; + pappl_dns_sd_hostname_changes++; } pthread_mutex_unlock(&pappl_dns_sd_hostname_mutex); } - // // 'dns_sd_printer_callback()' - Handle DNS-SD printer registration events. // static void DNSSD_API dns_sd_printer_callback( - DNSServiceRef sdRef, // I - Service reference - DNSServiceFlags flags, // I - Status flags - DNSServiceErrorType errorCode, // I - Error, if any - const char *name, // I - Service name - const char *regtype, // I - Service type - const char *domain, // I - Domain for service - pappl_printer_t *printer) // I - Printer + DNSServiceRef sdRef, // I - Service reference + DNSServiceFlags flags, // I - Status flags + DNSServiceErrorType errorCode, // I - Error, if any + const char *name, // I - Service name + const char *regtype, // I - Service type + const char *domain, // I - Domain for service + pappl_printer_t *printer) // I - Printer { (void)name; (void)sdRef; @@ -1320,7 +1717,7 @@ dns_sd_printer_callback( _papplRWLockWrite(printer->system); _papplRWLockWrite(printer); - printer->dns_sd_collision = true; + printer->dns_sd_collision = true; printer->system->dns_sd_any_collision = true; _papplRWUnlock(printer); @@ -1333,31 +1730,66 @@ dns_sd_printer_callback( } } +/ + // 'dns_sd_scanner_callback()' - Handle DNS-SD scanner registration events. + // + + static void DNSSD_API + dns_sd_scanner_callback( + DNSServiceRef sdRef, // I - Service reference + DNSServiceFlags flags, // I - Status flags + DNSServiceErrorType errorCode, // I - Error, if any + const char *name, // I - Service name + const char *regtype, // I - Service type + const char *domain, // I - Domain for service + pappl_scanner_t *scanner) // I - Scanner +{ + (void)name; + (void)sdRef; + (void)flags; + (void)domain; + + if (errorCode == kDNSServiceErr_NameConflict) + { + _papplRWLockWrite(scanner->system); + _papplRWLockWrite(scanner); + + scanner->dns_sd_collision = true; + scanner->system->dns_sd_any_collision = true; + + _papplRWUnlock(scanner); + _papplRWUnlock(scanner->system); + } + else if (errorCode) + { + papplLogScanner(scanner, PAPPL_LOGLEVEL_ERROR, "DNSServiceRegister for '%s' failed with error %d (%s).", regtype, (int)errorCode, _papplDNSSDStrError(errorCode)); + return; + } +} // // 'dns_sd_run()' - Handle DNS-SD traffic. // -static void * // O - Exit status -dns_sd_run(void *data) // I - System object +static void * // O - Exit status +dns_sd_run(void *data) // I - System object { - int err; // Status + int err; // Status pappl_system_t *system = (pappl_system_t *)data; - // System object - struct pollfd pfd; // Poll data - + // System object + struct pollfd pfd; // Poll data pfd.events = POLLIN | POLLERR; - pfd.fd = DNSServiceRefSockFD(pappl_dns_sd_master); + pfd.fd = DNSServiceRefSockFD(pappl_dns_sd_master); for (;;) { // Wait up to 1 second for new data... -# if _WIN32 +#if _WIN32 if (poll(&pfd, 1, 1000) < 0 && WSAGetLastError() == WSAEINTR) -# else +#else if (poll(&pfd, 1, 1000) < 0 && errno != EINTR && errno != EAGAIN) -# endif // _WIN32 +#endif // _WIN32 { papplLog(system, PAPPL_LOGLEVEL_ERROR, "DNS-SD poll failed: %s", strerror(errno)); break; @@ -1368,8 +1800,8 @@ dns_sd_run(void *data) // I - System object // Read DNS-SD data... if ((err = DNSServiceProcessResult(pappl_dns_sd_master)) != kDNSServiceErr_NoError) { - papplLog(system, PAPPL_LOGLEVEL_ERROR, "DNSServiceProcessResult returned %d (%s).", err, _papplDNSSDStrError(err)); - break; + papplLog(system, PAPPL_LOGLEVEL_ERROR, "DNSServiceProcessResult returned %d (%s).", err, _papplDNSSDStrError(err)); + break; } } else if (pfd.revents) @@ -1382,20 +1814,19 @@ dns_sd_run(void *data) // I - System object return (NULL); } - // // 'dns_sd_system_callback()' - Handle DNS-SD system registration events. // static void DNSSD_API dns_sd_system_callback( - DNSServiceRef sdRef, // I - Service reference - DNSServiceFlags flags, // I - Status flags - DNSServiceErrorType errorCode, // I - Error, if any - const char *name, // I - Service name - const char *regtype, // I - Service type - const char *domain, // I - Domain for service - pappl_system_t *system) // I - System + DNSServiceRef sdRef, // I - Service reference + DNSServiceFlags flags, // I - Status flags + DNSServiceErrorType errorCode, // I - Error, if any + const char *name, // I - Service name + const char *regtype, // I - Service type + const char *domain, // I - Domain for service + pappl_system_t *system) // I - System { (void)sdRef; (void)flags; @@ -1405,7 +1836,7 @@ dns_sd_system_callback( if (errorCode == kDNSServiceErr_NameConflict) { _papplRWLockWrite(system); - system->dns_sd_collision = true; + system->dns_sd_collision = true; system->dns_sd_any_collision = true; _papplRWUnlock(system); } @@ -1416,7 +1847,6 @@ dns_sd_system_callback( } } - #elif defined(HAVE_AVAHI) // //'dns_sd_client_cb()' - Client callback for Avahi. @@ -1426,13 +1856,12 @@ dns_sd_system_callback( static void dns_sd_client_cb( - AvahiClient *c, // I - Client - AvahiClientState state, // I - Current state - void *data) // I - Callback data (unused) + AvahiClient *c, // I - Client + AvahiClientState state, // I - Current state + void *data) // I - Callback data (unused) { (void)data; - if (!c) return; @@ -1446,21 +1875,20 @@ dns_sd_client_cb( else if (state == AVAHI_CLIENT_S_RUNNING) { pthread_mutex_lock(&pappl_dns_sd_hostname_mutex); - pappl_dns_sd_hostname_changes ++; + pappl_dns_sd_hostname_changes++; pthread_mutex_unlock(&pappl_dns_sd_hostname_mutex); } } - // // 'dns_sd_printer_callback()' - Handle DNS-SD printer registration events. // static void dns_sd_printer_callback( - AvahiEntryGroup *srv, // I - Service - AvahiEntryGroupState state, // I - Registration state - pappl_printer_t *printer) // I - Printer + AvahiEntryGroup *srv, // I - Service + AvahiEntryGroupState state, // I - Registration state + pappl_printer_t *printer) // I - Printer { (void)srv; @@ -1468,13 +1896,35 @@ dns_sd_printer_callback( { _papplRWLockWrite(printer->system); _papplRWLockWrite(printer); - printer->dns_sd_collision = true; + printer->dns_sd_collision = true; printer->system->dns_sd_any_collision = true; _papplRWUnlock(printer); _papplRWUnlock(printer->system); } } +// +// 'dns_sd_scanner_callback()' - Handle DNS-SD scanner registration events. +// + +static void +dns_sd_scanner_callback( + AvahiEntryGroup *srv, // I - Service + AvahiEntryGroupState state, // I - Registration state + pappl_scanner_t *scanner) // I - Scanner +{ + (void)srv; + + if (state == AVAHI_ENTRY_GROUP_COLLISION) + { + _papplRWLockWrite(scanner->system); + _papplRWLockWrite(scanner); + scanner->dns_sd_collision = true; + scanner->system->dns_sd_any_collision = true; + _papplRWUnlock(scanner); + _papplRWUnlock(scanner->system); + } +} // // 'dns_sd_system_callback()' - Handle DNS-SD system registration events. @@ -1482,16 +1932,16 @@ dns_sd_printer_callback( static void dns_sd_system_callback( - AvahiEntryGroup *srv, // I - Service - AvahiEntryGroupState state, // I - Registration state - pappl_system_t *system) // I - System + AvahiEntryGroup *srv, // I - Service + AvahiEntryGroupState state, // I - Registration state + pappl_system_t *system) // I - System { (void)srv; if (state == AVAHI_ENTRY_GROUP_COLLISION) { _papplRWLockWrite(system); - system->dns_sd_collision = true; + system->dns_sd_collision = true; system->dns_sd_any_collision = true; _papplRWUnlock(system); } diff --git a/pappl/scanner-private.h b/pappl/scanner-private.h index eba9112f..2c8ae3e5 100644 --- a/pappl/scanner-private.h +++ b/pappl/scanner-private.h @@ -69,6 +69,7 @@ struct _pappl_scanner_s // Scanner data that get configured when a scanning jo cups_array_t *links; // Web navigation links # ifdef HAVE_MDNSRESPONDER _pappl_srv_t dns_sd_http_ref, // DNS-SD HTTP service + _pappl_srv_t dns_sd_escl_ref, // DNS-SD eSCL service DNSRecordRef dns_sd_escl_loc_ref, // DNS-SD LOC record for ESCL service # elif defined(HAVE_AVAHI) _pappl_srv_t dns_sd_ref; // DNS-SD services From 3da7f2c6e7bb66fab9015ee3a6b2cac63406ffd7 Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Sat, 2 Nov 2024 21:30:04 +0000 Subject: [PATCH 21/26] Add job-scan.c This commit creates a new file job-scan.c with various functions to handle scanning jobs. The file is added to the Makefile and the job.h and job-private.h header file are updated to include the new functions. Signed-off-by: Akarshan Kapoor --- pappl/Makefile | 1 + pappl/job-private.h | 4 + pappl/job-scan.c | 603 ++++++++++++++++++++++++++++++++++++++++++++ pappl/job.h | 3 + 4 files changed, 611 insertions(+) create mode 100644 pappl/job-scan.c diff --git a/pappl/Makefile b/pappl/Makefile index 54776b27..c1dc1742 100644 --- a/pappl/Makefile +++ b/pappl/Makefile @@ -30,6 +30,7 @@ BASEOBJS = \ job-filter.o \ job-ipp.o \ job-process.o \ + job-scan.o \ job.o \ link.o \ loc.o \ diff --git a/pappl/job-private.h b/pappl/job-private.h index 55b998c2..08930f41 100644 --- a/pappl/job-private.h +++ b/pappl/job-private.h @@ -62,6 +62,7 @@ extern void _papplJobCopyAttributesNoLock(pappl_job_t *job, pappl_client_t *cli extern void _papplJobCopyDocumentData(pappl_client_t *client, pappl_job_t *job) _PAPPL_PRIVATE; extern void _papplJobCopyStateNoLock(pappl_job_t *job, ipp_tag_t group_tag, ipp_t *ipp, cups_array_t *ra) _PAPPL_PRIVATE; extern pappl_job_t *_papplJobCreate(pappl_printer_t *printer, int job_id, const char *username, const char *format, const char *job_name, ipp_t *attrs) _PAPPL_PRIVATE; +extern pappl_job_t *_papplScanJobCreate(pappl_scanner_t *scanner, int job_id, const char *username, const char *format, const char *job_name) _PAPPL_PRIVATE; // no extra attributes required extern void _papplJobDelete(pappl_job_t *job) _PAPPL_PRIVATE; # ifdef HAVE_LIBJPEG extern bool _papplJobFilterJPEG(pappl_job_t *job, pappl_device_t *device, void *data); @@ -72,6 +73,9 @@ extern bool _papplJobFilterPNG(pappl_job_t *job, pappl_device_t *device, void * extern bool _papplJobHoldNoLock(pappl_job_t *job, const char *username, const char *until, time_t until_time) _PAPPL_PRIVATE; extern void *_papplJobProcess(pappl_job_t *job) _PAPPL_PRIVATE; extern void _papplJobProcessIPP(pappl_client_t *client) _PAPPL_PRIVATE; +// TODO +extern void _papplJobProcessESCL(pappl_client_t *client) _PAPPL_PRIVATE; + extern void _papplJobProcessRaster(pappl_job_t *job, pappl_client_t *client) _PAPPL_PRIVATE; extern const char *_papplJobReasonString(pappl_jreason_t reason) _PAPPL_PRIVATE; extern void _papplJobReleaseNoLock(pappl_job_t *job, const char *username) _PAPPL_PRIVATE; diff --git a/pappl/job-scan.c b/pappl/job-scan.c new file mode 100644 index 00000000..30b7bcfa --- /dev/null +++ b/pappl/job-scan.c @@ -0,0 +1,603 @@ +// +// Scan Job functions for the Scanner Application Framework +// +// Copyright © 2020-2024 by Michael R Sweet. +// +// Licensed under Apache License v2.0. See the file "LICENSE" for more +// information. +// + +#include "pappl-private.h" + +// Internal Helper Functions +// +// Helper functions for scanner option handling +// + +// +// '_papplValidateDocumentFormat()' - Validate document format against supported formats. +// +static bool // O - TRUE if valid, FALSE if not +_papplValidateDocumentFormat( + const char *format, // I - Format to validate + const char **supported, // I - Array of supported formats + size_t num_supported) // I - Number of supported formats +{ + size_t i; + + if (!format || !supported || num_supported == 0) + return (false); + + for (i = 0; i < num_supported && supported[i]; i++) + { + if (!strcmp(format, supported[i])) + return (true); + } + + return (false); +} + +// +// '_papplValidateScanResolution()' - Validate scan resolution against supported values. +// +static bool // O - TRUE if valid, FALSE if not +_papplValidateScanResolution( + int resolution, // I - Resolution to validate + const int *supported, // I - Array of supported resolutions + size_t num_supported) // I - Number of supported resolutions +{ + size_t i; // Looping var + + if (resolution <= 0 || !supported || num_supported == 0) + return (false); + + for (i = 0; i < num_supported && supported[i] > 0; i++) + { + if (resolution == supported[i]) + return (true); + } + + return (false); +} + +// +// '_papplValidateScanRegion()' - Validate scan region against supported dimensions. +// +static bool // O - TRUE if valid, FALSE if not +_papplValidateScanRegion( + int x, // I - X offset + int y, // I - Y offset + int w, // I - Width + int h, // I - Height + const int supported[4]) // I - Supported region values [x,y,w,h] +{ + if (!supported) + return (false); + + return (x >= supported[0] && y >= supported[1] && + w <= supported[2] && h <= supported[3] && + w > 0 && h > 0); +} + +// End of helper functions + + + + +// +// 'papplJobGetScanner()' - Get the scanner for the job. +// +// This function returns the scanner containing the job. +// + +pappl_scanner_t * // O - Scanner +papplJobGetScanner(pappl_job_t *job) // I - Job +{ + pappl_scanner_t *ret = NULL; // Return value + + if (job) + { + _papplRWLockRead(job); + ret = job->scanner; + _papplRWUnlock(job); + } + + return (ret); +} + +// +// 'papplJobDeleteScanOptions()' - Delete a job options structure. +// +// This function frees the memory used for a job options structure. +// + +void papplJobDeleteScanOptions( + pappl_sc_options_t *options) // I - Scan options +{ + if (options) + { + free(options); + } +} + + +// +// 'papplJobCreateScanOptions()' - Create the scanner options for a job. +// +// This function allocates a scanner options structure and computes the scan +// options for a job based upon the job configuration and default values +// set in the scanner driver data. +// + +pappl_sc_options_t * // O - Job options data or `NULL` on error +papplJobCreateScanOptions( + pappl_job_t *job) // I - Job +{ + pappl_sc_options_t *options; // New options data + pappl_scanner_t *scanner; // Scanner + int i; // Looping var + bool mode_supported, // Is color mode supported? + source_supported, // Is source supported? + intent_supported; // Is intent supported? + + if (!job) + return (NULL); + + scanner = (pappl_scanner_t *)job->printer; + if (!scanner) + return (NULL); + + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "Getting scan options for job"); + + // Clear all options... + if ((options = calloc(1, sizeof(pappl_sc_options_t))) == NULL) + return (NULL); + + _papplRWLockRead(scanner); + + // Document format - Validate against supported formats + if (_papplValidateDocumentFormat(scanner->driver_data.default_document_format, + scanner->driver_data.document_formats_supported, + PAPPL_MAX_FORMATS)) + { + papplCopyString(options->document_format, + scanner->driver_data.default_document_format, + sizeof(options->document_format)); + } + else if (scanner->driver_data.document_formats_supported[0]) + { + // Default to first supported format if default is invalid + papplCopyString(options->document_format, + scanner->driver_data.document_formats_supported[0], + sizeof(options->document_format)); + } + else + { + // Fallback to a safe default + papplCopyString(options->document_format, "application/pdf", sizeof(options->document_format)); + } + + // Color mode - Validate and set + mode_supported = false; + for (i = 0; i < PAPPL_MAX_COLOR_MODES; i++) + { + if (scanner->driver_data.color_modes_supported[i] == scanner->driver_data.default_color_mode) + { + mode_supported = true; + break; + } + } + options->color_mode = mode_supported ? scanner->driver_data.default_color_mode : PAPPL_BLACKANDWHITE1; + + // Resolution - Validate against supported resolutions + if (_papplValidateScanResolution(scanner->driver_data.default_resolution, + scanner->driver_data.resolutions, + MAX_RESOLUTIONS)) + { + options->resolution = scanner->driver_data.default_resolution; + } + else if (scanner->driver_data.resolutions[0] > 0) + { + options->resolution = scanner->driver_data.resolutions[0]; + } + else + { + options->resolution = 300; // Safe default + } + + // Input source - Validate against supported sources + source_supported = false; + for (i = 0; i < PAPPL_MAX_SOURCES; i++) + { + if (scanner->driver_data.input_sources_supported[i] == scanner->driver_data.default_input_source) + { + source_supported = true; + break; + } + } + options->input_source = source_supported ? scanner->driver_data.default_input_source : PAPPL_FLATBED; + + // Duplex - Only enable if supported + options->duplex = scanner->driver_data.duplex_supported ? false : false; + + // Scan intent - Validate against supported intents + intent_supported = false; + for (i = 0; scanner->driver_data.mandatory_intents[i] && i < 5; i++) + { + if (!strcmp(scanner->driver_data.default_intent, scanner->driver_data.mandatory_intents[i])) + { + intent_supported = true; + break; + } + } + if (intent_supported) + { + papplCopyString(options->intent, + scanner->driver_data.default_intent, + sizeof(options->intent)); + } + else if (scanner->driver_data.mandatory_intents[0]) + { + papplCopyString(options->intent, + scanner->driver_data.mandatory_intents[0], + sizeof(options->intent)); + } + else + { + papplCopyString(options->intent, "document", sizeof(options->intent)); + } + + // Scan area - Validate against supported dimensions + if (_papplValidateScanRegion(0, 0, + scanner->driver_data.default_scan_area[0], + scanner->driver_data.default_scan_area[1], + scanner->driver_data.scan_region_supported)) + { + options->scan_area.width = scanner->driver_data.default_scan_area[0]; + options->scan_area.height = scanner->driver_data.default_scan_area[1]; + options->scan_area.x_offset = 0; + options->scan_area.y_offset = 0; + } + else + { + // Use maximum supported dimensions if defaults are invalid + options->scan_area.width = scanner->driver_data.scan_region_supported[2]; + options->scan_area.height = scanner->driver_data.scan_region_supported[3]; + options->scan_area.x_offset = scanner->driver_data.scan_region_supported[0]; + options->scan_area.y_offset = scanner->driver_data.scan_region_supported[1]; + } + + // Image adjustments + options->adjustments.brightness = scanner->driver_data.adjustments.brightness; + options->adjustments.contrast = scanner->driver_data.adjustments.contrast; + options->adjustments.gamma = scanner->driver_data.adjustments.gamma; + options->adjustments.threshold = scanner->driver_data.adjustments.threshold; + options->adjustments.saturation = scanner->driver_data.adjustments.saturation; + options->adjustments.sharpness = scanner->driver_data.adjustments.sharpness; + + // Processing options - Set based on capability + options->blank_page_removal = false; + options->compression_factor = 0; + options->noise_removal = false; + options->sharpening = false; + + // Number of pages - Based on input source + options->num_pages = (options->input_source == PAPPL_ADF) ? 0 : 1; + + // Log all options + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "document-format='%s'", options->document_format); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "color-mode=%d", options->color_mode); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "resolution=%ddpi", options->resolution); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "input-source=%d", options->input_source); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "duplex=%s", options->duplex ? "true" : "false"); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "intent='%s'", options->intent); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "scan-area=[%d,%d,%d,%d]", + options->scan_area.x_offset, options->scan_area.y_offset, + options->scan_area.width, options->scan_area.height); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "adjustments.brightness=%d", options->adjustments.brightness); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "adjustments.contrast=%d", options->adjustments.contrast); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "adjustments.gamma=%d", options->adjustments.gamma); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "adjustments.threshold=%d", options->adjustments.threshold); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "adjustments.saturation=%d", options->adjustments.saturation); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "adjustments.sharpness=%d", options->adjustments.sharpness); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "blank-page-removal=%s", options->blank_page_removal ? "true" : "false"); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "compression-factor=%d", options->compression_factor); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "noise-removal=%s", options->noise_removal ? "true" : "false"); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "sharpening=%s", options->sharpening ? "true" : "false"); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "num-pages=%u", options->num_pages); + + _papplRWUnlock(scanner); + + return (options); +} + +// +// 'papplScanJobCreate()' - Create a new/existing scan job object. +// + +pappl_job_t * // O - Job +papplScanJobCreate( + pappl_scanner_t *scanner, // I - Scanner + int job_id, // I - Job ID or `0` for new job + const char *username, // I - Username + const char *format, // I - Document format + const char *job_name) // I - Job name +{ + pappl_job_t *job; // Job + char job_uri[1024]; // job-uri value + char job_uuid[64]; // job-uuid value + + if (!scanner || !username || !job_name) + return (NULL); + + // Check if scanner is accepting jobs + _papplRWLockWrite(scanner); + + if (!scanner->is_accepting) + { + _papplRWUnlock(scanner); + return (NULL); + } + + // Allocate and initialize the job object + if ((job = calloc(1, sizeof(pappl_job_t))) == NULL) + { + papplLog(scanner->system, PAPPL_LOGLEVEL_ERROR, "Unable to allocate memory for job: %s", strerror(errno)); + _papplRWUnlock(scanner); + return (NULL); + } + + pthread_rwlock_init(&job->rwlock, NULL); + + // Initialize basic job properties + job->system = scanner->system; + job->format = format ? format : scanner->driver_data.default_document_format; + job->name = job_name; + job->username = username; + job->state = ESCL_SSTATE_IDLE; + job->created = time(NULL); + job->fd = -1; + + // Set job ID + job->job_id = job_id > 0 ? job_id : scanner->next_job_id++; + + // Create HTTPS URI for eSCL + httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), + "https", NULL, scanner->system->hostname, scanner->system->port, + "%s/ScanJobs/%d", scanner->resource, job->job_id); + + // Create job UUID + _papplSystemMakeUUID(scanner->system, scanner->name, job->job_id, job_uuid, + sizeof(job_uuid)); + + // Set job times + job->processing = 0; + job->completed = 0; + + + // Add event and update system configuration + papplSystemAddEvent(scanner->system, NULL, job, PAPPL_EVENT_JOB_CREATED, NULL); + _papplSystemConfigChanged(scanner->system); + + _papplRWUnlock(scanner); + + papplLogJob(job, PAPPL_LOGLEVEL_INFO, "Created scan job %d.", job->job_id); + + return (job); +} + +static bool // O - `true` on success, `false` otherwise +start_job(pappl_job_t *job) // I - Job +{ + bool ret = false; // Return value + pappl_scanner_t *scanner = job->scanner; + // Scanner + bool first_open = true; // Is this the first time we try to open the device? + + // Move the job to the 'processing' state... + _papplRWLockWrite(scanner); + _papplRWLockWrite(job); + + papplLogJob(job, PAPPL_LOGLEVEL_INFO, "Starting scan job."); + + job->state = IPP_JSTATE_PROCESSING; + job->processing = time(NULL); + scanner->processing_job = job; + + // First event call is correct + _papplSystemAddEventNoLock(scanner->system, NULL, scanner, job, PAPPL_EVENT_JOB_STATE_CHANGED, NULL); + + _papplRWUnlock(job); + + // Open the output device... + if (scanner->device_in_use) + { + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "Waiting for device to become available."); + + while (scanner->device_in_use && !scanner->is_deleted && !job->is_canceled && papplSystemIsRunning(scanner->system)) + { + _papplRWUnlock(scanner); + sleep(1); + _papplRWLockWrite(scanner); + } + } + + while (!scanner->device && !scanner->is_deleted && !job->is_canceled && papplSystemIsRunning(scanner->system)) + { + papplLogScanner(scanner, PAPPL_LOGLEVEL_DEBUG, "Opening device for job %d.", job->job_id); + + scanner->device = papplDeviceOpen(scanner->device_uri, job->name, papplLogDevice, job->system); + + if (!scanner->device && !scanner->is_deleted && !job->is_canceled) + { + // Log that the printer is unavailable then sleep for 5 seconds to retry. + if (first_open) + { + papplLogScanner(scanner, PAPPL_LOGLEVEL_ERROR, "Unable to open device '%s', pausing until scanner becomes available.", scanner->device_uri); + first_open = false; + + scanner->state = ESCL_SSTATE_STOPPED; + scanner->state_time = time(NULL); + } + else + { + papplLogScanner(scanner, PAPPL_LOGLEVEL_DEBUG, "Still unable to open device."); + } + + _papplRWUnlock(scanner); + sleep(5); + _papplRWLockWrite(scanner); + } + } + + if (!papplSystemIsRunning(scanner->system)) + { + job->state = IPP_JSTATE_PENDING; + + _papplRWLockRead(job); + // Corrected event call: pass `job` as the fourth argument and event as the fifth + _papplSystemAddEventNoLock(job->system, NULL, job->scanner, job, PAPPL_EVENT_JOB_STATE_CHANGED, NULL); + _papplRWUnlock(job); + + if (scanner->device) + { + papplDeviceClose(scanner->device); + scanner->device = NULL; + } + } + + if (scanner->device) + { + // Move the scanner to the 'processing' state... + scanner->state = ESCL_SSTATE_PROCESSING; + scanner->state_time = time(NULL); + ret = true; + } + + _papplSystemAddEventNoLock(scanner->system, NULL, scanner, NULL, PAPPL_EVENT_SCANNER_STATE_CHANGED, NULL); + + _papplRWUnlock(scanner); + + return (ret); +} + +static void +finish_job(pappl_job_t *job) // I - Job +{ + pappl_scanner_t *scanner = job->scanner; + // Scanner + static const char *const job_states[] = + { + "Pending", + "Held", + "Processing", + "Canceled", + "Aborted", + "Completed"}; + + _papplRWLockWrite(scanner); + _papplRWLockWrite(job); + + if (job->is_canceled) + job->state = IPP_JSTATE_CANCELED; + else if (job->state == IPP_JSTATE_PROCESSING) + job->state = IPP_JSTATE_COMPLETED; + + // Ensure job->state is within the bounds of job_states array + if ((job->state - IPP_JSTATE_PENDING) >= 0 && + (job->state - IPP_JSTATE_PENDING) < (sizeof(job_states) / sizeof(job_states[0]))) + { + papplLogJob(job, PAPPL_LOGLEVEL_INFO, "%s, job-impressions-completed=%d.", + job_states[job->state - IPP_JSTATE_PENDING], + job->impcompleted); + } + else + { + papplLogJob(job, PAPPL_LOGLEVEL_WARN, "Unknown job state: %d, job-impressions-completed=%d.", + job->state, job->impcompleted); + } + + if (job->state >= IPP_JSTATE_CANCELED) + job->completed = time(NULL); + + _papplJobSetRetain(job); + + scanner->processing_job = NULL; + + + // Corrected Call: Ensure fifth argument is the event, and sixth is the message + _papplSystemAddEventNoLock(scanner->system, NULL, scanner, job, PAPPL_EVENT_JOB_COMPLETED, NULL); + + if (scanner->is_stopped) + { + // New scanner-state is 'stopped'... + scanner->state = ESCL_SSTATE_STOPPED; + scanner->is_stopped = false; + } + else + { + // New scanner-state is 'idle'... + scanner->state = ESCL_SSTATE_IDLE; + } + + scanner->state_time = time(NULL); + + if (!job->system->clean_time) + job->system->clean_time = time(NULL) + 60; + + _papplRWUnlock(job); + + // Corrected Call: Ensure fifth argument is the event, and sixth is the message + _papplSystemAddEventNoLock(scanner->system, NULL, scanner, NULL, PAPPL_EVENT_SCANNER_STATE_CHANGED, NULL); + // ^ Changed event type to PAPPL_EVENT_SCANNER_STATE_CHANGED + + _papplRWUnlock(scanner); + + _papplSystemConfigChanged(scanner->system); + + if (papplScannerIsDeleted(scanner)) + { + papplScannerDelete(scanner); + return; + } + else if (!strncmp(scanner->device_uri, "file:", 5)) + { + pappl_devmetrics_t metrics; // Metrics for device IO + + _papplRWLockWrite(scanner); + + papplDeviceGetMetrics(scanner->device, &metrics); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "Device read metrics: %lu requests, %lu bytes, %lu msecs", + (unsigned long)metrics.read_requests, + (unsigned long)metrics.read_bytes, + (unsigned long)metrics.read_msecs); + papplLogJob(job, PAPPL_LOGLEVEL_DEBUG, "Device write metrics: %lu requests, %lu bytes, %lu msecs", + (unsigned long)metrics.write_requests, + (unsigned long)metrics.write_bytes, + (unsigned long)metrics.write_msecs); + + papplLogScanner(scanner, PAPPL_LOGLEVEL_DEBUG, "Closing device for job %d.", job->job_id); + + papplDeviceClose(scanner->device); + scanner->device = NULL; + + _papplRWUnlock(scanner); + } +} + +// +// '_papplScanJobProcess()' - Process a scan job. +// + +void * // O - Thread exit status +_papplScanJobProcess(pappl_job_t *job) // I - Job +{ + + // Start processing the job... + start_job(job); + + // Move the job to a completed state... + finish_job(job); + + return (NULL); +} \ No newline at end of file diff --git a/pappl/job.h b/pappl/job.h index a5bd5925..557aecd3 100644 --- a/pappl/job.h +++ b/pappl/job.h @@ -59,9 +59,11 @@ typedef unsigned int pappl_jreason_t; // Bitfield for IPP "job-state-reasons" va extern void papplJobCancel(pappl_job_t *job) _PAPPL_PUBLIC; extern pappl_pr_options_t *papplJobCreatePrintOptions(pappl_job_t *job, unsigned num_pages, bool color) _PAPPL_PUBLIC; +extern pappl_sc_options_t *papplJobCreateScanOptions(pappl_job_t *job) _PAPPL_PUBLIC; extern pappl_job_t *papplJobCreateWithFile(pappl_printer_t *printer, const char *username, const char *format, const char *job_name, int num_options, cups_option_t *options, const char *filename); extern void papplJobDeletePrintOptions(pappl_pr_options_t *options); +extern void papplJobDeleteScanOptions(pappl_sc_options_t *options); extern bool papplJobFilterImage(pappl_job_t *job, pappl_device_t *device, pappl_pr_options_t *options, const unsigned char *pixels, int width, int height, int depth, int ppi, bool smoothing) _PAPPL_PUBLIC; @@ -77,6 +79,7 @@ extern int papplJobGetImpressionsCompleted(pappl_job_t *job) _PAPPL_PUBLIC; extern const char *papplJobGetMessage(pappl_job_t *job) _PAPPL_PUBLIC; extern const char *papplJobGetName(pappl_job_t *job) _PAPPL_PUBLIC; extern pappl_printer_t *papplJobGetPrinter(pappl_job_t *job) _PAPPL_PUBLIC; +extern pappl_scanner_t *papplJobGetScanner(pappl_job_t *job) _PAPPL_PUBLIC; extern pappl_jreason_t papplJobGetReasons(pappl_job_t *job) _PAPPL_PUBLIC; extern ipp_jstate_t papplJobGetState(pappl_job_t *job) _PAPPL_PUBLIC; extern time_t papplJobGetTimeCompleted(pappl_job_t *job) _PAPPL_PUBLIC; From 128769a4877cdbdeb18e6e4f48f4eaa55cd801fa Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Sun, 3 Nov 2024 16:05:22 +0000 Subject: [PATCH 22/26] Add system related scanner function Signed-off-by: Akarshan Kapoor --- pappl/scanner.h | 16 +-------- pappl/system-accessors.c | 77 ++++++++++++++++++++++++++++++++++++++++ pappl/system.h | 14 ++++++++ 3 files changed, 92 insertions(+), 15 deletions(-) diff --git a/pappl/scanner.h b/pappl/scanner.h index dab80b9f..8f0577c3 100644 --- a/pappl/scanner.h +++ b/pappl/scanner.h @@ -10,6 +10,7 @@ #ifndef _PAPPL_SCANNER_H_ # define _PAPPL_SCANNER_H_ # include "base.h" +#include "system.h" # ifdef __cplusplus extern "C" { # endif // __cplusplus @@ -68,21 +69,6 @@ typedef enum { typedef unsigned pappl_identify_sc_actions_t; // eSCL actions for identifying the scanner -// -// Callback functions... -// -typedef pappl_sc_driver_data_t (*pappl_sc_capabilities_cb_t)(pappl_scanner_t *scanner); // Callback for getting scanner capabilities -typedef void (*pappl_sc_identify_cb_t)(pappl_scanner_t *scanner, pappl_identify_sc_actions_t actions, const char *message); // Callback for identifying the scanner -typedef void (*pappl_sc_delete_cb_t)(pappl_scanner_t *scanner, pappl_sc_driver_data_t *data); -typedef void (*pappl_sc_job_create_cb_t)(pappl_job_t *job, pappl_sc_options_t *options, pappl_device_t *device); // Callback for creating a scan job -typedef void (*pappl_sc_job_delete_cb_t)(pappl_job_t *job); // Callback for deleting a scan job -typedef bool (*pappl_sc_data_cb_t)(pappl_job_t *job, pappl_device_t *device, void *buffer, size_t bufsize); // Callback for getting scan data -typedef bool (*pappl_sc_status_cb_t)(pappl_scanner_t *scanner); // Callback for getting scanner status -typedef void (*pappl_sc_job_complete_cb_t)(pappl_job_t *job); // Callback for completing a scan job -typedef bool (*pappl_sc_job_cancel_cb_t)(pappl_job_t *job); // Callback for cancelling a scan job -typedef void (*pappl_sc_buffer_info_cb_t)(pappl_job_t *job, pappl_sc_options_t *options, pappl_device_t *device); // Callback for getting buffer information -typedef void (*pappl_sc_image_info_cb_t)(pappl_job_t *job, pappl_device_t *device, void *data); // Callback for getting scan image information - // // Structures // diff --git a/pappl/system-accessors.c b/pappl/system-accessors.c index 65b5b1e1..00c08cd3 100644 --- a/pappl/system-accessors.c +++ b/pappl/system-accessors.c @@ -2316,6 +2316,33 @@ papplSystemSetNextPrinterID( } } +// +// 'papplSystemSetNextScannerID()' - Set the next "scanner-id" value. +// +// This function sets the unique positive integer identifier that will be used +// for the next scanner that is created. It is typically only called as part +// of restoring the state of a system. +// +// > Note: The next scanner ID can only be set prior to calling +// > @link papplSystemRun@. +// + +void +papplSystemSetNextScannerID( + pappl_system_t *system, // I - System + int next_scanner_id) // I - Next "scanner-id" value +{ + if (system && !system->is_running) + { + _papplRWLockWrite(system); + + system->next_scanner_id = next_scanner_id; + + _papplSystemConfigChanged(system); + + _papplRWUnlock(system); + } +} // // 'papplSystemSetOperationCallback()' - Set the IPP operation callback. @@ -2472,6 +2499,56 @@ papplSystemSetPrinterDrivers( } } +// +// 'papplSystemSetScannerDrivers()' - Set the list of drivers and the driver +// callbacks for scanners. +// + +void +papplSystemSetScannerDrivers( + pappl_system_t *system, // I - System + int num_drivers, // I - Number of drivers + pappl_sc_driver_t *drivers, // I - Scanner drivers + pappl_sc_identify_cb_t identify_cb, // I - Identify scanner callback or `NULL` if none + pappl_sc_create_cb_t create_cb, // I - Scanner creation callback or `NULL` if none + pappl_sc_driver_cb_t driver_cb, // I - Driver initialization callback + pappl_sc_delete_cb_t sc_delete_cb, // I - Scanner delete callback or `NULL` if none + pappl_sc_capabilities_cb_t capabilities_cb, // I - Scanner capabilities callback + pappl_sc_job_create_cb_t job_create_cb, // I - Job creation callback + pappl_sc_job_delete_cb_t job_delete_cb, // I - Job delete callback + pappl_sc_data_cb_t data_cb, // I - Data processing callback + pappl_sc_status_cb_t status_cb, // I - Status callback + pappl_sc_job_complete_cb_t job_complete_cb, // I - Job completion callback + pappl_sc_job_cancel_cb_t job_cancel_cb, // I - Job cancel callback + pappl_sc_buffer_info_cb_t buffer_info_cb, // I - Buffer information callback + pappl_sc_image_info_cb_t image_info_cb, // I - Image information callback + void *data) // I - Callback data +{ + if (system) + { + _papplRWLockWrite(system); + + // Set the system's scanner-related fields + system->num_sc_drivers = (cups_len_t)num_drivers; + system->sc_drivers = drivers; + system->sc_identify_cb = identify_cb; + system->sc_create_cb = create_cb; + system->sc_driver_cb = driver_cb; + system->sc_delete_cb = sc_delete_cb; + system->sc_capabilities_cb = capabilities_cb; + system->sc_job_create_cb = job_create_cb; + system->sc_job_delete_cb = job_delete_cb; + system->sc_data_cb = data_cb; + system->sc_status_cb = status_cb; + system->sc_job_complete_cb = job_complete_cb; + system->sc_job_cancel_cb = job_cancel_cb; + system->sc_buffer_info_cb = buffer_info_cb; + system->sc_image_info_cb = image_info_cb; + system->sc_cbdata = data; + + _papplRWUnlock(system); + } +} // // 'papplSystemSetSaveCallback()' - Set the save callback. diff --git a/pappl/system.h b/pappl/system.h index 5d058086..62b69fca 100644 --- a/pappl/system.h +++ b/pappl/system.h @@ -150,6 +150,18 @@ typedef int (*pappl_wifi_list_cb_t)(pappl_system_t *system, void *data, cups_des typedef pappl_wifi_t *(*pappl_wifi_status_cb_t)(pappl_system_t *system, void *data, pappl_wifi_t *wifi_data); // Wi-Fi status callback +typedef unsigned pappl_identify_sc_actions_t; // eSCL actions for identifying the scanner +typedef pappl_sc_driver_data_t (*pappl_sc_capabilities_cb_t)(pappl_scanner_t *scanner); // Callback for getting scanner capabilities +typedef void (*pappl_sc_identify_cb_t)(pappl_scanner_t *scanner, pappl_identify_sc_actions_t actions, const char *message); // Callback for identifying the scanner +typedef void (*pappl_sc_delete_cb_t)(pappl_scanner_t *scanner, pappl_sc_driver_data_t *data); +typedef void (*pappl_sc_job_create_cb_t)(pappl_job_t *job, pappl_sc_options_t *options, pappl_device_t *device); // Callback for creating a scan job +typedef void (*pappl_sc_job_delete_cb_t)(pappl_job_t *job); // Callback for deleting a scan job +typedef bool (*pappl_sc_data_cb_t)(pappl_job_t *job, pappl_device_t *device, void *buffer, size_t bufsize); // Callback for getting scan data +typedef bool (*pappl_sc_status_cb_t)(pappl_scanner_t *scanner); // Callback for getting scanner status +typedef void (*pappl_sc_job_complete_cb_t)(pappl_job_t *job); // Callback for completing a scan job +typedef bool (*pappl_sc_job_cancel_cb_t)(pappl_job_t *job); // Callback for cancelling a scan job +typedef void (*pappl_sc_buffer_info_cb_t)(pappl_job_t *job, pappl_sc_options_t *options, pappl_device_t *device); // Callback for getting buffer information +typedef void (*pappl_sc_image_info_cb_t)(pappl_job_t *job, pappl_device_t *device, void *data); // Callback for getting scan image information // // Functions... @@ -240,11 +252,13 @@ extern void papplSystemSetMaxSubscriptions(pappl_system_t *system, size_t max_s extern void papplSystemSetMIMECallback(pappl_system_t *system, pappl_mime_cb_t cb, void *data) _PAPPL_PUBLIC; extern void papplSystemSetNetworkCallbacks(pappl_system_t *system, pappl_network_get_cb_t get_cb, pappl_network_set_cb_t set_cb, void *cb_data) _PAPPL_PUBLIC; extern void papplSystemSetNextPrinterID(pappl_system_t *system, int next_printer_id) _PAPPL_PUBLIC; +extern void papplSystemSetNextScannerID(pappl_system_t *system, int next_scanner_id) _PAPPL_PUBLIC; extern void papplSystemSetOperationCallback(pappl_system_t *system, pappl_ipp_op_cb_t cb, void *data) _PAPPL_PUBLIC; extern void papplSystemSetOrganization(pappl_system_t *system, const char *value) _PAPPL_PUBLIC; extern void papplSystemSetOrganizationalUnit(pappl_system_t *system, const char *value) _PAPPL_PUBLIC; extern void papplSystemSetPassword(pappl_system_t *system, const char *hash) _PAPPL_PUBLIC; extern void papplSystemSetPrinterDrivers(pappl_system_t *system, int num_drivers, pappl_pr_driver_t *drivers, pappl_pr_autoadd_cb_t autoadd_cb, pappl_pr_create_cb_t create_cb, pappl_pr_driver_cb_t driver_cb, void *data) _PAPPL_PUBLIC; +extern void papplSystemSetScannerDrivers(pappl_system_t *system, int num_drivers, pappl_sc_driver_t *drivers, pappl_sc_identify_cb_t identify_cb, pappl_sc_create_cb_t create_cb, pappl_sc_driver_cb_t driver_cb, pappl_sc_delete_cb_t sc_delete_cb, pappl_sc_capabilities_cb_t capabilities_cb, pappl_sc_job_create_cb_t job_create_cb, pappl_sc_job_delete_cb_t job_delete_cb, pappl_sc_data_cb_t data_cb, pappl_sc_status_cb_t status_cb, pappl_sc_job_complete_cb_t job_complete_cb, pappl_sc_job_cancel_cb_t job_cancel_cb, pappl_sc_buffer_info_cb_t buffer_info_cb, pappl_sc_image_info_cb_t image_info_cb, void *data) _PAPPL_PUBLIC; extern void papplSystemSetSaveCallback(pappl_system_t *system, pappl_save_cb_t cb, void *data) _PAPPL_PUBLIC; extern void papplSystemSetUUID(pappl_system_t *system, const char *value) _PAPPL_PUBLIC; extern void papplSystemSetVersions(pappl_system_t *system, int num_versions, pappl_version_t *versions) _PAPPL_PUBLIC; From a34e61220c0315d800df049c03da937e0837ea03 Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Sun, 3 Nov 2024 17:43:37 +0000 Subject: [PATCH 23/26] Addition of mainloop functions for Scan API Signed-off-by: Akarshan Kapoor --- pappl/mainloop-private.h | 10 ++++ pappl/mainloop-subcommands.c | 89 ++++++++++++++++++++++++++++++++++++ pappl/scanner.h | 2 +- pappl/system-accessors.c | 30 ++++++------ pappl/system-private.h | 15 ++++++ 5 files changed, 129 insertions(+), 17 deletions(-) diff --git a/pappl/mainloop-private.h b/pappl/mainloop-private.h index 414b7933..28c1c74a 100644 --- a/pappl/mainloop-private.h +++ b/pappl/mainloop-private.h @@ -28,28 +28,38 @@ extern char *_papplMainloopPath _PAPPL_PRIVATE; // extern int _papplMainloopAddPrinter(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; +extern int _papplMainloopAddScanner(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopAutoAddPrinters(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopCancelJob(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopDeletePrinter(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; +extern int _papplMainloopDeleteScanner(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopGetSetDefaultPrinter(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; +extern int _papplMainloopGetSetDefaultScanner(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopModifyPrinter(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopPausePrinter(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopResumePrinter(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; + +// TODO : Introduce functionality for scanner callbacks and scanner drivers. extern int _papplMainloopRunServer(const char *base_name, const char *version, const char *footer_html, cups_len_t num_drivers, pappl_pr_driver_t *drivers, pappl_pr_autoadd_cb_t autoadd_cb, pappl_pr_driver_cb_t driver_cb, cups_len_t num_options, cups_option_t **options, pappl_ml_system_cb_t system_cb, void *data) _PAPPL_PRIVATE; extern int _papplMainloopShowDevices(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; + +// TODO : Introduce functionality for scanner callbacks and scanner drivers. extern int _papplMainloopShowDrivers(const char *base_name, cups_len_t num_drivers, pappl_pr_driver_t *drivers, pappl_pr_autoadd_cb_t autoadd_cb, pappl_pr_driver_cb_t driver_cb, cups_len_t num_options, cups_option_t *options, pappl_ml_system_cb_t system_cb, void *data) _PAPPL_PRIVATE; extern int _papplMainloopShowJobs(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopShowOptions(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopShowPrinters(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; +extern int _papplMainloopShowScanners(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopShowStatus(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopShutdownServer(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopSubmitJob(const char *base_name, cups_len_t num_options, cups_option_t *options, cups_len_t num_files, char **files) _PAPPL_PRIVATE; extern void _papplMainloopAddOptions(ipp_t *request, cups_len_t num_options, cups_option_t *options, ipp_t *supported) _PAPPL_PRIVATE; extern void _papplMainloopAddPrinterURI(ipp_t *request, const char *printer_name, char *resource,size_t rsize) _PAPPL_PRIVATE; +extern void _papplMainloopAddScannerURI(ipp_t *request, const char *scanner_name, char *resource, size_t rsize) _PAPPL_PRIVATE; // Request type ipp ? extern http_t *_papplMainloopConnect(const char *base_name, bool auto_start) _PAPPL_PRIVATE; extern http_t *_papplMainloopConnectURI(const char *base_name, const char *printer_uri, char *resource, size_t rsize) _PAPPL_PRIVATE; extern char *_papplMainloopGetDefaultPrinter(http_t *http, char *buffer, size_t bufsize) _PAPPL_PRIVATE; +extern char *_papplMainloopGetDefaultScanner(http_t *http, char *buffer, size_t bufsize) _PAPPL_PRIVATE; extern char *_papplMainloopGetServerPath(const char *base_name, uid_t uid, char *buffer, size_t bufsize) _PAPPL_PRIVATE; extern int _papplMainloopGetServerPort(const char *base_name) _PAPPL_PRIVATE; diff --git a/pappl/mainloop-subcommands.c b/pappl/mainloop-subcommands.c index 62f8c874..39e9b5e8 100644 --- a/pappl/mainloop-subcommands.c +++ b/pappl/mainloop-subcommands.c @@ -111,6 +111,95 @@ _papplMainloopAddPrinter( } + +// +// '_papplMainloopAddScanner()' - Add a scanner using eSCL. +// +int +_papplMainloopAddScanner( + const char *base_name, // I - Base name + cups_len_t num_options, // I - Number of options + cups_option_t *options) // I - Options +{ + http_t *http = NULL; // Connection to server + const char *device_uri, // Device URI + *scanner_name, // Name of scanner + *scanner_uri, // Scanner URI + *escl_path; // eSCL resource path + char resource[1024]; // Resource path for connection + bool status = false; // Status of scanner addition + + // Get required values... + device_uri = cupsGetOption("device-uri", (int)num_options, options); + scanner_name = cupsGetOption("scanner-name", (int)num_options, options); + escl_path = cupsGetOption("escl", (int)num_options, options); + + // Rest of the implementation remains the same... + if (!device_uri || !scanner_name) + { + if (!scanner_name) + _papplLocPrintf(stderr, _PAPPL_LOC("%s: Missing '-d SCANNER'."), base_name); + if (!device_uri) + _papplLocPrintf(stderr, _PAPPL_LOC("%s: Missing '-v DEVICE-URI'."), base_name); + return (1); + } + + if ((scanner_uri = cupsGetOption("scanner-uri", (int)num_options, options)) != NULL) + { + if ((http = _papplMainloopConnectURI(base_name, scanner_uri, resource, + sizeof(resource))) == NULL) + return (1); + } + + // Set up eSCL connection and registration + if (!escl_path) + escl_path = "/eSCL/"; // Default eSCL path if not specified + + // Create scanner registration request + char *post_data = NULL; + size_t post_size = 0; + FILE *post_file = open_memstream(&post_data, &post_size); + + if (post_file) + { + // Format eSCL scanner registration XML + fprintf(post_file, "\n"); + fprintf(post_file, "\n"); + fprintf(post_file, " %s\n", scanner_name); + fprintf(post_file, " %s\n", device_uri); + fprintf(post_file, "\n"); + fclose(post_file); + + // Set up HTTP POST request + httpClearFields(http); + httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/xml"); + httpSetLength(http, post_size); + + // Send the registration request + if (httpPost(http, escl_path) == HTTP_STATUS_OK) + { + http_status_t response = httpUpdate(http); + if (response == HTTP_STATUS_OK || response == HTTP_STATUS_CREATED) + status = true; + } + + free(post_data); + } + + httpClose(http); + + if (!status) + { + _papplLocPrintf(stderr, _PAPPL_LOC("%s: Unable to add scanner: %s"), + base_name, cupsGetErrorString()); + return (1); + } + + return (0); +} + + + // // '_papplMainloopAutoAddPrinters()' - Automatically add printers. // diff --git a/pappl/scanner.h b/pappl/scanner.h index 8f0577c3..b39c99cb 100644 --- a/pappl/scanner.h +++ b/pappl/scanner.h @@ -125,7 +125,7 @@ typedef struct pappl_sc_driver_data_s // Initially polling the scanner driver f pappl_identify_sc_actions_t identify_default; // "identify-actions-default" values pappl_identify_sc_actions_t identify_supported; // "identify-actions-supported" values - pappl_icon_sc_t icons[3]; // "printer-icons" values + pappl_icon_sc_t icons[3]; // "scanner-icons" values char make_and_model[128]; // Make and model of the scanner const char *document_formats_supported[PAPPL_MAX_FORMATS]; // Supported document formats (JPEG, PDF, TIFF, PNG, BMP) diff --git a/pappl/system-accessors.c b/pappl/system-accessors.c index 00c08cd3..2821169b 100644 --- a/pappl/system-accessors.c +++ b/pappl/system-accessors.c @@ -2529,22 +2529,20 @@ papplSystemSetScannerDrivers( _papplRWLockWrite(system); // Set the system's scanner-related fields - system->num_sc_drivers = (cups_len_t)num_drivers; - system->sc_drivers = drivers; - system->sc_identify_cb = identify_cb; - system->sc_create_cb = create_cb; - system->sc_driver_cb = driver_cb; - system->sc_delete_cb = sc_delete_cb; - system->sc_capabilities_cb = capabilities_cb; - system->sc_job_create_cb = job_create_cb; - system->sc_job_delete_cb = job_delete_cb; - system->sc_data_cb = data_cb; - system->sc_status_cb = status_cb; - system->sc_job_complete_cb = job_complete_cb; - system->sc_job_cancel_cb = job_cancel_cb; - system->sc_buffer_info_cb = buffer_info_cb; - system->sc_image_info_cb = image_info_cb; - system->sc_cbdata = data; + system->num_scanner_drivers = (cups_len_t)num_drivers; + system->scanner_drivers = drivers; + system->identify_cb = identify_cb; + system->sc_delete_cb = sc_delete_cb; + system->capabilities_cb = capabilities_cb; + system->job_create_cb = job_create_cb; + system->job_delete_cb = job_delete_cb; + system->data_cb = data_cb; + system->status_cb = status_cb; + system->job_complete_cb = job_complete_cb; + system->job_cancel_cb = job_cancel_cb; + system->buffer_info_cb = buffer_info_cb; + system->image_info_cb = image_info_cb; + system->sc_driver_cbdata = data; _papplRWUnlock(system); } diff --git a/pappl/system-private.h b/pappl/system-private.h index 61de2a15..17df61cb 100644 --- a/pappl/system-private.h +++ b/pappl/system-private.h @@ -112,6 +112,21 @@ struct _pappl_system_s // System data pappl_pr_driver_t *drivers; // Printer drivers pappl_sc_driver_t *scanner_drivers; // Scanner drivers + + cups_len_t num_scanner_drivers; // Number of scanner drivers + pappl_sc_identify_cb_t identify_cb; // Callback for identifying the scanner + pappl_sc_delete_cb_t sc_delete_cb; // Scanner deletion callback + pappl_sc_capabilities_cb_t capabilities_cb; // Callback for getting scanner capabilities + pappl_sc_job_create_cb_t job_create_cb; // Callback for creating a scan job + pappl_sc_job_delete_cb_t job_delete_cb; // Callback for deleting a scan job + pappl_sc_data_cb_t data_cb; // Callback for getting scan data + pappl_sc_status_cb_t status_cb; // Callback for getting scanner status + pappl_sc_job_complete_cb_t job_complete_cb; // Callback for completing a scan job + pappl_sc_job_cancel_cb_t job_cancel_cb; // Callback for cancelling a scan job + pappl_sc_buffer_info_cb_t buffer_info_cb; // Callback for getting buffer information + pappl_sc_image_info_cb_t image_info_cb; // Callback for getting image information + pappl_identify_sc_actions_t identify_default; // "identify-actions-default" values + pappl_identify_sc_actions_t identify_supported; // "identify-actions-supported" values pappl_sc_autoadd_cb_t autoadd_sc_cb; // Scanner driver auto-add callback pappl_sc_create_cb_t create_sc_cb; // Scanner driver creation callback pappl_sc_driver_cb_t driver_sc_cb; // Scanner driver initialization callback From 980c31277bb4a3aa5d9e0564d60c89bd95a0a4ea Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Sun, 3 Nov 2024 20:30:56 +0000 Subject: [PATCH 24/26] Add mainloop support, implementing basic scan API Signed-off-by: Akarshan Kapoor --- pappl/mainloop-private.h | 5 +- pappl/mainloop-subcommands.c | 101 +++++++++++++++++++++++++++++++++++ pappl/mainloop-support.c | 57 ++++++++++++++++++++ 3 files changed, 159 insertions(+), 4 deletions(-) diff --git a/pappl/mainloop-private.h b/pappl/mainloop-private.h index 28c1c74a..5f9d3263 100644 --- a/pappl/mainloop-private.h +++ b/pappl/mainloop-private.h @@ -34,7 +34,6 @@ extern int _papplMainloopCancelJob(const char *base_name, cups_len_t num_options extern int _papplMainloopDeletePrinter(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopDeleteScanner(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopGetSetDefaultPrinter(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; -extern int _papplMainloopGetSetDefaultScanner(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopModifyPrinter(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopPausePrinter(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopResumePrinter(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; @@ -48,18 +47,16 @@ extern int _papplMainloopShowDrivers(const char *base_name, cups_len_t num_drive extern int _papplMainloopShowJobs(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopShowOptions(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopShowPrinters(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; -extern int _papplMainloopShowScanners(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopShowStatus(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopShutdownServer(const char *base_name, cups_len_t num_options, cups_option_t *options) _PAPPL_PRIVATE; extern int _papplMainloopSubmitJob(const char *base_name, cups_len_t num_options, cups_option_t *options, cups_len_t num_files, char **files) _PAPPL_PRIVATE; extern void _papplMainloopAddOptions(ipp_t *request, cups_len_t num_options, cups_option_t *options, ipp_t *supported) _PAPPL_PRIVATE; extern void _papplMainloopAddPrinterURI(ipp_t *request, const char *printer_name, char *resource,size_t rsize) _PAPPL_PRIVATE; -extern void _papplMainloopAddScannerURI(ipp_t *request, const char *scanner_name, char *resource, size_t rsize) _PAPPL_PRIVATE; // Request type ipp ? +extern int _papplMainloopAddScannerURI(http_t *request, const char *scanner_name, char *resource, size_t rsize) _PAPPL_PRIVATE; // Request type ipp ? extern http_t *_papplMainloopConnect(const char *base_name, bool auto_start) _PAPPL_PRIVATE; extern http_t *_papplMainloopConnectURI(const char *base_name, const char *printer_uri, char *resource, size_t rsize) _PAPPL_PRIVATE; extern char *_papplMainloopGetDefaultPrinter(http_t *http, char *buffer, size_t bufsize) _PAPPL_PRIVATE; -extern char *_papplMainloopGetDefaultScanner(http_t *http, char *buffer, size_t bufsize) _PAPPL_PRIVATE; extern char *_papplMainloopGetServerPath(const char *base_name, uid_t uid, char *buffer, size_t bufsize) _PAPPL_PRIVATE; extern int _papplMainloopGetServerPort(const char *base_name) _PAPPL_PRIVATE; diff --git a/pappl/mainloop-subcommands.c b/pappl/mainloop-subcommands.c index 39e9b5e8..9faae3e6 100644 --- a/pappl/mainloop-subcommands.c +++ b/pappl/mainloop-subcommands.c @@ -392,6 +392,107 @@ _papplMainloopDeletePrinter( return (0); } +// +// '_papplMainloopDeleteScanner()' - Delete a scanner registration. +// + +int // O - Exit status +_papplMainloopDeleteScanner( + const char *base_name, // I - Base name + cups_len_t num_options, // I - Number of options + cups_option_t *options) // I - Options +{ + http_t *http = NULL; // Connection to server + const char *device_uri, // Device URI + *scanner_name, // Name of scanner + *scanner_uri, // Scanner URI + *escl_path; // eSCL resource path + char resource[1024]; // Resource path for connection + bool status = false; // Status of scanner deletion + http_status_t response; // HTTP response status + + // Get required values... + device_uri = cupsGetOption("device-uri", (int)num_options, options); + scanner_name = cupsGetOption("scanner-name", (int)num_options, options); + escl_path = cupsGetOption("escl", (int)num_options, options); + + // Check if we're deleting a remote scanner + scanner_uri = cupsGetOption("scanner-uri", (int)num_options, options); + if (scanner_uri) + { + // Connect to the remote scanner... + http = _papplMainloopConnectURI(base_name, scanner_uri, resource, sizeof(resource)); + if (!http) + { + _papplLocPrintf(stderr, _PAPPL_LOC("%s: Unable to connect to remote scanner at '%s'"), + base_name, scanner_uri); + return (1); + } + } + else + { + // Validate required parameters for local scanner + if (!scanner_name) + { + _papplLocPrintf(stderr, _PAPPL_LOC("%s: Missing '-d SCANNER'."), base_name); + return (1); + } + + if (!device_uri) + { + _papplLocPrintf(stderr, _PAPPL_LOC("%s: Missing '-v DEVICE-URI'."), base_name); + return (1); + } + + // Connect to local scanner + http = httpConnect2(device_uri, 0, NULL, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL); + if (!http) + { + _papplLocPrintf(stderr, _PAPPL_LOC("%s: Unable to connect to scanner at '%s'"), + base_name, device_uri); + return (1); + } + } + + // Set up eSCL path + if (!escl_path) + escl_path = "/eSCL/"; // Default eSCL path if not specified + + // Construct the deletion path + char delete_path[1024]; + snprintf(delete_path, sizeof(delete_path), "%sregistration/%s", + escl_path, scanner_name); + + // Send DELETE request to remove scanner registration + httpClearFields(http); + + if (httpDelete(http, delete_path) != HTTP_STATUS_OK) + { + _papplLocPrintf(stderr, _PAPPL_LOC("%s: Unable to send deletion request: %s"), + base_name, cupsGetErrorString()); + httpClose(http); + return (1); + } + + // Check the response + response = httpUpdate(http); + if (response == HTTP_STATUS_OK || response == HTTP_STATUS_NO_CONTENT) + { + status = true; + _papplLocPrintf(stderr, _PAPPL_LOC("%s: Successfully deleted scanner '%s'"), + base_name, scanner_name); + } + else + { + _papplLocPrintf(stderr, _PAPPL_LOC("%s: Scanner deletion failed with status %d"), + base_name, response); + } + + // Clean up + httpClose(http); + + return (status ? 0 : 1); +} // // '_papplMainloopGetSetDefaultPrinter()' - Get/set the default printer. diff --git a/pappl/mainloop-support.c b/pappl/mainloop-support.c index eceaa595..a92c160c 100644 --- a/pappl/mainloop-support.c +++ b/pappl/mainloop-support.c @@ -392,6 +392,63 @@ _papplMainloopAddPrinterURI( } +// '_papplMainloopAddScannerURI()' - Add the scanner-uri attribute and return a +// resource path. +// + +int +_papplMainloopAddScannerURI( + http_t *request, // I - HTTP request + const char *scanner_name, // I - Scanner name + char *resource, // I - Resource path buffer + size_t rsize) // I - Size of buffer +{ + char uri[1024]; // scanner-uri value + char *resptr; // Pointer into resource path + int ret; + + // Construct the initial resource path for the scanner + ret = snprintf(resource, rsize, "/escl/scan/%s", scanner_name); + if (ret < 0 || (size_t)ret >= rsize) { + fprintf(stderr, "Error: Resource path buffer too small.\n"); + return -1; + } + + // Sanitize the resource path by replacing invalid characters with '_' + for (resptr = resource + strlen("/escl/scan/"); *resptr; resptr++) { + if ((*resptr & 255) <= ' ' || strchr("\177/\\\'\"?#", *resptr)) { + *resptr = '_'; + } + } + + // Eliminate duplicate and trailing underscores + resptr = resource + strlen("/escl/scan/"); + while (*resptr) { + if (resptr[0] == '_' && resptr[1] == '_') { + memmove(resptr, resptr + 1, strlen(resptr)); + // Duplicate underscores removed, do not advance resptr + } + else if (resptr[0] == '_' && !resptr[1]) { + *resptr = '\0'; // Trailing underscore removed + break; + } + else { + resptr++; + } + } + + // Assemble the full URI using HTTP + ret = httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "http", NULL, "localhost", 0, resource); + + if (ret < 0) { + fprintf(stderr, "Error: Failed to assemble URI.\n"); + return -1; + } + + httpSetField(request, HTTP_FIELD_CONTENT_TYPE, uri); + return 0; +} + // // '_papplMainloopConnect()' - Connect to the local server. // From a1231d02a45bcf14e5ea744d055f7e955fb121c1 Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Sun, 3 Nov 2024 21:02:15 +0000 Subject: [PATCH 25/26] Add eSCL functions for scan settings and XML parsing Signed-off-by: Akarshan Kapoor --- pappl/Makefile | 1 + pappl/esclops.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 pappl/esclops.c diff --git a/pappl/Makefile b/pappl/Makefile index c1dc1742..123387cc 100644 --- a/pappl/Makefile +++ b/pappl/Makefile @@ -25,6 +25,7 @@ BASEOBJS = \ device-network.o \ device-usb.o \ dnssd.o \ + esclops.o \ httpmon.o \ job-accessors.o \ job-filter.o \ diff --git a/pappl/esclops.c b/pappl/esclops.c new file mode 100644 index 00000000..aa424b47 --- /dev/null +++ b/pappl/esclops.c @@ -0,0 +1,176 @@ +// +// Scan eSCL functions for the Printer Application Framework +// +// Copyright © 2020-2024 by Michael R Sweet. +// +// Licensed under Apache License v2.0. See the file "LICENSE" for more +// information. +// + +// +// Include necessary headers... +// + +#include "pappl-private.h" +#include +#include +#include +#include +#include +// #include "esclops.h" + +// Function to read XML content from a file +char * +readXmlContent( + const char *filePath) // I - Path to the XML file +{ + char *xmlContent = NULL; + long length; + FILE *file = fopen(filePath, "rb"); + if (file) + { + fseek(file, 0, SEEK_END); + length = ftell(file); + fseek(file, 0, SEEK_SET); + xmlContent = (char *)malloc(length + 1); + if (xmlContent) + { + fread(xmlContent, 1, length, file); + xmlContent[length] = '\0'; + } + fclose(file); + } + return xmlContent; +} + +typedef struct ScanSettingsXml +{ + char *xml; + +} ScanSettingsXml; // Structure for XML settings of a scan + +// Function to initialize scan settings with provided XML string +void initScanSettingsXml( + ScanSettingsXml *settings, // I - Pointer to the ScanSettingsXml structure to be initialized + const char *s) // I- XML string used for initialization +{ + settings->xml = (char *)malloc(strlen(s) + 1); + strcpy(settings->xml, s); +} + +// Function to extract string using regular expression from XML settings +char *getString( + const ScanSettingsXml *settings, // I - Pointer to the ScanSettingsXml structure + const char *name, // I - Name of the XML element to be extracted + const char *pattern) // I - Regular expression pattern used for extraction +{ + const int max_matches = 2; + regex_t regex; + regmatch_t matches[max_matches]; + + if (regcomp(®ex, pattern, REG_EXTENDED) != 0) + { + fprintf(stderr, "Could not compile regex\n"); + exit(1); + } + + if (regexec(®ex, settings->xml, max_matches, matches, 0) == 0) + { + size_t match_length = matches[1].rm_eo - matches[1].rm_so; + char *result = (char *)malloc(match_length + 1); + strncpy(result, settings->xml + matches[1].rm_so, match_length); + result[match_length] = '\0'; + + regfree(®ex); + return result; + } + regfree(®ex); + char *empty = (char *)malloc(1); + empty[0] = '\0'; + return empty; +} + +double getNumber( + const ScanSettingsXml *settings, // I - Pointer to the ScanSettingsXml structure + const char *name, // I - Name of the XML element to be extracted + const char *pattern) // I - Regular expression pattern used for extraction +{ + char *string_value = getString(settings, name, pattern); + double result = strtod(string_value, NULL); + free(string_value); + return result; +} + +// Function to check if a client has already initiated air scan +bool ClientAlreadyAirScan( + pappl_client_t *client) // I - Pointer to the pappl_client_t structure +{ + const char *airscan_string = "AirScanScanner"; + size_t airscan_length = strlen(airscan_string); + + const char *user_agent = httpGetField(client->http, HTTP_FIELD_USER_AGENT); + const char *result = strstr(user_agent, airscan_string); + + if (result != NULL) + { + size_t substring_length = strlen(result); + if (substring_length > airscan_length) + { + char next_char = *(result + airscan_length); + if (next_char != ' ' && next_char != '\t' && next_char != '\r' && next_char != '\n') + { + return false; + } + } + return true; + } + return false; +} + +// Function to parse XML string and set up scan settings +void *ScanSettingsFromXML( + const char *xmlString, // I - XML string containing scan settings + pappl_client_t *client) // I - Pointer to the pappl_client_t structure +{ + ScanSettingsXml scanSettings; + initScanSettingsXml(&scanSettings, xmlString); + + char *versionPattern = "([^<]*)"; + char *version = getString(&scanSettings, "Version", versionPattern); + + char *intentPattern = "([^<]*)"; + char *intent = getString(&scanSettings, "Intent", intentPattern); + + char *heightPattern = "([^<]*)"; + char *height = getString(&scanSettings, "Height", heightPattern); + + char *contentRegionUnitsPattern = "([^<]*)"; + char *contentRegionUnits = getString(&scanSettings, "ContentRegionUnits", contentRegionUnitsPattern); + + char *widthPattern = "([^<]*)"; + double width = getNumber(&scanSettings, "Width", widthPattern); + + char *xOffsetPattern = "([^<]*)"; + double xOffset = getNumber(&scanSettings, "XOffset", xOffsetPattern); + + char *yOffsetPattern = "([^<]*)"; + double yOffset = getNumber(&scanSettings, "YOffset", yOffsetPattern); + + char *inputSourcePattern = "([^<]*)"; + char *inputSource = getString(&scanSettings, "InputSource", inputSourcePattern); + + char *colorModePattern = "([^<]*)"; + char *colorMode = getString(&scanSettings, "ColorMode", colorModePattern); + + char *blankPageDetectionPattern = "([^<]*)"; + char *blankPageDetection = getString(&scanSettings, "BlankPageDetection", blankPageDetectionPattern); + + free(version); + free(intent); + free(height); + free(contentRegionUnits); + free(inputSource); + free(colorMode); + free(blankPageDetection); + free(scanSettings.xml); +} From b87ee5f6562198952f5283049dc39fa7360b5057 Mon Sep 17 00:00:00 2001 From: Akarshan Kapoor Date: Sun, 3 Nov 2024 21:14:05 +0000 Subject: [PATCH 26/26] Add Dummy Driver Files for testing Signed-off-by: Akarshan Kapoor --- .../DummyDriverFiles/ScannerCapabilities.txt | 105 ++++++++++++++++++ pappl/DummyDriverFiles/ScannerStatus.txt | 22 ++++ 2 files changed, 127 insertions(+) create mode 100644 pappl/DummyDriverFiles/ScannerCapabilities.txt create mode 100644 pappl/DummyDriverFiles/ScannerStatus.txt diff --git a/pappl/DummyDriverFiles/ScannerCapabilities.txt b/pappl/DummyDriverFiles/ScannerCapabilities.txt new file mode 100644 index 00000000..97998732 --- /dev/null +++ b/pappl/DummyDriverFiles/ScannerCapabilities.txt @@ -0,0 +1,105 @@ +- Version: 2.6 +- MakeAndModel: Hewlett-Packard Photosmart C4760 +- SerialNumber: CN017971874378PJ +- UUID: 96a4b400-2a9e-012f-6165-0025559efbc6f +- AdminURI: http://192.168.1.2/index.html +- IconURI: http://192.168.1.2/scanner.png + +Profile name: p1 + - ColorModes: + - ColorMode: BlackAndWhite1 + - ColorMode: Grayscale8 + - DocumentFormats: + - DocumentFormat: application/pdf + - DocumentFormat: image/jpeg + - DocumentFormatExt: application/pdf + - DocumentFormatExt: image/jpeg + - SupportedResolutions: + - DiscreteResolution: + - XResolution: 100 + - YResolution: 100 + - DiscreteResolution: + - XResolution: 200 + - YResolution: 200 + - DiscreteResolution: + - XResolution: 300 + - YResolution: 300 + - CcdChannels: + - CcdChannel: Red + - CcdChannel (default=true): Blue + - BinaryRenderings: + - BinaryRendering: Threshold + - BinaryRendering (default=true): Halftone + +Platen: + - PlatenInputCaps: + - MinWidth: 1 + - MaxWidth: 3000 + - MinHeight: 1 + - MaxHeight: 3600 + - MaxScanRegions: 2 + - SettingProfiles: + - ColorModes: + - ColorMode: RGB24 + - ColorMode: Grayscale8 + - ColorMode: BlackAndWhite1 + - DocumentFormats: + - DocumentFormat: image/jpeg + - DocumentFormat: application/pdf + - DocumentFormatExt: image/jpeg + - DocumentFormatExt: application/pdf + - SupportedResolutions: + - ResolutionRange: + - XResolutionRange: + - Min: 75 + - Max: 1200 + - Normal: 300 + - Step: 10 + - YResolutionRange: + - Min: 75 + - Max: 1200 + - Normal: 300 + - Step: 10 + - ColorSpaces: + - ColorSpace (default=true): sRGB + - CcdChannels: + - CcdChannel: Red + - CcdChannel: Blue + - CcdChannel: Green + - CcdChannel (default=true): NTSC + - BinaryRenderings: + - BinaryRendering (default=true): Halftone + - BinaryRendering: Threshold + - MaxOpticalXResolution: 1200 + - MaxOpticalYResolution: 1200 + - RiskyLeftMargin: 28 + - RiskyRightMargin: 30 + - RiskyTopMargin: 32 + - RiskyBottomMargin: 44 + +Adf: + - AdfSimplexInputCaps: + - MinWidth: 1 + - MaxWidth: 2600 + - MinHeight: 1 + - MaxHeight: 3400 + - SettingProfiles: + - SettingProfile ref: p1 + - EdgeAutoDetection: + - SupportedEdge: BottomEdge + - MaxOpticalXResolution: 300 + - MaxOpticalYResolution: 300 + - RiskyLeftMargin: 28 + - RiskyRightMargin: 30 + - RiskyTopMargin: 32 + - RiskyBottomMargin: 44 + - FeederCapacity: 100 + - AdfOptions: + - AdfOption: DetectPaperLoaded + - AdfOption: SelectSinglePage + +StoredJobRequestSupport: + - MaxStoredJobRequests: 10 + - TimeoutInSeconds: 120 +- BlankPageDetection: true +- BlankPageDetectionAndRemoval: true \ No newline at end of file diff --git a/pappl/DummyDriverFiles/ScannerStatus.txt b/pappl/DummyDriverFiles/ScannerStatus.txt new file mode 100644 index 00000000..e898df47 --- /dev/null +++ b/pappl/DummyDriverFiles/ScannerStatus.txt @@ -0,0 +1,22 @@ +- Version: 2.6 +- State: Processing + +Jobs: + +Job Information: + - Job URI: /ScanJobs/893e6fcd-487f-4056-a8c9-a87709b85daf + - Job UUID: 893e6fcd-487f-4056-a8c9-a87709b85daf + - Age: 10 + - Images Completed: 1 + - Images To Transfer: 1 + - Job State: Processing + - Job State Reasons: JobScanning + +Job Information: + - Job URI: /ScanJobs/898d6fcd-487f-4056-a8c9-a87709b85daf + - Job UUID: 898d6fcd-487f-4056-a8c9-a87709b85daf + - Age: 220 + - Images Completed: 5 + - Images To Transfer: 0 + - Job State: Completed + - Job State Reasons: JobCompletedSuccessfully \ No newline at end of file