gnome-control-center/panels/printers/pp-new-printer-dialog.c

2146 lines
73 KiB
C
Raw Normal View History

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright 2009-2010 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 3 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 "config.h"
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include <cups/cups.h>
#include <cups/ppd.h>
#include "pp-new-printer-dialog.h"
#include "pp-utils.h"
#include <dbus/dbus-glib.h>
#include <libnotify/notify.h>
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif
#define MECHANISM_BUS "org.opensuse.CupsPkHelper.Mechanism"
#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 FIREWALLD_BUS "org.fedoraproject.FirewallD"
#define FIREWALLD_PATH "/org/fedoraproject/FirewallD"
#define FIREWALLD_IFACE "org.fedoraproject.FirewallD"
#define SCP_BUS "org.fedoraproject.Config.Printing"
#define SCP_PATH "/org/fedoraproject/Config/Printing"
#define SCP_IFACE "org.fedoraproject.Config.Printing"
#define ALLOWED_CHARACTERS "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
static void pp_new_printer_dialog_hide (PpNewPrinterDialog *pp);
static void actualize_devices_list (PpNewPrinterDialog *pp);
enum
{
NOTEBOOK_LOCAL_PAGE = 0,
NOTEBOOK_NETWORK_PAGE,
NOTEBOOK_N_PAGES
};
enum
{
DEVICE_TYPE_ID_COLUMN = 0,
DEVICE_TYPE_NAME_COLUMN,
DEVICE_TYPE_TYPE_COLUMN,
DEVICE_TYPE_N_COLUMNS
};
enum
{
DEVICE_ID_COLUMN = 0,
DEVICE_NAME_COLUMN,
DEVICE_N_COLUMNS
};
enum
{
DEVICE_TYPE_LOCAL = 0,
DEVICE_TYPE_NETWORK
};
enum
{
STANDARD_TAB = 0,
WARNING_TAB
};
typedef struct{
gchar *device_class;
gchar *device_id;
gchar *device_info;
gchar *device_make_and_model;
gchar *device_uri;
gchar *device_location;
gchar *device_ppd_uri;
gchar *display_name;
gchar *hostname;
gint host_port;
gboolean show;
gboolean found;
} CupsDevice;
struct _PpNewPrinterDialog {
GtkBuilder *builder;
GtkWidget *parent;
GtkWidget *dialog;
gchar **device_connection_types;
gint num_device_connection_types;
CupsDevice *devices;
gint num_devices;
UserResponseCallback user_callback;
gpointer user_data;
GCancellable *cancellable;
gchar *warning;
gboolean show_warning;
gboolean searching;
};
static void
show_notification (gchar *primary_text,
gchar *secondary_text,
gchar *icon_name)
{
if (primary_text)
{
NotifyNotification *notification;
notification = notify_notification_new (primary_text,
secondary_text,
icon_name);
notify_notification_set_app_name (notification, _("Printers"));
notify_notification_set_hint (notification, "transient", g_variant_new_boolean (TRUE));
notify_notification_show (notification, NULL);
g_object_unref (notification);
}
}
static void
device_type_selection_changed_cb (GtkTreeSelection *selection,
gpointer user_data)
{
PpNewPrinterDialog *pp = (PpNewPrinterDialog *) user_data;
GtkTreeModel *model;
GtkTreeIter iter;
GtkWidget *treeview = NULL;
GtkWidget *notebook = NULL;
GtkWidget *widget;
gchar *device_type_name = NULL;
gint device_type_id = -1;
gint device_type = -1;
if (gtk_tree_selection_get_selected (selection, &model, &iter))
{
gtk_tree_model_get (model, &iter,
DEVICE_TYPE_ID_COLUMN, &device_type_id,
DEVICE_TYPE_NAME_COLUMN, &device_type_name,
DEVICE_TYPE_TYPE_COLUMN, &device_type,
-1);
}
if (device_type >= 0)
{
widget = (GtkWidget*)
gtk_builder_get_object (pp->builder, "device-type-notebook");
gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), device_type);
if (device_type == DEVICE_TYPE_LOCAL)
{
treeview = (GtkWidget*)
gtk_builder_get_object (pp->builder, "local-devices-treeview");
notebook = (GtkWidget*)
gtk_builder_get_object (pp->builder, "local-devices-notebook");
}
else if (device_type == DEVICE_TYPE_NETWORK)
{
treeview = (GtkWidget*)
gtk_builder_get_object (pp->builder, "network-devices-treeview");
notebook = (GtkWidget*)
gtk_builder_get_object (pp->builder, "network-devices-notebook");
}
if (notebook)
{
if (pp->show_warning && device_type == DEVICE_TYPE_NETWORK)
gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), WARNING_TAB);
else
gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), STANDARD_TAB);
}
widget = (GtkWidget*)
gtk_builder_get_object (pp->builder, "new-printer-add-button");
if (treeview)
gtk_widget_set_sensitive (widget,
gtk_tree_selection_get_selected (
gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
&model,
&iter));
}
}
static void
device_selection_changed_cb (GtkTreeSelection *selection,
gpointer user_data)
{
PpNewPrinterDialog *pp = (PpNewPrinterDialog *) user_data;
GtkTreeModel *model;
GtkTreeIter iter;
GtkWidget *treeview = NULL;
GtkWidget *widget;
gchar *device_type_name = NULL;
gint device_type_id = -1;
gint device_type = -1;
treeview = (GtkWidget*)
gtk_builder_get_object (pp->builder, "device-types-treeview");
if (gtk_tree_selection_get_selected (
gtk_tree_view_get_selection (
GTK_TREE_VIEW (treeview)), &model, &iter))
gtk_tree_model_get (model, &iter,
DEVICE_TYPE_ID_COLUMN, &device_type_id,
DEVICE_TYPE_NAME_COLUMN, &device_type_name,
DEVICE_TYPE_TYPE_COLUMN, &device_type,
-1);
if (device_type == DEVICE_TYPE_LOCAL)
treeview = (GtkWidget*)
gtk_builder_get_object (pp->builder, "local-devices-treeview");
else if (device_type == DEVICE_TYPE_NETWORK)
treeview = (GtkWidget*)
gtk_builder_get_object (pp->builder, "network-devices-treeview");
widget = (GtkWidget*)
gtk_builder_get_object (pp->builder, "new-printer-add-button");
if (treeview)
gtk_widget_set_sensitive (widget,
gtk_tree_selection_get_selected (
gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
&model,
&iter));
}
static void
free_devices (PpNewPrinterDialog *pp)
{
int i;
for (i = 0; i < pp->num_devices; i++)
{
g_free (pp->devices[i].device_class);
g_free (pp->devices[i].device_id);
g_free (pp->devices[i].device_info);
g_free (pp->devices[i].device_make_and_model);
g_free (pp->devices[i].device_uri);
g_free (pp->devices[i].device_location);
g_free (pp->devices[i].device_ppd_uri);
g_free (pp->devices[i].display_name);
g_free (pp->devices[i].hostname);
}
pp->num_devices = 0;
pp->devices = NULL;
}
static void
store_device_parameter (gpointer key,
gpointer value,
gpointer user_data)
{
PpNewPrinterDialog *pp = (PpNewPrinterDialog *) user_data;
gchar *cut;
gint index = -1;
cut = g_strrstr ((gchar *)key, ":");
if (cut)
index = atoi ((gchar *)cut + 1);
if (index >= 0)
{
if (g_str_has_prefix ((gchar *)key, "device-class"))
pp->devices[index].device_class = g_strdup ((gchar *)value);
else if (g_str_has_prefix ((gchar *)key, "device-id"))
pp->devices[index].device_id = g_strdup ((gchar *)value);
else if (g_str_has_prefix ((gchar *)key, "device-info"))
pp->devices[index].device_info = g_strdup ((gchar *)value);
else if (g_str_has_prefix ((gchar *)key, "device-make-and-model"))
pp->devices[index].device_make_and_model = g_strdup ((gchar *)value);
else if (g_str_has_prefix ((gchar *)key, "device-uri"))
pp->devices[index].device_uri = g_strdup ((gchar *)value);
else if (g_str_has_prefix ((gchar *)key, "device-location"))
pp->devices[index].device_location = g_strdup ((gchar *)value);
}
}
static void
devices_get_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PpNewPrinterDialog *pp = user_data;
cups_dest_t *dests;
GHashTable *devices = NULL;
GDBusProxy *proxy;
GtkWidget *widget = NULL;
GVariant *dg_output = NULL;
gboolean already_present;
GError *error = NULL;
gchar *new_name = NULL;
gchar *device_uri = NULL;
char *ret_error = NULL;
gint i, j, k;
gint name_index;
gint num_dests;
dg_output = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
res,
&error);
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
if (dg_output && g_variant_n_children (dg_output) == 2)
{
GVariant *devices_variant = NULL;
g_variant_get (dg_output, "(&s@a{ss})",
&ret_error,
&devices_variant);
if (devices_variant)
{
if (g_variant_is_of_type (devices_variant, G_VARIANT_TYPE ("a{ss}")))
{
GVariantIter *iter;
GVariant *item;
g_variant_get (devices_variant,
"a{ss}",
&iter);
devices = g_hash_table_new (g_str_hash, g_str_equal);
while ((item = g_variant_iter_next_value (iter)))
{
gchar *key;
gchar *value;
g_variant_get (item,
"{ss}",
&key,
&value);
g_hash_table_insert (devices, key, value);
}
}
g_variant_unref (devices_variant);
}
g_variant_unref (dg_output);
}
g_object_unref (source_object);
if (error || (ret_error && ret_error[0] != '\0'))
{
if (error)
g_warning ("%s", error->message);
if (ret_error && ret_error[0] != '\0')
g_warning ("%s", ret_error);
}
free_devices (pp);
if (devices)
{
GList *keys;
GList *iter;
gchar *cut;
gint max_index = -1;
gint index;
keys = g_hash_table_get_keys (devices);
for (iter = keys; iter; iter = iter->next)
{
index = -1;
cut = g_strrstr ((gchar *)iter->data, ":");
if (cut)
index = atoi (cut + 1);
if (index > max_index)
max_index = index;
}
if (max_index >= 0)
{
pp->num_devices = max_index + 1;
pp->devices = g_new0 (CupsDevice, pp->num_devices);
g_hash_table_foreach (devices, store_device_parameter, pp);
/* Assign names to devices */
for (i = 0; i < pp->num_devices; i++)
{
gchar *name = NULL;
if (pp->devices[i].device_id)
{
name = get_tag_value (pp->devices[i].device_id, "mdl");
if (!name)
name = get_tag_value (pp->devices[i].device_id, "model");
if (name)
name = g_strcanon (name, ALLOWED_CHARACTERS, '-');
}
if (!name &&
pp->devices[i].device_info)
{
name = g_strdup (pp->devices[i].device_info);
if (name)
name = g_strcanon (name, ALLOWED_CHARACTERS, '-');
}
name_index = 2;
already_present = FALSE;
num_dests = cupsGetDests (&dests);
do
{
if (already_present)
{
new_name = g_strdup_printf ("%s-%d", name, name_index);
name_index++;
}
else
new_name = g_strdup (name);
already_present = FALSE;
for (j = 0; j < num_dests; j++)
if (g_strcmp0 (dests[j].name, new_name) == 0)
already_present = TRUE;
if (already_present)
g_free (new_name);
else
{
g_free (name);
name = new_name;
}
} while (already_present);
cupsFreeDests (num_dests, dests);
pp->devices[i].display_name = name;
}
/* Set show bool
* Don't show duplicates.
* Show devices with device-id.
* Other preferences should apply here.
*/
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
SCP_BUS,
SCP_PATH,
SCP_IFACE,
NULL,
&error);
if (proxy)
{
GVariantBuilder device_list;
GVariantBuilder device_hash;
GVariant *input = NULL;
GVariant *output = NULL;
GVariant *array = NULL;
GVariant *subarray = NULL;
g_variant_builder_init (&device_list, G_VARIANT_TYPE ("a{sv}"));
for (i = 0; i < pp->num_devices; i++)
{
if (pp->devices[i].device_uri)
{
g_variant_builder_init (&device_hash, G_VARIANT_TYPE ("a{ss}"));
if (pp->devices[i].device_id)
g_variant_builder_add (&device_hash,
"{ss}",
"device-id",
pp->devices[i].device_id);
if (pp->devices[i].device_make_and_model)
g_variant_builder_add (&device_hash,
"{ss}",
"device-make-and-model",
pp->devices[i].device_make_and_model);
if (pp->devices[i].device_class)
g_variant_builder_add (&device_hash,
"{ss}",
"device-class",
pp->devices[i].device_class);
g_variant_builder_add (&device_list,
"{sv}",
pp->devices[i].device_uri,
g_variant_builder_end (&device_hash));
}
}
input = g_variant_new ("(v)", g_variant_builder_end (&device_list));
output = g_dbus_proxy_call_sync (proxy,
"GroupPhysicalDevices",
input,
G_DBUS_CALL_FLAGS_NONE,
60000,
NULL,
&error);
if (output && g_variant_n_children (output) == 1)
{
array = g_variant_get_child_value (output, 0);
if (array)
{
for (i = 0; i < g_variant_n_children (array); i++)
{
subarray = g_variant_get_child_value (array, i);
if (subarray)
{
device_uri = g_strdup (g_variant_get_string (
g_variant_get_child_value (subarray, 0),
NULL));
for (k = 0; k < pp->num_devices; k++)
if (g_str_has_prefix (pp->devices[k].device_uri, device_uri))
pp->devices[k].show = TRUE;
g_free (device_uri);
}
}
}
}
if (output)
g_variant_unref (output);
g_variant_unref (input);
g_object_unref (proxy);
}
if (error)
{
if (proxy == NULL ||
(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 \"GroupPhysicalDevices\" to group duplicates in device list.");
for (i = 0; i < pp->num_devices; i++)
pp->devices[i].show = TRUE;
}
for (i = 0; i < pp->num_devices; i++)
if (!pp->devices[i].device_id)
pp->devices[i].show = FALSE;
}
g_hash_table_destroy (devices);
actualize_devices_list (pp);
}
widget = (GtkWidget*)
gtk_builder_get_object (pp->builder, "get-devices-status-label");
gtk_label_set_text (GTK_LABEL (widget), " ");
widget = (GtkWidget*)
gtk_builder_get_object (pp->builder, "spinner");
gtk_spinner_stop (GTK_SPINNER (widget));
gtk_widget_set_sensitive (widget, FALSE);
gtk_widget_hide (widget);
if (pp->cancellable != NULL)
{
g_object_unref (pp->cancellable);
pp->cancellable = NULL;
}
g_clear_error (&error);
}
}
static void
devices_get (PpNewPrinterDialog *pp)
{
GDBusProxy *proxy;
GError *error = NULL;
GVariant *dg_input = NULL;
GVariantBuilder *in_include = NULL;
GVariantBuilder *in_exclude = NULL;
GtkWidget *widget = NULL;
pp->searching = TRUE;
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
MECHANISM_BUS,
"/",
MECHANISM_BUS,
NULL,
&error);
if (proxy)
{
if (pp->show_warning)
{
widget = (GtkWidget*)
gtk_builder_get_object (pp->builder, "local-devices-notebook");
gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), WARNING_TAB);
widget = (GtkWidget*)
gtk_builder_get_object (pp->builder, "network-devices-notebook");
gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), WARNING_TAB);
}
in_include = g_variant_builder_new (G_VARIANT_TYPE ("as"));
in_exclude = g_variant_builder_new (G_VARIANT_TYPE ("as"));
dg_input = g_variant_new ("(iiasas)",
0,
60,
in_include,
in_exclude);
widget = (GtkWidget*)
gtk_builder_get_object (pp->builder, "get-devices-status-label");
gtk_label_set_text (GTK_LABEL (widget), _("Getting devices..."));
widget = (GtkWidget*)
gtk_builder_get_object (pp->builder, "spinner");
gtk_spinner_start (GTK_SPINNER (widget));
gtk_widget_set_sensitive (widget, TRUE);
gtk_widget_show (widget);
pp->cancellable = g_cancellable_new ();
g_dbus_proxy_call (proxy,
"DevicesGet",
dg_input,
G_DBUS_CALL_FLAGS_NONE,
60000,
pp->cancellable,
devices_get_cb,
pp);
g_variant_builder_unref (in_exclude);
g_variant_builder_unref (in_include);
g_variant_unref (dg_input);
}
pp->searching = FALSE;
}
static gchar **
line_split (gchar *line)
{
gboolean escaped = FALSE;
gboolean quoted = FALSE;
gboolean in_word = FALSE;
gchar **words = NULL;
gchar **result = NULL;
gchar *buffer = NULL;
gchar ch;
gint n = 0;
gint i, j = 0, k = 0;
if (line)
{
n = strlen (line);
words = g_new0 (gchar *, n + 1);
buffer = g_new0 (gchar, n + 1);
for (i = 0; i < n; i++)
{
ch = line[i];
if (escaped)
{
buffer[k++] = ch;
escaped = FALSE;
continue;
}
if (ch == '\\')
{
in_word = TRUE;
escaped = TRUE;
continue;
}
if (in_word)
{
if (quoted)
{
if (ch == '"')
quoted = FALSE;
else
buffer[k++] = ch;
}
else if (g_ascii_isspace (ch))
{
words[j++] = g_strdup (buffer);
memset (buffer, 0, n + 1);
k = 0;
in_word = FALSE;
}
else if (ch == '"')
quoted = TRUE;
else
buffer[k++] = ch;
}
else
{
if (ch == '"')
{
in_word = TRUE;
quoted = TRUE;
}
else if (!g_ascii_isspace (ch))
{
in_word = TRUE;
buffer[k++] = ch;
}
}
}
}
if (buffer && buffer[0] != '\0')
words[j++] = g_strdup (buffer);
result = g_strdupv (words);
g_strfreev (words);
g_free (buffer);
return result;
}
static void
service_enable (gchar *service_name,
gint service_timeout)
{
GDBusProxy *proxy;
GVariant *input = NULL;
GVariant *output = NULL;
GError *error = NULL;
gint result;
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
FIREWALLD_BUS,
FIREWALLD_PATH,
FIREWALLD_IFACE,
NULL,
&error);
if (proxy)
{
input = g_variant_new ("(si)",
service_name,
service_timeout);
output = g_dbus_proxy_call_sync (proxy,
"enableService",
input,
G_DBUS_CALL_FLAGS_NONE,
60000,
NULL,
&error);
if (output && g_variant_n_children (output) == 1)
g_variant_get (output, "(i)", &result);
if (output)
g_variant_unref (output);
g_variant_unref (input);
g_object_unref (proxy);
}
}
static void
service_disable (gchar *service_name)
{
GDBusProxy *proxy;
GVariant *input = NULL;
GVariant *output = NULL;
GError *error = NULL;
gint result;
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
FIREWALLD_BUS,
FIREWALLD_PATH,
FIREWALLD_IFACE,
NULL,
&error);
if (proxy)
{
input = g_variant_new ("(s)", service_name);
output = g_dbus_proxy_call_sync (proxy,
"disableService",
input,
G_DBUS_CALL_FLAGS_NONE,
60000,
NULL,
&error);
if (output && g_variant_n_children (output) == 1)
g_variant_get (output, "(i)", &result);
if (output)
g_variant_unref (output);
g_variant_unref (input);
g_object_unref (proxy);
}
}
static gboolean
service_enabled (gchar *service_name)
{
GDBusProxy *proxy;
GVariant *input = NULL;
GVariant *output = NULL;
GError *error = NULL;
gint query_result = 0;
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
FIREWALLD_BUS,
FIREWALLD_PATH,
FIREWALLD_IFACE,
NULL,
&error);
if (proxy)
{
input = g_variant_new ("(s)",
service_name);
output = g_dbus_proxy_call_sync (proxy,
"queryService",
input,
G_DBUS_CALL_FLAGS_NONE,
60000,
NULL,
&error);
if (output && g_variant_n_children (output) == 1)
g_variant_get (output, "(i)", &query_result);
if (output)
g_variant_unref (output);
g_variant_unref (input);
g_object_unref (proxy);
}
if (query_result > 0)
return TRUE;
else
return FALSE;
}
static gboolean
dbus_method_available (gchar *name,
gchar *path,
gchar *iface,
gchar *method)
{
GDBusProxy *proxy;
GError *error = NULL;
GVariant *output = NULL;
gboolean result = FALSE;
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
name,
path,
iface,
NULL,
NULL);
if (proxy)
{
output = g_dbus_proxy_call_sync (proxy,
method,
NULL,
G_DBUS_CALL_FLAGS_NONE,
60000,
NULL,
&error);
if (error &&
error->domain == G_DBUS_ERROR &&
error->code == G_DBUS_ERROR_SERVICE_UNKNOWN)
result = FALSE;
else
result = TRUE;
if (output)
g_variant_unref (output);
g_object_unref (proxy);
}
return result;
}
static void
search_address_cb (GtkToggleButton *togglebutton,
gpointer user_data)
{
PpNewPrinterDialog *pp = (PpNewPrinterDialog*) user_data;
GtkWidget *widget;
gint i;
pp->searching = TRUE;
widget = (GtkWidget*)
gtk_builder_get_object (pp->builder, "search-by-address-checkbutton");
if (widget && gtk_toggle_button_get_active (togglebutton))
{
gchar *uri = NULL;
widget = (GtkWidget*)
gtk_builder_get_object (pp->builder, "address-entry");
uri = g_strdup (gtk_entry_get_text (GTK_ENTRY (widget)));
if (uri && uri[0] != '\0')
{
cups_dest_t *dests = NULL;
http_t *http;
GError *error = NULL;
gchar *tmp = NULL;
gchar *host = NULL;
gchar *port_string = NULL;
gchar *position;
gchar *command;
gchar *standard_output = NULL;
gint exit_status = -1;
gint num_dests = 0;
gint length;
int port = 631;
if (g_strrstr (uri, "://"))
tmp = g_strrstr (uri, "://") + 3;
else
tmp = uri;
if (g_strrstr (tmp, "@"))
tmp = g_strrstr (tmp, "@") + 1;
if ((position = g_strrstr (tmp, "/")))
{
*position = '\0';
host = g_strdup (tmp);
*position = '/';
}
else
host = g_strdup (tmp);
if ((position = g_strrstr (host, ":")))
{
*position = '\0';
port_string = position + 1;
}
if (port_string)
port = atoi (port_string);
if (host)
{
/* Use CUPS to get printer's informations */
http = httpConnectEncrypt (host, port, cupsEncryption ());
if (http)
{
gchar *device_uri = NULL;
gchar *device_ppd_uri = NULL;
num_dests = cupsGetDests2 (http, &dests);
if (num_dests > 0)
{
CupsDevice *devices = NULL;
devices = g_new0 (CupsDevice, pp->num_devices + num_dests);
for (i = 0; i < pp->num_devices; i++)
{
devices[i] = pp->devices[i];
pp->devices[i].device_class = NULL;
pp->devices[i].device_id = NULL;
pp->devices[i].device_info = NULL;
pp->devices[i].device_make_and_model = NULL;
pp->devices[i].device_uri = NULL;
pp->devices[i].device_location = NULL;
pp->devices[i].device_ppd_uri = NULL;
pp->devices[i].display_name = NULL;
pp->devices[i].hostname = NULL;
}
g_free (pp->devices);
pp->devices = devices;
for (i = 0; i < num_dests; i++)
{
device_uri = g_strdup_printf ("ipp://%s:%d/printers/%s", host, port, dests[i].name);
device_ppd_uri = g_strdup_printf ("%s.ppd", device_uri);
pp->devices[pp->num_devices + i].device_class = g_strdup ("network");
pp->devices[pp->num_devices + i].device_uri = device_uri;
pp->devices[pp->num_devices + i].display_name = g_strdup (dests[i].name);
pp->devices[pp->num_devices + i].device_ppd_uri = device_ppd_uri;
pp->devices[pp->num_devices + i].show = TRUE;
pp->devices[pp->num_devices + i].hostname = g_strdup (host);
pp->devices[pp->num_devices + i].host_port = port;
pp->devices[pp->num_devices + i].found = TRUE;
}
pp->num_devices += num_dests;
}
httpClose (http);
}
/* Use SNMP to get printer's informations */
command = g_strdup_printf ("/usr/lib/cups/backend/snmp %s", host);
if (g_spawn_command_line_sync (command, &standard_output, NULL, &exit_status, &error))
{
if (exit_status == 0 && standard_output)
{
gchar **printer_informations = NULL;
printer_informations = line_split (standard_output);
length = g_strv_length (printer_informations);
if (length >= 4)
{
CupsDevice *devices = NULL;
devices = g_new0 (CupsDevice, pp->num_devices + 1);
for (i = 0; i < pp->num_devices; i++)
{
devices[i] = pp->devices[i];
pp->devices[i].device_class = NULL;
pp->devices[i].device_id = NULL;
pp->devices[i].device_info = NULL;
pp->devices[i].device_make_and_model = NULL;
pp->devices[i].device_uri = NULL;
pp->devices[i].device_location = NULL;
pp->devices[i].device_ppd_uri = NULL;
pp->devices[i].display_name = NULL;
pp->devices[i].hostname = NULL;
}
g_free (pp->devices);
pp->devices = devices;
pp->devices[pp->num_devices].device_class = g_strdup (printer_informations[0]);
pp->devices[pp->num_devices].device_uri = g_strdup (printer_informations[1]);
pp->devices[pp->num_devices].device_make_and_model = g_strdup (printer_informations[2]);
pp->devices[pp->num_devices].device_info = g_strdup (printer_informations[3]);
pp->devices[pp->num_devices].display_name = g_strdup (printer_informations[3]);
pp->devices[pp->num_devices].display_name =
g_strcanon (pp->devices[pp->num_devices].display_name, ALLOWED_CHARACTERS, '-');
pp->devices[pp->num_devices].show = TRUE;
pp->devices[pp->num_devices].hostname = g_strdup (host);
pp->devices[pp->num_devices].host_port = port;
pp->devices[pp->num_devices].found = TRUE;
if (length >= 5 && printer_informations[4][0] != '\0')
pp->devices[pp->num_devices].device_id = g_strdup (printer_informations[4]);
if (length >= 6 && printer_informations[5][0] != '\0')
pp->devices[pp->num_devices].device_location = g_strdup (printer_informations[5]);
pp->num_devices++;
}
g_strfreev (printer_informations);
g_free (standard_output);
}
}
else
{
if (error)
g_warning ("%s", error->message);
}
g_free (command);
g_free (host);
}
}
g_free (uri);
}
else
{
gint length = 0;
gint j = 0;
for (i = 0; i < pp->num_devices; i++)
if (!pp->devices[i].found)
length++;
CupsDevice *devices = NULL;
devices = g_new0 (CupsDevice, length);
for (i = 0; i < pp->num_devices; i++)
{
if (!pp->devices[i].found)
{
devices[j] = pp->devices[i];
pp->devices[i].device_class = NULL;
pp->devices[i].device_id = NULL;
pp->devices[i].device_info = NULL;
pp->devices[i].device_make_and_model = NULL;
pp->devices[i].device_uri = NULL;
pp->devices[i].device_location = NULL;
pp->devices[i].device_ppd_uri = NULL;
pp->devices[i].display_name = NULL;
pp->devices[i].hostname = NULL;
j++;
}
}
g_free (pp->devices);
pp->devices = devices;
pp->num_devices = length;
}
pp->searching = FALSE;
actualize_devices_list (pp);
}
static void
actualize_devices_list (PpNewPrinterDialog *pp)
{
GtkListStore *network_store;
GtkListStore *local_store;
GtkTreeModel *model;
GtkTreeView *network_treeview;
GtkTreeView *local_treeview;
GtkTreeIter iter;
GtkWidget *treeview;
GtkWidget *widget;
GtkWidget *local_notebook;
GtkWidget *network_notebook;
gboolean no_local_device = TRUE;
gboolean no_network_device = TRUE;
gint i;
gint device_type = -1;
network_treeview = (GtkTreeView*)
gtk_builder_get_object (pp->builder, "network-devices-treeview");
local_treeview = (GtkTreeView*)
gtk_builder_get_object (pp->builder, "local-devices-treeview");
network_store = gtk_list_store_new (DEVICE_N_COLUMNS,
G_TYPE_INT,
G_TYPE_STRING);
local_store = gtk_list_store_new (DEVICE_N_COLUMNS,
G_TYPE_INT,
G_TYPE_STRING);
for (i = 0; i < pp->num_devices; i++)
{
if ((pp->devices[i].device_id || pp->devices[i].device_ppd_uri) &&
pp->devices[i].show)
{
if (g_strcmp0 (pp->devices[i].device_class, "network") == 0)
{
gtk_list_store_append (network_store, &iter);
gtk_list_store_set (network_store, &iter,
DEVICE_ID_COLUMN, i,
DEVICE_NAME_COLUMN, pp->devices[i].display_name,
-1);
pp->show_warning = FALSE;
no_network_device = FALSE;
}
else if (g_strcmp0 (pp->devices[i].device_class, "direct") == 0)
{
gtk_list_store_append (local_store, &iter);
gtk_list_store_set (local_store, &iter,
DEVICE_ID_COLUMN, i,
DEVICE_NAME_COLUMN, pp->devices[i].display_name,
-1);
no_local_device = FALSE;
}
}
}
if (no_local_device && !pp->searching)
{
gtk_list_store_append (local_store, &iter);
gtk_list_store_set (local_store, &iter,
DEVICE_ID_COLUMN, 0,
/* Translators: No localy connected printers were found */
DEVICE_NAME_COLUMN, _("No local printers found"),
-1);
gtk_widget_set_sensitive (GTK_WIDGET (local_treeview), FALSE);
}
else
gtk_widget_set_sensitive (GTK_WIDGET (local_treeview), TRUE);
if (no_network_device && !pp->show_warning && !pp->searching)
{
gtk_list_store_append (network_store, &iter);
gtk_list_store_set (network_store, &iter,
DEVICE_ID_COLUMN, 0,
/* Translators: No network printers were found */
DEVICE_NAME_COLUMN, _("No network printers found"),
-1);
gtk_widget_set_sensitive (GTK_WIDGET (network_treeview), FALSE);
}
else
gtk_widget_set_sensitive (GTK_WIDGET (network_treeview), TRUE);
gtk_tree_view_set_model (network_treeview, GTK_TREE_MODEL (network_store));
gtk_tree_view_set_model (local_treeview, GTK_TREE_MODEL (local_store));
if (!no_network_device &&
gtk_tree_model_get_iter_first ((GtkTreeModel *) network_store, &iter))
gtk_tree_selection_select_iter (
gtk_tree_view_get_selection (GTK_TREE_VIEW (network_treeview)),
&iter);
if (!no_local_device &&
gtk_tree_model_get_iter_first ((GtkTreeModel *) local_store, &iter))
gtk_tree_selection_select_iter (
gtk_tree_view_get_selection (GTK_TREE_VIEW (local_treeview)),
&iter);
treeview = (GtkWidget*)
gtk_builder_get_object (pp->builder, "device-types-treeview");
if (gtk_tree_selection_get_selected (
gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), &model, &iter))
gtk_tree_model_get (model, &iter,
DEVICE_TYPE_TYPE_COLUMN, &device_type,
-1);
widget = (GtkWidget*)
gtk_builder_get_object (pp->builder, "device-type-notebook");
local_notebook = (GtkWidget*)
gtk_builder_get_object (pp->builder, "local-devices-notebook");
network_notebook = (GtkWidget*)
gtk_builder_get_object (pp->builder, "network-devices-notebook");
gtk_notebook_set_current_page (GTK_NOTEBOOK (network_notebook), pp->show_warning ? WARNING_TAB : STANDARD_TAB);
gtk_notebook_set_current_page (GTK_NOTEBOOK (local_notebook), STANDARD_TAB);
gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), device_type);
g_object_unref (network_store);
g_object_unref (local_store);
}
static void
populate_devices_list (PpNewPrinterDialog *pp)
{
GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
GtkTextBuffer *text_buffer;
GtkTextView *warning_textview;
GtkTextIter text_iter;
GtkWidget *network_treeview;
GtkWidget *local_treeview;
network_treeview = (GtkWidget*)
gtk_builder_get_object (pp->builder, "network-devices-treeview");
local_treeview = (GtkWidget*)
gtk_builder_get_object (pp->builder, "local-devices-treeview");
g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (network_treeview)),
"changed", G_CALLBACK (device_selection_changed_cb), pp);
g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (local_treeview)),
"changed", G_CALLBACK (device_selection_changed_cb), pp);
actualize_devices_list (pp);
if (dbus_method_available (FIREWALLD_BUS,
FIREWALLD_PATH,
FIREWALLD_IFACE,
"getServices"))
{
if (!service_enabled ("mdns"))
service_enable ("mdns", 300);
if (!service_enabled ("ipp"))
service_enable ("ipp", 300);
if (!service_enabled ("ipp-client"))
service_enable ("ipp-client", 300);
if (!service_enabled ("samba-client"))
service_enable ("samba-client", 300);
}
else
{
pp->warning = g_strdup (_("FirewallD is not running. \
Network printer detection needs services mdns, ipp, ipp-client \
and samba-client enabled on firewall."));
warning_textview = (GtkTextView*)
gtk_builder_get_object (pp->builder, "local-warning");
text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (warning_textview));
gtk_text_buffer_set_text (text_buffer, "", 0);
gtk_text_buffer_get_iter_at_offset (text_buffer, &text_iter, 0);
gtk_text_buffer_insert (text_buffer, &text_iter, pp->warning, -1);
warning_textview = (GtkTextView*)
gtk_builder_get_object (pp->builder, "network-warning");
text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (warning_textview));
gtk_text_buffer_set_text (text_buffer, "", 0);
gtk_text_buffer_get_iter_at_offset (text_buffer, &text_iter, 0);
gtk_text_buffer_insert (text_buffer, &text_iter, pp->warning, -1);
pp->show_warning = TRUE;
}
devices_get (pp);
renderer = gtk_cell_renderer_text_new ();
/* Translators: Column of devices which can be installed */
column = gtk_tree_view_column_new_with_attributes (_("Devices"), renderer,
"text", DEVICE_NAME_COLUMN, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (network_treeview), column);
/* Translators: Column of devices which can be installed */
column = gtk_tree_view_column_new_with_attributes (_("Devices"), renderer,
"text", DEVICE_NAME_COLUMN, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (local_treeview), column);
}
static void
actualize_device_types_list (PpNewPrinterDialog *pp)
{
GtkListStore *store;
GtkTreeView *treeview;
GtkTreeIter iter;
gint i;
treeview = (GtkTreeView*)
gtk_builder_get_object (pp->builder, "device-types-treeview");
store = gtk_list_store_new (DEVICE_TYPE_N_COLUMNS,
G_TYPE_INT,
G_TYPE_STRING,
G_TYPE_INT);
pp->device_connection_types = g_new (gchar*, 2);
pp->num_device_connection_types = 2;
/* Translators: Local means local printers */
pp->device_connection_types[0] = g_strdup (C_("printer type", "Local"));
/* Translators: Network means network printers */
pp->device_connection_types[1] = g_strdup (C_("printer type", "Network"));
for (i = 0; i < pp->num_device_connection_types; i++)
{
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
DEVICE_TYPE_ID_COLUMN, i,
DEVICE_TYPE_NAME_COLUMN, pp->device_connection_types[i],
DEVICE_TYPE_TYPE_COLUMN, i,
-1);
}
gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (store));
gtk_tree_model_get_iter_first ((GtkTreeModel *) store,
&iter);
gtk_tree_selection_select_iter (
gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
&iter);
g_object_unref (store);
}
static void
populate_device_types_list (PpNewPrinterDialog *pp)
{
GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
GtkWidget *treeview;
treeview = (GtkWidget*)
gtk_builder_get_object (pp->builder, "device-types-treeview");
actualize_device_types_list (pp);
g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
"changed", G_CALLBACK (device_type_selection_changed_cb), pp);
renderer = gtk_cell_renderer_text_new ();
/* Translators: Device types column (network or local) */
column = gtk_tree_view_column_new_with_attributes (_("Device types"), renderer,
"text", DEVICE_TYPE_NAME_COLUMN, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
}
static void
dialog_closed (GtkWidget *dialog,
gint response_id,
PpNewPrinterDialog *pp)
{
gtk_widget_destroy (dialog);
}
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;
}
static void
new_printer_add_button_cb (GtkButton *button,
gpointer user_data)
{
PpNewPrinterDialog *pp = (PpNewPrinterDialog*) user_data;
GtkResponseType dialog_response = GTK_RESPONSE_OK;
GtkTreeModel *model;
cups_dest_t *dests;
GtkTreeIter iter;
GtkWidget *treeview;
gboolean success = FALSE;
PPDName *ppd_name = NULL;
gchar *device_name = NULL;
gint device_id = -1;
gint device_type = -1;
gint i, j, k;
int num_dests;
treeview = (GtkWidget*)
gtk_builder_get_object (pp->builder, "device-types-treeview");
if (gtk_tree_selection_get_selected (
gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), &model, &iter))
gtk_tree_model_get (model, &iter,
DEVICE_TYPE_TYPE_COLUMN, &device_type,
-1);
switch (device_type)
{
case DEVICE_TYPE_LOCAL:
treeview = (GtkWidget*)
gtk_builder_get_object (pp->builder, "local-devices-treeview");
break;
case DEVICE_TYPE_NETWORK:
treeview = (GtkWidget*)
gtk_builder_get_object (pp->builder, "network-devices-treeview");
break;
default:
treeview = NULL;
break;
}
if (treeview &&
gtk_tree_selection_get_selected (
gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), &model, &iter))
{
gtk_tree_model_get (model, &iter,
DEVICE_ID_COLUMN, &device_id,
DEVICE_NAME_COLUMN, &device_name,
-1);
}
if (device_id >= 0)
{
if (pp->devices[device_id].device_ppd_uri)
{
http_t *http;
http = httpConnectEncrypt (pp->devices[device_id].hostname,
pp->devices[device_id].host_port,
cupsEncryption ());
if (http)
{
const char *ppd_file_name;
ppd_file_name = cupsGetPPD2 (http, pp->devices[device_id].display_name);
if (ppd_file_name)
{
DBusGProxy *proxy;
GError *error = NULL;
char *ret_error = NULL;
proxy = get_dbus_proxy (MECHANISM_BUS,
"/",
MECHANISM_BUS,
TRUE);
if (proxy)
{
dbus_g_proxy_call (proxy, "PrinterAddWithPpdFile", &error,
G_TYPE_STRING, pp->devices[device_id].display_name,
G_TYPE_STRING, pp->devices[device_id].device_uri,
G_TYPE_STRING, ppd_file_name,
G_TYPE_STRING, pp->devices[device_id].device_info,
G_TYPE_STRING, pp->devices[device_id].device_location,
G_TYPE_INVALID,
G_TYPE_STRING, &ret_error,
G_TYPE_INVALID);
if (error || (ret_error && ret_error[0] != '\0'))
{
dialog_response = GTK_RESPONSE_REJECT;
if (error)
g_warning ("%s", error->message);
if (ret_error && ret_error[0] != '\0')
g_warning ("%s", ret_error);
g_clear_error (&error);
}
else
success = TRUE;
g_object_unref (proxy);
}
g_unlink (ppd_file_name);
}
else
{
dialog_response = GTK_RESPONSE_REJECT;
g_warning ("Getting of PPD for %s from %s:%d failed.",
pp->devices[device_id].display_name,
pp->devices[device_id].hostname,
pp->devices[device_id].host_port);
}
}
}
else if (pp->devices[device_id].device_id)
{
/* Try whether CUPS has a driver for the new printer */
ppd_name = get_ppd_name (pp->devices[device_id].device_id,
pp->devices[device_id].device_make_and_model,
pp->devices[device_id].device_uri);
if (ppd_name == NULL || ppd_name->ppd_match_level < PPD_EXACT_MATCH)
{
/* Try PackageKit to install printer driver */
DBusGProxy *proxy;
GError *error = NULL;
proxy = get_dbus_proxy (PACKAGE_KIT_BUS,
PACKAGE_KIT_PATH,
PACKAGE_KIT_MODIFY_IFACE,
FALSE);
if (proxy)
{
gchar **device_ids = NULL;
device_ids = g_new (gchar *, 2);
device_ids[0] = pp->devices[device_id].device_id;
device_ids[1] = NULL;
dbus_g_proxy_call_with_timeout (proxy,
"InstallPrinterDrivers",
3600000,
&error,
#ifdef GDK_WINDOWING_X11
G_TYPE_UINT, GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (pp->dialog))),
#else
G_TYPE_UINT, 0,
#endif
G_TYPE_STRV, device_ids,
G_TYPE_STRING, "hide-finished",
G_TYPE_INVALID,
G_TYPE_INVALID);
g_object_unref (proxy);
if (error)
g_warning ("%s", error->message);
g_clear_error (&error);
if (ppd_name)
{
g_free (ppd_name->ppd_name);
g_free (ppd_name);
}
/* Search CUPS for driver */
ppd_name = get_ppd_name (pp->devices[device_id].device_id,
pp->devices[device_id].device_make_and_model,
pp->devices[device_id].device_uri);
g_free (device_ids);
}
}
/* Add the new printer */
if (ppd_name && ppd_name->ppd_name)
{
DBusGProxy *proxy;
GError *error = NULL;
char *ret_error = NULL;
proxy = get_dbus_proxy (MECHANISM_BUS,
"/",
MECHANISM_BUS,
TRUE);
if (proxy)
{
dbus_g_proxy_call (proxy, "PrinterAdd", &error,
G_TYPE_STRING, pp->devices[device_id].display_name,
G_TYPE_STRING, pp->devices[device_id].device_uri,
G_TYPE_STRING, ppd_name->ppd_name,
G_TYPE_STRING, pp->devices[device_id].device_info,
G_TYPE_STRING, pp->devices[device_id].device_location,
G_TYPE_INVALID,
G_TYPE_STRING, &ret_error,
G_TYPE_INVALID);
if (error || (ret_error && ret_error[0] != '\0'))
{
dialog_response = GTK_RESPONSE_REJECT;
if (error)
g_warning ("%s", error->message);
if (ret_error && ret_error[0] != '\0')
g_warning ("%s", ret_error);
g_clear_error (&error);
}
g_object_unref (proxy);
}
g_free (ppd_name->ppd_name);
g_free (ppd_name);
}
num_dests = cupsGetDests (&dests);
for (i = 0; i < num_dests; i++)
if (g_strcmp0 (dests[i].name, pp->devices[device_id].display_name) == 0)
success = TRUE;
cupsFreeDests (num_dests, dests);
}
/* Set some options of the new printer */
if (success)
{
const char *ppd_file_name = NULL;
DBusGProxy *proxy;
GError *error = NULL;
char *ret_error = NULL;
ppd_file_t *ppd_file = NULL;
gchar **value = NULL;
const gchar *paper_size;
ppd_file_name = cupsGetPPD (pp->devices[device_id].display_name);
proxy = get_dbus_proxy (MECHANISM_BUS,
"/",
MECHANISM_BUS,
TRUE);
if (proxy)
{
printer_set_accepting_jobs (pp->devices[device_id].display_name, TRUE, NULL);
printer_set_enabled (pp->devices[device_id].display_name, TRUE);
if (g_strcmp0 (pp->devices[device_id].device_class, "direct") == 0)
{
gchar *commands = get_dest_attr (pp->devices[device_id].display_name, "printer-commands");
gchar *commands_lowercase = g_ascii_strdown (commands, -1);
ipp_t *response = NULL;
if (g_strrstr (commands_lowercase, "autoconfigure"))
{
response = execute_maintenance_command (pp->devices[device_id].display_name,
"AutoConfigure",
/* Translators: Name of job which makes printer to autoconfigure itself */
_("Automatic configuration"));
if (response)
{
if (response->state == IPP_ERROR)
g_warning ("An error has occured during automatic configuration of new printer.");
ippDelete (response);
}
}
g_free (commands);
g_free (commands_lowercase);
}
/* Set default PaperSize according to the locale */
paper_size = gtk_paper_size_get_default ();
if (g_str_equal (paper_size, GTK_PAPER_NAME_LETTER))
paper_size = "Letter";
else
paper_size = "A4";
if (ppd_file_name)
{
ppd_file = ppdOpenFile (ppd_file_name);
if (ppd_file)
{
ppdMarkDefaults (ppd_file);
for (i = 0; i < ppd_file->num_groups; i++)
for (j = 0; j < ppd_file->groups[i].num_options; j++)
if (g_strcmp0 ("PageSize", ppd_file->groups[i].options[j].keyword) == 0)
{
for (k = 0; k < ppd_file->groups[i].options[j].num_choices; k++)
{
if (g_ascii_strncasecmp (paper_size,
ppd_file->groups[i].options[j].choices[k].choice,
strlen (paper_size)) == 0 &&
!ppd_file->groups[i].options[j].choices[k].marked)
{
value = g_new0 (gchar *, 2);
value[0] = g_strdup (ppd_file->groups[i].options[j].choices[k].choice);
break;
}
}
break;
}
ppdClose (ppd_file);
}
}
if (value)
{
dbus_g_proxy_call (proxy, "PrinterAddOptionDefault", &error,
G_TYPE_STRING, pp->devices[device_id].display_name,
G_TYPE_STRING, "PageSize",
G_TYPE_STRV, value,
G_TYPE_INVALID,
G_TYPE_STRING, &ret_error,
G_TYPE_INVALID);
if (error)
{
g_warning ("%s", error->message);
g_clear_error (&error);
}
if (ret_error && ret_error[0] != '\0')
g_warning ("%s", ret_error);
g_strfreev (value);
}
g_object_unref (proxy);
}
if (pp->devices[device_id].device_uri &&
dbus_method_available (FIREWALLD_BUS,
FIREWALLD_PATH,
FIREWALLD_IFACE,
"getServices"))
{
if (g_str_has_prefix (pp->devices[device_id].device_uri, "dnssd:") ||
g_str_has_prefix (pp->devices[device_id].device_uri, "mdns:"))
{
show_notification (_("Opening firewall for mDNS connections"),
NULL,
"dialog-information-symbolic");
service_disable ("mdns");
service_enable ("mdns", 0);
}
if (g_strrstr (pp->devices[device_id].device_uri, "smb:") != NULL)
{
show_notification (_("Opening firewall for Samba connections"),
NULL,
"dialog-information-symbolic");
service_disable ("samba-client");
service_enable ("samba-client", 0);
}
if (g_strrstr (pp->devices[device_id].device_uri, "ipp:") != NULL)
{
show_notification (_("Opening firewall for IPP connections"),
NULL,
"dialog-information-symbolic");
service_disable ("ipp");
service_enable ("ipp", 0);
service_disable ("ipp-client");
service_enable ("ipp-client", 0);
}
}
if (ppd_file_name)
{
GDBusProxy *proxy;
GVariant *input;
GVariant *output;
GVariant *array;
GList *executables = NULL;
GList *packages = NULL;
g_clear_error (&error);
error = NULL;
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
SCP_BUS,
SCP_PATH,
SCP_IFACE,
NULL,
&error);
if (proxy)
{
input = g_variant_new ("(s)",
ppd_file_name);
output = g_dbus_proxy_call_sync (proxy,
"MissingExecutables",
input,
G_DBUS_CALL_FLAGS_NONE,
60000,
NULL,
&error);
if (output && g_variant_n_children (output) == 1)
{
array = g_variant_get_child_value (output, 0);
if (array)
{
for (i = 0; i < g_variant_n_children (array); i++)
{
executables = g_list_append (
executables,
g_strdup (g_variant_get_string (
g_variant_get_child_value (array, i),
NULL)));
}
}
}
if (output)
g_variant_unref (output);
g_variant_unref (input);
g_object_unref (proxy);
}
if (proxy == NULL ||
(error &&
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.");
executables = g_list_sort (executables, (GCompareFunc) g_strcmp0);
executables = glist_uniq (executables);
if (executables)
{
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
PACKAGE_KIT_BUS,
PACKAGE_KIT_PATH,
PACKAGE_KIT_QUERY_IFACE,
NULL,
&error);
if (proxy)
{
GList *exec_iter;
for (exec_iter = executables; exec_iter; exec_iter = exec_iter->next)
{
input = g_variant_new ("(ss)", (gchar *) exec_iter->data, "");
output = g_dbus_proxy_call_sync (proxy,
"SearchFile",
input,
G_DBUS_CALL_FLAGS_NONE,
60000,
NULL,
&error);
if (error)
g_warning ("%s", error->message);
if (output)
{
gboolean installed;
gchar *package;
g_variant_get (output,
"(bs)",
&installed,
&package);
if (!installed)
packages = g_list_append (packages, g_strdup (package));
}
if (output)
g_variant_unref (output);
g_variant_unref (input);
}
g_object_unref (proxy);
}
g_list_free_full (executables, g_free);
}
packages = g_list_sort (packages, (GCompareFunc) g_strcmp0);
packages = glist_uniq (packages);
if (packages)
{
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
PACKAGE_KIT_BUS,
PACKAGE_KIT_PATH,
PACKAGE_KIT_MODIFY_IFACE,
NULL,
&error);
if (proxy)
{
GVariantBuilder array_builder;
GList *pkg_iter;
g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("as"));
for (pkg_iter = packages; pkg_iter; pkg_iter = pkg_iter->next)
g_variant_builder_add (&array_builder,
"s",
(gchar *) pkg_iter->data);
input = g_variant_new ("(uass)",
#ifdef GDK_WINDOWING_X11
GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (pp->dialog))),
#else
0,
#endif
&array_builder,
"hide-finished");
output = g_dbus_proxy_call_sync (proxy,
"InstallPackageNames",
input,
G_DBUS_CALL_FLAGS_NONE,
60000,
NULL,
&error);
if (error)
g_warning ("%s", error->message);
if (output)
g_variant_unref (output);
g_variant_unref (input);
g_object_unref (proxy);
}
g_list_free_full (packages, g_free);
}
}
if (ppd_file_name)
g_unlink (ppd_file_name);
}
}
pp_new_printer_dialog_hide (pp);
pp->user_callback (GTK_DIALOG (pp->dialog), dialog_response, pp->user_data);
}
static void
new_printer_cancel_button_cb (GtkButton *button,
gpointer user_data)
{
PpNewPrinterDialog *pp = (PpNewPrinterDialog*) user_data;
pp_new_printer_dialog_hide (pp);
pp->user_callback (GTK_DIALOG (pp->dialog), GTK_RESPONSE_CANCEL, pp->user_data);
}
PpNewPrinterDialog *
pp_new_printer_dialog_new (GtkWindow *parent,
UserResponseCallback user_callback,
gpointer user_data)
{
PpNewPrinterDialog *pp;
GtkWidget *widget;
GError *error = NULL;
gchar *objects[] = { "dialog", "main-vbox", NULL };
pp = g_new0 (PpNewPrinterDialog, 1);
pp->builder = gtk_builder_new ();
pp->parent = GTK_WIDGET (parent);
gtk_builder_add_objects_from_file (pp->builder,
DATADIR"/new-printer-dialog.ui",
objects, &error);
if (error)
{
g_warning ("Could not load ui: %s", error->message);
g_error_free (error);
return NULL;
}
pp->device_connection_types = NULL;
pp->num_device_connection_types = 0;
pp->devices = NULL;
pp->num_devices = 0;
pp->dialog = (GtkWidget *) gtk_builder_get_object (pp->builder, "dialog");
pp->user_callback = user_callback;
pp->user_data = user_data;
pp->cancellable = NULL;
pp->warning = NULL;
pp->show_warning = FALSE;
/* connect signals */
g_signal_connect (pp->dialog, "delete-event", G_CALLBACK (gtk_widget_hide_on_delete), NULL);
widget = (GtkWidget*)
gtk_builder_get_object (pp->builder, "new-printer-add-button");
g_signal_connect (widget, "clicked", G_CALLBACK (new_printer_add_button_cb), pp);
gtk_widget_set_sensitive (widget, FALSE);
widget = (GtkWidget*)
gtk_builder_get_object (pp->builder, "new-printer-cancel-button");
g_signal_connect (widget, "clicked", G_CALLBACK (new_printer_cancel_button_cb), pp);
widget = (GtkWidget*)
gtk_builder_get_object (pp->builder, "search-by-address-checkbutton");
g_signal_connect (widget, "toggled", G_CALLBACK (search_address_cb), pp);
gtk_window_set_transient_for (GTK_WINDOW (pp->dialog), GTK_WINDOW (parent));
gtk_window_set_modal (GTK_WINDOW (pp->dialog), TRUE);
gtk_window_present (GTK_WINDOW (pp->dialog));
gtk_widget_show_all (GTK_WIDGET (pp->dialog));
pp->searching = TRUE;
populate_device_types_list (pp);
populate_devices_list (pp);
return pp;
}
void
pp_new_printer_dialog_free (PpNewPrinterDialog *pp)
{
gint i;
for (i = 0; i < pp->num_device_connection_types; i++)
g_free (pp->device_connection_types[i]);
g_free (pp->device_connection_types);
pp->device_connection_types = NULL;
free_devices (pp);
gtk_widget_destroy (GTK_WIDGET (pp->dialog));
pp->dialog = NULL;
g_object_unref (pp->builder);
pp->builder = NULL;
if (pp->cancellable)
{
g_cancellable_cancel (pp->cancellable);
g_object_unref (pp->cancellable);
}
g_free (pp->warning);
g_free (pp);
}
static void
pp_new_printer_dialog_hide (PpNewPrinterDialog *pp)
{
gtk_widget_hide (GTK_WIDGET (pp->dialog));
}