diff options
author | Marek Kasik <mkasik@redhat.com> | 2009-02-17 16:55:54 +0100 |
---|---|---|
committer | Vincent Untz <vuntz@novell.com> | 2009-02-28 02:24:22 +0100 |
commit | 2a6fb5b50a5cfd790a24c69ab5fe7e26dab3a4ba (patch) | |
tree | 27d1c4727571cd6f25cc817cca19c11b3755e0bd | |
parent | 87f6b0f3669e11e565b1288cb59e4479dc76ad50 (diff) |
Add job related functions + reconnect ability
Add _cph_mechanism_get_callers_user_name() function. This function returns caller's user name.
Add handling of "file:" backend in cph_cups_is_printer_uri_local().
Signed-off-by: Vincent Untz <vuntz@novell.com>
-rw-r--r-- | src/cups-pk-helper-mechanism.c | 143 | ||||
-rw-r--r-- | src/cups-pk-helper-mechanism.h | 16 | ||||
-rw-r--r-- | src/cups-pk-helper-mechanism.xml | 18 | ||||
-rw-r--r-- | src/cups.c | 192 | ||||
-rw-r--r-- | src/cups.h | 24 | ||||
-rw-r--r-- | src/org.opensuse.cupspkhelper.mechanism.policy.in | 18 |
6 files changed, 406 insertions, 5 deletions
diff --git a/src/cups-pk-helper-mechanism.c b/src/cups-pk-helper-mechanism.c index f301e76..6a6a628 100644 --- a/src/cups-pk-helper-mechanism.c +++ b/src/cups-pk-helper-mechanism.c @@ -47,6 +47,8 @@ #include <polkit-dbus/polkit-dbus.h> +#include <pwd.h> + #include "cups-pk-helper-mechanism.h" #include "cups-pk-helper-mechanism-glue.h" #include "cups.h" @@ -56,7 +58,8 @@ static gboolean do_exit (gpointer user_data) { - g_object_unref (CPH_MECHANISM (user_data)); + if (user_data != NULL) + g_object_unref (CPH_MECHANISM (user_data)); exit (0); @@ -465,6 +468,28 @@ _cph_mechanism_get_action_for_name (CphMechanism *mechanism, return "printer-remote-edit"; } +char * +_cph_mechanism_get_callers_user_name (CphMechanism *mechanism, + DBusGMethodInvocation *context) +{ + unsigned long sender_uid; + struct passwd *password_entry; + DBusError dbus_error; + gchar *sender; + char *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); + + g_free (sender); + + return user_name; +} /* helpers */ @@ -536,10 +561,6 @@ cph_mechanism_file_put (CphMechanism *mechanism, ret = cph_cups_file_put (mechanism->priv->cups, resource, filename); _cph_mechanism_return_error (mechanism, context, !ret); - /* TODO: this is a workaround for bnc#447422 - * https://bugzilla.novell.com/show_bug.cgi?id=447422 */ - do_exit (NULL); - return TRUE; } @@ -1016,3 +1037,115 @@ cph_mechanism_server_set_settings (CphMechanism *mechanism, return TRUE; } + +gboolean +cph_mechanism_job_cancel (CphMechanism *mechanism, + int id, + DBusGMethodInvocation *context) +{ + CphJobStatus job_status; + gboolean ret; + char *user_name = NULL; + + reset_killtimer (mechanism); + + user_name = _cph_mechanism_get_callers_user_name (mechanism, context); + job_status = cph_cups_job_get_status (mechanism->priv->cups, id, user_name); + + switch (job_status) { + case CPH_JOB_STATUS_OWNED_BY_USER: { + if (!_check_polkit_for_action_v (mechanism, context, "job-not-owned-edit", "job-edit", NULL)) + return FALSE; + break; + } + case CPH_JOB_STATUS_NOT_OWNED_BY_USER: { + if (!_check_polkit_for_action (mechanism, context, "job-not-owned-edit")) + return FALSE; + break; + } + case CPH_JOB_STATUS_INVALID: + return FALSE; + } + + ret = cph_cups_job_cancel (mechanism->priv->cups, id, user_name); + _cph_mechanism_return_error (mechanism, context, !ret); + + g_free (user_name); + + return TRUE; +} + +gboolean +cph_mechanism_job_restart (CphMechanism *mechanism, + int id, + DBusGMethodInvocation *context) +{ + CphJobStatus job_status; + gboolean ret; + char *user_name = NULL; + + reset_killtimer (mechanism); + + user_name = _cph_mechanism_get_callers_user_name (mechanism, context); + job_status = cph_cups_job_get_status (mechanism->priv->cups, id, user_name); + + switch (job_status) { + case CPH_JOB_STATUS_OWNED_BY_USER: { + if (!_check_polkit_for_action_v (mechanism, context, "job-not-owned-edit", "job-edit", NULL)) + return FALSE; + break; + } + case CPH_JOB_STATUS_NOT_OWNED_BY_USER: { + if (!_check_polkit_for_action (mechanism, context, "job-not-owned-edit")) + return FALSE; + break; + } + case CPH_JOB_STATUS_INVALID: + return FALSE; + } + + ret = cph_cups_job_restart (mechanism->priv->cups, id, user_name); + _cph_mechanism_return_error (mechanism, context, !ret); + + g_free (user_name); + + return TRUE; +} + +gboolean +cph_mechanism_job_set_hold_until (CphMechanism *mechanism, + int id, + const char *job_hold_until, + DBusGMethodInvocation *context) +{ + CphJobStatus job_status; + gboolean ret; + char *user_name = NULL; + + reset_killtimer (mechanism); + + user_name = _cph_mechanism_get_callers_user_name (mechanism, context); + job_status = cph_cups_job_get_status (mechanism->priv->cups, id, user_name); + + switch (job_status) { + case CPH_JOB_STATUS_OWNED_BY_USER: { + if (!_check_polkit_for_action_v (mechanism, context, "job-not-owned-edit", "job-edit", NULL)) + return FALSE; + break; + } + case CPH_JOB_STATUS_NOT_OWNED_BY_USER: { + if (!_check_polkit_for_action (mechanism, context, "job-not-owned-edit")) + return FALSE; + break; + } + case CPH_JOB_STATUS_INVALID: + return FALSE; + } + + ret = cph_cups_job_set_hold_until (mechanism->priv->cups, id, job_hold_until, user_name); + _cph_mechanism_return_error (mechanism, context, !ret); + + g_free (user_name); + + return TRUE; +} diff --git a/src/cups-pk-helper-mechanism.h b/src/cups-pk-helper-mechanism.h index 3305ed3..986a704 100644 --- a/src/cups-pk-helper-mechanism.h +++ b/src/cups-pk-helper-mechanism.h @@ -220,6 +220,22 @@ cph_mechanism_server_set_settings (CphMechanism *mechanism, GHashTable *settings, DBusGMethodInvocation *context); +gboolean +cph_mechanism_job_cancel (CphMechanism *mechanism, + int id, + DBusGMethodInvocation *context); + +gboolean +cph_mechanism_job_restart (CphMechanism *mechanism, + int id, + DBusGMethodInvocation *context); + +gboolean +cph_mechanism_job_set_hold_until (CphMechanism *mechanism, + int id, + const char *job_hold_until, + DBusGMethodInvocation *context); + G_END_DECLS #endif /* CPH_MECHANISM_H */ diff --git a/src/cups-pk-helper-mechanism.xml b/src/cups-pk-helper-mechanism.xml index f0d3857..b7d4d07 100644 --- a/src/cups-pk-helper-mechanism.xml +++ b/src/cups-pk-helper-mechanism.xml @@ -174,5 +174,23 @@ <arg name="error" direction="out" type="s"/> </method> + <method name="JobCancel"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <arg name="jobid" direction="in" type="i"/> + <arg name="error" direction="out" type="s"/> + </method> + + <method name="JobRestart"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <arg name="jobid" direction="in" type="i"/> + <arg name="error" direction="out" type="s"/> + </method> + + <method name="JobSetHoldUntil"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <arg name="jobid" direction="in" type="i"/> + <arg name="job_hold_until" direction="in" type="s"/> + <arg name="error" direction="out" type="s"/> + </method> </interface> </node> @@ -45,6 +45,9 @@ #include "cups.h" +#define MAX_RECONNECT_ATTEMPTS 100 +#define RECONNECT_DELAY 100000 + /* getPrinters getDests @@ -114,6 +117,7 @@ struct CphCupsPrivate http_t *connection; ipp_status_t last_status; char *internal_status; + gboolean reconnecting; }; static GObject *cph_cups_constructor (GType type, @@ -172,6 +176,30 @@ cph_cups_init (CphCups *cups) cups->priv->connection = NULL; cups->priv->last_status = IPP_OK; cups->priv->internal_status = NULL; + cups->priv->reconnecting = FALSE; +} + +gboolean +cph_cups_reconnect (CphCups *cups) +{ + int return_value = -1; + int i; + + cups->priv->reconnecting = TRUE; + + for (i = 0; i < MAX_RECONNECT_ATTEMPTS; i++) { + return_value = httpReconnect (cups->priv->connection); + if (return_value == 0) + break; + g_usleep (RECONNECT_DELAY); + } + + cups->priv->reconnecting = FALSE; + + if (return_value == 0) + return TRUE; + else + return FALSE; } static void @@ -318,6 +346,7 @@ _CPH_CUPS_IS_VALID (ppd_filename, "PPD file", FALSE) _CPH_CUPS_IS_VALID (job_sheet, "job sheet", FALSE) _CPH_CUPS_IS_VALID (error_policy, "error policy", FALSE) _CPH_CUPS_IS_VALID (op_policy, "op policy", FALSE) +_CPH_CUPS_IS_VALID (job_hold_until, "job hold until", FALSE) /* Check for users. Those are some printable strings, which souldn't be NULL. * They should also not be empty, but it appears that it's possible to carry @@ -381,6 +410,18 @@ _cph_cups_add_class_uri (ipp_t *request, } static void +_cph_cups_add_job_uri (ipp_t *request, + int 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 +582,52 @@ _cph_cups_send_new_printer_class_request (CphCups *cups, 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, + int job_id, + const char *user_name, + CphResource resource) +{ + ipp_t *request; + + request = ippNewRequest (op); + + if (user_name != NULL) + ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, user_name); + + _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, + int job_id, + const char *name, + const char *value, + const char *user_name, + CphResource resource) +{ + cups_option_t *options = NULL; + ipp_t *request; + int num_options = 0; + + request = ippNewRequest (IPP_SET_JOB_ATTRIBUTES); + _cph_cups_add_job_uri (request, job_id); + + if (user_name != NULL) + ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, user_name); + + 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, @@ -801,6 +888,10 @@ cph_cups_file_get (CphCups *cups, const char *resource, const char *filename) { + struct stat file_stat; + uid_t uid = 0; + gid_t gid = 0; + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); if (!_cph_cups_is_resource_valid (cups, resource)) @@ -808,12 +899,33 @@ cph_cups_file_get (CphCups *cups, if (!_cph_cups_is_filename_valid (cups, filename)) return FALSE; + stat (filename, &file_stat); + uid = file_stat.st_uid; + gid = file_stat.st_gid; + /* reset the internal status: we'll use the cups status */ _cph_cups_set_internal_status (cups, NULL); cups->priv->last_status = cupsGetFile (cups->priv->connection, resource, filename); + if (cups->priv->last_status != HTTP_OK) { + int fd; + + if (cph_cups_reconnect (cups)) { + + /* if cupsGetFile fail then filename is erased */ + fd = open (filename, O_CREAT, S_IRUSR | S_IWUSR); + close (fd); + chown (filename, uid, gid); + + _cph_cups_set_internal_status (cups, NULL); + + cups->priv->last_status = cupsGetFile (cups->priv->connection, + resource, filename); + } + } + return cups->priv->last_status == HTTP_OK; } @@ -835,6 +947,9 @@ cph_cups_file_put (CphCups *cups, cups->priv->last_status = cupsPutFile (cups->priv->connection, resource, filename); + /* CUPS is being restarted, so we need to reconnect */ + cph_cups_reconnect (cups); + return (cups->priv->last_status == HTTP_OK || cups->priv->last_status == HTTP_CREATED); } @@ -1566,6 +1681,9 @@ cph_cups_server_set_settings (CphCups *cups, retval = cupsAdminSetServerSettings (cups->priv->connection, num_settings, cups_settings); + /* CUPS is being restarted, so we need to reconnect */ + cph_cups_reconnect (cups); + cupsFreeOptions (num_settings, cups_settings); if (retval == 0) { @@ -1581,6 +1699,79 @@ cph_cups_server_set_settings (CphCups *cups, return TRUE; } +gboolean +cph_cups_job_cancel (CphCups *cups, + int job_id, + const char *user_name) +{ + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + return _cph_cups_send_new_simple_job_request (cups, IPP_CANCEL_JOB, + job_id, + user_name, + CPH_RESOURCE_ADMIN); +} + +gboolean +cph_cups_job_restart (CphCups *cups, + int job_id, + const char *user_name) +{ + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + return _cph_cups_send_new_simple_job_request (cups, IPP_RESTART_JOB, + job_id, + user_name, + CPH_RESOURCE_ADMIN); +} + +gboolean +cph_cups_job_set_hold_until (CphCups *cups, + int job_id, + const char *job_hold_until, + const char *user_name) +{ + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + if (!_cph_cups_is_job_hold_until_valid (cups, job_hold_until)) + return FALSE; + + return _cph_cups_send_new_job_attributes_request (cups, + job_id, + "job-hold-until", + job_hold_until, + user_name, + CPH_RESOURCE_ADMIN); +} + +CphJobStatus +cph_cups_job_get_status (CphCups *cups, + int job_id, + const char *user) +{ + CphJobStatus status = CPH_JOB_STATUS_INVALID; + cups_job_t *jobs; + int num_jobs = 0; + int i; + + g_return_val_if_fail (CPH_IS_CUPS (cups), CPH_JOB_STATUS_INVALID); + + num_jobs = cupsGetJobs2 (cups->priv->connection, &jobs, NULL, 0, 0); + + for (i = 0; i < num_jobs; i++) { + if (jobs[i].id == job_id) { + status = CPH_JOB_STATUS_NOT_OWNED_BY_USER; + if (user != NULL && g_strcmp0 (jobs[i].user, user) == 0) + status = CPH_JOB_STATUS_OWNED_BY_USER; + break; + } + } + + cupsFreeJobs (num_jobs, jobs); + + return status; +} + /****************************************************** * Non-object functions ******************************************************/ @@ -1606,6 +1797,7 @@ cph_cups_is_printer_uri_local (const char *uri) g_str_has_prefix (lower_uri, "beh:") || g_str_has_prefix (lower_uri, "scsi:") || g_str_has_prefix (lower_uri, "serial:") || + g_str_has_prefix (lower_uri, "file:") || g_str_has_prefix (lower_uri, "pipe:")) { g_free (lower_uri); return TRUE; @@ -48,6 +48,13 @@ typedef struct GObjectClass parent_class; } CphCupsClass; +typedef enum +{ + CPH_JOB_STATUS_INVALID, + CPH_JOB_STATUS_OWNED_BY_USER, + CPH_JOB_STATUS_NOT_OWNED_BY_USER +} CphJobStatus; + GType cph_cups_get_type (void); CphCups *cph_cups_new (void); @@ -160,6 +167,23 @@ gboolean cph_cups_is_printer_local (CphCups *cups, gboolean cph_cups_is_printer_uri_local (const char *uri); +gboolean cph_cups_job_cancel (CphCups *cups, + int job_id, + const char *user_name); + +gboolean cph_cups_job_restart (CphCups *cups, + int job_id, + const char *user_name); + +gboolean cph_cups_job_set_hold_until (CphCups *cups, + int job_id, + const char *job_hold_until, + const char *user_name); + +CphJobStatus cph_cups_job_get_status (CphCups *cups, + int job_id, + const char *user); + G_END_DECLS #endif /* CPH_CUPS_H */ diff --git a/src/org.opensuse.cupspkhelper.mechanism.policy.in b/src/org.opensuse.cupspkhelper.mechanism.policy.in index cbff03a..7c6ba58 100644 --- a/src/org.opensuse.cupspkhelper.mechanism.policy.in +++ b/src/org.opensuse.cupspkhelper.mechanism.policy.in @@ -68,6 +68,24 @@ </defaults> </action> + <action id="org.opensuse.cupspkhelper.mechanism.job-edit"> + <_description>Restart/Cancel/Edit a job</_description> + <_message>Privileges are required to restart/cancel/edit a job.</_message> + <defaults> + <allow_inactive>no</allow_inactive> + <allow_active>auth_self</allow_active> + </defaults> + </action> + + <action id="org.opensuse.cupspkhelper.mechanism.job-not-owned-edit"> + <_description>Restart/Cancel/Edit a job owned by another user</_description> + <_message>Privileges are required to restart/cancel/edit a job owned by another user.</_message> + <defaults> + <allow_inactive>no</allow_inactive> + <allow_active>auth_admin</allow_active> + </defaults> + </action> + <!-- Deprecated --> <action id="org.opensuse.cupspkhelper.mechanism.printeraddremove"> <_description>Add/Remove/Edit a printer</_description> |