diff options
author | Vincent Untz <vuntz@novell.com> | 2008-09-21 06:48:34 +0200 |
---|---|---|
committer | Vincent Untz <vuntz@novell.com> | 2008-09-21 06:48:34 +0200 |
commit | e992a74d8f8ef2b0e28c035322ab67b97afd3f0f (patch) | |
tree | f672a40e07c9016a46e282494f4c62d8c0a535bd | |
parent | b4276a418cda637167be754a9dd5574505485fdf (diff) |
First pass at this.
There are two smalls test program to show this works :-)
-rw-r--r-- | .gitignore | 8 | ||||
-rwxr-xr-x | autogen.sh | 2 | ||||
-rw-r--r-- | configure.ac | 16 | ||||
-rw-r--r-- | src/Makefile.am | 41 | ||||
-rw-r--r-- | src/cups-methods.c | 0 | ||||
-rw-r--r-- | src/cups-pk-helper-mechanism.c | 101 | ||||
-rw-r--r-- | src/cups-pk-helper-mechanism.h | 9 | ||||
-rw-r--r-- | src/cups-pk-helper-mechanism.xml | 11 | ||||
-rw-r--r-- | src/cups.c | 683 | ||||
-rw-r--r-- | src/cups.h | 115 | ||||
-rw-r--r-- | src/main.c | 4 | ||||
-rw-r--r-- | src/org.opensuse.CupsPkHelper.Mechanism.conf (renamed from src/org.opensuse.cups-pk-helper.Mechanism.conf) | 4 | ||||
-rw-r--r-- | src/org.opensuse.CupsPkHelper.Mechanism.service.in (renamed from src/org.opensuse.cups-pk-helper.Mechanism.service.in) | 2 | ||||
-rw-r--r-- | src/org.opensuse.cupspkhelper.mechanism.policy.in (renamed from src/org.opensuse.cups-pk-helper.mechanism.policy.in) | 9 | ||||
-rw-r--r-- | src/test-cups-pk.c | 178 | ||||
-rw-r--r-- | src/test-cups.c | 52 |
16 files changed, 1212 insertions, 23 deletions
@@ -8,7 +8,7 @@ autom4te.cache/ compile config.guess config.h -config.h.in +config.h.in* config.log config.status config.sub @@ -33,6 +33,8 @@ src/Makefile src/Makefile.in src/cups-pk-helper-mechanism src/cups-pk-helper-mechanism-glue.h -src/org.opensuse.cups-pk-helper.Mechanism.service -src/org.opensuse.cups-pk-helper.mechanism.policy +src/org.opensuse.CupsPkHelper.Mechanism.service +src/org.opensuse.cupspkhelper.mechanism.policy +src/test-cups +src/test-cups-pk stamp-h1 @@ -7,7 +7,7 @@ test -z "$srcdir" && srcdir=. PKG_NAME="CUPS PolicyKit helper" (test -f $srcdir/configure.ac \ - && test -f $srcdir/src/cups-methods.c) || { + && test -f $srcdir/src/cups-pk-helper-mechanism.c) || { echo -n "**Error**: Directory "\`$srcdir\'" does not look like the" echo " top-level package directory" exit 1 diff --git a/configure.ac b/configure.ac index 4b42b54..560a034 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ AC_INIT([cups-pk-helper], [0.0.1], [https://bugzilla.novell.com/enter_bug.cgi?classification=7340&product=openSUSE+11.1]) -AC_CONFIG_SRCDIR(src/cups-methods.c) +AC_CONFIG_SRCDIR(src/cups-pk-helper-mechanism.c) AM_INIT_AUTOMAKE([1.9 no-dist-gzip dist-bzip2]) AM_CONFIG_HEADER(config.h) @@ -43,6 +43,8 @@ GLIB_REQUIRED=2.14.0 DBUS_REQUIRED=1.1.2 DBUS_GLIB_REQUIRED=0.74 POLKIT_DBUS_REQUIRED=0.8 +GTK_REQUIRED=2.12.0 +POLKIT_GNOME_REQUIRED=0.7 # pkg-config dependency checks PKG_CHECK_MODULES(CUPS_PK, glib-2.0 >= $GLIB_REQUIRED \ @@ -55,6 +57,18 @@ PKG_CHECK_MODULES(CUPS_PK, glib-2.0 >= $GLIB_REQUIRED \ AC_SUBST(CUPS_PK_CFLAGS) AC_SUBST(CUPS_PK_LIBS) +PKG_CHECK_MODULES(CUPS_PK_GNOME, gtk+-2.0 >= $GTK_REQUIRED \ + polkit-gnome >= $POLKIT_GNOME_REQUIRED \ + dbus-1 >= $DBUS_REQUIRED \ + dbus-glib-1 >= $DBUS_GLIB_REQUIRED) +AC_SUBST(CUPS_PK_GNOME_CFLAGS) +AC_SUBST(CUPS_PK_GNOME_LIBS) + +# check for cups +AC_CHECK_HEADERS(cups/cups.h cups/http.h cups/ipp.h) +CUPS_LIBS=-lcups +AC_SUBST(CUPS_LIBS) + AC_OUTPUT([ Makefile src/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index bd6e2d3..eaf91cb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,22 +1,45 @@ -INCLUDES = \ +INCLUDES = \ + $(WARN_CFLAGS) \ + $(DISABLE_DEPRECATED_CFLAGS) \ $(CUPS_PK_CFLAGS) - libexec_PROGRAMS = cups-pk-helper-mechanism +noinst_PROGRAMS = \ + test-cups \ + test-cups-pk + cups-pk-helper-mechanism-glue.h: $(srcdir)/cups-pk-helper-mechanism.xml dbus-binding-tool --prefix=cph_mechanism --mode=glib-server \ --output=cups-pk-helper-mechanism-glue.h \ $(srcdir)/cups-pk-helper-mechanism.xml cups_pk_helper_mechanism_SOURCES = \ - cups-methods.c \ - cups-methods.h \ + cups.c \ + cups.h \ cups-pk-helper-mechanism.c \ cups-pk-helper-mechanism.h \ main.c cups_pk_helper_mechanism_LDADD = \ - $(CUPS_PK_LIBS) + $(CUPS_PK_LIBS) \ + $(CUPS_LIBS) + +test_cups_SOURCES = \ + cups.c \ + cups.h \ + test-cups.c +test_cups_LDADD = \ + $(CUPS_PK_LIBS) \ + $(CUPS_LIBS) + +test_cups_pk_SOURCES = \ + test-cups-pk.c +test_cups_pk_CFLAGS = \ + $(CUPS_PK_GNOME_CFLAGS) +test_cups_pk_LDADD = \ + $(CUPS_PK_GNOME_LIBS) \ + $(CUPS_PK_LIBS) \ + $(CUPS_LIBS) BUILT_SOURCES = cups-pk-helper-mechanism-glue.h @@ -25,15 +48,15 @@ dbus_servicesdir = $(datadir)/dbus-1/system-services dbus_confdir = $(sysconfdir)/dbus-1/system.d polkitdir = $(datadir)/PolicyKit/policy -dbus_services_in_files = org.opensuse.cups-pk-helper.Mechanism.service.in -polkit_in_files = org.opensuse.cups-pk-helper.mechanism.policy.in +dbus_services_in_files = org.opensuse.CupsPkHelper.Mechanism.service.in +polkit_in_files = org.opensuse.cupspkhelper.mechanism.policy.in dbus_services_DATA = $(dbus_services_in_files:.service.in=.service) $(dbus_services_DATA): $(dbus_services_in_files) sed -e "s|\@LIBEXECDIR\@|$(libexecdir)|" $< > $@ -dbus_conf_DATA = org.opensuse.cups-pk-helper.Mechanism.conf +dbus_conf_DATA = org.opensuse.CupsPkHelper.Mechanism.conf @INTLTOOL_POLICY_RULE@ polkit_DATA = $(polkit_in_files:.policy.in=.policy) @@ -45,7 +68,7 @@ check: EXTRA_DIST = \ $(dbus_services_in_files) \ - org.opensuse.cups-pk-helper.Mechanism.conf \ + org.opensuse.CupsPkHelper.Mechanism.conf \ $(polkit_in_files) \ cups-pk-helper-mechanism.xml diff --git a/src/cups-methods.c b/src/cups-methods.c deleted file mode 100644 index e69de29..0000000 --- a/src/cups-methods.c +++ /dev/null diff --git a/src/cups-pk-helper-mechanism.c b/src/cups-pk-helper-mechanism.c index 64f1487..91944e3 100644 --- a/src/cups-pk-helper-mechanism.c +++ b/src/cups-pk-helper-mechanism.c @@ -1,4 +1,5 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * vim: set et ts=8 sw=8: * * Copyright (C) 2008 Novell, Inc. * @@ -48,26 +49,29 @@ #include "cups-pk-helper-mechanism.h" #include "cups-pk-helper-mechanism-glue.h" +#include "cups.h" /* exit timer */ static gboolean do_exit (gpointer user_data) { + g_object_unref (CPH_MECHANISM (user_data)); + exit (0); return FALSE; } static void -reset_killtimer (void) +reset_killtimer (CphMechanism *mechanism) { static guint timer_id = 0; if (timer_id > 0) g_source_remove (timer_id); - timer_id = g_timeout_add_seconds (30, do_exit, NULL); + timer_id = g_timeout_add_seconds (30, do_exit, mechanism); } /* error */ @@ -118,11 +122,23 @@ struct CphMechanismPrivate { DBusGConnection *system_bus_connection; PolKitContext *pol_ctx; + CphCups *cups; }; +static GObject *cph_mechanism_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties); +static void cph_mechanism_finalize (GObject *object); + + static void cph_mechanism_class_init (CphMechanismClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructor = cph_mechanism_constructor; + object_class->finalize = cph_mechanism_finalize; + g_type_class_add_private (klass, sizeof (CphMechanismPrivate)); dbus_g_object_type_install_info (CPH_TYPE_MECHANISM, @@ -132,10 +148,53 @@ cph_mechanism_class_init (CphMechanismClass *klass) CPH_MECHANISM_TYPE_ERROR); } +static GObject * +cph_mechanism_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *obj; + CphMechanism *mechanism; + + obj = G_OBJECT_CLASS (cph_mechanism_parent_class)->constructor ( + type, + n_construct_properties, + construct_properties); + + mechanism = CPH_MECHANISM (obj); + mechanism->priv->cups = cph_cups_new (); + + if (!mechanism->priv->cups) { + g_object_unref (mechanism); + return NULL; + } + + return obj; +} + static void cph_mechanism_init (CphMechanism *mechanism) { mechanism->priv = CPH_MECHANISM_GET_PRIVATE (mechanism); + + mechanism->priv->cups = NULL; +} + +static void +cph_mechanism_finalize (GObject *object) +{ + CphMechanism *mechanism; + + g_return_if_fail (object != NULL); + g_return_if_fail (CPH_IS_MECHANISM (object)); + + mechanism = CPH_MECHANISM (object); + + if (mechanism->priv->cups) + g_object_unref (mechanism->priv->cups); + mechanism->priv->cups = NULL; + + G_OBJECT_CLASS (cph_mechanism_parent_class)->finalize (object); } static gboolean @@ -210,7 +269,7 @@ register_mechanism (CphMechanism *mechanism) dbus_g_connection_register_g_object (mechanism->priv->system_bus_connection, "/", G_OBJECT (mechanism)); - reset_killtimer (); + reset_killtimer (mechanism); return TRUE; } @@ -234,7 +293,7 @@ cph_mechanism_new (void) static gboolean _check_polkit_for_action (CphMechanism *mechanism, DBusGMethodInvocation *context, - const char *action) + const char *action_method) { const char *sender; GError *error; @@ -242,9 +301,13 @@ _check_polkit_for_action (CphMechanism *mechanism, PolKitCaller *pk_caller; PolKitAction *pk_action; PolKitResult pk_result; + char *action; error = NULL; + action = g_strdup_printf ("org.opensuse.cupspkhelper.mechanism.%s", + action_method); + /* Check that caller is privileged */ sender = dbus_g_method_get_sender (context); dbus_error_init (&dbus_error); @@ -263,6 +326,7 @@ _check_polkit_for_action (CphMechanism *mechanism, dbus_error_free (&dbus_error); dbus_g_method_return_error (context, error); g_error_free (error); + g_free (action); return FALSE; } @@ -284,11 +348,40 @@ _check_polkit_for_action (CphMechanism *mechanism, dbus_error_free (&dbus_error); dbus_g_method_return_error (context, error); g_error_free (error); + g_free (action); return FALSE; } + g_free (action); + return TRUE; } /* exported methods */ + +gboolean +cph_mechanism_printer_add (CphMechanism *mechanism, + const char *name, + const char *uri, + const char *ppd, + const char *info, + const char *location, + DBusGMethodInvocation *context) +{ + const char *error; + + reset_killtimer (mechanism); + + if (!_check_polkit_for_action (mechanism, context, "printeradd")) + return FALSE; + + if (!cph_cups_printer_add (mechanism->priv->cups, + name, uri, ppd, info, location)) + error = cph_cups_last_status_to_string (mechanism->priv->cups); + else + error = ""; + + dbus_g_method_return (context, error); + return TRUE; +} diff --git a/src/cups-pk-helper-mechanism.h b/src/cups-pk-helper-mechanism.h index ae14a52..c005ad2 100644 --- a/src/cups-pk-helper-mechanism.h +++ b/src/cups-pk-helper-mechanism.h @@ -1,4 +1,5 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * vim: set et ts=8 sw=8: * * Copyright (C) 2008 Novell, Inc. * @@ -73,6 +74,14 @@ CphMechanism *cph_mechanism_new (void); /* exported methods */ +gboolean cph_mechanism_printer_add (CphMechanism *mechanism, + const char *name, + const char *uri, + const char *ppd, + const char *info, + const char *location, + 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 63975de..74eb4a5 100644 --- a/src/cups-pk-helper-mechanism.xml +++ b/src/cups-pk-helper-mechanism.xml @@ -1,5 +1,14 @@ <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node name="/"> - <interface name="org.opensuse.cups-pk-helper.Mechanism"> + <interface name="org.opensuse.CupsPkHelper.Mechanism"> + <method name="PrinterAdd"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <arg name="name" direction="in" type="s"/> + <arg name="uri" direction="in" type="s"/> + <arg name="ppd" direction="in" type="s"/> + <arg name="info" direction="in" type="s"/> + <arg name="location" direction="in" type="s"/> + <arg name="error" direction="out" type="s"/> + </method> </interface> </node> diff --git a/src/cups.c b/src/cups.c new file mode 100644 index 0000000..018c93e --- /dev/null +++ b/src/cups.c @@ -0,0 +1,683 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * vim: set et ts=8 sw=8: + * + * Copyright (C) 2008 Novell, Inc. + * + * Authors: Vincent Untz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <ctype.h> +#include <sys/wait.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> + +#include <config.h> + +#include <glib.h> +#include <glib/gstdio.h> +#include <glib/gi18n.h> + +#include <cups/cups.h> +#include <cups/http.h> +#include <cups/ipp.h> + +#include "cups.h" + +/* + getPrinters + getDests + getClasses + getPPDs + getServerPPD + getDocument + getDevices + getJobs + getJobAttributes + ! cancelJob + ! cancelAllJobs + ! authenticateJob + ! setJobHoldUntil + ! restartJob + getFile + putFile +~! addPrinter +~! setPrinterDevice +~! setPrinterInfo +~! setPrinterLocation +~! setPrinterShared +~! setPrinterJobSheets +~! setPrinterErrorPolicy +~! setPrinterOpPolicy + ! setPrinterUsersAllowed + ! setPrinterUsersDenied +~! addPrinterOptionDefault +~! deletePrinterOptionDefault +~! deletePrinter + getPrinterAttributes + ! addPrinterToClass + ! deletePrinterFromClass + ! deleteClass + getDefault +~! setDefault + getPPD +~! enablePrinter +~! disablePrinter +~! acceptJobs +~! rejectJobs + printTestPage + ! adminGetServerSettings + ! adminSetServerSettings + getSubscriptions + createSubscription + getNotifications + cancelSubscription + renewSubscription + printFile + printFiles +*/ + +G_DEFINE_TYPE (CphCups, cph_cups, G_TYPE_OBJECT) + +#define CPH_CUPS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CPH_TYPE_CUPS, CphCupsPrivate)) + +struct CphCupsPrivate +{ + http_t *connection; + ipp_status_t last_status; +}; + +static GObject *cph_cups_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties); +static void cph_cups_finalize (GObject *object); + + +static void +cph_cups_class_init (CphCupsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructor = cph_cups_constructor; + object_class->finalize = cph_cups_finalize; + + g_type_class_add_private (klass, sizeof (CphCupsPrivate)); +} + +static GObject * +cph_cups_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *obj; + CphCups *cups; + + obj = G_OBJECT_CLASS (cph_cups_parent_class)->constructor ( + type, + n_construct_properties, + construct_properties); + + cups = CPH_CUPS (obj); + + cups->priv->connection = httpConnectEncrypt (cupsServer (), + ippPort (), + cupsEncryption ()); + + if (!cups->priv->connection) { + g_critical ("Failed to connect to cupsd"); + g_object_unref (cups); + return NULL; + } + + return obj; +} + +static void +cph_cups_init (CphCups *cups) +{ + cups->priv = CPH_CUPS_GET_PRIVATE (cups); + + cups->priv->connection = NULL; + cups->priv->last_status = IPP_OK; +} + +static void +cph_cups_finalize (GObject *object) +{ + CphCups *cups; + + g_return_if_fail (object != NULL); + g_return_if_fail (CPH_IS_CUPS (object)); + + cups = CPH_CUPS (object); + + if (cups->priv->connection) + httpClose (cups->priv->connection); + cups->priv->connection = NULL; + + G_OBJECT_CLASS (cph_cups_parent_class)->finalize (object); +} + +CphCups * +cph_cups_new (void) +{ + return g_object_new (CPH_TYPE_CUPS, NULL); +} + +/****************************************************** + * Validation + ******************************************************/ + +static gboolean +_cph_cups_is_printer_name_valid (const char *name) +{ + if (!name || name[0] == '\0') + return FALSE; + + /* FIXME: what's a valid printer name? No space/tabs, etc. */ + return TRUE; +} + +/****************************************************** + * Helpers + ******************************************************/ + +static void +_cph_cups_add_printer_uri (ipp_t *request, + const char *name) +{ + char uri[HTTP_MAX_URI + 1]; + + g_snprintf (uri, sizeof (uri), + "ipp://localhost/printers/%s", name); + ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, uri); +} + +static void +_cph_cups_add_class_uri (ipp_t *request, + const char *name) +{ + char uri[HTTP_MAX_URI + 1]; + + g_snprintf (uri, sizeof (uri), + "ipp://localhost/classes/%s", name); + ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, uri); +} + +static void +_cph_cups_set_error_from_reply (CphCups *cups, + ipp_t *reply) +{ + if (reply) + cups->priv->last_status = reply->request.status.status_code; + else + cups->priv->last_status = cupsLastError (); +} + +static gboolean +_cph_cups_send_request (CphCups *cups, + ipp_t *request) +{ + gboolean retval; + ipp_t *reply; + + reply = cupsDoRequest (cups->priv->connection, request, "/"); + + if (!reply || reply->request.status.status_code > IPP_OK_CONFLICT) { + retval = FALSE; + _cph_cups_set_error_from_reply (cups, reply); + } else { + retval = TRUE; + cups->priv->last_status = IPP_OK; + } + + if (reply) + ippDelete (reply); + + return retval; +} + +static gboolean +_cph_cups_send_new_simple_request (CphCups *cups, + ipp_op_t op, + const char *printer_name) +{ + ipp_t *request; + + if (!_cph_cups_is_printer_name_valid (printer_name)) + /* FIXME: set status */ + return FALSE; + + request = ippNewRequest (IPP_PAUSE_PRINTER); + _cph_cups_add_printer_uri (request, printer_name); + + return _cph_cups_send_request (cups, request); +} + +static gboolean +_cph_cups_send_new_printer_class_request (CphCups *cups, + const char *printer_name, + ipp_tag_t group, + ipp_tag_t type, + const char *name, + const char *value) +{ + ipp_t *request; + + request = ippNewRequest (CUPS_ADD_MODIFY_PRINTER); + _cph_cups_add_printer_uri (request, printer_name); + ippAddString (request, group, type, name, NULL, value); + + if (_cph_cups_send_request (cups, request)) + return TRUE; + + /* it failed, maybe it was a class? */ + if (cups->priv->last_status != IPP_NOT_POSSIBLE) + return FALSE; + + request = ippNewRequest (CUPS_ADD_MODIFY_CLASS); + _cph_cups_add_class_uri (request, printer_name); + ippAddString (request, group, type, name, NULL, value); + + return _cph_cups_send_request (cups, request); +} + +/****************************************************** + * Now, the real methods + ******************************************************/ + +const char * +cph_cups_last_status_to_string (CphCups *cups) +{ + g_return_val_if_fail (CPH_IS_CUPS (cups), ""); + + return ippErrorString (cups->priv->last_status); +} + +gboolean +cph_cups_printer_add (CphCups *cups, + const char *printer_name, + const char *printer_uri, + const char *ppd_file, + const char *info, + const char *location) +{ + /* TODO: we might need to support putting a file on the server */ + ipp_t *request; + + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + /* FIXME check arguments are fine */ + + request = ippNewRequest (CUPS_ADD_MODIFY_PRINTER); + _cph_cups_add_printer_uri (request, printer_name); + + ippAddString (request, IPP_TAG_PRINTER, IPP_TAG_NAME, + "printer-name", NULL, printer_name); + ippAddString (request, IPP_TAG_PRINTER, IPP_TAG_URI, + "device-uri", NULL, printer_uri); + ippAddString (request, IPP_TAG_PRINTER, IPP_TAG_NAME, + "ppd-name", NULL, ppd_file); + + if (info) { + ippAddString (request, IPP_TAG_PRINTER, IPP_TAG_TEXT, + "printer-info", NULL, info); + } + if (location) { + ippAddString (request, IPP_TAG_PRINTER, IPP_TAG_TEXT, + "printer-location", NULL, location); + } + + return _cph_cups_send_request (cups, request); +} + +gboolean +cph_cups_printer_delete (CphCups *cups, + const char *printer_name) +{ + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + return _cph_cups_send_new_simple_request (cups, CUPS_DELETE_PRINTER, + printer_name); +} + +gboolean +cph_cups_printer_set_default (CphCups *cups, + const char *printer_name) +{ + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + return _cph_cups_send_new_simple_request (cups, CUPS_SET_DEFAULT, + printer_name); +} + +gboolean +cph_cups_printer_set_enabled (CphCups *cups, + const char *printer_name, + gboolean enabled) +{ + ipp_op_t op; + + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + op = enabled ? IPP_RESUME_PRINTER : IPP_PAUSE_PRINTER; + + return _cph_cups_send_new_simple_request (cups, op, printer_name); +} + +gboolean +cph_cups_printer_set_uri (CphCups *cups, + const char *printer_name, + const char *printer_uri) +{ + ipp_t *request; + + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + /* FIXME check arguments are fine */ + + request = ippNewRequest (CUPS_ADD_MODIFY_PRINTER); + _cph_cups_add_printer_uri (request, printer_name); + + ippAddString (request, IPP_TAG_PRINTER, IPP_TAG_URI, + "device-uri", NULL, printer_uri); + + return _cph_cups_send_request (cups, request); +} + +/* reason must be NULL if accept is TRUE */ +gboolean +cph_cups_printer_set_accept_jobs (CphCups *cups, + const char *printer_name, + gboolean accept, + const char *reason) +{ + ipp_t *request; + + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + g_return_val_if_fail (!accept || reason == NULL, FALSE); + + /* FIXME check arguments are fine */ + + if (accept) + return _cph_cups_send_new_simple_request (cups, + CUPS_ACCEPT_JOBS, + printer_name); + + /* !accept */ + request = ippNewRequest (CUPS_REJECT_JOBS); + _cph_cups_add_printer_uri (request, printer_name); + + if (reason) + ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_TEXT, + "printer-state-message", NULL, reason); + + return _cph_cups_send_request (cups, request); +} + +/* Functions that can work on printer and class */ + +gboolean +cph_cups_printer_class_set_info (CphCups *cups, + const char *printer_name, + const char *info) +{ + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + /* FIXME check arguments are fine */ + + return _cph_cups_send_new_printer_class_request (cups, printer_name, + IPP_TAG_PRINTER, + IPP_TAG_TEXT, + "printer-info", + info); +} + +gboolean +cph_cups_printer_class_set_location (CphCups *cups, + const char *printer_name, + const char *location) +{ + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + /* FIXME check arguments are fine */ + + return _cph_cups_send_new_printer_class_request (cups, printer_name, + IPP_TAG_PRINTER, + IPP_TAG_TEXT, + "printer-location", + location); +} + +gboolean +cph_cups_printer_class_set_shared (CphCups *cups, + const char *printer_name, + gboolean shared) +{ + ipp_t *request; + + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + /* FIXME check arguments are fine */ + + request = ippNewRequest (CUPS_ADD_MODIFY_PRINTER); + _cph_cups_add_printer_uri (request, printer_name); + ippAddBoolean (request, IPP_TAG_OPERATION, + "printer-is-shared", shared ? 1 : 0); + + if (_cph_cups_send_request (cups, request)) + return TRUE; + + /* it failed, maybe it was a class? */ + if (cups->priv->last_status != IPP_NOT_POSSIBLE) + return FALSE; + + request = ippNewRequest (CUPS_ADD_MODIFY_CLASS); + _cph_cups_add_class_uri (request, printer_name); + ippAddBoolean (request, IPP_TAG_OPERATION, + "printer-is-shared", shared ? 1 : 0); + + return _cph_cups_send_request (cups, request); +} + +gboolean +cph_cups_printer_class_set_job_sheets (CphCups *cups, + const char *printer_name, + const char *start, + const char *end) +{ + ipp_t *request; + const char * const values[2] = { start, end }; + + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + /* FIXME check arguments are fine */ + + request = ippNewRequest (CUPS_ADD_MODIFY_PRINTER); + _cph_cups_add_printer_uri (request, printer_name); + ippAddStrings (request, IPP_TAG_PRINTER, IPP_TAG_NAME, + "job-sheets-default", 2, NULL, values); + + if (_cph_cups_send_request (cups, request)) + return TRUE; + + /* it failed, maybe it was a class? */ + if (cups->priv->last_status != IPP_NOT_POSSIBLE) + return FALSE; + + request = ippNewRequest (CUPS_ADD_MODIFY_CLASS); + _cph_cups_add_class_uri (request, printer_name); + ippAddStrings (request, IPP_TAG_PRINTER, IPP_TAG_NAME, + "job-sheets-default", 2, NULL, values); + + return _cph_cups_send_request (cups, request); +} + +gboolean +cph_cups_printer_class_set_error_policy (CphCups *cups, + const char *printer_name, + const char *policy) +{ + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + /* FIXME check arguments are fine */ + + return _cph_cups_send_new_printer_class_request (cups, printer_name, + IPP_TAG_PRINTER, + IPP_TAG_NAME, + "printer-error-policy", + policy); +} + +gboolean +cph_cups_printer_class_set_op_policy (CphCups *cups, + const char *printer_name, + const char *policy) +{ + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + /* FIXME check arguments are fine */ + + return _cph_cups_send_new_printer_class_request (cups, printer_name, + IPP_TAG_PRINTER, + IPP_TAG_NAME, + "printer-op-policy", + policy); +} + +/* set first_value to NULL to delete the default */ +gboolean +cph_cups_printer_class_set_option_default (CphCups *cups, + const char *printer_name, + const char *option, + const char *first_value, + ...) +{ + char *option_name; + const char *value; + va_list var_args; + GSList *values; + int len; + ipp_t *request; + ipp_attribute_t *attr; + gboolean retval; + + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + /* FIXME check arguments are fine */ + + option_name = g_strdup_printf ("%s-default", option); + + /* delete default value for option */ + if (!first_value) { + retval = _cph_cups_send_new_printer_class_request ( + cups, + printer_name, + IPP_TAG_PRINTER, + IPP_TAG_DELETEATTR, + option_name, + NULL); + g_free (option_name); + + return retval; + } + + /* set default vaule for option */ + + values = NULL; + len = 0; + value = first_value; + va_start (var_args, first_value); + + while (value) { + /* cast to remove warning */ + values = g_slist_prepend (values, (char *) value); + len++; + value = va_arg (var_args, char *); + } + + va_end (var_args); + + values = g_slist_reverse (values); + + request = ippNewRequest (CUPS_ADD_MODIFY_PRINTER); + _cph_cups_add_printer_uri (request, printer_name); + + if (len == 1) + ippAddString (request, IPP_TAG_PRINTER, IPP_TAG_NAME, + option_name, NULL, first_value); + else { + GSList *value_l; + int i; + + attr = ippAddStrings (request, IPP_TAG_PRINTER, IPP_TAG_NAME, + option_name, len, NULL, NULL); + + i = 0; + for (value_l = values; value_l; value_l = value_l->next) { + attr->values[i].string.text = g_strdup (value_l->data); + i++; + } + } + + if (_cph_cups_send_request (cups, request)) { + retval = TRUE; + goto out; + } + + /* it failed, maybe it was a class? */ + if (cups->priv->last_status != IPP_NOT_POSSIBLE) { + retval = FALSE; + goto out; + } + + request = ippNewRequest (CUPS_ADD_MODIFY_CLASS); + _cph_cups_add_class_uri (request, printer_name); + + if (len == 1) + ippAddString (request, IPP_TAG_PRINTER, IPP_TAG_NAME, + option_name, NULL, first_value); + else { + GSList *value_l; + int i; + + attr = ippAddStrings (request, IPP_TAG_PRINTER, IPP_TAG_NAME, + option_name, len, NULL, NULL); + + i = 0; + for (value_l = values; value_l; value_l = value_l->next) { + attr->values[i].string.text = g_strdup (value_l->data); + i++; + } + } + + retval = _cph_cups_send_request (cups, request); + +out: + g_free (option_name); + g_slist_free (values); + + return retval; +} diff --git a/src/cups.h b/src/cups.h new file mode 100644 index 0000000..f647ca8 --- /dev/null +++ b/src/cups.h @@ -0,0 +1,115 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * vim: set et ts=8 sw=8: + * + * Copyright (C) 2008 Novell, Inc. + * + * Authors: Vincent Untz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef CPH_CUPS_H +#define CPH_CUPS_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define CPH_TYPE_CUPS (cph_cups_get_type ()) +#define CPH_CUPS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CPH_TYPE_CUPS, CphCups)) +#define CPH_CUPS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CPH_TYPE_CUPS, CphCupsClass)) +#define CPH_IS_CUPS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CPH_TYPE_CUPS)) +#define CPH_IS_CUPS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CPH_TYPE_CUPS)) +#define CPH_CUPS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CPH_TYPE_CUPS, CphCupsClass)) + +typedef struct CphCupsPrivate CphCupsPrivate; + +typedef struct +{ + GObject parent; + CphCupsPrivate *priv; +} CphCups; + +typedef struct +{ + GObjectClass parent_class; +} CphCupsClass; + +GType cph_cups_get_type (void); + +CphCups *cph_cups_new (void); + +const char *cph_cups_last_status_to_string (CphCups *cups); + +gboolean cph_cups_printer_add (CphCups *cups, + const char *printer_name, + const char *printer_uri, + const char *ppd_file, + const char *info, + const char *location); + +gboolean cph_cups_printer_delete (CphCups *cups, + const char *printer_name); + +gboolean cph_cups_printer_set_default (CphCups *cups, + const char *printer_name); + +gboolean cph_cups_printer_set_enabled (CphCups *cups, + const char *printer_name, + gboolean enabled); + +gboolean cph_cups_printer_set_uri (CphCups *cups, + const char *printer_name, + const char *printer_uri); + +gboolean cph_cups_printer_set_accept_jobs (CphCups *cups, + const char *printer_name, + gboolean enabled, + const char *reason); + +gboolean cph_cups_printer_class_set_info (CphCups *cups, + const char *printer_name, + const char *info); + +gboolean cph_cups_printer_class_set_location (CphCups *cups, + const char *printer_name, + const char *location); + +gboolean cph_cups_printer_class_set_shared (CphCups *cups, + const char *printer_name, + gboolean shared); + +gboolean cph_cups_printer_class_set_job_sheets (CphCups *cups, + const char *printer_name, + const char *start, + const char *end); + +gboolean cph_cups_printer_class_set_error_policy (CphCups *cups, + const char *printer_name, + const char *policy); + +gboolean cph_cups_printer_class_set_op_policy (CphCups *cups, + const char *printer_name, + const char *policy); + +gboolean cph_cups_printer_class_set_option_default (CphCups *cups, + const char *printer_name, + const char *option, + const char *first_value, + ...); +G_END_DECLS + +#endif /* CPH_CUPS_H */ @@ -1,4 +1,5 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * vim: set et ts=8 sw=8: * * Copyright (C) 2008 Novell, Inc. * @@ -47,7 +48,7 @@ #include "cups-pk-helper-mechanism.h" -#define BUS_NAME "org.opensuse.cups-pk-helper.Mechanism" +#define BUS_NAME "org.opensuse.CupsPkHelper.Mechanism" static DBusGProxy * get_bus_proxy (DBusGConnection *connection) @@ -93,7 +94,6 @@ main (int argc, char **argv) CphMechanism *mechanism; DBusGProxy *bus_proxy; DBusGConnection *connection; - int ret; if (!g_thread_supported ()) g_thread_init (NULL); diff --git a/src/org.opensuse.cups-pk-helper.Mechanism.conf b/src/org.opensuse.CupsPkHelper.Mechanism.conf index e519ff8..2f47e22 100644 --- a/src/org.opensuse.cups-pk-helper.Mechanism.conf +++ b/src/org.opensuse.CupsPkHelper.Mechanism.conf @@ -7,11 +7,13 @@ <!-- Only root can own the service --> <policy user="root"> - <allow own="org.opensuse.cups-pk-helper.Mechanism"/> + <allow own="org.opensuse.CupsPkHelper.Mechanism"/> + <allow send_interface="org.opensuse.CupsPkHelper.Mechanism"/> </policy> <!-- Allow anyone to invoke methods on the interfaces --> <policy context="default"> + <allow send_interface="org.opensuse.CupsPkHelper.Mechanism"/> </policy> </busconfig> diff --git a/src/org.opensuse.cups-pk-helper.Mechanism.service.in b/src/org.opensuse.CupsPkHelper.Mechanism.service.in index 6751364..87fd6f7 100644 --- a/src/org.opensuse.cups-pk-helper.Mechanism.service.in +++ b/src/org.opensuse.CupsPkHelper.Mechanism.service.in @@ -1,4 +1,4 @@ [D-BUS Service] -Name=org.opensuse.cups-pk-helper.Mechanism +Name=org.opensuse.CupsPkHelper.Mechanism Exec=@LIBEXECDIR@/cups-pk-helper-mechanism User=root diff --git a/src/org.opensuse.cups-pk-helper.mechanism.policy.in b/src/org.opensuse.cupspkhelper.mechanism.policy.in index 27b89b7..892309d 100644 --- a/src/org.opensuse.cups-pk-helper.mechanism.policy.in +++ b/src/org.opensuse.cupspkhelper.mechanism.policy.in @@ -7,4 +7,13 @@ <vendor>The openSUSE Project</vendor> <vendor_url>http://www.opensuse.org/</vendor_url> <icon_name>printer</icon_name> + + <action id="org.opensuse.cupspkhelper.mechanism.printeradd"> + <_description>Add a printer</_description> + <_message>Privileges are required to add a printer.</_message> + <defaults> + <allow_inactive>no</allow_inactive> + <allow_active>auth_admin</allow_active> + </defaults> + </action> </policyconfig> diff --git a/src/test-cups-pk.c b/src/test-cups-pk.c new file mode 100644 index 0000000..ec86a30 --- /dev/null +++ b/src/test-cups-pk.c @@ -0,0 +1,178 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * vim: set et ts=8 sw=8: + * + * Copyright (C) 2008 Novell, Inc. + * + * Authors: Vincent Untz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include <unistd.h> + +#include <gtk/gtk.h> + +#include <glib.h> +#include <glib-object.h> + +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> + +#define MECHANISM_BUS "org.opensuse.CupsPkHelper.Mechanism" + +static gboolean +do_auth (DBusGConnection *bus, + const gchar *action, + const gchar *result) +{ + DBusGProxy *proxy; + GError *error; + gboolean ret; + gboolean ret_gained_privilege; + + proxy = dbus_g_proxy_new_for_name (bus, + "org.freedesktop.PolicyKit.AuthenticationAgent", + "/", + "org.freedesktop.PolicyKit.AuthenticationAgent"); + + if (!proxy) + return FALSE; + + error = NULL; + ret_gained_privilege = FALSE; + ret = dbus_g_proxy_call (proxy, "ObtainAuthorization", &error, + G_TYPE_STRING, action, /* action_id */ + G_TYPE_UINT, 0, /* xid */ + G_TYPE_UINT, getpid (), /* pid */ + G_TYPE_INVALID, + G_TYPE_BOOLEAN, &ret_gained_privilege, + G_TYPE_INVALID); + + if (!ret) { + g_print ("dbus error: %s\n", error->message); + g_error_free (error); + } + + return ret_gained_privilege; +} + +static gboolean +printer_add (DBusGConnection *bus, + const char *printer_name, + const char *printer_uri, + const char *ppd_file, + const char *info, + const char *location, + GError **error) +{ + DBusGProxy *proxy; + gboolean ret; + char *ret_error; + + proxy = dbus_g_proxy_new_for_name (bus, + MECHANISM_BUS, + "/", + MECHANISM_BUS); + + if (!proxy) + return FALSE; + + *error = NULL; + ret_error = NULL; + + ret = dbus_g_proxy_call (proxy, "PrinterAdd", error, + G_TYPE_STRING, printer_name, + G_TYPE_STRING, printer_uri, + G_TYPE_STRING, ppd_file, + G_TYPE_STRING, info, + G_TYPE_STRING, location, + G_TYPE_INVALID, + G_TYPE_STRING, &ret_error, + G_TYPE_INVALID); + + if (ret) { + if (!ret_error || ret_error[0] == '\0') + g_print ("worked\n"); + else + g_print ("ouch: %s\n", ret_error); + } + + return ret; +} + +int +main (int argc, char **argv) +{ + DBusGConnection *system_bus; + DBusGConnection *session_bus; + gboolean try; + gboolean ret; + GError *error; + + gtk_init (&argc, &argv); + + error = NULL; + system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (system_bus == NULL) { + g_warning ("Could not connect to system bus: %s", + error->message); + g_error_free (error); + return 1; + } + + error = NULL; + session_bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + if (session_bus == NULL) { + g_warning ("Could not connect to session bus: %s", + error->message); + g_error_free (error); + return 1; + } + + try = TRUE; + while (try) { + try = FALSE; + error = NULL; + ret = printer_add (system_bus, + "MyPrinter", "smb://really/cool", + "HP/Business_Inkjet_2200-chp2200.ppd.gz", + "This is my printer", "At home", + &error); + + if (!ret) { + if (dbus_g_error_has_name (error, MECHANISM_BUS".NotPrivileged")) { + gchar **tokens; + + tokens = g_strsplit (error->message, " ", 2); + g_error_free (error); + if (g_strv_length (tokens) == 2) { + /* FIXME: this fails because of timeout if the user waits too long */ + try = do_auth (session_bus, tokens[0], tokens[1]); + if (!try) + g_print ("not authorized\n"); + } else + g_warning ("helper return string malformed"); + g_strfreev (tokens); + } else if (error) { + g_print ("dbus error: %s\n", error->message); + g_error_free (error); + } else + g_print ("unknown error\n"); + } + } + + return 0; +} diff --git a/src/test-cups.c b/src/test-cups.c new file mode 100644 index 0000000..e22612a --- /dev/null +++ b/src/test-cups.c @@ -0,0 +1,52 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * vim: set et ts=8 sw=8: + * + * Copyright (C) 2008 Novell, Inc. + * + * Authors: Vincent Untz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include <glib.h> +#include <glib-object.h> + +#include "cups.h" + +int +main (int argc, char **argv) +{ + CphCups *cups; + + g_type_init (); + + cups = cph_cups_new (); + + if (cups == NULL) + return 1; + + //if (cph_cups_add_printer (cups, "MyPrinter", "smb://really/cool", "HP/Business_Inkjet_2200-chp2200.ppd.gz", "This is my printer", "At home")) { + //if (cph_cups_delete_printer (cups, "MyPrinter")) { + if (cph_cups_printer_class_set_job_sheets (cups, "DesignJet-650C", "none", "none")) { + g_print ("worked\n"); + } else { + g_print ("ouch: %s\n", cph_cups_last_status_to_string (cups)); + } + + g_object_unref (cups); + + return 0; +} |