gnome-control-center/panels/printers/pp-new-printer-dialog.c
Marek Kasik 7962a25ecf Printers: Open firewall for required connections when searching for printers
This commit enables services mdns, ipp, ipp-client and samba-client on
firewall for 5 minutes for detection of network printers (#648784).
It enables required services permanently for printers selected by user
for addition then. It shows a notification for the permanent enable.
It uses firewalld, so if it is not installed or running it shows a warning
message to the user in the place where discovered printers will be shown
(both local and network). The warning disappears after the finish of
printers discovery (but not from network part if no printer was found).
2011-07-27 13:33:48 +02:00

1779 lines
59 KiB
C

/* -*- 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_IFACE "org.freedesktop.PackageKit.Modify"
#define FIREWALLD_BUS "org.fedoraproject.FirewallD"
#define FIREWALLD_PATH "/org/fedoraproject/FirewallD"
#define FIREWALLD_IFACE "org.fedoraproject.FirewallD"
#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,
DEVICE_TYPE_N
};
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;
};
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 *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");
if (pp->show_warning && device_type == DEVICE_TYPE_NETWORK)
gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 2);
else
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");
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
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;
GtkWidget *widget = NULL;
GVariant *dg_output = NULL;
gboolean already_present;
GError *error = NULL;
gchar *new_name = NULL;
char *ret_error = NULL;
gint i, j;
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.
*/
for (i = 0; i < pp->num_devices; i++)
{
for (j = 0; j < pp->num_devices; j++)
{
if (i != j)
{
if (g_strcmp0 (pp->devices[i].display_name, pp->devices[j].display_name) == 0)
{
if (pp->devices[i].device_id && !pp->devices[j].show)
{
pp->devices[i].show = TRUE;
}
}
}
}
}
}
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);
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;
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, "device-type-notebook");
gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 2);
}
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);
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);
}
}
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[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;
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;
}
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;
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)
{
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;
}
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);
}
}
}
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 (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 (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");
if (pp->show_warning && device_type == DEVICE_TYPE_NETWORK)
gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 2);
else
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, "warning-textview");
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 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_class,
pp->devices[device_id].device_id,
pp->devices[device_id].device_info,
pp->devices[device_id].device_make_and_model,
pp->devices[device_id].device_uri,
pp->devices[device_id].device_location);
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_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_class,
pp->devices[device_id].device_id,
pp->devices[device_id].device_info,
pp->devices[device_id].device_make_and_model,
pp->devices[device_id].device_uri,
pp->devices[device_id].device_location);
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)
{
DBusGProxy *proxy;
GError *error = NULL;
char *ret_error = NULL;
char *locale = NULL;
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 */
locale = setlocale (LC_PAPER, NULL);
if (locale == NULL)
locale = setlocale (LC_MESSAGES, NULL);
if (locale)
{
const char *ppd_file_name = NULL;
ppd_file_t *ppd_file = NULL;
gchar **value = NULL;
gchar *paper_size;
/* CLDR 2.0 alpha
* http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/territory_language_information.html
*/
if (g_regex_match_simple ("[^_.@]{2,3}_(BZ|CA|CL|CO|CR|GT|MX|NI|PA|PH|PR|SV|US|VE)",
locale, G_REGEX_ANCHORED, G_REGEX_MATCH_ANCHORED))
paper_size = g_strdup ("Letter");
else
paper_size = g_strdup ("A4");
ppd_file_name = cupsGetPPD (pp->devices[device_id].display_name);
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);
}
g_unlink (ppd_file_name);
}
if (value)
{
dbus_g_proxy_call (proxy, "PrinterAddOptionDefault", &error,
G_TYPE_STRING, pp->devices[device_id].display_name,
G_TYPE_STRING, "PageSize-default",
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_free (paper_size);
}
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);
}
}
}
}
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));
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));
}