gnome-control-center/panels/printers/pp-new-printer.c
Marek Kasik b5b421288c printers: Fix setting of page size
Set 'PageSize' instead of 'media' for new printers since we use PPD
for construction of the combo for selecting of default paper size.
Previously, we've been setting 'media' attribute for new printers.
Attribute 'media' is used by IPP but we set paper size using 'PageSize'
which comes from PPD in the options dialog. Sometimes (quite often) IPP
gets priority over PPD in print systems. Therefore there was inconsistency
of what user set as default paper size on the options dialog and what was used.

Also don't mark IPP and user's local options as default in PpPPDOptionWidget
since it should use just PPD (we can change PPD values only in this widget).
Since we use PPD for setting of paper size in the options dialog, we shouldn't
show a value which user does not change actually (IPP's 'media' vs. PPD's
'PageSize').

https://bugzilla.gnome.org/show_bug.cgi?id=748569
2015-06-12 16:23:45 +02:00

1441 lines
43 KiB
C

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright 2012 Red Hat, Inc,
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Author: Marek Kasik <mkasik@redhat.com>
*/
#include "pp-new-printer.h"
#include <glib/gstdio.h>
#include <glib/gi18n.h>
#include "pp-utils.h"
#include "pp-maintenance-command.h"
#define PACKAGE_KIT_BUS "org.freedesktop.PackageKit"
#define PACKAGE_KIT_PATH "/org/freedesktop/PackageKit"
#define PACKAGE_KIT_MODIFY_IFACE "org.freedesktop.PackageKit.Modify"
#define PACKAGE_KIT_QUERY_IFACE "org.freedesktop.PackageKit.Query"
#define DBUS_TIMEOUT 120000
#define DBUS_TIMEOUT_LONG 600000
#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
#define HAVE_CUPS_1_6 1
#endif
#ifndef HAVE_CUPS_1_6
#define ippGetState(ipp) ipp->state
#endif
struct _PpNewPrinterPrivate
{
gchar *name;
gchar *original_name;
gchar *device_uri;
gchar *device_id;
gchar *ppd_name;
gchar *ppd_file_name;
gchar *info;
gchar *location;
gchar *make_and_model;
gchar *host_name;
gint host_port;
gboolean is_network_device;
guint window_id;
gboolean unlink_ppd_file;
GSimpleAsyncResult *res;
GCancellable *cancellable;
};
G_DEFINE_TYPE (PpNewPrinter, pp_new_printer, G_TYPE_OBJECT);
enum {
PROP_0 = 0,
PROP_NAME,
PROP_ORIGINAL_NAME,
PROP_DEVICE_URI,
PROP_DEVICE_ID,
PROP_PPD_NAME,
PROP_PPD_FILE_NAME,
PROP_INFO,
PROP_LOCATION,
PROP_MAKE_AND_MODEL,
PROP_HOST_NAME,
PROP_HOST_PORT,
PROP_IS_NETWORK_DEVICE,
PROP_WINDOW_ID
};
static void
pp_new_printer_finalize (GObject *object)
{
PpNewPrinterPrivate *priv;
priv = PP_NEW_PRINTER (object)->priv;
if (priv->unlink_ppd_file && priv->ppd_file_name)
g_unlink (priv->ppd_file_name);
g_clear_pointer (&priv->name, g_free);
g_clear_pointer (&priv->original_name, g_free);
g_clear_pointer (&priv->device_uri, g_free);
g_clear_pointer (&priv->device_id, g_free);
g_clear_pointer (&priv->ppd_name, g_free);
g_clear_pointer (&priv->ppd_file_name, g_free);
g_clear_pointer (&priv->info, g_free);
g_clear_pointer (&priv->location, g_free);
g_clear_pointer (&priv->make_and_model, g_free);
g_clear_pointer (&priv->host_name, g_free);
if (priv->res)
g_object_unref (priv->res);
if (priv->cancellable)
g_object_unref (priv->cancellable);
G_OBJECT_CLASS (pp_new_printer_parent_class)->finalize (object);
}
static void
pp_new_printer_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *param_spec)
{
PpNewPrinter *self;
self = PP_NEW_PRINTER (object);
switch (prop_id)
{
case PROP_NAME:
g_value_set_string (value, self->priv->name);
break;
case PROP_ORIGINAL_NAME:
g_value_set_string (value, self->priv->original_name);
break;
case PROP_DEVICE_URI:
g_value_set_string (value, self->priv->device_uri);
break;
case PROP_DEVICE_ID:
g_value_set_string (value, self->priv->device_id);
break;
case PROP_PPD_NAME:
g_value_set_string (value, self->priv->ppd_name);
break;
case PROP_PPD_FILE_NAME:
g_value_set_string (value, self->priv->ppd_file_name);
break;
case PROP_INFO:
g_value_set_string (value, self->priv->info);
break;
case PROP_LOCATION:
g_value_set_string (value, self->priv->location);
break;
case PROP_MAKE_AND_MODEL:
g_value_set_string (value, self->priv->make_and_model);
break;
case PROP_HOST_NAME:
g_value_set_string (value, self->priv->host_name);
break;
case PROP_HOST_PORT:
g_value_set_int (value, self->priv->host_port);
break;
case PROP_IS_NETWORK_DEVICE:
g_value_set_boolean (value, self->priv->is_network_device);
break;
case PROP_WINDOW_ID:
g_value_set_uint (value, self->priv->window_id);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
prop_id,
param_spec);
break;
}
}
static void
pp_new_printer_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *param_spec)
{
PpNewPrinter *self = PP_NEW_PRINTER (object);
switch (prop_id)
{
case PROP_NAME:
g_free (self->priv->name);
self->priv->name = g_value_dup_string (value);
break;
case PROP_ORIGINAL_NAME:
g_free (self->priv->original_name);
self->priv->original_name = g_value_dup_string (value);
break;
case PROP_DEVICE_URI:
g_free (self->priv->device_uri);
self->priv->device_uri = g_value_dup_string (value);
break;
case PROP_DEVICE_ID:
g_free (self->priv->device_id);
self->priv->device_id = g_value_dup_string (value);
break;
case PROP_PPD_NAME:
g_free (self->priv->ppd_name);
self->priv->ppd_name = g_value_dup_string (value);
break;
case PROP_PPD_FILE_NAME:
g_free (self->priv->ppd_file_name);
self->priv->ppd_file_name = g_value_dup_string (value);
break;
case PROP_INFO:
g_free (self->priv->info);
self->priv->info = g_value_dup_string (value);
break;
case PROP_LOCATION:
g_free (self->priv->location);
self->priv->location = g_value_dup_string (value);
break;
case PROP_MAKE_AND_MODEL:
g_free (self->priv->make_and_model);
self->priv->make_and_model = g_value_dup_string (value);
break;
case PROP_HOST_NAME:
g_free (self->priv->host_name);
self->priv->host_name = g_value_dup_string (value);
break;
case PROP_HOST_PORT:
self->priv->host_port = g_value_get_int (value);
break;
case PROP_IS_NETWORK_DEVICE:
self->priv->is_network_device = g_value_get_boolean (value);
break;
case PROP_WINDOW_ID:
self->priv->window_id = g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
prop_id,
param_spec);
break;
}
}
static void
pp_new_printer_class_init (PpNewPrinterClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (PpNewPrinterPrivate));
gobject_class->set_property = pp_new_printer_set_property;
gobject_class->get_property = pp_new_printer_get_property;
gobject_class->finalize = pp_new_printer_finalize;
g_object_class_install_property (gobject_class, PROP_NAME,
g_param_spec_string ("name",
"Name",
"The new printer's name",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_ORIGINAL_NAME,
g_param_spec_string ("original-name",
"Original name",
"Original name of the new printer",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_DEVICE_URI,
g_param_spec_string ("device-uri",
"Device URI",
"The new printer's device URI",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_DEVICE_ID,
g_param_spec_string ("device-id",
"DeviceID",
"The new printer's DeviceID",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_PPD_NAME,
g_param_spec_string ("ppd-name",
"PPD name",
"Name of PPD for the new printer",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_PPD_FILE_NAME,
g_param_spec_string ("ppd-file-name",
"PPD file name",
"PPD file for the new printer",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_INFO,
g_param_spec_string ("info",
"Printer info",
"The new printer's info",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_LOCATION,
g_param_spec_string ("location",
"Printer location",
"The new printer's location",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_MAKE_AND_MODEL,
g_param_spec_string ("make-and-model",
"Printer make and model",
"The new printer's make and model",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_HOST_NAME,
g_param_spec_string ("host-name",
"Hostname",
"The new printer's hostname",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_HOST_PORT,
g_param_spec_int ("host-port",
"Host port",
"The port of the host",
0, G_MAXINT32, 631,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_IS_NETWORK_DEVICE,
g_param_spec_boolean ("is-network-device",
"Network device",
"Whether the new printer is a network device",
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_WINDOW_ID,
g_param_spec_uint ("window-id",
"WindowID",
"Window ID of parent window",
0, G_MAXUINT, 0,
G_PARAM_READWRITE));
}
static void
pp_new_printer_init (PpNewPrinter *printer)
{
printer->priv = G_TYPE_INSTANCE_GET_PRIVATE (printer,
PP_TYPE_NEW_PRINTER,
PpNewPrinterPrivate);
printer->priv->unlink_ppd_file = FALSE;
printer->priv->cancellable = NULL;
printer->priv->res = NULL;
}
PpNewPrinter *
pp_new_printer_new ()
{
return g_object_new (PP_TYPE_NEW_PRINTER, NULL);
}
static void printer_configure_async (PpNewPrinter *new_printer);
static void
_pp_new_printer_add_async_cb (gboolean success,
PpNewPrinter *printer)
{
PpNewPrinterPrivate *priv = printer->priv;
if (!success)
{
g_simple_async_result_set_error (priv->res,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"Installation of the new printer failed.");
}
g_simple_async_result_set_op_res_gboolean (priv->res, success);
g_simple_async_result_complete_in_idle (priv->res);
}
static void
printer_add_real_async_cb (cups_dest_t *destination,
gpointer user_data)
{
PpNewPrinter *printer = (PpNewPrinter *) user_data;
gboolean success = FALSE;
if (destination)
{
success = TRUE;
cupsFreeDests (1, destination);
}
if (success)
{
printer_configure_async (printer);
}
else
{
_pp_new_printer_add_async_cb (FALSE, printer);
}
}
static void
printer_add_real_async_dbus_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PpNewPrinter *printer = (PpNewPrinter *) user_data;
PpNewPrinterPrivate *priv = printer->priv;
GVariant *output;
GError *error = NULL;
output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
res,
&error);
g_object_unref (source_object);
if (output)
{
const gchar *ret_error;
g_variant_get (output, "(&s)", &ret_error);
if (ret_error[0] != '\0')
{
g_warning ("cups-pk-helper: addition of printer %s failed: %s", priv->name, ret_error);
}
g_variant_unref (output);
}
else
{
if (error->domain != G_IO_ERROR ||
error->code != G_IO_ERROR_CANCELLED)
g_warning ("%s", error->message);
}
if (!error ||
error->domain != G_IO_ERROR ||
error->code != G_IO_ERROR_CANCELLED)
{
get_named_dest_async (priv->name,
printer_add_real_async_cb,
printer);
}
if (error)
g_error_free (error);
}
static void
printer_add_real_async (PpNewPrinter *printer)
{
PpNewPrinterPrivate *priv = printer->priv;
GDBusConnection *bus;
GError *error = NULL;
if (!priv->ppd_name && !priv->ppd_file_name)
{
_pp_new_printer_add_async_cb (FALSE, printer);
return;
}
bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (!bus)
{
g_warning ("Failed to get system bus: %s", error->message);
g_error_free (error);
_pp_new_printer_add_async_cb (FALSE, printer);
return;
}
g_dbus_connection_call (bus,
MECHANISM_BUS,
"/",
MECHANISM_BUS,
priv->ppd_name ? "PrinterAdd" : "PrinterAddWithPpdFile",
g_variant_new ("(sssss)",
priv->name,
priv->device_uri,
priv->ppd_name ? priv->ppd_name : priv->ppd_file_name,
priv->info ? priv->info : "",
priv->location ? priv->location : ""),
G_VARIANT_TYPE ("(s)"),
G_DBUS_CALL_FLAGS_NONE,
DBUS_TIMEOUT,
NULL,
printer_add_real_async_dbus_cb,
printer);
}
static PPDName *
get_ppd_item_from_output (GVariant *output)
{
GVariant *array;
PPDName *ppd_item = NULL;
gint j;
static const char * const match_levels[] = {
"exact-cmd",
"exact",
"close",
"generic",
"none"};
if (output)
{
g_variant_get (output, "(@a(ss))", &array);
if (array)
{
GVariantIter *iter;
GVariant *item;
gchar *driver;
gchar *match;
for (j = 0; j < G_N_ELEMENTS (match_levels) && !ppd_item; j++)
{
g_variant_get (array, "a(ss)", &iter);
while ((item = g_variant_iter_next_value (iter)) && !ppd_item)
{
g_variant_get (item, "(ss)", &driver, &match);
if (g_str_equal (match, match_levels[j]))
{
ppd_item = g_new0 (PPDName, 1);
ppd_item->ppd_name = g_strdup (driver);
if (g_strcmp0 (match, "exact-cmd") == 0)
ppd_item->ppd_match_level = PPD_EXACT_CMD_MATCH;
else if (g_strcmp0 (match, "exact") == 0)
ppd_item->ppd_match_level = PPD_EXACT_MATCH;
else if (g_strcmp0 (match, "close") == 0)
ppd_item->ppd_match_level = PPD_CLOSE_MATCH;
else if (g_strcmp0 (match, "generic") == 0)
ppd_item->ppd_match_level = PPD_GENERIC_MATCH;
else if (g_strcmp0 (match, "none") == 0)
ppd_item->ppd_match_level = PPD_NO_MATCH;
}
g_free (driver);
g_free (match);
g_variant_unref (item);
}
}
g_variant_unref (array);
}
}
return ppd_item;
}
static void
printer_add_async_scb3 (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PpNewPrinter *printer = (PpNewPrinter *) user_data;
PpNewPrinterPrivate *priv = printer->priv;
GVariant *output;
PPDName *ppd_item = NULL;
GError *error = NULL;
output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
res,
&error);
g_object_unref (source_object);
if (output)
{
ppd_item = get_ppd_item_from_output (output);
g_variant_unref (output);
}
else
{
if (error->domain != G_IO_ERROR ||
error->code != G_IO_ERROR_CANCELLED)
g_warning ("%s", error->message);
}
if ((!error ||
error->domain != G_IO_ERROR ||
error->code != G_IO_ERROR_CANCELLED) &&
ppd_item && ppd_item->ppd_name)
{
priv->ppd_name = g_strdup (ppd_item->ppd_name);
printer_add_real_async (printer);
}
else
{
_pp_new_printer_add_async_cb (FALSE, printer);
}
if (error)
{
g_error_free (error);
}
if (ppd_item)
{
g_free (ppd_item->ppd_name);
g_free (ppd_item);
}
}
static void
install_printer_drivers_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PpNewPrinterPrivate *priv;
PpNewPrinter *printer;
GVariant *output;
GError *error = NULL;
output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
res,
&error);
g_object_unref (source_object);
if (output)
{
g_variant_unref (output);
}
else
{
if (error->domain != G_IO_ERROR ||
error->code != G_IO_ERROR_CANCELLED)
g_warning ("%s", error->message);
}
if (!error ||
error->domain != G_IO_ERROR ||
error->code != G_IO_ERROR_CANCELLED)
{
GDBusConnection *bus;
GError *error = NULL;
printer = (PpNewPrinter *) user_data;
priv = printer->priv;
/* Try whether CUPS has a driver for the new printer */
bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
if (bus)
{
g_dbus_connection_call (bus,
SCP_BUS,
SCP_PATH,
SCP_IFACE,
"GetBestDrivers",
g_variant_new ("(sss)",
priv->device_id,
priv->make_and_model ? priv->make_and_model : "",
priv->device_uri ? priv->device_uri : ""),
G_VARIANT_TYPE ("(a(ss))"),
G_DBUS_CALL_FLAGS_NONE,
DBUS_TIMEOUT_LONG,
priv->cancellable,
printer_add_async_scb3,
printer);
}
else
{
g_warning ("Failed to get system bus: %s", error->message);
g_error_free (error);
_pp_new_printer_add_async_cb (FALSE, printer);
}
}
if (error)
g_error_free (error);
}
static void
printer_add_async_scb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PpNewPrinter *printer = (PpNewPrinter *) user_data;
PpNewPrinterPrivate *priv = printer->priv;
GDBusConnection *bus;
GVariantBuilder array_builder;
GVariant *output;
gboolean cancelled = FALSE;
PPDName *ppd_item = NULL;
GError *error = NULL;
output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
res,
&error);
g_object_unref (source_object);
if (output)
{
ppd_item = get_ppd_item_from_output (output);
g_variant_unref (output);
}
else
{
cancelled = g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
if (!cancelled)
g_warning ("%s", error->message);
g_clear_error (&error);
}
if (!cancelled)
{
if (ppd_item == NULL || ppd_item->ppd_match_level < PPD_EXACT_MATCH)
{
bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
if (bus)
{
g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("as"));
g_variant_builder_add (&array_builder, "s", priv->device_id);
g_dbus_connection_call (bus,
PACKAGE_KIT_BUS,
PACKAGE_KIT_PATH,
PACKAGE_KIT_MODIFY_IFACE,
"InstallPrinterDrivers",
g_variant_new ("(uass)",
priv->window_id,
&array_builder,
"hide-finished"),
G_VARIANT_TYPE ("()"),
G_DBUS_CALL_FLAGS_NONE,
DBUS_TIMEOUT_LONG,
NULL,
install_printer_drivers_cb,
printer);
}
else
{
g_warning ("Failed to get session bus: %s", error->message);
g_error_free (error);
_pp_new_printer_add_async_cb (FALSE, printer);
}
}
else if (ppd_item && ppd_item->ppd_name)
{
priv->ppd_name = g_strdup (ppd_item->ppd_name);
printer_add_real_async (printer);
}
else
{
_pp_new_printer_add_async_cb (FALSE, printer);
}
}
if (ppd_item)
{
g_free (ppd_item->ppd_name);
g_free (ppd_item);
}
}
static void
printer_add_async_scb4 (const gchar *ppd_filename,
gpointer user_data)
{
PpNewPrinter *printer = (PpNewPrinter *) user_data;
PpNewPrinterPrivate *priv = printer->priv;
priv->ppd_file_name = g_strdup (ppd_filename);
if (priv->ppd_file_name)
{
priv->unlink_ppd_file = TRUE;
printer_add_real_async (printer);
}
else
{
_pp_new_printer_add_async_cb (FALSE, printer);
}
}
static GList *
glist_uniq (GList *list)
{
GList *result = NULL;
GList *iter = NULL;
GList *tmp = NULL;
for (iter = list; iter; iter = iter->next)
{
if (tmp == NULL ||
g_strcmp0 ((gchar *) tmp->data, (gchar *) iter->data) != 0)
{
tmp = iter;
result = g_list_append (result, g_strdup (iter->data));
}
}
g_list_free_full (list, g_free);
return result;
}
typedef struct
{
PpNewPrinter *new_printer;
GCancellable *cancellable;
gboolean set_accept_jobs_finished;
gboolean set_enabled_finished;
gboolean autoconfigure_finished;
gboolean set_media_size_finished;
gboolean install_missing_executables_finished;
} PCData;
static void
printer_configure_async_finish (PCData *data)
{
PpNewPrinterPrivate *priv = data->new_printer->priv;
if (data->set_accept_jobs_finished &&
data->set_enabled_finished &&
(data->autoconfigure_finished || priv->is_network_device) &&
data->set_media_size_finished &&
data->install_missing_executables_finished)
{
_pp_new_printer_add_async_cb (TRUE, data->new_printer);
if (data->cancellable)
g_object_unref (data->cancellable);
g_free (data);
}
}
static void
pao_cb (gboolean success,
gpointer user_data)
{
PCData *data = (PCData *) user_data;
data->set_media_size_finished = TRUE;
printer_configure_async_finish (data);
}
static void
printer_set_accepting_jobs_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GVariant *output;
PCData *data = (PCData *) user_data;
GError *error = NULL;
output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
res,
&error);
g_object_unref (source_object);
if (output)
{
g_variant_unref (output);
}
else
{
if (error->domain != G_IO_ERROR ||
error->code != G_IO_ERROR_CANCELLED)
g_warning ("%s", error->message);
g_error_free (error);
}
data->set_accept_jobs_finished = TRUE;
printer_configure_async_finish (data);
}
static void
printer_set_enabled_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GVariant *output;
PCData *data = (PCData *) user_data;
GError *error = NULL;
output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
res,
&error);
g_object_unref (source_object);
if (output)
{
g_variant_unref (output);
}
else
{
if (error->domain != G_IO_ERROR ||
error->code != G_IO_ERROR_CANCELLED)
g_warning ("%s", error->message);
g_error_free (error);
}
data->set_enabled_finished = TRUE;
printer_configure_async_finish (data);
}
typedef struct
{
GList *executables;
GList *packages;
guint window_id;
gchar *ppd_file_name;
GCancellable *cancellable;
gpointer user_data;
} IMEData;
static void
install_missing_executables_cb (IMEData *data)
{
PCData *pc_data = (PCData *) data->user_data;
pc_data->install_missing_executables_finished = TRUE;
printer_configure_async_finish (pc_data);
if (data->ppd_file_name)
{
g_unlink (data->ppd_file_name);
g_clear_pointer (&data->ppd_file_name, g_free);
}
if (data->executables)
{
g_list_free_full (data->executables, g_free);
data->executables = NULL;
}
if (data->packages)
{
g_list_free_full (data->packages, g_free);
data->packages = NULL;
}
if (data->cancellable)
g_clear_object (&data->cancellable);
g_free (data);
}
static void
install_package_names_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GVariant *output;
IMEData *data = (IMEData *) user_data;
GError *error = NULL;
output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
res,
&error);
g_object_unref (source_object);
if (output)
{
g_variant_unref (output);
}
else
{
if (error->domain != G_IO_ERROR ||
error->code != G_IO_ERROR_CANCELLED)
g_warning ("%s", error->message);
g_error_free (error);
}
install_missing_executables_cb (data);
}
static void
search_files_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GVariant *output;
IMEData *data = (IMEData *) user_data;
GError *error = NULL;
GList *item;
output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
res,
&error);
if (output)
{
gboolean installed;
gchar *package;
g_variant_get (output,
"(bs)",
&installed,
&package);
if (!installed)
data->packages = g_list_append (data->packages, g_strdup (package));
g_variant_unref (output);
}
else
{
if (error->domain != G_IO_ERROR ||
error->code != G_IO_ERROR_CANCELLED)
g_warning ("%s", error->message);
g_error_free (error);
}
if (data->executables)
{
item = data->executables;
g_dbus_connection_call (G_DBUS_CONNECTION (source_object),
PACKAGE_KIT_BUS,
PACKAGE_KIT_PATH,
PACKAGE_KIT_QUERY_IFACE,
"SearchFile",
g_variant_new ("(ss)",
(gchar *) item->data,
""),
G_VARIANT_TYPE ("(bs)"),
G_DBUS_CALL_FLAGS_NONE,
DBUS_TIMEOUT_LONG,
data->cancellable,
search_files_cb,
data);
data->executables = g_list_remove_link (data->executables, item);
g_list_free_full (item, g_free);
}
else
{
GVariantBuilder array_builder;
GList *pkg_iter;
data->packages = g_list_sort (data->packages, (GCompareFunc) g_strcmp0);
data->packages = glist_uniq (data->packages);
if (data->packages)
{
g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("as"));
for (pkg_iter = data->packages; pkg_iter; pkg_iter = pkg_iter->next)
g_variant_builder_add (&array_builder,
"s",
(gchar *) pkg_iter->data);
g_dbus_connection_call (G_DBUS_CONNECTION (source_object),
PACKAGE_KIT_BUS,
PACKAGE_KIT_PATH,
PACKAGE_KIT_MODIFY_IFACE,
"InstallPackageNames",
g_variant_new ("(uass)",
data->window_id,
&array_builder,
"hide-finished"),
NULL,
G_DBUS_CALL_FLAGS_NONE,
DBUS_TIMEOUT_LONG,
data->cancellable,
install_package_names_cb,
data);
g_list_free_full (data->packages, g_free);
data->packages = NULL;
}
else
{
g_object_unref (source_object);
install_missing_executables_cb (data);
}
}
}
static void
get_missing_executables_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GVariant *output;
IMEData *data = (IMEData *) user_data;
GError *error = NULL;
GList *executables = NULL;
GList *item;
if (data->ppd_file_name)
{
g_unlink (data->ppd_file_name);
g_clear_pointer (&data->ppd_file_name, g_free);
}
output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
res,
&error);
if (output)
{
GVariant *array;
g_variant_get (output, "(@as)", &array);
if (array)
{
GVariantIter *iter;
GVariant *item;
gchar *executable;
g_variant_get (array, "as", &iter);
while ((item = g_variant_iter_next_value (iter)))
{
g_variant_get (item, "s", &executable);
executables = g_list_append (executables, executable);
g_variant_unref (item);
}
g_variant_unref (array);
}
g_variant_unref (output);
}
else if (error->domain == G_DBUS_ERROR &&
(error->code == G_DBUS_ERROR_SERVICE_UNKNOWN ||
error->code == G_DBUS_ERROR_UNKNOWN_METHOD))
{
g_warning ("Install system-config-printer which provides \
DBus method \"MissingExecutables\" to find missing executables and filters.");
g_error_free (error);
}
else
{
if (error->domain != G_IO_ERROR ||
error->code != G_IO_ERROR_CANCELLED)
g_warning ("%s", error->message);
g_error_free (error);
}
executables = g_list_sort (executables, (GCompareFunc) g_strcmp0);
executables = glist_uniq (executables);
if (executables)
{
data->executables = executables;
item = data->executables;
g_dbus_connection_call (g_object_ref (source_object),
PACKAGE_KIT_BUS,
PACKAGE_KIT_PATH,
PACKAGE_KIT_QUERY_IFACE,
"SearchFile",
g_variant_new ("(ss)",
(gchar *) item->data,
""),
G_VARIANT_TYPE ("(bs)"),
G_DBUS_CALL_FLAGS_NONE,
DBUS_TIMEOUT_LONG,
data->cancellable,
search_files_cb,
data);
data->executables = g_list_remove_link (data->executables, item);
g_list_free_full (item, g_free);
}
else
{
g_object_unref (source_object);
install_missing_executables_cb (data);
}
}
static void
printer_get_ppd_cb (const gchar *ppd_filename,
gpointer user_data)
{
GDBusConnection *bus;
IMEData *data = (IMEData *) user_data;
GError *error = NULL;
data->ppd_file_name = g_strdup (ppd_filename);
if (data->ppd_file_name)
{
bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
if (!bus)
{
g_warning ("%s", error->message);
g_error_free (error);
}
else
{
g_dbus_connection_call (bus,
SCP_BUS,
SCP_PATH,
SCP_IFACE,
"MissingExecutables",
g_variant_new ("(s)", data->ppd_file_name),
G_VARIANT_TYPE ("(as)"),
G_DBUS_CALL_FLAGS_NONE,
DBUS_TIMEOUT,
data->cancellable,
get_missing_executables_cb,
data);
return;
}
}
install_missing_executables_cb (data);
}
static void
pp_maintenance_command_execute_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PpMaintenanceCommand *command = (PpMaintenanceCommand *) source_object;
GError *error = NULL;
PCData *data;
gboolean result;
result = pp_maintenance_command_execute_finish (command, res, &error);
g_object_unref (source_object);
if (result)
{
data = (PCData *) user_data;
data->autoconfigure_finished = TRUE;
printer_configure_async_finish (data);
}
else
{
if (error->domain != G_IO_ERROR ||
error->code != G_IO_ERROR_CANCELLED)
{
data = (PCData *) user_data;
g_warning ("%s", error->message);
data->autoconfigure_finished = TRUE;
printer_configure_async_finish (data);
}
g_error_free (error);
}
}
static void
printer_configure_async (PpNewPrinter *new_printer)
{
PpNewPrinterPrivate *priv = new_printer->priv;
GDBusConnection *bus;
PCData *data;
IMEData *ime_data;
gchar **values;
GError *error = NULL;
data = g_new0 (PCData, 1);
data->new_printer = new_printer;
data->set_accept_jobs_finished = FALSE;
data->set_enabled_finished = FALSE;
data->autoconfigure_finished = FALSE;
data->set_media_size_finished = FALSE;
data->install_missing_executables_finished = FALSE;
/* Enable printer and make it accept jobs */
if (priv->name)
{
bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (bus)
{
g_dbus_connection_call (bus,
MECHANISM_BUS,
"/",
MECHANISM_BUS,
"PrinterSetAcceptJobs",
g_variant_new ("(sbs)",
priv->name,
TRUE,
""),
G_VARIANT_TYPE ("(s)"),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
printer_set_accepting_jobs_cb,
data);
g_dbus_connection_call (g_object_ref (bus),
MECHANISM_BUS,
"/",
MECHANISM_BUS,
"PrinterSetEnabled",
g_variant_new ("(sb)",
priv->name,
TRUE),
G_VARIANT_TYPE ("(s)"),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
printer_set_enabled_cb,
data);
}
else
{
g_warning ("Failed to get system bus: %s", error->message);
g_error_free (error);
data->set_accept_jobs_finished = TRUE;
data->set_enabled_finished = TRUE;
}
}
else
{
data->set_accept_jobs_finished = TRUE;
data->set_enabled_finished = TRUE;
}
/* Run autoconfiguration of printer */
if (!priv->is_network_device)
{
PpMaintenanceCommand *command;
command = pp_maintenance_command_new (priv->name,
"autoconfigure",
/* Translators: Name of job which makes printer to autoconfigure itself */
_("Automatic configuration"));
pp_maintenance_command_execute_async (command,
NULL,
pp_maintenance_command_execute_cb,
data);
}
/* Set media size for printer */
values = g_new0 (gchar *, 2);
values[0] = g_strdup (get_page_size_from_locale ());
printer_add_option_async (priv->name, "PageSize", values, FALSE, NULL, pao_cb, data);
g_strfreev (values);
/* Install missing executables for printer */
ime_data = g_new0 (IMEData, 1);
ime_data->window_id = priv->window_id;
if (data->cancellable)
ime_data->cancellable = g_object_ref (data->cancellable);
ime_data->user_data = data;
printer_get_ppd_async (priv->name,
NULL,
0,
printer_get_ppd_cb,
ime_data);
}
static void
_pp_new_printer_add_async (GSimpleAsyncResult *res,
GObject *object,
GCancellable *cancellable)
{
PpNewPrinter *printer = PP_NEW_PRINTER (object);
PpNewPrinterPrivate *priv = printer->priv;
priv->res = g_object_ref (res);
priv->cancellable = g_object_ref (cancellable);
if (priv->ppd_name || priv->ppd_file_name)
{
/* We have everything we need */
printer_add_real_async (printer);
}
else if (priv->device_id)
{
GDBusConnection *bus;
GError *error = NULL;
/* Try whether CUPS has a driver for the new printer */
bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
if (bus)
{
g_dbus_connection_call (bus,
SCP_BUS,
SCP_PATH,
SCP_IFACE,
"GetBestDrivers",
g_variant_new ("(sss)",
priv->device_id,
priv->make_and_model ? priv->make_and_model : "",
priv->device_uri ? priv->device_uri : ""),
G_VARIANT_TYPE ("(a(ss))"),
G_DBUS_CALL_FLAGS_NONE,
DBUS_TIMEOUT_LONG,
cancellable,
printer_add_async_scb,
printer);
}
else
{
g_warning ("Failed to get system bus: %s", error->message);
g_error_free (error);
_pp_new_printer_add_async_cb (FALSE, printer);
}
}
else if (priv->original_name && priv->host_name)
{
/* Try to get PPD from remote CUPS */
printer_get_ppd_async (priv->original_name,
priv->host_name,
priv->host_port,
printer_add_async_scb4,
printer);
}
else
{
_pp_new_printer_add_async_cb (FALSE, printer);
}
}
void
pp_new_printer_add_async (PpNewPrinter *printer,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *res;
res = g_simple_async_result_new (G_OBJECT (printer), callback, user_data, pp_new_printer_add_async);
g_simple_async_result_set_check_cancellable (res, cancellable);
_pp_new_printer_add_async (res, G_OBJECT (printer), cancellable);
g_object_unref (res);
}
gboolean
pp_new_printer_add_finish (PpNewPrinter *printer,
GAsyncResult *res,
GError **error)
{
GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == pp_new_printer_add_async);
if (g_simple_async_result_propagate_error (simple, error))
return FALSE;
return g_simple_async_result_get_op_res_gboolean (simple);
}