diff options
Diffstat (limited to 'panels/printers/pp-new-printer-dialog.c')
-rw-r--r-- | panels/printers/pp-new-printer-dialog.c | 1929 |
1 files changed, 1929 insertions, 0 deletions
diff --git a/panels/printers/pp-new-printer-dialog.c b/panels/printers/pp-new-printer-dialog.c new file mode 100644 index 0000000..a3c0e48 --- /dev/null +++ b/panels/printers/pp-new-printer-dialog.c @@ -0,0 +1,1929 @@ +/* -*- 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 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/>. + * + */ + +#include "config.h" + +#include <unistd.h> +#include <stdlib.h> + +#include <adwaita.h> +#include <glib.h> +#include <glib/gi18n.h> +#include <glib/gstdio.h> +#include <gdk/x11/gdkx.h> +#include <gtk/gtk.h> + +#include "pp-new-printer-dialog.h" +#include "pp-cups.h" +#include "pp-host.h" +#include "pp-new-printer.h" +#include "pp-ppd-selection-dialog.h" +#include "pp-samba.h" +#include "pp-utils.h" + +#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 + +/* + * Additional delay to the default 150ms delay in GtkSearchEntry + * resulting in total delay of 500ms. + */ +#define HOST_SEARCH_DELAY (500 - 150) + +#define AUTHENTICATION_PAGE "authentication-page" +#define ADDPRINTER_PAGE "addprinter-page" + +static void set_device (PpNewPrinterDialog *self, + PpPrintDevice *device, + GtkTreeIter *iter); +static void replace_device (PpNewPrinterDialog *self, + PpPrintDevice *old_device, + PpPrintDevice *new_device); +static void populate_devices_list (PpNewPrinterDialog *self); +static void search_entry_activated_cb (PpNewPrinterDialog *self); +static void search_entry_changed_cb (PpNewPrinterDialog *self); +static void new_printer_dialog_response_cb (PpNewPrinterDialog *self, + gint response_id); +static void update_dialog_state (PpNewPrinterDialog *self); +static void add_devices_to_list (PpNewPrinterDialog *self, + GPtrArray *devices); +static void remove_device_from_list (PpNewPrinterDialog *self, + const gchar *device_name); + +enum +{ + DEVICE_GICON_COLUMN = 0, + DEVICE_NAME_COLUMN, + DEVICE_DISPLAY_NAME_COLUMN, + DEVICE_DESCRIPTION_COLUMN, + SERVER_NEEDS_AUTHENTICATION_COLUMN, + DEVICE_VISIBLE_COLUMN, + DEVICE_COLUMN, + DEVICE_N_COLUMNS +}; + +struct _PpNewPrinterDialog +{ + GtkDialog parent_instance; + + GPtrArray *local_cups_devices; + + GtkListStore *devices_liststore; + GtkTreeModelFilter *devices_model_filter; + + /* headerbar */ + GtkHeaderBar *headerbar; + AdwWindowTitle *header_title; + + /* headerbar topleft buttons */ + GtkStack *headerbar_topleft_buttons; + GtkButton *go_back_button; + + /* headerbar topright buttons */ + GtkStack *headerbar_topright_buttons; + GtkButton *new_printer_add_button; + GtkButton *unlock_button; + GtkButton *authenticate_button; + /* end headerbar */ + + /* dialogstack */ + GtkStack *dialog_stack; + GtkStack *stack; + + /* scrolledwindow1 */ + GtkScrolledWindow *scrolledwindow1; + GtkTreeView *devices_treeview; + + GtkEntry *search_entry; + + /* authentication page */ + GtkLabel *authentication_title; + GtkLabel *authentication_text; + GtkEntry *username_entry; + GtkEntry *password_entry; + /* end dialog stack */ + + UserResponseCallback user_callback; + gpointer user_data; + + cups_dest_t *dests; + gint num_of_dests; + + GCancellable *cancellable; + GCancellable *remote_host_cancellable; + + gboolean cups_searching; + gboolean samba_authenticated_searching; + gboolean samba_searching; + + PpPPDSelectionDialog *ppd_selection_dialog; + + PpPrintDevice *new_device; + + PPDList *list; + + GIcon *local_printer_icon; + GIcon *remote_printer_icon; + GIcon *authenticated_server_icon; + + PpHost *snmp_host; + PpHost *socket_host; + PpHost *lpd_host; + PpHost *remote_cups_host; + PpSamba *samba_host; + guint host_search_timeout_id; +}; + +G_DEFINE_TYPE (PpNewPrinterDialog, pp_new_printer_dialog, GTK_TYPE_DIALOG) + +typedef struct +{ + gchar *server_name; + gpointer dialog; +} AuthSMBData; + +static void +get_authenticated_samba_devices_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + AuthSMBData *data = user_data; + PpNewPrinterDialog *self = PP_NEW_PRINTER_DIALOG (data->dialog); + g_autoptr(GPtrArray) devices = NULL; + gboolean cancelled = FALSE; + g_autoptr(GError) error = NULL; + + devices = pp_samba_get_devices_finish (PP_SAMBA (source_object), res, &error); + + if (devices != NULL) + { + self->samba_authenticated_searching = FALSE; + + for (guint i = 0; i < devices->len; i++) + { + PpPrintDevice *device = g_ptr_array_index (devices, i); + + if (pp_print_device_is_authenticated_server (device)) + { + cancelled = TRUE; + break; + } + } + + if (!cancelled) + { + if (devices != NULL) + { + add_devices_to_list (self, devices); + + if (devices->len > 0) + { + gtk_editable_set_text (GTK_EDITABLE (self->search_entry), + pp_print_device_get_device_location (g_ptr_array_index (devices, 0))); + search_entry_activated_cb (self); + } + } + } + + update_dialog_state (self); + } + else + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_warning ("%s", error->message); + + self->samba_authenticated_searching = FALSE; + update_dialog_state (self); + } + } + + g_free (data->server_name); + g_free (data); +} + +static void +go_to_page (PpNewPrinterDialog *self, + const gchar *page) +{ + gtk_stack_set_visible_child_name (self->dialog_stack, page); + gtk_stack_set_visible_child_name (self->headerbar_topright_buttons, page); + gtk_stack_set_visible_child_name (self->headerbar_topleft_buttons, page); +} + +static void +on_authenticate (PpNewPrinterDialog *self) +{ + gchar *hostname = NULL; + gchar *username = NULL; + gchar *password = NULL; + + username = g_strdup (gtk_editable_get_text (GTK_EDITABLE (self->username_entry))); + password = g_strdup (gtk_editable_get_text (GTK_EDITABLE (self->password_entry))); + + if ((username == NULL) || (username[0] == '\0') || + (password == NULL) || (password[0] == '\0')) + { + g_clear_pointer (&username, g_free); + g_clear_pointer (&password, g_free); + return; + } + + pp_samba_set_auth_info (PP_SAMBA (self->samba_host), username, password); + + adw_window_title_set_title (self->header_title, _("Add Printer")); + go_to_page (self, ADDPRINTER_PAGE); + + g_object_get (PP_HOST (self->samba_host), "hostname", &hostname, NULL); + remove_device_from_list (self, hostname); +} + +static void +on_authentication_required (PpNewPrinterDialog *self) +{ + g_autofree gchar *hostname = NULL; + g_autofree gchar *title = NULL; + g_autofree gchar *text = NULL; + + adw_window_title_set_subtitle (self->header_title, NULL); + adw_window_title_set_title (self->header_title, _("Unlock Print Server")); + + g_object_get (self->samba_host, "hostname", &hostname, NULL); + /* Translators: Samba server needs authentication of the user to show list of its printers. */ + title = g_strdup_printf (_("Unlock %s."), hostname); + gtk_label_set_text (self->authentication_title, title); + + /* Translators: Samba server needs authentication of the user to show list of its printers. */ + text = g_strdup_printf (_("Enter username and password to view printers on %s."), hostname); + gtk_label_set_text (self->authentication_text, text); + + go_to_page (self, AUTHENTICATION_PAGE); + + g_signal_connect_object (self->authenticate_button, "clicked", G_CALLBACK (on_authenticate), self, G_CONNECT_SWAPPED); +} + +static void +auth_entries_changed (PpNewPrinterDialog *self) +{ + gboolean can_authenticate = FALSE; + gchar *username = NULL; + gchar *password = NULL; + + username = g_strdup (gtk_editable_get_text (GTK_EDITABLE (self->username_entry))); + password = g_strdup (gtk_editable_get_text (GTK_EDITABLE (self->password_entry))); + + can_authenticate = (username != NULL && username[0] != '\0' && + password != NULL && password[0] != '\0'); + + gtk_widget_set_sensitive (GTK_WIDGET (self->authenticate_button), can_authenticate); + + g_clear_pointer (&username, g_free); + g_clear_pointer (&password, g_free); +} + +static void +on_go_back_button_clicked (PpNewPrinterDialog *self) +{ + pp_samba_set_auth_info (self->samba_host, NULL, NULL); + g_clear_object (&self->samba_host); + + go_to_page (self, ADDPRINTER_PAGE); + adw_window_title_set_title (self->header_title, _("Add Printer")); + gtk_widget_set_sensitive (GTK_WIDGET (self->new_printer_add_button), FALSE); + + gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (self->devices_treeview)); +} + +static void +authenticate_samba_server (PpNewPrinterDialog *self) +{ + GtkTreeModel *model; + GtkTreeIter iter; + AuthSMBData *data; + gchar *server_name = NULL; + + gtk_widget_set_sensitive (GTK_WIDGET (self->unlock_button), FALSE); + gtk_widget_set_sensitive (GTK_WIDGET (self->authenticate_button), FALSE); + gtk_widget_grab_focus (GTK_WIDGET (self->username_entry)); + + if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (self->devices_treeview), &model, &iter)) + { + gtk_tree_model_get (model, &iter, + DEVICE_NAME_COLUMN, &server_name, + -1); + + if (server_name != NULL) + { + g_clear_object (&self->samba_host); + + self->samba_host = pp_samba_new (server_name); + g_signal_connect_object (self->samba_host, + "authentication-required", + G_CALLBACK (on_authentication_required), + self, G_CONNECT_SWAPPED); + + self->samba_authenticated_searching = TRUE; + update_dialog_state (self); + + data = g_new (AuthSMBData, 1); + data->server_name = server_name; + data->dialog = self; + + pp_samba_get_devices_async (self->samba_host, + TRUE, + self->cancellable, + get_authenticated_samba_devices_cb, + data); + } + } +} + +static void +device_selection_changed_cb (PpNewPrinterDialog *self) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gboolean authentication_needed; + gboolean selected; + + selected = gtk_tree_selection_get_selected (gtk_tree_view_get_selection (self->devices_treeview), + &model, + &iter); + + if (selected) + { + gtk_tree_model_get (model, &iter, + SERVER_NEEDS_AUTHENTICATION_COLUMN, &authentication_needed, + -1); + + gtk_widget_set_sensitive (GTK_WIDGET (self->new_printer_add_button), selected); + gtk_widget_set_sensitive (GTK_WIDGET (self->unlock_button), authentication_needed); + + if (authentication_needed) + gtk_stack_set_visible_child_name (self->headerbar_topright_buttons, "unlock_button"); + else + gtk_stack_set_visible_child_name (self->headerbar_topright_buttons, ADDPRINTER_PAGE); + } +} + +static void +remove_device_from_list (PpNewPrinterDialog *self, + const gchar *device_name) +{ + GtkTreeIter iter; + gboolean cont; + + cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->devices_liststore), &iter); + while (cont) + { + g_autoptr(PpPrintDevice) device = NULL; + + gtk_tree_model_get (GTK_TREE_MODEL (self->devices_liststore), &iter, + DEVICE_COLUMN, &device, + -1); + + if (g_strcmp0 (pp_print_device_get_device_name (device), device_name) == 0) + { + gtk_list_store_remove (self->devices_liststore, &iter); + break; + } + + cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->devices_liststore), &iter); + } + + update_dialog_state (self); +} + +static gboolean +prepend_original_name (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + g_autoptr(PpPrintDevice) device = NULL; + GList **list = data; + + gtk_tree_model_get (model, iter, + DEVICE_COLUMN, &device, + -1); + + *list = g_list_prepend (*list, g_strdup (pp_print_device_get_device_original_name (device))); + + return FALSE; +} + +static void +add_device_to_list (PpNewPrinterDialog *self, + PpPrintDevice *device) +{ + GList *original_names_list = NULL; + gint acquisition_method; + + if (device) + { + if (pp_print_device_get_host_name (device) == NULL) + { + g_autofree gchar *host_name = guess_device_hostname (device); + g_object_set (device, "host-name", host_name, NULL); + } + + acquisition_method = pp_print_device_get_acquisition_method (device); + if (pp_print_device_get_device_id (device) || + pp_print_device_get_device_ppd (device) || + (pp_print_device_get_host_name (device) && + acquisition_method == ACQUISITION_METHOD_REMOTE_CUPS_SERVER) || + acquisition_method == ACQUISITION_METHOD_SAMBA_HOST || + acquisition_method == ACQUISITION_METHOD_SAMBA || + (pp_print_device_get_device_uri (device) && + (acquisition_method == ACQUISITION_METHOD_JETDIRECT || + acquisition_method == ACQUISITION_METHOD_LPD))) + { + g_autofree gchar *canonicalized_name = NULL; + + g_object_set (device, + "device-original-name", pp_print_device_get_device_name (device), + NULL); + + gtk_tree_model_foreach (GTK_TREE_MODEL (self->devices_liststore), + prepend_original_name, + &original_names_list); + + original_names_list = g_list_reverse (original_names_list); + + canonicalized_name = canonicalize_device_name (original_names_list, + self->local_cups_devices, + self->dests, + self->num_of_dests, + device); + + g_list_free_full (original_names_list, g_free); + + g_object_set (device, + "display-name", canonicalized_name, + "device-name", canonicalized_name, + NULL); + + if (pp_print_device_get_acquisition_method (device) == ACQUISITION_METHOD_DEFAULT_CUPS_SERVER) + g_ptr_array_add (self->local_cups_devices, g_object_ref (device)); + else + set_device (self, device, NULL); + } + else if (pp_print_device_is_authenticated_server (device) && + pp_print_device_get_host_name (device) != NULL) + { + g_autoptr(PpPrintDevice) store_device = NULL; + + store_device = g_object_new (PP_TYPE_PRINT_DEVICE, + "device-name", pp_print_device_get_host_name (device), + "host-name", pp_print_device_get_host_name (device), + "is-authenticated-server", pp_print_device_is_authenticated_server (device), + NULL); + + set_device (self, store_device, NULL); + } + } +} + +static void +add_devices_to_list (PpNewPrinterDialog *self, + GPtrArray *devices) +{ + for (guint i = 0; i < devices->len; i++) + add_device_to_list (self, g_ptr_array_index (devices, i)); +} + +static PpPrintDevice * +device_in_list (gchar *device_uri, + GPtrArray *device_list) +{ + for (guint i = 0; i < device_list->len; i++) + { + PpPrintDevice *device = g_ptr_array_index (device_list, i); + /* GroupPhysicalDevices returns uris without port numbers */ + if (pp_print_device_get_device_uri (device) != NULL && + g_str_has_prefix (pp_print_device_get_device_uri (device), device_uri)) + return g_object_ref (device); + } + + return NULL; +} + +static PpPrintDevice * +device_in_liststore (gchar *device_uri, + GtkListStore *device_liststore) +{ + GtkTreeIter iter; + gboolean cont; + + cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (device_liststore), &iter); + while (cont) + { + g_autoptr(PpPrintDevice) device = NULL; + + gtk_tree_model_get (GTK_TREE_MODEL (device_liststore), &iter, + DEVICE_COLUMN, &device, + -1); + + /* GroupPhysicalDevices returns uris without port numbers */ + if (pp_print_device_get_device_uri (device) != NULL && + g_str_has_prefix (pp_print_device_get_device_uri (device), device_uri)) + { + return g_steal_pointer(&device); + } + + cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (device_liststore), &iter); + } + + return NULL; +} + +static void +update_dialog_state (PpNewPrinterDialog *self) +{ + GtkTreeIter iter; + gboolean searching; + + searching = self->cups_searching || + self->remote_cups_host != NULL || + self->snmp_host != NULL || + self->socket_host != NULL || + self->lpd_host != NULL || + self->samba_host != NULL || + self->samba_authenticated_searching || + self->samba_searching; + + if (searching) + { + adw_window_title_set_subtitle (self->header_title, _("Searching for Printers")); + } + else + { + adw_window_title_set_subtitle (self->header_title, NULL); + } + + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->devices_liststore), &iter)) + gtk_stack_set_visible_child_name (self->stack, "standard-page"); + else + gtk_stack_set_visible_child_name (self->stack, searching ? "loading-page" : "no-printers-page"); +} + +static void +group_physical_devices_cb (gchar ***device_uris, + gpointer user_data) +{ + PpNewPrinterDialog *self = user_data; + gint i, j; + + if (device_uris != NULL) + { + for (i = 0; device_uris[i] != NULL; i++) + { + /* Is there any device in this sublist? */ + if (device_uris[i][0] != NULL) + { + g_autoptr(PpPrintDevice) device = NULL; + + for (j = 0; device_uris[i][j] != NULL; j++) + { + device = device_in_liststore (device_uris[i][j], self->devices_liststore); + if (device != NULL) + break; + } + + /* Is this sublist represented in the current list of devices? */ + if (device != NULL) + { + /* Is there better device in the sublist? */ + if (j != 0) + { + g_autoptr(PpPrintDevice) better_device = NULL; + + better_device = device_in_list (device_uris[i][0], self->local_cups_devices); + replace_device (self, device, better_device); + } + } + else + { + device = device_in_list (device_uris[i][0], self->local_cups_devices); + if (device != NULL) + set_device (self, device, NULL); + } + } + } + + for (i = 0; device_uris[i] != NULL; i++) + g_strfreev (device_uris[i]); + + g_free (device_uris); + } + else + { + for (i = 0; i < self->local_cups_devices->len; i++) + set_device (self, g_ptr_array_index (self->local_cups_devices, i), NULL); + g_ptr_array_set_size (self->local_cups_devices, 0); + } + + update_dialog_state (self); +} + +static void +group_physical_devices_dbus_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GVariant) output = NULL; + g_autoptr(GError) error = NULL; + gchar ***result = NULL; + gint i; + + output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), + res, + &error); + + if (output) + { + g_autoptr(GVariant) array = NULL; + + g_variant_get (output, "(@aas)", &array); + + if (array) + { + g_autoptr(GVariantIter) iter = NULL; + GStrv device_uris; + + result = g_new0 (gchar **, g_variant_n_children (array) + 1); + g_variant_get (array, "aas", &iter); + i = 0; + while (g_variant_iter_next (iter, "^as", &device_uris)) + { + result[i] = device_uris; + i++; + } + } + } + else if (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 \"GroupPhysicalDevices\" to group duplicates in device list."); + } + else + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("%s", error->message); + } + + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + group_physical_devices_cb (result, user_data); +} + +static void +get_cups_devices_cb (GPtrArray *devices, + gboolean finished, + gboolean cancelled, + gpointer user_data) +{ + PpNewPrinterDialog *self = user_data; + g_autoptr(GDBusConnection) bus = NULL; + GVariantBuilder device_list; + GVariantBuilder device_hash; + PpPrintDevice **all_devices; + const gchar *device_class; + GtkTreeIter iter; + gboolean cont; + g_autoptr(GError) error = NULL; + gint length, i; + + + if (!cancelled) + { + if (finished) + { + self->cups_searching = FALSE; + } + + if (devices != NULL) + { + add_devices_to_list (self, devices); + + length = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (self->devices_liststore), NULL) + self->local_cups_devices->len; + if (length > 0) + { + all_devices = g_new0 (PpPrintDevice *, length); + + i = 0; + cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->devices_liststore), &iter); + while (cont) + { + g_autoptr(PpPrintDevice) device = NULL; + + gtk_tree_model_get (GTK_TREE_MODEL (self->devices_liststore), &iter, + DEVICE_COLUMN, &device, + -1); + + all_devices[i] = g_object_new (PP_TYPE_PRINT_DEVICE, + "device-id", pp_print_device_get_device_id (device), + "device-make-and-model", pp_print_device_get_device_make_and_model (device), + "is-network-device", pp_print_device_is_network_device (device), + "device-uri", pp_print_device_get_device_uri (device), + NULL); + i++; + + cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->devices_liststore), &iter); + } + + for (guint j = 0; j < self->local_cups_devices->len; j++) + { + PpPrintDevice *pp_device = g_ptr_array_index (self->local_cups_devices, j); + all_devices[i] = g_object_new (PP_TYPE_PRINT_DEVICE, + "device-id", pp_print_device_get_device_id (pp_device), + "device-make-and-model", pp_print_device_get_device_make_and_model (pp_device), + "is-network-device", pp_print_device_is_network_device (pp_device), + "device-uri", pp_print_device_get_device_uri (pp_device), + NULL); + i++; + } + + bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); + if (bus) + { + g_variant_builder_init (&device_list, G_VARIANT_TYPE ("a{sv}")); + + for (i = 0; i < length; i++) + { + if (pp_print_device_get_device_uri (all_devices[i])) + { + g_variant_builder_init (&device_hash, G_VARIANT_TYPE ("a{ss}")); + + if (pp_print_device_get_device_id (all_devices[i])) + g_variant_builder_add (&device_hash, + "{ss}", + "device-id", + pp_print_device_get_device_id (all_devices[i])); + + if (pp_print_device_get_device_make_and_model (all_devices[i])) + g_variant_builder_add (&device_hash, + "{ss}", + "device-make-and-model", + pp_print_device_get_device_make_and_model (all_devices[i])); + + if (pp_print_device_is_network_device (all_devices[i])) + device_class = "network"; + else + device_class = "direct"; + + g_variant_builder_add (&device_hash, + "{ss}", + "device-class", + device_class); + + g_variant_builder_add (&device_list, + "{sv}", + pp_print_device_get_device_uri (all_devices[i]), + g_variant_builder_end (&device_hash)); + } + } + + g_dbus_connection_call (bus, + SCP_BUS, + SCP_PATH, + SCP_IFACE, + "GroupPhysicalDevices", + g_variant_new ("(v)", g_variant_builder_end (&device_list)), + G_VARIANT_TYPE ("(aas)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + self->cancellable, + group_physical_devices_dbus_cb, + self); + } + else + { + g_warning ("Failed to get system bus: %s", error->message); + group_physical_devices_cb (NULL, user_data); + } + + for (i = 0; i < length; i++) + g_object_unref (all_devices[i]); + g_free (all_devices); + } + else + { + update_dialog_state (self); + } + } + else + { + update_dialog_state (self); + } + } +} + +static void +get_snmp_devices_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + PpNewPrinterDialog *self = user_data; + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) devices = NULL; + + devices = pp_host_get_snmp_devices_finish (PP_HOST (source_object), res, &error); + + if (devices != NULL) + { + g_clear_object(&self->snmp_host); + + add_devices_to_list (self, devices); + + update_dialog_state (self); + } + else + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_warning ("%s", error->message); + + g_clear_object(&self->snmp_host); + + update_dialog_state (self); + } + } +} + +static void +get_remote_cups_devices_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + PpNewPrinterDialog *self = user_data; + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) devices = NULL; + + devices = pp_host_get_remote_cups_devices_finish (PP_HOST (source_object), res, &error); + + if (devices != NULL) + { + g_clear_object(&self->remote_cups_host); + + add_devices_to_list (self, devices); + + update_dialog_state (self); + } + else + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_warning ("%s", error->message); + + g_clear_object(&self->remote_cups_host); + + update_dialog_state (self); + } + } +} + +static void +get_samba_host_devices_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + PpNewPrinterDialog *self = user_data; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GError) error = NULL; + + devices = pp_samba_get_devices_finish (PP_SAMBA (source_object), res, &error); + + if (devices != NULL) + { + g_clear_object(&self->samba_host); + + add_devices_to_list (self, devices); + + update_dialog_state (self); + } + else + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_warning ("%s", error->message); + + g_clear_object(&self->samba_host); + + update_dialog_state (self); + } + } +} + +static void +get_samba_devices_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + PpNewPrinterDialog *self = user_data; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GError) error = NULL; + + devices = pp_samba_get_devices_finish (PP_SAMBA (source_object), res, &error); + + if (devices != NULL) + { + self->samba_searching = FALSE; + + add_devices_to_list (self, devices); + + update_dialog_state (self); + } + else + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_warning ("%s", error->message); + + self->samba_searching = FALSE; + + update_dialog_state (self); + } + } +} + +static void +get_jetdirect_devices_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + PpNewPrinterDialog *self = user_data; + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) devices = NULL; + + devices = pp_host_get_jetdirect_devices_finish (PP_HOST (source_object), res, &error); + + if (devices != NULL) + { + g_clear_object(&self->socket_host); + + add_devices_to_list (self, devices); + + update_dialog_state (self); + } + else + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_warning ("%s", error->message); + + g_clear_object(&self->socket_host); + + update_dialog_state (self); + } + } +} + +static void +get_lpd_devices_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + PpNewPrinterDialog *self = user_data; + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) devices = NULL; + + devices = pp_host_get_lpd_devices_finish (PP_HOST (source_object), res, &error); + + if (devices != NULL) + { + g_clear_object(&self->lpd_host); + + add_devices_to_list (self, devices); + + update_dialog_state (self); + } + else + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_warning ("%s", error->message); + + g_clear_object(&self->lpd_host); + + update_dialog_state (self); + } + } +} + +static void +get_cups_devices (PpNewPrinterDialog *self) +{ + self->cups_searching = TRUE; + update_dialog_state (self); + + get_cups_devices_async (self->cancellable, + get_cups_devices_cb, + self); +} + +static gboolean +parse_uri (const gchar *uri, + gchar **scheme, + gchar **host, + gint *port) +{ + const gchar *tmp = NULL; + g_autofree gchar *resulting_host = NULL; + gchar *position; + + *port = PP_HOST_UNSET_PORT; + + position = g_strrstr (uri, "://"); + if (position != NULL) + { + *scheme = g_strndup (uri, position - uri); + tmp = position + 3; + } + else + { + tmp = uri; + } + + if (g_strrstr (tmp, "@")) + tmp = g_strrstr (tmp, "@") + 1; + + if ((position = g_strrstr (tmp, "/"))) + { + *position = '\0'; + resulting_host = g_strdup (tmp); + *position = '/'; + } + else + { + resulting_host = g_strdup (tmp); + } + + if ((position = g_strrstr (resulting_host, ":"))) + { + *position = '\0'; + *port = atoi (position + 1); + } + + *host = g_uri_unescape_string (resulting_host, + G_URI_RESERVED_CHARS_GENERIC_DELIMITERS + G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS); + + return TRUE; +} + +typedef struct +{ + PpNewPrinterDialog *dialog; + gchar *host_scheme; + gchar *host_name; + gint host_port; +} THostSearchData; + +static void +search_for_remote_printers_free (THostSearchData *data) +{ + g_free (data->host_scheme); + g_free (data->host_name); + g_free (data); +} + +static gboolean +search_for_remote_printers (THostSearchData *data) +{ + PpNewPrinterDialog *self = data->dialog; + + g_cancellable_cancel (self->remote_host_cancellable); + g_clear_object (&self->remote_host_cancellable); + + self->remote_host_cancellable = g_cancellable_new (); + + self->remote_cups_host = pp_host_new (data->host_name); + self->snmp_host = pp_host_new (data->host_name); + self->socket_host = pp_host_new (data->host_name); + self->lpd_host = pp_host_new (data->host_name); + + if (data->host_port != PP_HOST_UNSET_PORT) + { + g_object_set (self->remote_cups_host, "port", data->host_port, NULL); + g_object_set (self->snmp_host, "port", data->host_port, NULL); + + /* Accept port different from the default one only if user specifies + * scheme (for socket and lpd printers). + */ + if (data->host_scheme != NULL && + g_ascii_strcasecmp (data->host_scheme, "socket") == 0) + g_object_set (self->socket_host, "port", data->host_port, NULL); + + if (data->host_scheme != NULL && + g_ascii_strcasecmp (data->host_scheme, "lpd") == 0) + g_object_set (self->lpd_host, "port", data->host_port, NULL); + } + + self->samba_host = pp_samba_new (data->host_name); + + update_dialog_state (data->dialog); + + pp_host_get_remote_cups_devices_async (self->remote_cups_host, + self->remote_host_cancellable, + get_remote_cups_devices_cb, + data->dialog); + + pp_host_get_snmp_devices_async (self->snmp_host, + self->remote_host_cancellable, + get_snmp_devices_cb, + data->dialog); + + pp_host_get_jetdirect_devices_async (self->socket_host, + self->remote_host_cancellable, + get_jetdirect_devices_cb, + data->dialog); + + pp_host_get_lpd_devices_async (self->lpd_host, + self->remote_host_cancellable, + get_lpd_devices_cb, + data->dialog); + + pp_samba_get_devices_async (self->samba_host, + FALSE, + self->remote_host_cancellable, + get_samba_host_devices_cb, + data->dialog); + + self->host_search_timeout_id = 0; + + return G_SOURCE_REMOVE; +} + +static void +search_address (const gchar *text, + PpNewPrinterDialog *self, + gboolean delay_search) +{ + GtkTreeIter iter; + gboolean found = FALSE; + gboolean subfound; + gboolean next_set; + gboolean cont; + g_autofree gchar *lowercase_text = NULL; + gchar **words; + gint words_length = 0; + gint i; + gint acquisition_method; + + lowercase_text = g_ascii_strdown (text, -1); + words = g_strsplit_set (lowercase_text, " ", -1); + + if (words) + { + words_length = g_strv_length (words); + + cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->devices_liststore), &iter); + while (cont) + { + g_autoptr(PpPrintDevice) device = NULL; + g_autofree gchar *lowercase_name = NULL; + g_autofree gchar *lowercase_location = NULL; + + gtk_tree_model_get (GTK_TREE_MODEL (self->devices_liststore), &iter, + DEVICE_COLUMN, &device, + -1); + + lowercase_name = g_ascii_strdown (pp_print_device_get_device_name (device), -1); + if (pp_print_device_get_device_location (device)) + lowercase_location = g_ascii_strdown (pp_print_device_get_device_location (device), -1); + else + lowercase_location = NULL; + + subfound = TRUE; + for (i = 0; words[i]; i++) + { + if (!g_strrstr (lowercase_name, words[i]) && + (!lowercase_location || !g_strrstr (lowercase_location, words[i]))) + subfound = FALSE; + } + + if (subfound) + found = TRUE; + + gtk_list_store_set (GTK_LIST_STORE (self->devices_liststore), &iter, + DEVICE_VISIBLE_COLUMN, subfound, + -1); + + cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->devices_liststore), &iter); + } + + g_strfreev (words); + } + + /* + * The given word is probably an address since it was not found among + * already present devices. + */ + if (!found && words_length == 1) + { + cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->devices_liststore), &iter); + while (cont) + { + g_autoptr(PpPrintDevice) device = NULL; + + next_set = FALSE; + gtk_tree_model_get (GTK_TREE_MODEL (self->devices_liststore), &iter, + DEVICE_COLUMN, &device, + -1); + + gtk_list_store_set (GTK_LIST_STORE (self->devices_liststore), &iter, + DEVICE_VISIBLE_COLUMN, TRUE, + -1); + + acquisition_method = pp_print_device_get_acquisition_method (device); + if (acquisition_method == ACQUISITION_METHOD_REMOTE_CUPS_SERVER || + acquisition_method == ACQUISITION_METHOD_SNMP || + acquisition_method == ACQUISITION_METHOD_JETDIRECT || + acquisition_method == ACQUISITION_METHOD_LPD || + acquisition_method == ACQUISITION_METHOD_SAMBA_HOST) + { + if (!gtk_list_store_remove (self->devices_liststore, &iter)) + break; + else + next_set = TRUE; + } + + if (!next_set) + cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->devices_liststore), &iter); + } + + if (text && text[0] != '\0') + { + g_autoptr(GSocketConnectable) conn = NULL; + g_autofree gchar *test_uri = NULL; + g_autofree gchar *test_port = NULL; + gchar *scheme = NULL; + gchar *host = NULL; + gint port; + + parse_uri (text, &scheme, &host, &port); + + if (host != NULL) + { + if (port >= 0) + test_port = g_strdup_printf (":%d", port); + else + test_port = g_strdup (""); + + test_uri = g_strdup_printf ("%s://%s%s", + scheme != NULL && scheme[0] != '\0' ? scheme : "none", + host, + test_port); + + conn = g_network_address_parse_uri (test_uri, 0, NULL); + if (conn != NULL) + { + THostSearchData *search_data; + + search_data = g_new (THostSearchData, 1); + search_data->host_scheme = scheme; + search_data->host_name = host; + search_data->host_port = port; + search_data->dialog = self; + + if (self->host_search_timeout_id != 0) + { + g_source_remove (self->host_search_timeout_id); + self->host_search_timeout_id = 0; + } + + if (delay_search) + { + self->host_search_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT, + HOST_SEARCH_DELAY, + (GSourceFunc) search_for_remote_printers, + search_data, + (GDestroyNotify) search_for_remote_printers_free); + } + else + { + search_for_remote_printers (search_data); + search_for_remote_printers_free (search_data); + } + } + } + } + } +} + +static void +search_entry_activated_cb (PpNewPrinterDialog *self) +{ + search_address (gtk_editable_get_text (GTK_EDITABLE (self->search_entry)), + self, + FALSE); +} + +static void +search_entry_changed_cb (PpNewPrinterDialog *self) +{ + search_address (gtk_editable_get_text (GTK_EDITABLE (self->search_entry)), + self, + TRUE); +} + +static gchar * +get_local_scheme_description_from_uri (gchar *device_uri) +{ + gchar *description = NULL; + + if (device_uri != NULL) + { + if (g_str_has_prefix (device_uri, "usb") || + g_str_has_prefix (device_uri, "hp:/usb/") || + g_str_has_prefix (device_uri, "hpfax:/usb/")) + { + /* Translators: The found device is a printer connected via USB */ + description = g_strdup (_("USB")); + } + else if (g_str_has_prefix (device_uri, "serial")) + { + /* Translators: The found device is a printer connected via serial port */ + description = g_strdup (_("Serial Port")); + } + else if (g_str_has_prefix (device_uri, "parallel") || + g_str_has_prefix (device_uri, "hp:/par/") || + g_str_has_prefix (device_uri, "hpfax:/par/")) + { + /* Translators: The found device is a printer connected via parallel port */ + description = g_strdup (_("Parallel Port")); + } + else if (g_str_has_prefix (device_uri, "bluetooth")) + { + /* Translators: The found device is a printer connected via Bluetooth */ + description = g_strdup (_("Bluetooth")); + } + } + + return description; +} + +static void +set_device (PpNewPrinterDialog *self, + PpPrintDevice *device, + GtkTreeIter *iter) +{ + GtkTreeIter titer; + gint acquisition_method; + + if (device != NULL) + { + acquisition_method = pp_print_device_get_acquisition_method (device); + if (pp_print_device_get_display_name (device) && + (pp_print_device_get_device_id (device) || + pp_print_device_get_device_ppd (device) || + (pp_print_device_get_host_name (device) && + acquisition_method == ACQUISITION_METHOD_REMOTE_CUPS_SERVER) || + (pp_print_device_get_device_uri (device) && + (acquisition_method == ACQUISITION_METHOD_JETDIRECT || + acquisition_method == ACQUISITION_METHOD_LPD)) || + acquisition_method == ACQUISITION_METHOD_SAMBA_HOST || + acquisition_method == ACQUISITION_METHOD_SAMBA)) + { + g_autofree gchar *description = NULL; + + description = get_local_scheme_description_from_uri (pp_print_device_get_device_uri (device)); + if (description == NULL) + { + if (pp_print_device_get_device_location (device) != NULL && pp_print_device_get_device_location (device)[0] != '\0') + { + /* Translators: Location of found network printer (e.g. Kitchen, Reception) */ + description = g_strdup_printf (_("Location: %s"), pp_print_device_get_device_location (device)); + } + else if (pp_print_device_get_host_name (device) != NULL && pp_print_device_get_host_name (device)[0] != '\0') + { + /* Translators: Network address of found printer */ + description = g_strdup_printf (_("Address: %s"), pp_print_device_get_host_name (device)); + } + } + + if (iter == NULL) + gtk_list_store_append (self->devices_liststore, &titer); + + gtk_list_store_set (self->devices_liststore, iter == NULL ? &titer : iter, + DEVICE_GICON_COLUMN, pp_print_device_is_network_device (device) ? self->remote_printer_icon : self->local_printer_icon, + DEVICE_NAME_COLUMN, pp_print_device_get_device_name (device), + DEVICE_DISPLAY_NAME_COLUMN, pp_print_device_get_display_name (device), + DEVICE_DESCRIPTION_COLUMN, description, + DEVICE_VISIBLE_COLUMN, TRUE, + DEVICE_COLUMN, device, + -1); + } + else if (pp_print_device_is_authenticated_server (device) && + pp_print_device_get_host_name (device) != NULL) + { + if (iter == NULL) + gtk_list_store_append (self->devices_liststore, &titer); + + gtk_list_store_set (self->devices_liststore, iter == NULL ? &titer : iter, + DEVICE_GICON_COLUMN, self->authenticated_server_icon, + DEVICE_NAME_COLUMN, pp_print_device_get_host_name (device), + DEVICE_DISPLAY_NAME_COLUMN, pp_print_device_get_host_name (device), + /* Translators: This item is a server which needs authentication to show its printers */ + DEVICE_DESCRIPTION_COLUMN, _("Server requires authentication"), + SERVER_NEEDS_AUTHENTICATION_COLUMN, TRUE, + DEVICE_VISIBLE_COLUMN, TRUE, + DEVICE_COLUMN, device, + -1); + } + } +} + +static void +replace_device (PpNewPrinterDialog *self, + PpPrintDevice *old_device, + PpPrintDevice *new_device) +{ + GtkTreeIter iter; + gboolean cont; + + if (old_device != NULL && new_device != NULL) + { + cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->devices_liststore), &iter); + while (cont) + { + g_autoptr(PpPrintDevice) device = NULL; + + gtk_tree_model_get (GTK_TREE_MODEL (self->devices_liststore), &iter, + DEVICE_COLUMN, &device, + -1); + + if (old_device == device) + { + set_device (self, new_device, &iter); + break; + } + + cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->devices_liststore), &iter); + } + } +} + +static void +cups_get_dests_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + PpNewPrinterDialog *self = user_data; + PpCupsDests *dests; + g_autoptr(GError) error = NULL; + + dests = pp_cups_get_dests_finish (PP_CUPS (source_object), res, &error); + + if (dests) + { + self->dests = dests->dests; + self->num_of_dests = dests->num_of_dests; + + get_cups_devices (self); + } + else + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_warning ("%s", error->message); + + get_cups_devices (self); + } + } +} + +static void +row_activated_cb (PpNewPrinterDialog *self) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gboolean authentication_needed; + gboolean selected; + + selected = gtk_tree_selection_get_selected (gtk_tree_view_get_selection (self->devices_treeview), + &model, + &iter); + + if (selected) + { + gtk_tree_model_get (model, &iter, SERVER_NEEDS_AUTHENTICATION_COLUMN, &authentication_needed, -1); + + if (authentication_needed) + { + authenticate_samba_server (self); + } + else + { + gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_OK); + } + } +} + +static void +cell_data_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + gpointer user_data) +{ + PpNewPrinterDialog *self = user_data; + gboolean selected = FALSE; + g_autofree gchar *name = NULL; + g_autofree gchar *description = NULL; + + selected = gtk_tree_selection_iter_is_selected (gtk_tree_view_get_selection (self->devices_treeview), iter); + + gtk_tree_model_get (tree_model, iter, + DEVICE_DISPLAY_NAME_COLUMN, &name, + DEVICE_DESCRIPTION_COLUMN, &description, + -1); + + if (name != NULL) + { + g_autofree gchar *text = NULL; + + if (description != NULL) + { + if (selected) + text = g_markup_printf_escaped ("<b>%s</b>\n<small>%s</small>", + name, + description); + else + text = g_markup_printf_escaped ("<b>%s</b>\n<small><span foreground=\"#555555\">%s</span></small>", + name, + description); + } + else + { + text = g_markup_printf_escaped ("<b>%s</b>\n ", + name); + } + + g_object_set (G_OBJECT (cell), + "markup", text, + NULL); + } +} + +static void +populate_devices_list (PpNewPrinterDialog *self) +{ + GtkTreeViewColumn *column; + g_autoptr(PpSamba) samba = NULL; + g_autoptr(GEmblem) emblem = NULL; + g_autoptr(PpCups) cups = NULL; + g_autoptr(GIcon) icon = NULL; + g_autoptr(GIcon) emblem_icon = NULL; + GtkCellRenderer *text_renderer; + GtkCellRenderer *icon_renderer; + + g_signal_connect_object (gtk_tree_view_get_selection (self->devices_treeview), + "changed", G_CALLBACK (device_selection_changed_cb), self, G_CONNECT_SWAPPED); + + g_signal_connect_object (self->devices_treeview, + "row-activated", G_CALLBACK (row_activated_cb), self, G_CONNECT_SWAPPED); + + self->local_printer_icon = g_themed_icon_new ("printer"); + self->remote_printer_icon = g_themed_icon_new ("printer-network"); + + icon = g_themed_icon_new ("network-server"); + emblem_icon = g_themed_icon_new ("changes-prevent"); + emblem = g_emblem_new (emblem_icon); + + self->authenticated_server_icon = g_emblemed_icon_new (icon, emblem); + + icon_renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set (icon_renderer, "icon-size", GTK_ICON_SIZE_LARGE, NULL); + gtk_cell_renderer_set_alignment (icon_renderer, 1.0, 0.5); + gtk_cell_renderer_set_padding (icon_renderer, 4, 4); + column = gtk_tree_view_column_new_with_attributes ("Icon", icon_renderer, + "gicon", DEVICE_GICON_COLUMN, NULL); + gtk_tree_view_column_set_max_width (column, -1); + gtk_tree_view_column_set_min_width (column, 80); + gtk_tree_view_append_column (self->devices_treeview, column); + + + text_renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Devices", text_renderer, + NULL); + gtk_tree_view_column_set_cell_data_func (column, text_renderer, cell_data_func, + self, NULL); + gtk_tree_view_append_column (self->devices_treeview, column); + + gtk_tree_model_filter_set_visible_column (self->devices_model_filter, DEVICE_VISIBLE_COLUMN); + + cups = pp_cups_new (); + pp_cups_get_dests_async (cups, self->cancellable, cups_get_dests_cb, self); + + self->samba_searching = TRUE; + update_dialog_state (self); + + samba = pp_samba_new (NULL); + pp_samba_get_devices_async (samba, FALSE, self->cancellable, get_samba_devices_cb, self); +} + +static void +ppd_selection_cb (GtkDialog *_dialog, + gint response_id, + gpointer user_data) +{ + PpNewPrinterDialog *self = user_data; + GList *original_names_list = NULL; + g_autofree gchar *ppd_name = NULL; + g_autofree gchar *ppd_display_name = NULL; + gint acquisition_method; + + if (response_id == GTK_RESPONSE_OK) { + ppd_name = pp_ppd_selection_dialog_get_ppd_name (self->ppd_selection_dialog); + ppd_display_name = pp_ppd_selection_dialog_get_ppd_display_name (self->ppd_selection_dialog); + } + + if (ppd_name) + { + g_object_set (self->new_device, "device-ppd", ppd_name, NULL); + + acquisition_method = pp_print_device_get_acquisition_method (self->new_device); + if ((acquisition_method == ACQUISITION_METHOD_JETDIRECT || + acquisition_method == ACQUISITION_METHOD_LPD) && + ppd_display_name != NULL) + { + g_autofree gchar *printer_name = NULL; + + g_object_set (self->new_device, + "device-name", ppd_display_name, + "device-original-name", ppd_display_name, + NULL); + + gtk_tree_model_foreach (GTK_TREE_MODEL (self->devices_liststore), + prepend_original_name, + &original_names_list); + + original_names_list = g_list_reverse (original_names_list); + + printer_name = canonicalize_device_name (original_names_list, + self->local_cups_devices, + self->dests, + self->num_of_dests, + self->new_device); + + g_list_free_full (original_names_list, g_free); + + g_object_set (self->new_device, + "device-name", printer_name, + "device-original-name", printer_name, + NULL); + } + } + + /* This is needed here since parent dialog is destroyed first. */ + gtk_window_set_transient_for (GTK_WINDOW (self->ppd_selection_dialog), NULL); + + self->user_callback (GTK_DIALOG (self), response_id, self->user_data); +} + +static void +new_printer_dialog_response_cb (PpNewPrinterDialog *self, + gint response_id) +{ + g_autoptr(PpPrintDevice) device = NULL; + GtkTreeModel *model; + GtkTreeIter iter; + gint acquisition_method; + + if (response_id == GTK_RESPONSE_OK) + { + g_cancellable_cancel (self->cancellable); + g_clear_object (&self->cancellable); + + if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (self->devices_treeview), &model, &iter)) + { + gtk_tree_model_get (model, &iter, + DEVICE_COLUMN, &device, + -1); + } + + if (device) + { + acquisition_method = pp_print_device_get_acquisition_method (device); + if (acquisition_method == ACQUISITION_METHOD_SAMBA || + acquisition_method == ACQUISITION_METHOD_SAMBA_HOST || + acquisition_method == ACQUISITION_METHOD_JETDIRECT || + acquisition_method == ACQUISITION_METHOD_LPD) + { + self->new_device = pp_print_device_copy (device); + self->ppd_selection_dialog = + pp_ppd_selection_dialog_new (self->list, + NULL, + ppd_selection_cb, + self); + + gtk_window_set_transient_for (GTK_WINDOW (self->ppd_selection_dialog), + GTK_WINDOW (self)); + + /* New device will be set at return from ppd selection */ + gtk_widget_show (GTK_WIDGET (self->ppd_selection_dialog)); + } + else + { + self->new_device = pp_print_device_copy (device); + self->user_callback (GTK_DIALOG (self), GTK_RESPONSE_OK, self->user_data); + } + } + } + else + { + self->user_callback (GTK_DIALOG (self), GTK_RESPONSE_CANCEL, self->user_data); + } +} + +PpNewPrinterDialog * +pp_new_printer_dialog_new (PPDList *ppd_list, + UserResponseCallback user_callback, + gpointer user_data) +{ + PpNewPrinterDialog *self; + + self = g_object_new (pp_new_printer_dialog_get_type (), NULL); + + self->user_callback = user_callback; + self->user_data = user_data; + + self->list = ppd_list_copy (ppd_list); + + self->local_cups_devices = g_ptr_array_new_with_free_func (g_object_unref); + + /* GCancellable for cancelling of async operations */ + self->cancellable = g_cancellable_new (); + + g_signal_connect_object (self, "response", G_CALLBACK (new_printer_dialog_response_cb), self, G_CONNECT_SWAPPED); + + g_signal_connect_object (self->search_entry, "activate", G_CALLBACK (search_entry_activated_cb), self, G_CONNECT_SWAPPED); + g_signal_connect_object (self->search_entry, "search-changed", G_CALLBACK (search_entry_changed_cb), self, G_CONNECT_SWAPPED); + + g_signal_connect_object (self->unlock_button, "clicked", G_CALLBACK (authenticate_samba_server), self, G_CONNECT_SWAPPED); + + /* Authentication form widgets */ + g_signal_connect_object (self->username_entry, "changed", G_CALLBACK (auth_entries_changed), self, G_CONNECT_SWAPPED); + g_signal_connect_object (self->password_entry, "changed", G_CALLBACK (auth_entries_changed), self, G_CONNECT_SWAPPED); + g_signal_connect_object (self->go_back_button, "clicked", G_CALLBACK (on_go_back_button_clicked), self, G_CONNECT_SWAPPED); + + /* Set titlebar */ + gtk_window_set_titlebar(GTK_WINDOW (self), GTK_WIDGET (self->headerbar)); + + /* Fill with data */ + populate_devices_list (self); + + return self; +} + +static void +pp_new_printer_dialog_dispose (GObject *object) +{ + PpNewPrinterDialog *self = PP_NEW_PRINTER_DIALOG (object); + + g_cancellable_cancel (self->remote_host_cancellable); + g_cancellable_cancel (self->cancellable); + + g_clear_handle_id (&self->host_search_timeout_id, g_source_remove); + g_clear_object (&self->remote_host_cancellable); + g_clear_object (&self->cancellable); + g_clear_pointer (&self->list, ppd_list_free); + g_clear_pointer (&self->local_cups_devices, g_ptr_array_unref); + g_clear_object (&self->new_device); + g_clear_object (&self->local_printer_icon); + g_clear_object (&self->remote_printer_icon); + g_clear_object (&self->authenticated_server_icon); + g_clear_object (&self->snmp_host); + g_clear_object (&self->socket_host); + g_clear_object (&self->lpd_host); + g_clear_object (&self->remote_cups_host); + g_clear_object (&self->samba_host); + + if (self->ppd_selection_dialog != NULL) + { + gtk_window_destroy (GTK_WINDOW (self->ppd_selection_dialog)); + self->ppd_selection_dialog = NULL; + } + + if (self->num_of_dests > 0) + { + cupsFreeDests (self->num_of_dests, self->dests); + self->num_of_dests = 0; + self->dests = NULL; + } + + G_OBJECT_CLASS (pp_new_printer_dialog_parent_class)->dispose (object); +} + +void +pp_new_printer_dialog_class_init (PpNewPrinterDialogClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_ensure (PP_TYPE_PRINT_DEVICE); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/printers/new-printer-dialog.ui"); + + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, devices_liststore); + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, devices_model_filter); + + /* headerbar */ + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, headerbar); + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, header_title); + + /* headerbar topleft buttons */ + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, headerbar_topleft_buttons); + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, go_back_button); + + /* headerbar topright buttons */ + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, headerbar_topright_buttons); + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, new_printer_add_button); + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, unlock_button); + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, authenticate_button); + + /* dialogstack */ + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, dialog_stack); + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, stack); + + /* scrolledwindow1 */ + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, scrolledwindow1); + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, devices_treeview); + + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, search_entry); + + /* authentication page */ + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, authentication_title); + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, authentication_text); + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, username_entry); + gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, password_entry); + + object_class->dispose = pp_new_printer_dialog_dispose; +} + + +void +pp_new_printer_dialog_init (PpNewPrinterDialog *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); +} + +void +pp_new_printer_dialog_set_ppd_list (PpNewPrinterDialog *self, + PPDList *list) +{ + self->list = ppd_list_copy (list); + + if (self->ppd_selection_dialog) + pp_ppd_selection_dialog_set_ppd_list (self->ppd_selection_dialog, self->list); +} + +PpNewPrinter * +pp_new_printer_dialog_get_new_printer (PpNewPrinterDialog *self) +{ + PpNewPrinter *new_printer = NULL; + + new_printer = pp_new_printer_new (); + g_object_set (new_printer, + "name", pp_print_device_get_device_name (self->new_device), + "original-name", pp_print_device_get_device_original_name (self->new_device), + "device-uri", pp_print_device_get_device_uri (self->new_device), + "device-id", pp_print_device_get_device_id (self->new_device), + "ppd-name", pp_print_device_get_device_ppd (self->new_device), + "ppd-file-name", pp_print_device_get_device_ppd (self->new_device), + "info", pp_print_device_get_device_info (self->new_device), + "location", pp_print_device_get_device_location (self->new_device), + "make-and-model", pp_print_device_get_device_make_and_model (self->new_device), + "host-name", pp_print_device_get_host_name (self->new_device), + "host-port", pp_print_device_get_host_port (self->new_device), + "is-network-device", pp_print_device_is_network_device (self->new_device), + "window-id", 0, + NULL); + + return new_printer; +} |