summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Kasik <mkasik@redhat.com>2009-02-17 16:55:54 +0100
committerVincent Untz <vuntz@novell.com>2009-02-28 02:24:22 +0100
commit2a6fb5b50a5cfd790a24c69ab5fe7e26dab3a4ba (patch)
tree27d1c4727571cd6f25cc817cca19c11b3755e0bd
parent87f6b0f3669e11e565b1288cb59e4479dc76ad50 (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.c143
-rw-r--r--src/cups-pk-helper-mechanism.h16
-rw-r--r--src/cups-pk-helper-mechanism.xml18
-rw-r--r--src/cups.c192
-rw-r--r--src/cups.h24
-rw-r--r--src/org.opensuse.cupspkhelper.mechanism.policy.in18
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>
diff --git a/src/cups.c b/src/cups.c
index 2d4ffda..00ed4fc 100644
--- a/src/cups.c
+++ b/src/cups.c
@@ -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;
diff --git a/src/cups.h b/src/cups.h
index b13751b..0044e4a 100644
--- a/src/cups.h
+++ b/src/cups.h
@@ -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>