diff options
author | Marek Kasik <mkasik@redhat.com> | 2012-03-02 13:58:24 +0100 |
---|---|---|
committer | Vincent Untz <vuntz@novell.com> | 2012-03-02 14:22:25 +0100 |
commit | c03420571c22187627ddfff52c3dcfff4495c6c3 (patch) | |
tree | 71421557dd70a22d43e768e419d3368b22d19031 | |
parent | 3bc57bf29ab31e7790bc81717e111c3160f265d9 (diff) |
Add PrinterAddOption D-Bus method
New method to set options, without a "-default" suffix.
https://bugs.freedesktop.org/show_bug.cgi?id=45304
-rw-r--r-- | src/cups-pk-helper-mechanism.c | 28 | ||||
-rw-r--r-- | src/cups-pk-helper-mechanism.xml | 8 | ||||
-rw-r--r-- | src/cups.c | 234 | ||||
-rw-r--r-- | src/cups.h | 5 |
4 files changed, 275 insertions, 0 deletions
diff --git a/src/cups-pk-helper-mechanism.c b/src/cups-pk-helper-mechanism.c index 083bdda..b20d078 100644 --- a/src/cups-pk-helper-mechanism.c +++ b/src/cups-pk-helper-mechanism.c @@ -1186,6 +1186,30 @@ cph_mechanism_printer_delete_option_default (CphIfaceMechanism *object, } static gboolean +cph_mechanism_printer_add_option (CphIfaceMechanism *object, + GDBusMethodInvocation *context, + const char *name, + const char *option, + const char *const *values) +{ + CphMechanism *mechanism = CPH_MECHANISM (object); + gboolean ret; + + _cph_mechanism_emit_called (mechanism); + + if (!_check_polkit_for_printer_class (mechanism, context, name)) + return TRUE; + + ret = cph_cups_printer_class_set_option (mechanism->priv->cups, + name, option, values); + + cph_iface_mechanism_complete_printer_add_option ( + object, context, + _cph_mechanism_return_error (mechanism, !ret)); + return TRUE; +} + +static gboolean cph_mechanism_job_cancel_purge (CphIfaceMechanism *object, GDBusMethodInvocation *context, int id, @@ -1420,6 +1444,10 @@ cph_mechanism_connect_signals (CphMechanism *mechanism) G_CALLBACK (cph_mechanism_printer_add_option_default), NULL); g_signal_connect (mechanism, + "handle-printer-add-option", + G_CALLBACK (cph_mechanism_printer_add_option), + NULL); + g_signal_connect (mechanism, "handle-printer-add-with-ppd-file", G_CALLBACK (cph_mechanism_printer_add_with_ppd_file), NULL); diff --git a/src/cups-pk-helper-mechanism.xml b/src/cups-pk-helper-mechanism.xml index c9915da..b3c5f7f 100644 --- a/src/cups-pk-helper-mechanism.xml +++ b/src/cups-pk-helper-mechanism.xml @@ -194,6 +194,14 @@ <arg name="error" direction="out" type="s"/> </method> + <method name="PrinterAddOption"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <arg name="name" direction="in" type="s"/> + <arg name="option" direction="in" type="s"/> + <arg name="values" direction="in" type="as"/> + <arg name="error" direction="out" type="s"/> + </method> + <!-- Methods for jobs --> <!-- JobCancel is deprecated; JobCancelPurge should be used instead --> @@ -43,6 +43,7 @@ #include <cups/cups.h> #include <cups/http.h> #include <cups/ipp.h> +#include <cups/ppd.h> #include "cups.h" @@ -506,6 +507,18 @@ _cph_cups_add_job_uri (ipp_t *request, } static void +_cph_cups_add_requesting_user_name (ipp_t *request, + const char *username) +{ + if (username) + ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, username); + else + ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, cupsUser ()); +} + +static void _cph_cups_set_internal_status (CphCups *cups, const char *status) { @@ -2132,6 +2145,227 @@ out: return retval; } +/* + * This function sets given options to specified values in file 'ppdfile'. + * This needs to be done because of applications which use content of PPD files + * instead of IPP attributes. + * CUPS doesn't do this automatically (but hopefully will since 1.6) + */ +static gchar * +_cph_cups_prepare_ppd_for_options (CphCups *cups, + const gchar *ppdfile, + cups_option_t *options, + gint num_options) +{ + ppd_choice_t *choice; + cups_file_t *in = NULL; + cups_file_t *out = NULL; + ppd_file_t *ppd; + const char *value; + gboolean ppdchanged = FALSE; + gchar *result = NULL; + gchar *error; + char newppdfile[1024]; + char line[1024]; + char keyword[1024]; + char *keyptr; + + ppd = ppdOpenFile (ppdfile); + if (!ppd) { + error = g_strdup_printf ("Unable to open PPD file \"%s\" - %s", ppdfile, strerror (errno)); + _cph_cups_set_internal_status (cups, error); + g_free (error); + + goto out; + } + + out = cupsTempFile2 (newppdfile, sizeof (newppdfile)); + if (!out) { + _cph_cups_set_internal_status (cups, "Unable to create temporary file"); + + goto out; + } + + in = cupsFileOpen (ppdfile, "r"); + if (!in) { + error = g_strdup_printf ("Unable to open PPD file \"%s\" - %s", ppdfile, strerror (errno)); + _cph_cups_set_internal_status (cups, error); + g_free (error); + + goto out; + } + + /* + * Mark default values and values of options we are changing. + */ + ppdMarkDefaults (ppd); + cupsMarkOptions (ppd, num_options, options); + + while (cupsFileGets (in, line, sizeof (line))) { + if (!g_str_has_prefix (line, "*Default")) { + cupsFilePrintf (out, "%s\n", line); + } else { + /* + * This part parses lines with *Default on their beginning. + * Example: + * "*DefaultResolution: 1200dpi" becomes: + * - keyword: Resolution + * - keyptr: 1200dpi + */ + g_strlcpy (keyword, line + strlen ("*Default"), sizeof (keyword)); + + for (keyptr = keyword; *keyptr; keyptr++) + if (*keyptr == ':' || isspace (*keyptr & 255)) + break; + + *keyptr++ = '\0'; + while (isspace (*keyptr & 255)) + keyptr++; + + /* + * We have to change PageSize if any of PageRegion, PageSize, + * PaperDimension or ImageableArea changes. We change PageRegion + * if PageSize is not available. + */ + if (g_str_equal (keyword, "PageRegion") || + g_str_equal (keyword, "PageSize") || + g_str_equal (keyword, "PaperDimension") || + g_str_equal (keyword, "ImageableArea")) { + choice = ppdFindMarkedChoice (ppd, "PageSize"); + if (!choice) + choice = ppdFindMarkedChoice (ppd, "PageRegion"); + } else { + choice = ppdFindMarkedChoice (ppd, keyword); + } + + if (choice && !g_str_equal (choice->choice, keyptr)) { + if (!g_str_equal (choice->choice, "Custom")) { + cupsFilePrintf (out, "*Default%s: %s\n", keyword, choice->choice); + ppdchanged = TRUE; + } else { + /* + * We have to set the value in PPD manually if a custom value was passed in + * because cupsMarkOptions() marks just "Custom" choice but we need the input + * value to be set. + * Custom values has "Custom." prefix and has to be enabled. + */ + value = cupsGetOption (keyword, num_options, options); + if (value) { + cupsFilePrintf (out, "*Default%s: %s\n", keyword, value); + ppdchanged = TRUE; + } else { + cupsFilePrintf (out, "%s\n", line); + } + } + } else { + cupsFilePrintf (out, "%s\n", line); + } + } + } + + if (ppdchanged) + result = g_strdup (newppdfile); + +out: + + if (in) + cupsFileClose (in); + if (out) + cupsFileClose (out); + if (ppd) + ppdClose (ppd); + + return result; +} + +gboolean +cph_cups_printer_class_set_option (CphCups *cups, + const char *printer_name, + const char *option, + const char *const *values) +{ + ipp_attribute_t *attr; + cups_option_t *options; + gboolean retval; + gboolean is_class; + ipp_t *request; + char *ppdfile = NULL; + char *newppdfile = NULL; + gint length = 0; + gint num_options = 0; + gint i; + + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + + if (!_cph_cups_is_printer_name_valid (cups, printer_name)) + return FALSE; + + if (!_cph_cups_is_option_valid (cups, option)) + return FALSE; + + /* check the validity of values, and get the length of the array at the + * same time */ + if (values) { + while (values[length] != NULL) { + if (!_cph_cups_is_option_value_valid (cups, + values[length])) + return FALSE; + length++; + } + } + + if (length == 0) + return FALSE; + + is_class = cph_cups_is_class (cups, printer_name); + + /* + * We permit only one value to change in PPD file because we are setting + * default value in it. + */ + if (!is_class && length == 1) { + num_options = cupsAddOption (option, values[0], num_options, &options); + + ppdfile = g_strdup (cupsGetPPD (printer_name)); + + newppdfile = _cph_cups_prepare_ppd_for_options (cups, ppdfile, options, num_options); + + g_unlink (ppdfile); + g_free (ppdfile); + cupsFreeOptions (num_options, options); + } + + if (is_class) { + request = ippNewRequest (CUPS_ADD_MODIFY_CLASS); + _cph_cups_add_class_uri (request, printer_name); + } else { + request = ippNewRequest (CUPS_ADD_MODIFY_PRINTER); + _cph_cups_add_printer_uri (request, printer_name); + } + _cph_cups_add_requesting_user_name (request, NULL); + + if (length == 1) { + ippAddString (request, IPP_TAG_PRINTER, IPP_TAG_NAME, + option, NULL, values[0]); + } else { + attr = ippAddStrings (request, IPP_TAG_PRINTER, IPP_TAG_NAME, + option, length, NULL, NULL); + + for (i = 0; i < length; i++) + attr->values[i].string.text = g_strdup (values[i]); + } + + if (newppdfile) { + retval = _cph_cups_post_request (cups, request, newppdfile, CPH_RESOURCE_ADMIN); + g_unlink (newppdfile); + g_free (newppdfile); + } else { + retval = _cph_cups_send_request (cups, request, CPH_RESOURCE_ADMIN); + } + + return retval; +} + /* Functions that work on jobs */ gboolean @@ -173,6 +173,11 @@ gboolean cph_cups_printer_class_set_option_default (CphCups *cups, const char *option, const char *const *values); +gboolean cph_cups_printer_class_set_option (CphCups *cups, + const char *printer_name, + const char *option, + const char *const *values); + gboolean cph_cups_job_cancel (CphCups *cups, int job_id, gboolean purge_job, |