diff --git a/CHANGES.md b/CHANGES.md index 9cead063..49cac5de 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,8 @@ Changes in PAPPL Changes in v1.2b1 ----------------- +- Added IPP notifications support with `papplSystemAddEvent` and + `papplSubscriptionXxx` functions (Issue #191) - Added `papplPrinterDisable` and `papplPrinterEnable` functions and proper support for the IPP "printer-is-accepting-jobs" attribute. - Updated `papplPrinterSetReadyMedia` to support up to `PAPPL_MAX_SOURCE` diff --git a/pappl/job-process.c b/pappl/job-process.c index 020b2c85..f5b586eb 100644 --- a/pappl/job-process.c +++ b/pappl/job-process.c @@ -530,6 +530,8 @@ _papplJobProcessRaster( papplLogJob(job, PAPPL_LOGLEVEL_INFO, "Page %u raster data is %ux%ux%u (%s)", page, header.cupsWidth, header.cupsHeight, header.cupsBitsPerPixel, cups_cspace_string(header.cupsColorSpace)); + papplSystemAddEvent(printer->system, printer, job, PAPPL_EVENT_JOB_PROGRESS, NULL); + // Set options for this page... papplJobDeletePrintOptions(options); options = papplJobCreatePrintOptions(job, (unsigned)job->impressions, header.cupsBitsPerPixel > 8); @@ -876,6 +878,8 @@ finish_job(pappl_job_t *job) // I - Job _papplJobRemoveFile(job); + _papplSystemAddEventNoLock(job->system, job->printer, job, PAPPL_EVENT_JOB_COMPLETED, NULL); + pthread_rwlock_unlock(&job->rwlock); if (printer->is_stopped) @@ -900,6 +904,8 @@ finish_job(pappl_job_t *job) // I - Job if (!job->system->clean_time) job->system->clean_time = time(NULL) + 60; + _papplSystemAddEventNoLock(printer->system, printer, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, NULL); + pthread_rwlock_unlock(&printer->rwlock); _papplSystemConfigChanged(printer->system); @@ -954,6 +960,8 @@ start_job(pappl_job_t *job) // I - Job pthread_rwlock_unlock(&job->rwlock); + _papplSystemAddEventNoLock(printer->system, printer, job, PAPPL_EVENT_JOB_STATE_CHANGED, NULL); + // Open the output device... while (!printer->device && !printer->is_deleted && !job->is_canceled && papplSystemIsRunning(printer->system)) { @@ -978,8 +986,12 @@ start_job(pappl_job_t *job) // I - Job } if (!papplSystemIsRunning(printer->system)) + { job->state = IPP_JSTATE_PENDING; + papplSystemAddEvent(job->system, job->printer, job, PAPPL_EVENT_JOB_STATE_CHANGED, NULL); + } + if (printer->device) { // Move the printer to the 'processing' state... @@ -987,6 +999,8 @@ start_job(pappl_job_t *job) // I - Job printer->state_time = time(NULL); } + _papplSystemAddEventNoLock(printer->system, printer, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, NULL); + pthread_rwlock_unlock(&printer->rwlock); return (printer->device != NULL); diff --git a/pappl/job.c b/pappl/job.c index d667d882..1ca01229 100644 --- a/pappl/job.c +++ b/pappl/job.c @@ -1,7 +1,7 @@ // // Job object for the Printer Application Framework // -// Copyright © 2019-2021 by Michael R Sweet. +// Copyright © 2019-2022 by Michael R Sweet. // Copyright © 2010-2019 by Apple Inc. // // Licensed under Apache License v2.0. See the file "LICENSE" for more @@ -53,6 +53,8 @@ papplJobCancel(pappl_job_t *job) // I - Job job->system->clean_time = time(NULL) + 60; pthread_rwlock_unlock(&job->rwlock); + + papplSystemAddEvent(job->system, job->printer, job, PAPPL_EVENT_JOB_COMPLETED, NULL); } diff --git a/pappl/printer-accessors.c b/pappl/printer-accessors.c index 7adecfd1..e9d58beb 100644 --- a/pappl/printer-accessors.c +++ b/pappl/printer-accessors.c @@ -53,6 +53,7 @@ papplPrinterDisable( if (printer) { printer->is_accepting = false; + papplSystemAddEvent(printer->system, printer, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, NULL); } } @@ -70,6 +71,7 @@ papplPrinterEnable( if (printer) { printer->is_accepting = true; + papplSystemAddEvent(printer->system, printer, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, NULL); } } @@ -793,6 +795,8 @@ papplPrinterPause( else printer->state = IPP_PSTATE_STOPPED; + _papplSystemAddEventNoLock(printer->system, printer, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED | PAPPL_EVENT_PRINTER_STOPPED, NULL); + pthread_rwlock_unlock(&printer->rwlock); } @@ -815,6 +819,8 @@ papplPrinterResume( printer->is_stopped = false; printer->state = IPP_PSTATE_IDLE; + _papplSystemAddEventNoLock(printer->system, printer, NULL, PAPPL_EVENT_PRINTER_STATE_CHANGED, NULL); + pthread_rwlock_unlock(&printer->rwlock); _papplPrinterCheckJobs(printer); diff --git a/pappl/printer-ipp.c b/pappl/printer-ipp.c index e9b95388..6cbd4f9c 100644 --- a/pappl/printer-ipp.c +++ b/pappl/printer-ipp.c @@ -803,6 +803,7 @@ _papplPrinterProcessIPP( break; case IPP_OP_PAUSE_PRINTER : + case IPP_OP_PAUSE_PRINTER_AFTER_CURRENT_JOB : ipp_pause_printer(client); break; @@ -1146,7 +1147,7 @@ _papplPrinterSetAttributes( if (ippGetStatusCode(client->response) != IPP_STATUS_OK) { cupsFreeOptions(num_vendor, vendor); - return (0); + return (false); } // Now apply changes... @@ -1154,7 +1155,7 @@ _papplPrinterSetAttributes( { papplClientRespondIPP(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, "One or more attribute values were not supported."); cupsFreeOptions(num_vendor, vendor); - return (0); + return (false); } cupsFreeOptions(num_vendor, vendor); @@ -1162,7 +1163,7 @@ _papplPrinterSetAttributes( if (do_ready && !papplPrinterSetReadyMedia(printer, driver_data.num_source, driver_data.media_ready)) { papplClientRespondIPP(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, "One or more attribute values were not supported."); - return (0); + return (false); } if (do_wifi) @@ -1170,7 +1171,7 @@ _papplPrinterSetAttributes( if (!(printer->system->wifi_join_cb)(printer->system, printer->system->wifi_cbdata, wifi_ssid, wifi_password)) { papplClientRespondIPP(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, "Unable to join Wi-Fi network '%s'.", wifi_ssid); - return (0); + return (false); } } @@ -1189,7 +1190,9 @@ _papplPrinterSetAttributes( if (org_unit) papplPrinterSetGeoLocation(printer, org_unit); - return (1); + papplSystemAddEvent(printer->system, printer, NULL, PAPPL_EVENT_PRINTER_CONFIG_CHANGED, NULL); + + return (true); } diff --git a/pappl/printer.c b/pappl/printer.c index 27cb987a..893e2e8d 100644 --- a/pappl/printer.c +++ b/pappl/printer.c @@ -149,6 +149,7 @@ papplPrinterCreate( IPP_OP_GET_NOTIFICATIONS, IPP_OP_ENABLE_PRINTER, IPP_OP_DISABLE_PRINTER, + IPP_OP_PAUSE_PRINTER_AFTER_CURRENT_JOB, IPP_OP_CANCEL_CURRENT_JOB, IPP_OP_CANCEL_JOBS, IPP_OP_CANCEL_MY_JOBS, diff --git a/pappl/system-ipp.c b/pappl/system-ipp.c index c095e4d2..f503e95b 100644 --- a/pappl/system-ipp.c +++ b/pappl/system-ipp.c @@ -31,13 +31,16 @@ typedef struct _pappl_attr_s // Input attribute structure // Local functions... // -static void ipp_create_printer(pappl_client_t *client); -static void ipp_delete_printer(pappl_client_t *client); -static void ipp_get_printers(pappl_client_t *client); -static void ipp_get_system_attributes(pappl_client_t *client); -static void ipp_set_system_attributes(pappl_client_t *client); -static void ipp_shutdown_all_printers(pappl_client_t *client); - +static void ipp_create_printer(pappl_client_t *client); +static void ipp_delete_printer(pappl_client_t *client); +static void ipp_disable_all_printers(pappl_client_t *client); +static void ipp_enable_all_printers(pappl_client_t *client); +static void ipp_get_printers(pappl_client_t *client); +static void ipp_get_system_attributes(pappl_client_t *client); +static void ipp_pause_all_printers(pappl_client_t *client); +static void ipp_resume_all_printers(pappl_client_t *client); +static void ipp_set_system_attributes(pappl_client_t *client); +static void ipp_shutdown_all_printers(pappl_client_t *client); // // '_papplSystemProcessIPP()' - Process an IPP System request. @@ -76,6 +79,23 @@ _papplSystemProcessIPP( ipp_set_system_attributes(client); break; + case IPP_OP_DISABLE_ALL_PRINTERS : + ipp_disable_all_printers(client); + break; + + case IPP_OP_ENABLE_ALL_PRINTERS : + ipp_enable_all_printers(client); + break; + + case IPP_OP_PAUSE_ALL_PRINTERS : + case IPP_OP_PAUSE_ALL_PRINTERS_AFTER_CURRENT_JOB : + ipp_pause_all_printers(client); + break; + + case IPP_OP_RESUME_ALL_PRINTERS : + ipp_resume_all_printers(client); + break; + case IPP_OP_SHUTDOWN_ALL_PRINTERS : ipp_shutdown_all_printers(client); break; @@ -248,6 +268,8 @@ ipp_create_printer( return; } + papplSystemAddEvent(printer->system, printer, NULL, PAPPL_EVENT_PRINTER_CREATED, NULL); + if (!_papplPrinterSetAttributes(client, printer)) return; @@ -291,6 +313,8 @@ ipp_delete_printer( return; } + papplSystemAddEvent(client->system, client->printer, NULL, PAPPL_EVENT_PRINTER_DELETED, NULL); + if (!client->printer->processing_job) papplPrinterDelete(client->printer); else @@ -300,6 +324,68 @@ ipp_delete_printer( } +// +// 'ipp_disable_all_printers()' - Disable all printers. +// + +static void +ipp_disable_all_printers( + pappl_client_t *client) // I - Client +{ + pappl_system_t *system = client->system; + // System + pappl_printer_t *printer; // Current printer + http_status_t auth_status; // Authorization status + + + // Verify the connection is authorized... + if ((auth_status = papplClientIsAuthorized(client)) != HTTP_STATUS_CONTINUE) + { + papplClientRespond(client, auth_status, NULL, NULL, 0, 0); + return; + } + + // Loop through the printers... + pthread_rwlock_rdlock(&system->rwlock); + for (printer = (pappl_printer_t *)cupsArrayGetFirst(system->printers); printer; printer = (pappl_printer_t *)cupsArrayGetNext(system->printers)) + { + papplPrinterDisable(printer); + } + pthread_rwlock_unlock(&system->rwlock); +} + + +// +// 'ipp_enable_all_printers()' - Enable all printers. +// + +static void +ipp_enable_all_printers( + pappl_client_t *client) // I - Client +{ + pappl_system_t *system = client->system; + // System + pappl_printer_t *printer; // Current printer + http_status_t auth_status; // Authorization status + + + // Verify the connection is authorized... + if ((auth_status = papplClientIsAuthorized(client)) != HTTP_STATUS_CONTINUE) + { + papplClientRespond(client, auth_status, NULL, NULL, 0, 0); + return; + } + + // Loop through the printers... + pthread_rwlock_rdlock(&system->rwlock); + for (printer = (pappl_printer_t *)cupsArrayGetFirst(system->printers); printer; printer = (pappl_printer_t *)cupsArrayGetNext(system->printers)) + { + papplPrinterEnable(printer); + } + pthread_rwlock_unlock(&system->rwlock); +} + + // // 'ipp_get_printers()' - Get printers. // @@ -554,6 +640,68 @@ ipp_get_system_attributes( } +// +// 'ipp_pause_all_printers()' - all printers. +// + +static void +ipp_pause_all_printers( + pappl_client_t *client) // I - Client +{ + pappl_system_t *system = client->system; + // System + pappl_printer_t *printer; // Current printer + http_status_t auth_status; // Authorization status + + + // Verify the connection is authorized... + if ((auth_status = papplClientIsAuthorized(client)) != HTTP_STATUS_CONTINUE) + { + papplClientRespond(client, auth_status, NULL, NULL, 0, 0); + return; + } + + // Loop through the printers... + pthread_rwlock_rdlock(&system->rwlock); + for (printer = (pappl_printer_t *)cupsArrayGetFirst(system->printers); printer; printer = (pappl_printer_t *)cupsArrayGetNext(system->printers)) + { + papplPrinterPause(client->printer); + } + pthread_rwlock_unlock(&system->rwlock); +} + + +// +// 'ipp_resume_all_printers()' - all printers. +// + +static void +ipp_resume_all_printers( + pappl_client_t *client) // I - Client +{ + pappl_system_t *system = client->system; + // System + pappl_printer_t *printer; // Current printer + http_status_t auth_status; // Authorization status + + + // Verify the connection is authorized... + if ((auth_status = papplClientIsAuthorized(client)) != HTTP_STATUS_CONTINUE) + { + papplClientRespond(client, auth_status, NULL, NULL, 0, 0); + return; + } + + // Loop through the printers... + pthread_rwlock_rdlock(&system->rwlock); + for (printer = (pappl_printer_t *)cupsArrayGetFirst(system->printers); printer; printer = (pappl_printer_t *)cupsArrayGetNext(system->printers)) + { + papplPrinterResume(client->printer); + } + pthread_rwlock_unlock(&system->rwlock); +} + + // // 'ipp_set_system_attributes()' - Set system attributes. // @@ -674,6 +822,8 @@ ipp_set_system_attributes( pthread_rwlock_unlock(&system->rwlock); + papplSystemAddEvent(system, NULL, NULL, PAPPL_EVENT_SYSTEM_CONFIG_CHANGED, NULL); + papplClientRespondIPP(client, IPP_STATUS_OK, NULL); } diff --git a/pappl/system-subscription.c b/pappl/system-subscription.c index 81557b8d..99f0a6fe 100644 --- a/pappl/system-subscription.c +++ b/pappl/system-subscription.c @@ -40,13 +40,19 @@ papplSystemAddEvent( if (!system || !message) return; - pthread_rwlock_wrlock(&system->rwlock); + if (job) + pthread_rwlock_rdlock(&job->rwlock); + if (printer) + pthread_rwlock_rdlock(&printer->rwlock); va_start(ap, message); _papplSystemAddEventNoLockv(system, printer, job, event, message, ap); va_end(ap); - pthread_rwlock_unlock(&system->rwlock); + if (printer) + pthread_rwlock_unlock(&printer->rwlock); + if (job) + pthread_rwlock_unlock(&job->rwlock); } @@ -93,6 +99,8 @@ _papplSystemAddEventNoLockv( // Loop through all of the subscriptions and deliver any events... + pthread_rwlock_rdlock(&system->rwlock); + for (sub = (pappl_subscription_t *)cupsArrayFirst(system->subscriptions); sub; sub = (pappl_subscription_t *)cupsArrayNext(system->subscriptions)) { if ((sub->mask & event) && (!sub->job || job == sub->job) && (!sub->printer || printer == sub->printer)) @@ -159,9 +167,11 @@ _papplSystemAddEventNoLockv( pthread_rwlock_unlock(&sub->rwlock); - // TODO: broadcast notification + pthread_cond_broadcast(&system->subscription_cond); } } + + pthread_rwlock_unlock(&system->rwlock); } diff --git a/pappl/system.c b/pappl/system.c index 04629b61..baeaea75 100644 --- a/pappl/system.c +++ b/pappl/system.c @@ -785,8 +785,6 @@ make_attributes(pappl_system_t *system) // I - System IPP_OP_CREATE_PRINTER, IPP_OP_DELETE_PRINTER, IPP_OP_GET_PRINTERS, - IPP_OP_SHUTDOWN_ONE_PRINTER, - IPP_OP_STARTUP_ONE_PRINTER, IPP_OP_CREATE_SYSTEM_SUBSCRIPTIONS, IPP_OP_DISABLE_ALL_PRINTERS, IPP_OP_ENABLE_ALL_PRINTERS, @@ -794,11 +792,9 @@ make_attributes(pappl_system_t *system) // I - System IPP_OP_GET_SYSTEM_SUPPORTED_VALUES, IPP_OP_PAUSE_ALL_PRINTERS, IPP_OP_PAUSE_ALL_PRINTERS_AFTER_CURRENT_JOB, - IPP_OP_RESTART_SYSTEM, IPP_OP_RESUME_ALL_PRINTERS, IPP_OP_SET_SYSTEM_ATTRIBUTES, IPP_OP_SHUTDOWN_ALL_PRINTERS, - IPP_OP_STARTUP_ALL_PRINTERS, IPP_OP_CUPS_GET_DEFAULT, IPP_OP_CUPS_GET_PRINTERS };