From bba7024cb63a34da0ba077ba6cc8ba32fdf71404 Mon Sep 17 00:00:00 2001 From: Marek Kasik Date: Fri, 24 May 2019 16:29:02 +0200 Subject: print-notifications: Allow ignoring of events for print jobs Adds DBus interface for ignoring of events related to print jobs. There is DBus method DoNotNotifyJob which takes job id and ignored events as parameters. If a job with the id is processed then the plugin checks whether the current event should be ignored from the notification point of view. The interface stores the ginored events as flags which values are determined as "1 << value" where value comes from ipp_jstate_t enum. Its values ranges from 3 to 9 so they fit into the 64 bits of the uint64. This allow us to ignore more events at once but this is not used yet. Fixes #412 --- .../gsd-print-notifications-manager.c | 287 +++++++++++++++++---- 1 file changed, 234 insertions(+), 53 deletions(-) diff --git a/plugins/print-notifications/gsd-print-notifications-manager.c b/plugins/print-notifications/gsd-print-notifications-manager.c index 53aaccff..6735110f 100644 --- a/plugins/print-notifications/gsd-print-notifications-manager.c +++ b/plugins/print-notifications/gsd-print-notifications-manager.c @@ -44,6 +44,14 @@ #define CUPS_DBUS_PATH "/org/cups/cupsd/Notifier" #define CUPS_DBUS_INTERFACE "org.cups.cupsd.Notifier" +#define GSD_DBUS_NAME "org.gnome.SettingsDaemon" +#define GSD_DBUS_PATH "/org/gnome/SettingsDaemon" +#define GSD_DBUS_BASE_INTERFACE "org.gnome.SettingsDaemon" + +#define GSD_PRINT_NOTIFICATIONS_DBUS_NAME GSD_DBUS_NAME ".PrintNotifications" +#define GSD_PRINT_NOTIFICATIONS_DBUS_PATH GSD_DBUS_PATH "/PrintNotifications" +#define GSD_PRINT_NOTIFICATIONS_DBUS_INTERFACE GSD_DBUS_BASE_INTERFACE ".PrintNotifications" + #define RENEW_INTERVAL 3500 #define SUBSCRIPTION_DURATION 3600 #define CONNECTING_TIMEOUT 60 @@ -73,11 +81,26 @@ ippNextAttribute (ipp_t *ipp) } #endif +/* + * Ignored events for print jobs are stored as "1 << value" + * where the value is from ipp_jstate_t enum which ranges from 3 to 9. + */ +static const gchar introspection_xml[] = +"" +" " +" " +" " +" " +" " +" " +""; + struct _GsdPrintNotificationsManager { GObject parent; GDBusConnection *cups_bus_connection; + GDBusConnection *session_bus_connection; gint subscription_id; cups_dest_t *dests; gint num_dests; @@ -93,6 +116,10 @@ struct _GsdPrintNotificationsManager gint last_notify_sequence_number; guint start_idle_id; GList *held_jobs; + + guint name_id; + GDBusNodeInfo *introspection_data; + GList *ignored_jobs; }; static void gsd_print_notifications_manager_class_init (GsdPrintNotificationsManagerClass *klass); @@ -557,6 +584,38 @@ check_job_for_authentication (gpointer userdata) return G_SOURCE_REMOVE; } +struct +{ + gint job_id; + guint64 ignored_events; +} typedef TIgnoredJob; + +static TIgnoredJob * +find_ignored_job (GsdPrintNotificationsManager *manager, + gint job_id) +{ + TIgnoredJob *ignored_job = NULL; + GList *iter; + + for (iter = manager->ignored_jobs; iter != NULL; iter = iter->next) { + if (((TIgnoredJob *) iter->data)->job_id == job_id) { + ignored_job = (TIgnoredJob *) iter->data; + } + } + + return ignored_job; +} + +static void +remove_ignored_job (GsdPrintNotificationsManager *manager, + TIgnoredJob *ignored_job) +{ + if (ignored_job != NULL) { + manager->ignored_jobs = g_list_remove (manager->ignored_jobs, ignored_job); + g_free (ignored_job); + } +} + static void process_cups_notification (GsdPrintNotificationsManager *manager, const char *notify_subscribed_event, @@ -573,6 +632,7 @@ process_cups_notification (GsdPrintNotificationsManager *manager, gint job_impressions_completed) { ipp_attribute_t *attr; + TIgnoredJob *ignored_job = NULL; gboolean my_job = FALSE; gboolean known_reason; HeldJob *held_job; @@ -657,6 +717,8 @@ process_cups_notification (GsdPrintNotificationsManager *manager, g_free (job_uri); httpClose (http); } + + ignored_job = find_ignored_job (manager, notify_job_id); } if (g_strcmp0 (notify_subscribed_event, "printer-added") == 0) { @@ -683,72 +745,102 @@ process_cups_notification (GsdPrintNotificationsManager *manager, case IPP_JOB_PROCESSING: break; case IPP_JOB_STOPPED: - /* Translators: A print job has been stopped */ - primary_text = g_strdup (C_("print job state", "Printing stopped")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_STOPPED))) { + /* Translators: A print job has been stopped */ + primary_text = g_strdup (C_("print job state", "Printing stopped")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } break; case IPP_JOB_CANCELED: - /* Translators: A print job has been canceled */ - primary_text = g_strdup (C_("print job state", "Printing canceled")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_CANCELED))) { + /* Translators: A print job has been canceled */ + primary_text = g_strdup (C_("print job state", "Printing canceled")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } else { + remove_ignored_job (manager, ignored_job); + } break; case IPP_JOB_ABORTED: - /* Translators: A print job has been aborted */ - primary_text = g_strdup (C_("print job state", "Printing aborted")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_ABORTED))) { + /* Translators: A print job has been aborted */ + primary_text = g_strdup (C_("print job state", "Printing aborted")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } else { + remove_ignored_job (manager, ignored_job); + } break; case IPP_JOB_COMPLETED: - /* Translators: A print job has been completed */ - primary_text = g_strdup (C_("print job state", "Printing completed")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_COMPLETED))) { + /* Translators: A print job has been completed */ + primary_text = g_strdup (C_("print job state", "Printing completed")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } else { + remove_ignored_job (manager, ignored_job); + } break; } } else if (g_strcmp0 (notify_subscribed_event, "job-state-changed") == 0 && my_job) { switch (job_state) { case IPP_JOB_PROCESSING: - g_hash_table_insert (manager->printing_printers, - g_strdup (printer_name), NULL); - - /* Translators: A job is printing */ - primary_text = g_strdup (C_("print job state", "Printing")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_PROCESSING))) { + g_hash_table_insert (manager->printing_printers, + g_strdup (printer_name), NULL); + + /* Translators: A job is printing */ + primary_text = g_strdup (C_("print job state", "Printing")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } break; case IPP_JOB_STOPPED: - g_hash_table_remove (manager->printing_printers, - printer_name); - /* Translators: A print job has been stopped */ - primary_text = g_strdup (C_("print job state", "Printing stopped")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_STOPPED))) { + g_hash_table_remove (manager->printing_printers, + printer_name); + /* Translators: A print job has been stopped */ + primary_text = g_strdup (C_("print job state", "Printing stopped")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } break; case IPP_JOB_CANCELED: - g_hash_table_remove (manager->printing_printers, - printer_name); - /* Translators: A print job has been canceled */ - primary_text = g_strdup (C_("print job state", "Printing canceled")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_CANCELED))) { + g_hash_table_remove (manager->printing_printers, + printer_name); + /* Translators: A print job has been canceled */ + primary_text = g_strdup (C_("print job state", "Printing canceled")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } else { + remove_ignored_job (manager, ignored_job); + } break; case IPP_JOB_ABORTED: - g_hash_table_remove (manager->printing_printers, - printer_name); - /* Translators: A print job has been aborted */ - primary_text = g_strdup (C_("print job state", "Printing aborted")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_ABORTED))) { + g_hash_table_remove (manager->printing_printers, + printer_name); + /* Translators: A print job has been aborted */ + primary_text = g_strdup (C_("print job state", "Printing aborted")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } else { + remove_ignored_job (manager, ignored_job); + } break; case IPP_JOB_COMPLETED: - g_hash_table_remove (manager->printing_printers, - printer_name); - /* Translators: A print job has been completed */ - primary_text = g_strdup (C_("print job state", "Printing completed")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_COMPLETED))) { + g_hash_table_remove (manager->printing_printers, + printer_name); + /* Translators: A print job has been completed */ + primary_text = g_strdup (C_("print job state", "Printing completed")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } else { + remove_ignored_job (manager, ignored_job); + } break; case IPP_JOB_HELD: held_job = g_new (HeldJob, 1); @@ -766,13 +858,15 @@ process_cups_notification (GsdPrintNotificationsManager *manager, } } else if (g_strcmp0 (notify_subscribed_event, "job-created") == 0 && my_job) { if (job_state == IPP_JOB_PROCESSING) { - g_hash_table_insert (manager->printing_printers, - g_strdup (printer_name), NULL); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_PROCESSING))) { + g_hash_table_insert (manager->printing_printers, + g_strdup (printer_name), NULL); - /* Translators: A job is printing */ - primary_text = g_strdup (C_("print job state", "Printing")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + /* Translators: A job is printing */ + primary_text = g_strdup (C_("print job state", "Printing")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } } } else if (g_strcmp0 (notify_subscribed_event, "printer-state-changed") == 0) { cups_dest_t *dest = NULL; @@ -1514,6 +1608,73 @@ gsd_print_notifications_manager_got_dbus_connection (GObject *source_object } } +static void +handle_method_call (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + GsdPrintNotificationsManager *manager = GSD_PRINT_NOTIFICATIONS_MANAGER (user_data); + + if (g_strcmp0 (method_name, "DoNotNotifyJob") == 0) { + TIgnoredJob *ignored_job; + guint64 events = 0; + gint job_id = 0; + + g_variant_get (parameters, "(it)", &job_id, &events); + + if (job_id > 0 && events > 0) { + ignored_job = g_new (TIgnoredJob, 1); + ignored_job->job_id = job_id; + ignored_job->ignored_events = events; + manager->ignored_jobs = g_list_prepend (manager->ignored_jobs, ignored_job); + } + + g_dbus_method_invocation_return_value (invocation, NULL); + } else { + g_assert_not_reached (); + } +} + +static const GDBusInterfaceVTable interface_vtable = +{ + handle_method_call, + NULL, + NULL +}; + +static void +gsd_print_notifications_manager_got_session_dbus_connection (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GsdPrintNotificationsManager *manager = (GsdPrintNotificationsManager *) user_data; + GError *error = NULL; + + manager->session_bus_connection = g_bus_get_finish (res, &error); + if (manager->session_bus_connection != NULL) { + g_dbus_connection_register_object (manager->session_bus_connection, + GSD_PRINT_NOTIFICATIONS_DBUS_PATH, + manager->introspection_data->interfaces[0], + &interface_vtable, + manager, + NULL, + NULL); + + manager->name_id = g_bus_own_name_on_connection (manager->session_bus_connection, + GSD_PRINT_NOTIFICATIONS_DBUS_NAME, + G_BUS_NAME_OWNER_FLAGS_NONE, + NULL, NULL, NULL, NULL); + } else { + g_warning ("Connection to message bus failed: %s", error->message); + g_error_free (error); + } +} + static gboolean gsd_print_notifications_manager_start_idle (gpointer data) { @@ -1523,6 +1684,11 @@ gsd_print_notifications_manager_start_idle (gpointer data) manager->printing_printers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + g_bus_get (G_BUS_TYPE_SESSION, + NULL, + gsd_print_notifications_manager_got_session_dbus_connection, + data); + /* * Set a password callback which cancels authentication * before we prepare a correct solution (see bug #725440). @@ -1569,6 +1735,10 @@ gsd_print_notifications_manager_start (GsdPrintNotificationsManager *manager, manager->cups_connection_timeout_id = 0; manager->last_notify_sequence_number = -1; manager->held_jobs = NULL; + manager->ignored_jobs = NULL; + manager->session_bus_connection = NULL; + manager->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); + g_assert (manager->introspection_data != NULL); manager->start_idle_id = g_idle_add (gsd_print_notifications_manager_start_idle, manager); g_source_set_name_by_id (manager->start_idle_id, "[gnome-settings-daemon] gsd_print_notifications_manager_start_idle"); @@ -1588,6 +1758,17 @@ gsd_print_notifications_manager_stop (GsdPrintNotificationsManager *manager) g_debug ("Stopping print-notifications manager"); + if (manager->name_id != 0) { + g_bus_unown_name (manager->name_id); + manager->name_id = 0; + } + + g_clear_object (&manager->session_bus_connection); + + g_clear_pointer (&manager->introspection_data, g_dbus_node_info_unref); + + g_list_free_full (manager->ignored_jobs, g_free); + cupsFreeDests (manager->num_dests, manager->dests); manager->num_dests = 0; manager->dests = NULL; -- cgit v1.2.1