--- src/cups.c 2009-01-28 12:51:49.000000000 +0100 +++ src/cups.c 2009-01-28 10:59:36.000000000 +0100 @@ -381,6 +381,18 @@ _cph_cups_add_class_uri (ipp_t *req } static void +_cph_cups_add_job_uri (ipp_t *request, + gint job_id) +{ + char uri[HTTP_MAX_URI + 1]; + + g_snprintf (uri, sizeof (uri), + "ipp://localhost/jobs/%d", job_id); + ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI, + "job-uri", NULL, uri); +} + +static void _cph_cups_set_internal_status (CphCups *cups, const char *status) { @@ -541,6 +553,41 @@ _cph_cups_send_new_printer_class_request return _cph_cups_send_request (cups, request, CPH_RESOURCE_ADMIN); } +static gboolean +_cph_cups_send_new_simple_job_request (CphCups *cups, + ipp_op_t op, + gint job_id, + CphResource resource) +{ + ipp_t *request; + + request = ippNewRequest (op); + _cph_cups_add_job_uri (request, job_id); + + return _cph_cups_send_request (cups, request, resource); +} + +static gboolean +_cph_cups_send_new_job_attributes_request (CphCups *cups, + gint job_id, + const char *name, + const char *value, + CphResource resource) +{ + cups_option_t *options = NULL; + ipp_t *request; + gint num_options = 0; + + request = ippNewRequest (IPP_SET_JOB_ATTRIBUTES); + _cph_cups_add_job_uri (request, job_id); + + num_options = cupsAddOption (name, value, + num_options, &options); + cupsEncodeOptions (request, num_options, options); + + return _cph_cups_send_request (cups, request, resource); +} + static int _cph_cups_class_has_printer (CphCups *cups, const char *class_name, @@ -1581,6 +1628,42 @@ cph_cups_server_set_settings (CphCups return TRUE; } +gboolean +cph_cups_job_cancel (CphCups *cups, + gint job_id) +{ + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + return _cph_cups_send_new_simple_job_request (cups, IPP_CANCEL_JOB, + job_id, + CPH_RESOURCE_ADMIN); +} + +gboolean +cph_cups_job_restart (CphCups *cups, + gint job_id) +{ + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + return _cph_cups_send_new_simple_job_request (cups, IPP_RESTART_JOB, + job_id, + CPH_RESOURCE_ADMIN); +} + +gboolean +cph_cups_job_set_hold_until (CphCups *cups, + gint job_id, + const char *job_hold_until) +{ + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + return _cph_cups_send_new_job_attributes_request (cups, + job_id, + "job-hold-until", + job_hold_until, + CPH_RESOURCE_ADMIN); +} + /****************************************************** * Non-object functions ******************************************************/ @@ -1647,3 +1730,28 @@ cph_cups_is_printer_uri_local (const cha /* we don't know, so we assume it's not local */ return FALSE; } + +gboolean +cph_cups_is_job_owner (CphCups *cups, + gint job_id, + const char *user) +{ + cups_job_t *jobs; + gboolean user_job = FALSE; + gint num_jobs = 0; + gint i; + + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + if (user == NULL) + return FALSE; + + num_jobs = cupsGetJobs2 (cups->priv->connection, &jobs, NULL, 0, 0); + + for (i = 0; i < num_jobs; i++) { + if (jobs[i].id == job_id && g_strcmp0 (jobs[i].user, user) == 0) + user_job = TRUE; + } + + return user_job; +} --- src/cups.h 2008-11-21 01:50:42.000000000 +0100 +++ src/cups.h 2009-01-27 17:33:00.000000000 +0100 @@ -160,6 +160,20 @@ gboolean cph_cups_is_printer_local (CphC gboolean cph_cups_is_printer_uri_local (const char *uri); +gboolean cph_cups_job_cancel (CphCups *cups, + gint job_id); + +gboolean cph_cups_job_restart (CphCups *cups, + gint job_id); + +gboolean cph_cups_job_set_hold_until (CphCups *cups, + gint job_id, + const char *job_hold_until); + +gboolean cph_cups_is_job_owner (CphCups *cups, + gint job_id, + const char *user); + G_END_DECLS #endif /* CPH_CUPS_H */ --- src/cups-pk-helper-mechanism.c 2009-01-28 12:51:49.000000000 +0100 +++ src/cups-pk-helper-mechanism.c 2009-01-28 11:39:16.000000000 +0100 @@ -47,6 +47,10 @@ #include +#include + +#include + #include "cups-pk-helper-mechanism.h" #include "cups-pk-helper-mechanism-glue.h" #include "cups.h" @@ -1011,3 +1015,116 @@ cph_mechanism_server_set_settings (CphMe return TRUE; } + +gchar * +cph_mechanism_get_callers_user_name (CphMechanism *mechanism, + DBusGMethodInvocation *context) +{ + unsigned long sender_uid; + struct passwd *password_entry; + const gchar *sender; + DBusError dbus_error; + gchar *user_name = NULL; + + sender = dbus_g_method_get_sender (context); + dbus_error_init (&dbus_error); + sender_uid = dbus_bus_get_unix_user (dbus_g_connection_get_connection (mechanism->priv->system_bus_connection), sender, &dbus_error); + password_entry = getpwuid ((uid_t) sender_uid); + + if (password_entry != NULL) { + user_name = g_strdup(password_entry->pw_name); + } + + return user_name; +} + +gboolean +cph_mechanism_job_cancel (CphMechanism *mechanism, + gint id, + DBusGMethodInvocation *context) +{ + gboolean ret; + gboolean callers_job = FALSE; + char *user_name = NULL; + + reset_killtimer (mechanism); + + user_name = cph_mechanism_get_callers_user_name (mechanism, context); + callers_job = cph_cups_is_job_owner (mechanism->priv->cups, id, user_name); + g_free (user_name); + + if (callers_job) { + if (!_check_polkit_for_action (mechanism, context, "job-cancel")) + return FALSE; + } + else { + if (!_check_polkit_for_action (mechanism, context, "job-cancel-another-owner")) + return FALSE; + } + + ret = cph_cups_job_cancel (mechanism->priv->cups, id); + _cph_mechanism_return_error (mechanism, context, !ret); + + return TRUE; +} + +gboolean +cph_mechanism_job_restart (CphMechanism *mechanism, + gint id, + DBusGMethodInvocation *context) +{ + gboolean ret; + gboolean callers_job = FALSE; + char *user_name = NULL; + + reset_killtimer (mechanism); + + user_name = cph_mechanism_get_callers_user_name (mechanism, context); + callers_job = cph_cups_is_job_owner (mechanism->priv->cups, id, user_name); + g_free (user_name); + + if (callers_job) { + if (!_check_polkit_for_action (mechanism, context, "job-restart")) + return FALSE; + } + else { + if (!_check_polkit_for_action (mechanism, context, "job-restart-another-owner")) + return FALSE; + } + + ret = cph_cups_job_restart (mechanism->priv->cups, id); + _cph_mechanism_return_error (mechanism, context, !ret); + + return TRUE; +} + +gboolean +cph_mechanism_job_set_hold_until (CphMechanism *mechanism, + gint id, + const char *job_hold_until, + DBusGMethodInvocation *context) +{ + gboolean ret; + gboolean callers_job = FALSE; + char *user_name = NULL; + + reset_killtimer (mechanism); + + user_name = cph_mechanism_get_callers_user_name (mechanism, context); + callers_job = cph_cups_is_job_owner (mechanism->priv->cups, id, user_name); + g_free (user_name); + + if (callers_job) { + if (!_check_polkit_for_action (mechanism, context, "job-set-hold-until")) + return FALSE; + } + else { + if (!_check_polkit_for_action (mechanism, context, "job-set-hold-until-another-owner")) + return FALSE; + } + + ret = cph_cups_job_set_hold_until (mechanism->priv->cups, id, job_hold_until); + _cph_mechanism_return_error (mechanism, context, !ret); + + return TRUE; +} --- src/cups-pk-helper-mechanism.h 2008-11-21 01:57:03.000000000 +0100 +++ src/cups-pk-helper-mechanism.h 2009-01-27 17:31:20.000000000 +0100 @@ -220,6 +220,22 @@ cph_mechanism_server_set_settings (CphMe GHashTable *settings, DBusGMethodInvocation *context); +gboolean +cph_mechanism_job_cancel (CphMechanism *mechanism, + gint id, + DBusGMethodInvocation *context); + +gboolean +cph_mechanism_job_restart (CphMechanism *mechanism, + gint id, + DBusGMethodInvocation *context); + +gboolean +cph_mechanism_job_set_hold_until (CphMechanism *mechanism, + gint id, + const char *job_hold_until, + DBusGMethodInvocation *context); + G_END_DECLS #endif /* CPH_MECHANISM_H */ --- src/cups-pk-helper-mechanism.xml 2008-11-21 01:55:52.000000000 +0100 +++ src/cups-pk-helper-mechanism.xml 2009-01-27 17:26:57.000000000 +0100 @@ -174,5 +174,23 @@ + + + + + + + + + + + + + + + + + + --- src/org.opensuse.cupspkhelper.mechanism.policy.in 2008-11-21 00:58:16.000000000 +0100 +++ src/org.opensuse.cupspkhelper.mechanism.policy.in 2009-01-28 12:47:49.000000000 +0100 @@ -68,6 +68,60 @@ + + <_description>Cancel a job + <_message>Privileges are required to cancel a job. + + no + auth_self + + + + + <_description>Cancel a job owned by another user + <_message>Privileges are required to cancel a job owned by another user. + + no + auth_admin + + + + + <_description>Restart a job + <_message>Privileges are required to restart a job. + + no + yes + + + + + <_description>Restart a job owned by another user + <_message>Privileges are required to restart a job owned by another user. + + no + auth_admin + + + + + <_description>Set hold-until time of a job + <_message>Privileges are required to set hold-until time of a job. + + no + yes + + + + + <_description>Set hold-until time of a job owned by another + <_message>Privileges are required to set hold-until time of a job owned by another user. + + no + auth_admin + + + <_description>Add/Remove/Edit a printer