summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Untz <vuntz@novell.com>2008-11-20 17:52:20 +0100
committerVincent Untz <vuntz@novell.com>2008-11-20 17:52:20 +0100
commit23eef6329f90e91bd5dadf9f66db4ab3da4b5b78 (patch)
tree2c75386f7b8d50f4a93af78be0cf06d73a3c0323
parent1e69640f8200b74b3bd044ddd046a51220326a69 (diff)
Implement ClassAddPrinter/ClassDeletePrinter/ClassDelete methods.
-rw-r--r--src/cups-pk-helper-mechanism.c58
-rw-r--r--src/cups-pk-helper-mechanism.h15
-rw-r--r--src/cups-pk-helper-mechanism.xml20
-rw-r--r--src/cups.c252
-rw-r--r--src/cups.h11
5 files changed, 353 insertions, 3 deletions
diff --git a/src/cups-pk-helper-mechanism.c b/src/cups-pk-helper-mechanism.c
index 5cca42c..471d80e 100644
--- a/src/cups-pk-helper-mechanism.c
+++ b/src/cups-pk-helper-mechanism.c
@@ -682,6 +682,64 @@ cph_mechanism_printer_delete (CphMechanism *mechanism,
}
gboolean
+cph_mechanism_class_add_printer (CphMechanism *mechanism,
+ const char *name,
+ const char *printer,
+ DBusGMethodInvocation *context)
+{
+ gboolean ret;
+
+ reset_killtimer (mechanism);
+
+ if (!_check_polkit_for_action (mechanism, context, "printeraddremove"))
+ return FALSE;
+
+ ret = cph_cups_class_add_printer (mechanism->priv->cups,
+ name, printer);
+ _cph_mechanism_return_error (mechanism, context, !ret);
+
+ return TRUE;
+}
+
+gboolean
+cph_mechanism_class_delete_printer (CphMechanism *mechanism,
+ const char *name,
+ const char *printer,
+ DBusGMethodInvocation *context)
+{
+ gboolean ret;
+
+ reset_killtimer (mechanism);
+
+ if (!_check_polkit_for_action (mechanism, context, "printeraddremove"))
+ return FALSE;
+
+ ret = cph_cups_class_delete_printer (mechanism->priv->cups,
+ name, printer);
+ _cph_mechanism_return_error (mechanism, context, !ret);
+
+ return TRUE;
+}
+
+gboolean
+cph_mechanism_class_delete (CphMechanism *mechanism,
+ const char *name,
+ DBusGMethodInvocation *context)
+{
+ gboolean ret;
+
+ reset_killtimer (mechanism);
+
+ if (!_check_polkit_for_action (mechanism, context, "printeraddremove"))
+ return FALSE;
+
+ ret = cph_cups_class_delete (mechanism->priv->cups, name);
+ _cph_mechanism_return_error (mechanism, context, !ret);
+
+ return TRUE;
+}
+
+gboolean
cph_mechanism_printer_set_default (CphMechanism *mechanism,
const char *name,
DBusGMethodInvocation *context)
diff --git a/src/cups-pk-helper-mechanism.h b/src/cups-pk-helper-mechanism.h
index 7864dc0..1f394b5 100644
--- a/src/cups-pk-helper-mechanism.h
+++ b/src/cups-pk-helper-mechanism.h
@@ -166,6 +166,21 @@ cph_mechanism_printer_delete (CphMechanism *mechanism,
DBusGMethodInvocation *context);
gboolean
+cph_mechanism_class_add_printer (CphMechanism *mechanism,
+ const char *name,
+ const char *printer,
+ DBusGMethodInvocation *context);
+gboolean
+cph_mechanism_class_delete_printer (CphMechanism *mechanism,
+ const char *name,
+ const char *printer,
+ DBusGMethodInvocation *context);
+gboolean
+cph_mechanism_class_delete (CphMechanism *mechanism,
+ const char *name,
+ DBusGMethodInvocation *context);
+
+gboolean
cph_mechanism_printer_set_default (CphMechanism *mechanism,
const char *name,
DBusGMethodInvocation *context);
diff --git a/src/cups-pk-helper-mechanism.xml b/src/cups-pk-helper-mechanism.xml
index 7c23b85..b7f79af 100644
--- a/src/cups-pk-helper-mechanism.xml
+++ b/src/cups-pk-helper-mechanism.xml
@@ -107,6 +107,26 @@
<arg name="error" direction="out" type="s"/>
</method>
+ <method name="ClassAddPrinter">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg name="name" direction="in" type="s"/>
+ <arg name="printer" direction="in" type="s"/>
+ <arg name="error" direction="out" type="s"/>
+ </method>
+
+ <method name="ClassDeletePrinter">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg name="name" direction="in" type="s"/>
+ <arg name="printer" direction="in" type="s"/>
+ <arg name="error" direction="out" type="s"/>
+ </method>
+
+ <method name="ClassDelete">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg name="name" direction="in" type="s"/>
+ <arg name="error" direction="out" type="s"/>
+ </method>
+
<method name="PrinterSetDefault">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="name" direction="in" type="s"/>
diff --git a/src/cups.c b/src/cups.c
index 41286a2..d4391a5 100644
--- a/src/cups.c
+++ b/src/cups.c
@@ -76,9 +76,9 @@
~!+* deletePrinterOptionDefault
~!+* deletePrinter
getPrinterAttributes
- ! addPrinterToClass
- ! deletePrinterFromClass
- ! deleteClass
+~!+* addPrinterToClass
+~!+* deletePrinterFromClass
+~!+* deleteClass
getDefault
~!+* setDefault
getPPD
@@ -280,6 +280,23 @@ _cph_cups_is_printer_name_valid (CphCups *cups,
return FALSE;
}
+/* class is similar to printer in terms of validity checks */
+static gboolean
+_cph_cups_is_class_name_valid (CphCups *cups,
+ const char *name)
+{
+ char *error;
+
+ if (_cph_cups_is_printer_name_valid_internal (name))
+ return TRUE;
+
+ error = g_strdup_printf ("\"%s\" is not a valid class name.", name);
+ _cph_cups_set_internal_status (cups, error);
+ g_free (error);
+
+ return FALSE;
+}
+
/* This is some text, but we could potentially do more checks. We don't do them
* because cups will already do them.
* + for the URI, we could check that the scheme is supported and that the
@@ -467,6 +484,23 @@ _cph_cups_send_new_simple_request (CphCups *cups,
}
static gboolean
+_cph_cups_send_new_simple_class_request (CphCups *cups,
+ ipp_op_t op,
+ const char *class_name,
+ CphResource resource)
+{
+ ipp_t *request;
+
+ if (!_cph_cups_is_class_name_valid (cups, class_name))
+ return FALSE;
+
+ request = ippNewRequest (op);
+ _cph_cups_add_class_uri (request, class_name);
+
+ return _cph_cups_send_request (cups, request, resource);
+}
+
+static gboolean
_cph_cups_send_new_printer_class_request (CphCups *cups,
const char *printer_name,
ipp_tag_t group,
@@ -494,6 +528,56 @@ _cph_cups_send_new_printer_class_request (CphCups *cups,
return _cph_cups_send_request (cups, request, CPH_RESOURCE_ADMIN);
}
+static int
+_cph_cups_class_has_printer (CphCups *cups,
+ const char *class_name,
+ const char *printer_name,
+ ipp_t **reply)
+{
+ gboolean retval;
+ const char *resource_char;
+ ipp_t *request;
+ ipp_t *internal_reply;
+ ipp_attribute_t *printer_names;
+ int i;
+
+ retval = -1;
+
+ if (reply)
+ *reply = NULL;
+
+ request = ippNewRequest (IPP_GET_PRINTER_ATTRIBUTES);
+ _cph_cups_add_class_uri (request, class_name);
+ resource_char = _cph_cups_get_resource (CPH_RESOURCE_ROOT);
+ internal_reply = cupsDoRequest (cups->priv->connection,
+ request, resource_char);
+
+ if (!internal_reply)
+ return -1;
+
+ printer_names = ippFindAttribute (internal_reply,
+ "member-names", IPP_TAG_NAME);
+
+ if (!printer_names)
+ goto out;
+
+ for (i = 0; i < printer_names->num_values; i++) {
+ if (!g_ascii_strcasecmp (printer_names->values[i].string.text,
+ printer_name)) {
+ retval = i;
+ break;
+ }
+ }
+
+out:
+ if (reply)
+ *reply = internal_reply;
+ else
+ ippDelete (internal_reply);
+
+ return retval;
+}
+
static gboolean
_cph_cups_printer_class_set_users (CphCups *cups,
const char *printer_name,
@@ -760,6 +844,168 @@ cph_cups_printer_set_accept_jobs (CphCups *cups,
return _cph_cups_send_request (cups, request, CPH_RESOURCE_ADMIN);
}
+/* Functions that work on a class */
+
+gboolean
+cph_cups_class_add_printer (CphCups *cups,
+ const char *class_name,
+ const char *printer_name)
+{
+ int printer_index;
+ ipp_t *reply;
+ ipp_t *request;
+ int new_len;
+ ipp_attribute_t *printer_uris;
+ char printer_uri[HTTP_MAX_URI + 1];
+ ipp_attribute_t *attr;
+
+ g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE);
+
+ if (!_cph_cups_is_class_name_valid (cups, class_name))
+ return FALSE;
+ if (!_cph_cups_is_printer_name_valid (cups, printer_name))
+ return FALSE;
+
+ /* check that the printer is not already in the class */
+ printer_index = _cph_cups_class_has_printer (cups,
+ class_name, printer_name,
+ &reply);
+ if (printer_index >= 0) {
+ char *error;
+
+ if (reply)
+ ippDelete (reply);
+
+ error = g_strdup_printf ("Printer %s is already in class %s.",
+ printer_name, class_name);
+ _cph_cups_set_internal_status (cups, error);
+ g_free (error);
+
+ return FALSE;
+ }
+
+ /* add the printer to the class */
+
+ request = ippNewRequest (CUPS_ADD_CLASS);
+ _cph_cups_add_class_uri (request, class_name);
+
+ g_snprintf (printer_uri, sizeof (printer_uri),
+ "ipp://localhost/printers/%s", printer_name);
+
+ /* new length: 1 + what we had before */
+ new_len = 1;
+ if (reply) {
+ printer_uris = ippFindAttribute (reply,
+ "member-uris", IPP_TAG_URI);
+ if (printer_uris)
+ new_len += printer_uris->num_values;
+ } else
+ printer_uris = NULL;
+
+ attr = ippAddStrings (request, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "member-uris", new_len,
+ NULL, NULL);
+ if (printer_uris) {
+ int i;
+
+ for (i = 0; i < printer_uris->num_values; i++)
+ attr->values[i].string.text = g_strdup (printer_uris->values[i].string.text);
+ }
+
+ if (reply)
+ ippDelete (reply);
+
+ attr->values[new_len - 1].string.text = g_strdup (printer_uri);
+
+ return _cph_cups_send_request (cups, request, CPH_RESOURCE_ADMIN);
+}
+
+gboolean
+cph_cups_class_delete_printer (CphCups *cups,
+ const char *class_name,
+ const char *printer_name)
+{
+ int printer_index;
+ ipp_t *reply;
+ ipp_t *request;
+ int new_len;
+ ipp_attribute_t *printer_uris;
+ ipp_attribute_t *attr;
+ int i;
+
+ g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE);
+
+ if (!_cph_cups_is_class_name_valid (cups, class_name))
+ return FALSE;
+ if (!_cph_cups_is_printer_name_valid (cups, printer_name))
+ return FALSE;
+
+ /* check that the printer is in the class */
+ printer_index = _cph_cups_class_has_printer (cups,
+ class_name, printer_name,
+ &reply);
+ /* Note: the second condition (!reply) is only here for safety purpose.
+ * When it's TRUE, the first one should be TRUE too */
+ if (printer_index < 0 || !reply) {
+ char *error;
+
+ if (reply)
+ ippDelete (reply);
+
+ error = g_strdup_printf ("Printer %s is not in class %s.",
+ printer_name, class_name);
+ _cph_cups_set_internal_status (cups, error);
+ g_free (error);
+
+ return FALSE;
+ }
+
+ /* remove the printer from the class */
+
+ /* new length: -1 + what we had before */
+ new_len = -1;
+ printer_uris = ippFindAttribute (reply,
+ "member-uris", IPP_TAG_URI);
+ if (printer_uris)
+ new_len += printer_uris->num_values;
+
+ /* empty class: we delete it */
+ if (new_len <= 0) {
+ ippDelete (reply);
+ return cph_cups_class_delete (cups, class_name);
+ }
+
+ /* printer_uris is not NULL and reply is not NULL */
+
+ request = ippNewRequest (CUPS_ADD_CLASS);
+ _cph_cups_add_class_uri (request, class_name);
+
+ attr = ippAddStrings (request, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "member-uris", new_len,
+ NULL, NULL);
+
+ /* copy all printers from the class, except the one we remove */
+ for (i = 0; i < printer_index; i++)
+ attr->values[i].string.text = g_strdup (printer_uris->values[i].string.text);
+ for (i = printer_index + 1; i < printer_uris->num_values; i++)
+ attr->values[i].string.text = g_strdup (printer_uris->values[i].string.text);
+
+ ippDelete (reply);
+
+ return _cph_cups_send_request (cups, request, CPH_RESOURCE_ADMIN);
+}
+
+gboolean
+cph_cups_class_delete (CphCups *cups,
+ const char *class_name)
+{
+ g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE);
+
+ return _cph_cups_send_new_simple_class_request (cups, CUPS_DELETE_CLASS,
+ class_name,
+ CPH_RESOURCE_ADMIN);
+}
+
/* Functions that can work on printer and class */
gboolean
diff --git a/src/cups.h b/src/cups.h
index e1f9a92..093ff52 100644
--- a/src/cups.h
+++ b/src/cups.h
@@ -87,6 +87,17 @@ gboolean cph_cups_printer_set_accept_jobs (CphCups *cups,
gboolean enabled,
const char *reason);
+gboolean cph_cups_class_add_printer (CphCups *cups,
+ const char *class_name,
+ const char *printer_name);
+
+gboolean cph_cups_class_delete_printer (CphCups *cups,
+ const char *class_name,
+ const char *printer_name);
+
+gboolean cph_cups_class_delete (CphCups *cups,
+ const char *class_name);
+
gboolean cph_cups_printer_class_set_info (CphCups *cups,
const char *printer_name,
const char *info);