GCC Code Coverage Report


Directory: ./
File: panels/printers/pp-new-printer-dialog.c
Date: 2024-05-04 07:58:27
Exec Total Coverage
Lines: 0 789 0.0%
Functions: 0 51 0.0%
Branches: 0 507 0.0%

Line Branch Exec Source
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright 2009-2010 Red Hat, Inc,
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20 #include "config.h"
21
22 #include <unistd.h>
23 #include <stdlib.h>
24
25 #include <adwaita.h>
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <glib/gstdio.h>
29 #include <gdk/x11/gdkx.h>
30 #include <gtk/gtk.h>
31
32 #include "pp-new-printer-dialog.h"
33 #include "pp-cups.h"
34 #include "pp-host.h"
35 #include "pp-new-printer.h"
36 #include "pp-ppd-selection-dialog.h"
37 #include "pp-samba.h"
38 #include "pp-utils.h"
39
40 #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
41 #define HAVE_CUPS_1_6 1
42 #endif
43
44 #ifndef HAVE_CUPS_1_6
45 #define ippGetState(ipp) ipp->state
46 #endif
47
48 /*
49 * Additional delay to the default 150ms delay in GtkSearchEntry
50 * resulting in total delay of 500ms.
51 */
52 #define HOST_SEARCH_DELAY (500 - 150)
53
54 #define AUTHENTICATION_PAGE "authentication-page"
55 #define ADDPRINTER_PAGE "addprinter-page"
56
57 static void set_device (PpNewPrinterDialog *self,
58 PpPrintDevice *device,
59 GtkTreeIter *iter);
60 static void replace_device (PpNewPrinterDialog *self,
61 PpPrintDevice *old_device,
62 PpPrintDevice *new_device);
63 static void populate_devices_list (PpNewPrinterDialog *self);
64 static void search_entry_activated_cb (PpNewPrinterDialog *self);
65 static void search_entry_changed_cb (PpNewPrinterDialog *self);
66 static void add_cb (PpNewPrinterDialog *self);
67 static void cancel_cb (PpNewPrinterDialog *self);
68 static void update_dialog_state (PpNewPrinterDialog *self);
69 static void add_devices_to_list (PpNewPrinterDialog *self,
70 GPtrArray *devices);
71 static void remove_device_from_list (PpNewPrinterDialog *self,
72 const gchar *device_name);
73
74 enum
75 {
76 DEVICE_GICON_COLUMN = 0,
77 DEVICE_NAME_COLUMN,
78 DEVICE_DISPLAY_NAME_COLUMN,
79 DEVICE_DESCRIPTION_COLUMN,
80 SERVER_NEEDS_AUTHENTICATION_COLUMN,
81 DEVICE_VISIBLE_COLUMN,
82 DEVICE_COLUMN,
83 DEVICE_N_COLUMNS
84 };
85
86 struct _PpNewPrinterDialog
87 {
88 AdwWindow parent_instance;
89
90 GPtrArray *local_cups_devices;
91
92 GtkListStore *devices_liststore;
93 GtkTreeModelFilter *devices_model_filter;
94
95 /* headerbar */
96 AdwWindowTitle *header_title;
97
98 /* headerbar topleft buttons */
99 GtkStack *headerbar_topleft_buttons;
100 GtkButton *go_back_button;
101
102 /* headerbar topright buttons */
103 GtkStack *headerbar_topright_buttons;
104 GtkButton *new_printer_add_button;
105 GtkButton *unlock_button;
106 GtkButton *authenticate_button;
107 /* end headerbar */
108
109 /* dialogstack */
110 GtkStack *dialog_stack;
111 GtkStack *stack;
112
113 /* scrolledwindow1 */
114 GtkScrolledWindow *scrolledwindow1;
115 GtkTreeView *devices_treeview;
116
117 GtkEntry *search_entry;
118
119 /* authentication page */
120 GtkLabel *authentication_title;
121 GtkLabel *authentication_text;
122 GtkEntry *username_entry;
123 GtkEntry *password_entry;
124 /* end dialog stack */
125
126 UserResponseCallback user_callback;
127 gpointer user_data;
128
129 cups_dest_t *dests;
130 gint num_of_dests;
131
132 GCancellable *cancellable;
133 GCancellable *remote_host_cancellable;
134
135 gboolean cups_searching;
136 gboolean samba_authenticated_searching;
137 gboolean samba_searching;
138
139 PpPPDSelectionDialog *ppd_selection_dialog;
140
141 PpPrintDevice *new_device;
142
143 PPDList *list;
144
145 GIcon *local_printer_icon;
146 GIcon *remote_printer_icon;
147 GIcon *authenticated_server_icon;
148
149 PpHost *snmp_host;
150 PpHost *socket_host;
151 PpHost *lpd_host;
152 PpHost *remote_cups_host;
153 PpSamba *samba_host;
154 guint host_search_timeout_id;
155 };
156
157 G_DEFINE_TYPE (PpNewPrinterDialog, pp_new_printer_dialog, ADW_TYPE_WINDOW)
158
159 typedef struct
160 {
161 gchar *server_name;
162 gpointer dialog;
163 } AuthSMBData;
164
165 static void
166 get_authenticated_samba_devices_cb (GObject *source_object,
167 GAsyncResult *res,
168 gpointer user_data)
169 {
170 AuthSMBData *data = user_data;
171 PpNewPrinterDialog *self = PP_NEW_PRINTER_DIALOG (data->dialog);
172 g_autoptr(GPtrArray) devices = NULL;
173 gboolean cancelled = FALSE;
174 g_autoptr(GError) error = NULL;
175
176 devices = pp_samba_get_devices_finish (PP_SAMBA (source_object), res, &error);
177
178 if (devices != NULL)
179 {
180 self->samba_authenticated_searching = FALSE;
181
182 for (guint i = 0; i < devices->len; i++)
183 {
184 PpPrintDevice *device = g_ptr_array_index (devices, i);
185
186 if (pp_print_device_is_authenticated_server (device))
187 {
188 cancelled = TRUE;
189 break;
190 }
191 }
192
193 if (!cancelled)
194 {
195 if (devices != NULL)
196 {
197 add_devices_to_list (self, devices);
198
199 if (devices->len > 0)
200 {
201 gtk_editable_set_text (GTK_EDITABLE (self->search_entry),
202 pp_print_device_get_device_location (g_ptr_array_index (devices, 0)));
203 search_entry_activated_cb (self);
204 }
205 }
206 }
207
208 update_dialog_state (self);
209 }
210 else
211 {
212 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
213 {
214 g_warning ("%s", error->message);
215
216 self->samba_authenticated_searching = FALSE;
217 update_dialog_state (self);
218 }
219 }
220
221 g_free (data->server_name);
222 g_free (data);
223 }
224
225 static void
226 go_to_page (PpNewPrinterDialog *self,
227 const gchar *page)
228 {
229 gtk_stack_set_visible_child_name (self->dialog_stack, page);
230 gtk_stack_set_visible_child_name (self->headerbar_topright_buttons, page);
231 gtk_stack_set_visible_child_name (self->headerbar_topleft_buttons, page);
232 }
233
234 static void
235 on_authenticate (PpNewPrinterDialog *self)
236 {
237 gchar *hostname = NULL;
238 gchar *username = NULL;
239 gchar *password = NULL;
240
241 username = g_strdup (gtk_editable_get_text (GTK_EDITABLE (self->username_entry)));
242 password = g_strdup (gtk_editable_get_text (GTK_EDITABLE (self->password_entry)));
243
244 if ((username == NULL) || (username[0] == '\0') ||
245 (password == NULL) || (password[0] == '\0'))
246 {
247 g_clear_pointer (&username, g_free);
248 g_clear_pointer (&password, g_free);
249 return;
250 }
251
252 pp_samba_set_auth_info (PP_SAMBA (self->samba_host), username, password);
253
254 adw_window_title_set_title (self->header_title, _("Add Printer"));
255 go_to_page (self, ADDPRINTER_PAGE);
256
257 g_object_get (PP_HOST (self->samba_host), "hostname", &hostname, NULL);
258 remove_device_from_list (self, hostname);
259 }
260
261 static void
262 on_authentication_required (PpNewPrinterDialog *self)
263 {
264 g_autofree gchar *hostname = NULL;
265 g_autofree gchar *title = NULL;
266 g_autofree gchar *text = NULL;
267
268 adw_window_title_set_subtitle (self->header_title, NULL);
269 adw_window_title_set_title (self->header_title, _("Unlock Print Server"));
270
271 g_object_get (self->samba_host, "hostname", &hostname, NULL);
272 /* Translators: Samba server needs authentication of the user to show list of its printers. */
273 title = g_strdup_printf (_("Unlock %s."), hostname);
274 gtk_label_set_text (self->authentication_title, title);
275
276 /* Translators: Samba server needs authentication of the user to show list of its printers. */
277 text = g_strdup_printf (_("Enter username and password to view printers on %s."), hostname);
278 gtk_label_set_text (self->authentication_text, text);
279
280 go_to_page (self, AUTHENTICATION_PAGE);
281
282 g_signal_connect_object (self->authenticate_button, "clicked", G_CALLBACK (on_authenticate), self, G_CONNECT_SWAPPED);
283 }
284
285 static void
286 auth_entries_changed (PpNewPrinterDialog *self)
287 {
288 gboolean can_authenticate = FALSE;
289 gchar *username = NULL;
290 gchar *password = NULL;
291
292 username = g_strdup (gtk_editable_get_text (GTK_EDITABLE (self->username_entry)));
293 password = g_strdup (gtk_editable_get_text (GTK_EDITABLE (self->password_entry)));
294
295 can_authenticate = (username != NULL && username[0] != '\0' &&
296 password != NULL && password[0] != '\0');
297
298 gtk_widget_set_sensitive (GTK_WIDGET (self->authenticate_button), can_authenticate);
299
300 g_clear_pointer (&username, g_free);
301 g_clear_pointer (&password, g_free);
302 }
303
304 static void
305 on_go_back_button_clicked (PpNewPrinterDialog *self)
306 {
307 pp_samba_set_auth_info (self->samba_host, NULL, NULL);
308 g_clear_object (&self->samba_host);
309
310 go_to_page (self, ADDPRINTER_PAGE);
311 adw_window_title_set_title (self->header_title, _("Add Printer"));
312 gtk_widget_set_sensitive (GTK_WIDGET (self->new_printer_add_button), FALSE);
313
314 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (self->devices_treeview));
315 }
316
317 static void
318 authenticate_samba_server (PpNewPrinterDialog *self)
319 {
320 GtkTreeModel *model;
321 GtkTreeIter iter;
322 AuthSMBData *data;
323 gchar *server_name = NULL;
324
325 gtk_widget_set_sensitive (GTK_WIDGET (self->unlock_button), FALSE);
326 gtk_widget_set_sensitive (GTK_WIDGET (self->authenticate_button), FALSE);
327 gtk_widget_grab_focus (GTK_WIDGET (self->username_entry));
328
329 if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (self->devices_treeview), &model, &iter))
330 {
331 gtk_tree_model_get (model, &iter,
332 DEVICE_NAME_COLUMN, &server_name,
333 -1);
334
335 if (server_name != NULL)
336 {
337 g_clear_object (&self->samba_host);
338
339 self->samba_host = pp_samba_new (server_name);
340 g_signal_connect_object (self->samba_host,
341 "authentication-required",
342 G_CALLBACK (on_authentication_required),
343 self, G_CONNECT_SWAPPED);
344
345 self->samba_authenticated_searching = TRUE;
346 update_dialog_state (self);
347
348 data = g_new (AuthSMBData, 1);
349 data->server_name = server_name;
350 data->dialog = self;
351
352 pp_samba_get_devices_async (self->samba_host,
353 TRUE,
354 self->cancellable,
355 get_authenticated_samba_devices_cb,
356 data);
357 }
358 }
359 }
360
361 static void
362 device_selection_changed_cb (PpNewPrinterDialog *self)
363 {
364 GtkTreeModel *model;
365 GtkTreeIter iter;
366 gboolean authentication_needed;
367 gboolean selected;
368
369 selected = gtk_tree_selection_get_selected (gtk_tree_view_get_selection (self->devices_treeview),
370 &model,
371 &iter);
372
373 if (selected)
374 {
375 gtk_tree_model_get (model, &iter,
376 SERVER_NEEDS_AUTHENTICATION_COLUMN, &authentication_needed,
377 -1);
378
379 gtk_widget_set_sensitive (GTK_WIDGET (self->new_printer_add_button), selected);
380 gtk_widget_set_sensitive (GTK_WIDGET (self->unlock_button), authentication_needed);
381
382 if (authentication_needed)
383 gtk_stack_set_visible_child_name (self->headerbar_topright_buttons, "unlock_button");
384 else
385 gtk_stack_set_visible_child_name (self->headerbar_topright_buttons, ADDPRINTER_PAGE);
386 }
387 }
388
389 static void
390 remove_device_from_list (PpNewPrinterDialog *self,
391 const gchar *device_name)
392 {
393 GtkTreeIter iter;
394 gboolean cont;
395
396 cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->devices_liststore), &iter);
397 while (cont)
398 {
399 g_autoptr(PpPrintDevice) device = NULL;
400
401 gtk_tree_model_get (GTK_TREE_MODEL (self->devices_liststore), &iter,
402 DEVICE_COLUMN, &device,
403 -1);
404
405 if (g_strcmp0 (pp_print_device_get_device_name (device), device_name) == 0)
406 {
407 gtk_list_store_remove (self->devices_liststore, &iter);
408 break;
409 }
410
411 cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->devices_liststore), &iter);
412 }
413
414 update_dialog_state (self);
415 }
416
417 static gboolean
418 prepend_original_name (GtkTreeModel *model,
419 GtkTreePath *path,
420 GtkTreeIter *iter,
421 gpointer data)
422 {
423 g_autoptr(PpPrintDevice) device = NULL;
424 GList **list = data;
425
426 gtk_tree_model_get (model, iter,
427 DEVICE_COLUMN, &device,
428 -1);
429
430 *list = g_list_prepend (*list, g_strdup (pp_print_device_get_device_original_name (device)));
431
432 return FALSE;
433 }
434
435 static void
436 add_device_to_list (PpNewPrinterDialog *self,
437 PpPrintDevice *device)
438 {
439 GList *original_names_list = NULL;
440 gint acquisition_method;
441
442 if (device)
443 {
444 if (pp_print_device_get_host_name (device) == NULL)
445 {
446 g_autofree gchar *host_name = guess_device_hostname (device);
447 g_object_set (device, "host-name", host_name, NULL);
448 }
449
450 acquisition_method = pp_print_device_get_acquisition_method (device);
451 if (pp_print_device_get_device_id (device) ||
452 pp_print_device_get_device_ppd (device) ||
453 (pp_print_device_get_host_name (device) &&
454 acquisition_method == ACQUISITION_METHOD_REMOTE_CUPS_SERVER) ||
455 acquisition_method == ACQUISITION_METHOD_SAMBA_HOST ||
456 acquisition_method == ACQUISITION_METHOD_SAMBA ||
457 (pp_print_device_get_device_uri (device) &&
458 (acquisition_method == ACQUISITION_METHOD_JETDIRECT ||
459 acquisition_method == ACQUISITION_METHOD_LPD)))
460 {
461 g_autofree gchar *canonicalized_name = NULL;
462
463 g_object_set (device,
464 "device-original-name", pp_print_device_get_device_name (device),
465 NULL);
466
467 gtk_tree_model_foreach (GTK_TREE_MODEL (self->devices_liststore),
468 prepend_original_name,
469 &original_names_list);
470
471 original_names_list = g_list_reverse (original_names_list);
472
473 canonicalized_name = canonicalize_device_name (original_names_list,
474 self->local_cups_devices,
475 self->dests,
476 self->num_of_dests,
477 device);
478
479 g_list_free_full (original_names_list, g_free);
480
481 g_object_set (device,
482 "display-name", canonicalized_name,
483 "device-name", canonicalized_name,
484 NULL);
485
486 if (pp_print_device_get_acquisition_method (device) == ACQUISITION_METHOD_DEFAULT_CUPS_SERVER)
487 g_ptr_array_add (self->local_cups_devices, g_object_ref (device));
488 else
489 set_device (self, device, NULL);
490 }
491 else if (pp_print_device_is_authenticated_server (device) &&
492 pp_print_device_get_host_name (device) != NULL)
493 {
494 g_autoptr(PpPrintDevice) store_device = NULL;
495
496 store_device = g_object_new (PP_TYPE_PRINT_DEVICE,
497 "device-name", pp_print_device_get_host_name (device),
498 "host-name", pp_print_device_get_host_name (device),
499 "is-authenticated-server", pp_print_device_is_authenticated_server (device),
500 NULL);
501
502 set_device (self, store_device, NULL);
503 }
504 }
505 }
506
507 static void
508 add_devices_to_list (PpNewPrinterDialog *self,
509 GPtrArray *devices)
510 {
511 for (guint i = 0; i < devices->len; i++)
512 add_device_to_list (self, g_ptr_array_index (devices, i));
513 }
514
515 static PpPrintDevice *
516 device_in_list (gchar *device_uri,
517 GPtrArray *device_list)
518 {
519 for (guint i = 0; i < device_list->len; i++)
520 {
521 PpPrintDevice *device = g_ptr_array_index (device_list, i);
522 /* GroupPhysicalDevices returns uris without port numbers */
523 if (pp_print_device_get_device_uri (device) != NULL &&
524 g_str_has_prefix (pp_print_device_get_device_uri (device), device_uri))
525 return g_object_ref (device);
526 }
527
528 return NULL;
529 }
530
531 static PpPrintDevice *
532 device_in_liststore (gchar *device_uri,
533 GtkListStore *device_liststore)
534 {
535 GtkTreeIter iter;
536 gboolean cont;
537
538 cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (device_liststore), &iter);
539 while (cont)
540 {
541 g_autoptr(PpPrintDevice) device = NULL;
542
543 gtk_tree_model_get (GTK_TREE_MODEL (device_liststore), &iter,
544 DEVICE_COLUMN, &device,
545 -1);
546
547 /* GroupPhysicalDevices returns uris without port numbers */
548 if (pp_print_device_get_device_uri (device) != NULL &&
549 g_str_has_prefix (pp_print_device_get_device_uri (device), device_uri))
550 {
551 return g_steal_pointer(&device);
552 }
553
554 cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (device_liststore), &iter);
555 }
556
557 return NULL;
558 }
559
560 static void
561 update_dialog_state (PpNewPrinterDialog *self)
562 {
563 GtkTreeIter iter;
564 gboolean searching;
565
566 searching = self->cups_searching ||
567 self->remote_cups_host != NULL ||
568 self->snmp_host != NULL ||
569 self->socket_host != NULL ||
570 self->lpd_host != NULL ||
571 self->samba_host != NULL ||
572 self->samba_authenticated_searching ||
573 self->samba_searching;
574
575 if (searching)
576 {
577 adw_window_title_set_subtitle (self->header_title, _("Searching for Printers"));
578 }
579 else
580 {
581 adw_window_title_set_subtitle (self->header_title, NULL);
582 }
583
584 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->devices_liststore), &iter))
585 gtk_stack_set_visible_child_name (self->stack, "standard-page");
586 else
587 gtk_stack_set_visible_child_name (self->stack, searching ? "loading-page" : "no-printers-page");
588 }
589
590 static void
591 group_physical_devices_cb (gchar ***device_uris,
592 gpointer user_data)
593 {
594 PpNewPrinterDialog *self = user_data;
595 gint i, j;
596
597 if (device_uris != NULL)
598 {
599 for (i = 0; device_uris[i] != NULL; i++)
600 {
601 /* Is there any device in this sublist? */
602 if (device_uris[i][0] != NULL)
603 {
604 g_autoptr(PpPrintDevice) device = NULL;
605
606 for (j = 0; device_uris[i][j] != NULL; j++)
607 {
608 device = device_in_liststore (device_uris[i][j], self->devices_liststore);
609 if (device != NULL)
610 break;
611 }
612
613 /* Is this sublist represented in the current list of devices? */
614 if (device != NULL)
615 {
616 /* Is there better device in the sublist? */
617 if (j != 0)
618 {
619 g_autoptr(PpPrintDevice) better_device = NULL;
620
621 better_device = device_in_list (device_uris[i][0], self->local_cups_devices);
622 replace_device (self, device, better_device);
623 }
624 }
625 else
626 {
627 device = device_in_list (device_uris[i][0], self->local_cups_devices);
628 if (device != NULL)
629 set_device (self, device, NULL);
630 }
631 }
632 }
633
634 for (i = 0; device_uris[i] != NULL; i++)
635 g_strfreev (device_uris[i]);
636
637 g_free (device_uris);
638 }
639 else
640 {
641 for (i = 0; i < self->local_cups_devices->len; i++)
642 set_device (self, g_ptr_array_index (self->local_cups_devices, i), NULL);
643 g_ptr_array_set_size (self->local_cups_devices, 0);
644 }
645
646 update_dialog_state (self);
647 }
648
649 static void
650 group_physical_devices_dbus_cb (GObject *source_object,
651 GAsyncResult *res,
652 gpointer user_data)
653 {
654 g_autoptr(GVariant) output = NULL;
655 g_autoptr(GError) error = NULL;
656 gchar ***result = NULL;
657 gint i;
658
659 output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
660 res,
661 &error);
662
663 if (output)
664 {
665 g_autoptr(GVariant) array = NULL;
666
667 g_variant_get (output, "(@aas)", &array);
668
669 if (array)
670 {
671 g_autoptr(GVariantIter) iter = NULL;
672 GStrv device_uris;
673
674 result = g_new0 (gchar **, g_variant_n_children (array) + 1);
675 g_variant_get (array, "aas", &iter);
676 i = 0;
677 while (g_variant_iter_next (iter, "^as", &device_uris))
678 {
679 result[i] = device_uris;
680 i++;
681 }
682 }
683 }
684 else if (error &&
685 error->domain == G_DBUS_ERROR &&
686 (error->code == G_DBUS_ERROR_SERVICE_UNKNOWN ||
687 error->code == G_DBUS_ERROR_UNKNOWN_METHOD))
688 {
689 g_warning ("Install system-config-printer which provides \
690 DBus method \"GroupPhysicalDevices\" to group duplicates in device list.");
691 }
692 else
693 {
694 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
695 g_warning ("%s", error->message);
696 }
697
698 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
699 group_physical_devices_cb (result, user_data);
700 }
701
702 static void
703 get_cups_devices_cb (GPtrArray *devices,
704 gboolean finished,
705 gboolean cancelled,
706 gpointer user_data)
707 {
708 PpNewPrinterDialog *self = user_data;
709 g_autoptr(GDBusConnection) bus = NULL;
710 GVariantBuilder device_list;
711 GVariantBuilder device_hash;
712 PpPrintDevice **all_devices;
713 const gchar *device_class;
714 GtkTreeIter iter;
715 gboolean cont;
716 g_autoptr(GError) error = NULL;
717 gint length, i;
718
719
720 if (!cancelled)
721 {
722 if (finished)
723 {
724 self->cups_searching = FALSE;
725 }
726
727 if (devices != NULL)
728 {
729 add_devices_to_list (self, devices);
730
731 length = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (self->devices_liststore), NULL) + self->local_cups_devices->len;
732 if (length > 0)
733 {
734 all_devices = g_new0 (PpPrintDevice *, length);
735
736 i = 0;
737 cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->devices_liststore), &iter);
738 while (cont)
739 {
740 g_autoptr(PpPrintDevice) device = NULL;
741
742 gtk_tree_model_get (GTK_TREE_MODEL (self->devices_liststore), &iter,
743 DEVICE_COLUMN, &device,
744 -1);
745
746 all_devices[i] = g_object_new (PP_TYPE_PRINT_DEVICE,
747 "device-id", pp_print_device_get_device_id (device),
748 "device-make-and-model", pp_print_device_get_device_make_and_model (device),
749 "is-network-device", pp_print_device_is_network_device (device),
750 "device-uri", pp_print_device_get_device_uri (device),
751 NULL);
752 i++;
753
754 cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->devices_liststore), &iter);
755 }
756
757 for (guint j = 0; j < self->local_cups_devices->len; j++)
758 {
759 PpPrintDevice *pp_device = g_ptr_array_index (self->local_cups_devices, j);
760 all_devices[i] = g_object_new (PP_TYPE_PRINT_DEVICE,
761 "device-id", pp_print_device_get_device_id (pp_device),
762 "device-make-and-model", pp_print_device_get_device_make_and_model (pp_device),
763 "is-network-device", pp_print_device_is_network_device (pp_device),
764 "device-uri", pp_print_device_get_device_uri (pp_device),
765 NULL);
766 i++;
767 }
768
769 bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
770 if (bus)
771 {
772 g_variant_builder_init (&device_list, G_VARIANT_TYPE ("a{sv}"));
773
774 for (i = 0; i < length; i++)
775 {
776 if (pp_print_device_get_device_uri (all_devices[i]))
777 {
778 g_variant_builder_init (&device_hash, G_VARIANT_TYPE ("a{ss}"));
779
780 if (pp_print_device_get_device_id (all_devices[i]))
781 g_variant_builder_add (&device_hash,
782 "{ss}",
783 "device-id",
784 pp_print_device_get_device_id (all_devices[i]));
785
786 if (pp_print_device_get_device_make_and_model (all_devices[i]))
787 g_variant_builder_add (&device_hash,
788 "{ss}",
789 "device-make-and-model",
790 pp_print_device_get_device_make_and_model (all_devices[i]));
791
792 if (pp_print_device_is_network_device (all_devices[i]))
793 device_class = "network";
794 else
795 device_class = "direct";
796
797 g_variant_builder_add (&device_hash,
798 "{ss}",
799 "device-class",
800 device_class);
801
802 g_variant_builder_add (&device_list,
803 "{sv}",
804 pp_print_device_get_device_uri (all_devices[i]),
805 g_variant_builder_end (&device_hash));
806 }
807 }
808
809 g_dbus_connection_call (bus,
810 SCP_BUS,
811 SCP_PATH,
812 SCP_IFACE,
813 "GroupPhysicalDevices",
814 g_variant_new ("(v)", g_variant_builder_end (&device_list)),
815 G_VARIANT_TYPE ("(aas)"),
816 G_DBUS_CALL_FLAGS_NONE,
817 -1,
818 self->cancellable,
819 group_physical_devices_dbus_cb,
820 self);
821 }
822 else
823 {
824 g_warning ("Failed to get system bus: %s", error->message);
825 group_physical_devices_cb (NULL, user_data);
826 }
827
828 for (i = 0; i < length; i++)
829 g_object_unref (all_devices[i]);
830 g_free (all_devices);
831 }
832 else
833 {
834 update_dialog_state (self);
835 }
836 }
837 else
838 {
839 update_dialog_state (self);
840 }
841 }
842 }
843
844 static void
845 get_snmp_devices_cb (GObject *source_object,
846 GAsyncResult *res,
847 gpointer user_data)
848 {
849 PpNewPrinterDialog *self = user_data;
850 g_autoptr(GError) error = NULL;
851 g_autoptr(GPtrArray) devices = NULL;
852
853 devices = pp_host_get_snmp_devices_finish (PP_HOST (source_object), res, &error);
854
855 if (devices != NULL)
856 {
857 g_clear_object(&self->snmp_host);
858
859 add_devices_to_list (self, devices);
860
861 update_dialog_state (self);
862 }
863 else
864 {
865 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
866 {
867 g_warning ("%s", error->message);
868
869 g_clear_object(&self->snmp_host);
870
871 update_dialog_state (self);
872 }
873 }
874 }
875
876 static void
877 get_remote_cups_devices_cb (GObject *source_object,
878 GAsyncResult *res,
879 gpointer user_data)
880 {
881 PpNewPrinterDialog *self = user_data;
882 g_autoptr(GError) error = NULL;
883 g_autoptr(GPtrArray) devices = NULL;
884
885 devices = pp_host_get_remote_cups_devices_finish (PP_HOST (source_object), res, &error);
886
887 if (devices != NULL)
888 {
889 g_clear_object(&self->remote_cups_host);
890
891 add_devices_to_list (self, devices);
892
893 update_dialog_state (self);
894 }
895 else
896 {
897 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
898 {
899 g_warning ("%s", error->message);
900
901 g_clear_object(&self->remote_cups_host);
902
903 update_dialog_state (self);
904 }
905 }
906 }
907
908 static void
909 get_samba_host_devices_cb (GObject *source_object,
910 GAsyncResult *res,
911 gpointer user_data)
912 {
913 PpNewPrinterDialog *self = user_data;
914 g_autoptr(GPtrArray) devices = NULL;
915 g_autoptr(GError) error = NULL;
916
917 devices = pp_samba_get_devices_finish (PP_SAMBA (source_object), res, &error);
918
919 if (devices != NULL)
920 {
921 g_clear_object(&self->samba_host);
922
923 add_devices_to_list (self, devices);
924
925 update_dialog_state (self);
926 }
927 else
928 {
929 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
930 {
931 g_warning ("%s", error->message);
932
933 g_clear_object(&self->samba_host);
934
935 update_dialog_state (self);
936 }
937 }
938 }
939
940 static void
941 get_samba_devices_cb (GObject *source_object,
942 GAsyncResult *res,
943 gpointer user_data)
944 {
945 PpNewPrinterDialog *self = user_data;
946 g_autoptr(GPtrArray) devices = NULL;
947 g_autoptr(GError) error = NULL;
948
949 devices = pp_samba_get_devices_finish (PP_SAMBA (source_object), res, &error);
950
951 if (devices != NULL)
952 {
953 self->samba_searching = FALSE;
954
955 add_devices_to_list (self, devices);
956
957 update_dialog_state (self);
958 }
959 else
960 {
961 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
962 {
963 g_warning ("%s", error->message);
964
965 self->samba_searching = FALSE;
966
967 update_dialog_state (self);
968 }
969 }
970 }
971
972 static void
973 get_jetdirect_devices_cb (GObject *source_object,
974 GAsyncResult *res,
975 gpointer user_data)
976 {
977 PpNewPrinterDialog *self = user_data;
978 g_autoptr(GError) error = NULL;
979 g_autoptr(GPtrArray) devices = NULL;
980
981 devices = pp_host_get_jetdirect_devices_finish (PP_HOST (source_object), res, &error);
982
983 if (devices != NULL)
984 {
985 g_clear_object(&self->socket_host);
986
987 add_devices_to_list (self, devices);
988
989 update_dialog_state (self);
990 }
991 else
992 {
993 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
994 {
995 g_warning ("%s", error->message);
996
997 g_clear_object(&self->socket_host);
998
999 update_dialog_state (self);
1000 }
1001 }
1002 }
1003
1004 static void
1005 get_lpd_devices_cb (GObject *source_object,
1006 GAsyncResult *res,
1007 gpointer user_data)
1008 {
1009 PpNewPrinterDialog *self = user_data;
1010 g_autoptr(GError) error = NULL;
1011 g_autoptr(GPtrArray) devices = NULL;
1012
1013 devices = pp_host_get_lpd_devices_finish (PP_HOST (source_object), res, &error);
1014
1015 if (devices != NULL)
1016 {
1017 g_clear_object(&self->lpd_host);
1018
1019 add_devices_to_list (self, devices);
1020
1021 update_dialog_state (self);
1022 }
1023 else
1024 {
1025 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1026 {
1027 g_warning ("%s", error->message);
1028
1029 g_clear_object(&self->lpd_host);
1030
1031 update_dialog_state (self);
1032 }
1033 }
1034 }
1035
1036 static void
1037 get_cups_devices (PpNewPrinterDialog *self)
1038 {
1039 self->cups_searching = TRUE;
1040 update_dialog_state (self);
1041
1042 get_cups_devices_async (self->cancellable,
1043 get_cups_devices_cb,
1044 self);
1045 }
1046
1047 static gboolean
1048 parse_uri (const gchar *uri,
1049 gchar **scheme,
1050 gchar **host,
1051 gint *port)
1052 {
1053 const gchar *tmp = NULL;
1054 g_autofree gchar *resulting_host = NULL;
1055 gchar *position;
1056
1057 *port = PP_HOST_UNSET_PORT;
1058
1059 position = g_strrstr (uri, "://");
1060 if (position != NULL)
1061 {
1062 *scheme = g_strndup (uri, position - uri);
1063 tmp = position + 3;
1064 }
1065 else
1066 {
1067 tmp = uri;
1068 }
1069
1070 if (g_strrstr (tmp, "@"))
1071 tmp = g_strrstr (tmp, "@") + 1;
1072
1073 if ((position = g_strrstr (tmp, "/")))
1074 {
1075 *position = '\0';
1076 resulting_host = g_strdup (tmp);
1077 *position = '/';
1078 }
1079 else
1080 {
1081 resulting_host = g_strdup (tmp);
1082 }
1083
1084 if ((position = g_strrstr (resulting_host, ":")))
1085 {
1086 *position = '\0';
1087 *port = atoi (position + 1);
1088 }
1089
1090 *host = g_uri_unescape_string (resulting_host,
1091 G_URI_RESERVED_CHARS_GENERIC_DELIMITERS
1092 G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS);
1093
1094 return TRUE;
1095 }
1096
1097 typedef struct
1098 {
1099 PpNewPrinterDialog *dialog;
1100 gchar *host_scheme;
1101 gchar *host_name;
1102 gint host_port;
1103 } THostSearchData;
1104
1105 static void
1106 search_for_remote_printers_free (THostSearchData *data)
1107 {
1108 g_free (data->host_scheme);
1109 g_free (data->host_name);
1110 g_free (data);
1111 }
1112
1113 static gboolean
1114 search_for_remote_printers (THostSearchData *data)
1115 {
1116 PpNewPrinterDialog *self = data->dialog;
1117
1118 g_cancellable_cancel (self->remote_host_cancellable);
1119 g_clear_object (&self->remote_host_cancellable);
1120
1121 self->remote_host_cancellable = g_cancellable_new ();
1122
1123 self->remote_cups_host = pp_host_new (data->host_name);
1124 self->snmp_host = pp_host_new (data->host_name);
1125 self->socket_host = pp_host_new (data->host_name);
1126 self->lpd_host = pp_host_new (data->host_name);
1127
1128 if (data->host_port != PP_HOST_UNSET_PORT)
1129 {
1130 g_object_set (self->remote_cups_host, "port", data->host_port, NULL);
1131 g_object_set (self->snmp_host, "port", data->host_port, NULL);
1132
1133 /* Accept port different from the default one only if user specifies
1134 * scheme (for socket and lpd printers).
1135 */
1136 if (data->host_scheme != NULL &&
1137 g_ascii_strcasecmp (data->host_scheme, "socket") == 0)
1138 g_object_set (self->socket_host, "port", data->host_port, NULL);
1139
1140 if (data->host_scheme != NULL &&
1141 g_ascii_strcasecmp (data->host_scheme, "lpd") == 0)
1142 g_object_set (self->lpd_host, "port", data->host_port, NULL);
1143 }
1144
1145 self->samba_host = pp_samba_new (data->host_name);
1146
1147 update_dialog_state (data->dialog);
1148
1149 pp_host_get_remote_cups_devices_async (self->remote_cups_host,
1150 self->remote_host_cancellable,
1151 get_remote_cups_devices_cb,
1152 data->dialog);
1153
1154 pp_host_get_snmp_devices_async (self->snmp_host,
1155 self->remote_host_cancellable,
1156 get_snmp_devices_cb,
1157 data->dialog);
1158
1159 pp_host_get_jetdirect_devices_async (self->socket_host,
1160 self->remote_host_cancellable,
1161 get_jetdirect_devices_cb,
1162 data->dialog);
1163
1164 pp_host_get_lpd_devices_async (self->lpd_host,
1165 self->remote_host_cancellable,
1166 get_lpd_devices_cb,
1167 data->dialog);
1168
1169 pp_samba_get_devices_async (self->samba_host,
1170 FALSE,
1171 self->remote_host_cancellable,
1172 get_samba_host_devices_cb,
1173 data->dialog);
1174
1175 self->host_search_timeout_id = 0;
1176
1177 return G_SOURCE_REMOVE;
1178 }
1179
1180 static void
1181 search_address (const gchar *text,
1182 PpNewPrinterDialog *self,
1183 gboolean delay_search)
1184 {
1185 GtkTreeIter iter;
1186 gboolean found = FALSE;
1187 gboolean subfound;
1188 gboolean next_set;
1189 gboolean cont;
1190 g_autofree gchar *lowercase_text = NULL;
1191 gchar **words;
1192 gint words_length = 0;
1193 gint i;
1194 gint acquisition_method;
1195
1196 lowercase_text = g_ascii_strdown (text, -1);
1197 words = g_strsplit_set (lowercase_text, " ", -1);
1198
1199 if (words)
1200 {
1201 words_length = g_strv_length (words);
1202
1203 cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->devices_liststore), &iter);
1204 while (cont)
1205 {
1206 g_autoptr(PpPrintDevice) device = NULL;
1207 g_autofree gchar *lowercase_name = NULL;
1208 g_autofree gchar *lowercase_location = NULL;
1209
1210 gtk_tree_model_get (GTK_TREE_MODEL (self->devices_liststore), &iter,
1211 DEVICE_COLUMN, &device,
1212 -1);
1213
1214 lowercase_name = g_ascii_strdown (pp_print_device_get_device_name (device), -1);
1215 if (pp_print_device_get_device_location (device))
1216 lowercase_location = g_ascii_strdown (pp_print_device_get_device_location (device), -1);
1217 else
1218 lowercase_location = NULL;
1219
1220 subfound = TRUE;
1221 for (i = 0; words[i]; i++)
1222 {
1223 if (!g_strrstr (lowercase_name, words[i]) &&
1224 (!lowercase_location || !g_strrstr (lowercase_location, words[i])))
1225 subfound = FALSE;
1226 }
1227
1228 if (subfound)
1229 found = TRUE;
1230
1231 gtk_list_store_set (GTK_LIST_STORE (self->devices_liststore), &iter,
1232 DEVICE_VISIBLE_COLUMN, subfound,
1233 -1);
1234
1235 cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->devices_liststore), &iter);
1236 }
1237
1238 g_strfreev (words);
1239 }
1240
1241 /*
1242 * The given word is probably an address since it was not found among
1243 * already present devices.
1244 */
1245 if (!found && words_length == 1)
1246 {
1247 cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->devices_liststore), &iter);
1248 while (cont)
1249 {
1250 g_autoptr(PpPrintDevice) device = NULL;
1251
1252 next_set = FALSE;
1253 gtk_tree_model_get (GTK_TREE_MODEL (self->devices_liststore), &iter,
1254 DEVICE_COLUMN, &device,
1255 -1);
1256
1257 gtk_list_store_set (GTK_LIST_STORE (self->devices_liststore), &iter,
1258 DEVICE_VISIBLE_COLUMN, TRUE,
1259 -1);
1260
1261 acquisition_method = pp_print_device_get_acquisition_method (device);
1262 if (acquisition_method == ACQUISITION_METHOD_REMOTE_CUPS_SERVER ||
1263 acquisition_method == ACQUISITION_METHOD_SNMP ||
1264 acquisition_method == ACQUISITION_METHOD_JETDIRECT ||
1265 acquisition_method == ACQUISITION_METHOD_LPD ||
1266 acquisition_method == ACQUISITION_METHOD_SAMBA_HOST)
1267 {
1268 if (!gtk_list_store_remove (self->devices_liststore, &iter))
1269 break;
1270 else
1271 next_set = TRUE;
1272 }
1273
1274 if (!next_set)
1275 cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->devices_liststore), &iter);
1276 }
1277
1278 if (text && text[0] != '\0')
1279 {
1280 g_autoptr(GSocketConnectable) conn = NULL;
1281 g_autofree gchar *test_uri = NULL;
1282 g_autofree gchar *test_port = NULL;
1283 gchar *scheme = NULL;
1284 gchar *host = NULL;
1285 gint port;
1286
1287 parse_uri (text, &scheme, &host, &port);
1288
1289 if (host != NULL)
1290 {
1291 if (port >= 0)
1292 test_port = g_strdup_printf (":%d", port);
1293 else
1294 test_port = g_strdup ("");
1295
1296 test_uri = g_strdup_printf ("%s://%s%s",
1297 scheme != NULL && scheme[0] != '\0' ? scheme : "none",
1298 host,
1299 test_port);
1300
1301 conn = g_network_address_parse_uri (test_uri, 0, NULL);
1302 if (conn != NULL)
1303 {
1304 THostSearchData *search_data;
1305
1306 search_data = g_new (THostSearchData, 1);
1307 search_data->host_scheme = scheme;
1308 search_data->host_name = host;
1309 search_data->host_port = port;
1310 search_data->dialog = self;
1311
1312 g_clear_handle_id (&self->host_search_timeout_id, g_source_remove);
1313
1314 if (delay_search)
1315 {
1316 self->host_search_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
1317 HOST_SEARCH_DELAY,
1318 (GSourceFunc) search_for_remote_printers,
1319 search_data,
1320 (GDestroyNotify) search_for_remote_printers_free);
1321 }
1322 else
1323 {
1324 search_for_remote_printers (search_data);
1325 search_for_remote_printers_free (search_data);
1326 }
1327 }
1328 }
1329 }
1330 }
1331 }
1332
1333 static void
1334 search_entry_activated_cb (PpNewPrinterDialog *self)
1335 {
1336 search_address (gtk_editable_get_text (GTK_EDITABLE (self->search_entry)),
1337 self,
1338 FALSE);
1339 }
1340
1341 static void
1342 search_entry_changed_cb (PpNewPrinterDialog *self)
1343 {
1344 search_address (gtk_editable_get_text (GTK_EDITABLE (self->search_entry)),
1345 self,
1346 TRUE);
1347 }
1348
1349 static gchar *
1350 get_local_scheme_description_from_uri (gchar *device_uri)
1351 {
1352 gchar *description = NULL;
1353
1354 if (device_uri != NULL)
1355 {
1356 if (g_str_has_prefix (device_uri, "usb") ||
1357 g_str_has_prefix (device_uri, "hp:/usb/") ||
1358 g_str_has_prefix (device_uri, "hpfax:/usb/"))
1359 {
1360 /* Translators: The found device is a printer connected via USB */
1361 description = g_strdup (_("USB"));
1362 }
1363 else if (g_str_has_prefix (device_uri, "serial"))
1364 {
1365 /* Translators: The found device is a printer connected via serial port */
1366 description = g_strdup (_("Serial Port"));
1367 }
1368 else if (g_str_has_prefix (device_uri, "parallel") ||
1369 g_str_has_prefix (device_uri, "hp:/par/") ||
1370 g_str_has_prefix (device_uri, "hpfax:/par/"))
1371 {
1372 /* Translators: The found device is a printer connected via parallel port */
1373 description = g_strdup (_("Parallel Port"));
1374 }
1375 else if (g_str_has_prefix (device_uri, "bluetooth"))
1376 {
1377 /* Translators: The found device is a printer connected via Bluetooth */
1378 description = g_strdup (_("Bluetooth"));
1379 }
1380 }
1381
1382 return description;
1383 }
1384
1385 static void
1386 set_device (PpNewPrinterDialog *self,
1387 PpPrintDevice *device,
1388 GtkTreeIter *iter)
1389 {
1390 GtkTreeIter titer;
1391 gint acquisition_method;
1392
1393 if (device != NULL)
1394 {
1395 acquisition_method = pp_print_device_get_acquisition_method (device);
1396 if (pp_print_device_get_display_name (device) &&
1397 (pp_print_device_get_device_id (device) ||
1398 pp_print_device_get_device_ppd (device) ||
1399 (pp_print_device_get_host_name (device) &&
1400 acquisition_method == ACQUISITION_METHOD_REMOTE_CUPS_SERVER) ||
1401 (pp_print_device_get_device_uri (device) &&
1402 (acquisition_method == ACQUISITION_METHOD_JETDIRECT ||
1403 acquisition_method == ACQUISITION_METHOD_LPD)) ||
1404 acquisition_method == ACQUISITION_METHOD_SAMBA_HOST ||
1405 acquisition_method == ACQUISITION_METHOD_SAMBA))
1406 {
1407 g_autofree gchar *description = NULL;
1408
1409 description = get_local_scheme_description_from_uri (pp_print_device_get_device_uri (device));
1410 if (description == NULL)
1411 {
1412 if (pp_print_device_get_device_location (device) != NULL && pp_print_device_get_device_location (device)[0] != '\0')
1413 {
1414 /* Translators: Location of found network printer (e.g. Kitchen, Reception) */
1415 description = g_strdup_printf (_("Location: %s"), pp_print_device_get_device_location (device));
1416 }
1417 else if (pp_print_device_get_host_name (device) != NULL && pp_print_device_get_host_name (device)[0] != '\0')
1418 {
1419 /* Translators: Network address of found printer */
1420 description = g_strdup_printf (_("Address: %s"), pp_print_device_get_host_name (device));
1421 }
1422 }
1423
1424 if (iter == NULL)
1425 gtk_list_store_append (self->devices_liststore, &titer);
1426
1427 gtk_list_store_set (self->devices_liststore, iter == NULL ? &titer : iter,
1428 DEVICE_GICON_COLUMN, pp_print_device_is_network_device (device) ? self->remote_printer_icon : self->local_printer_icon,
1429 DEVICE_NAME_COLUMN, pp_print_device_get_device_name (device),
1430 DEVICE_DISPLAY_NAME_COLUMN, pp_print_device_get_display_name (device),
1431 DEVICE_DESCRIPTION_COLUMN, description,
1432 DEVICE_VISIBLE_COLUMN, TRUE,
1433 DEVICE_COLUMN, device,
1434 -1);
1435 }
1436 else if (pp_print_device_is_authenticated_server (device) &&
1437 pp_print_device_get_host_name (device) != NULL)
1438 {
1439 if (iter == NULL)
1440 gtk_list_store_append (self->devices_liststore, &titer);
1441
1442 gtk_list_store_set (self->devices_liststore, iter == NULL ? &titer : iter,
1443 DEVICE_GICON_COLUMN, self->authenticated_server_icon,
1444 DEVICE_NAME_COLUMN, pp_print_device_get_host_name (device),
1445 DEVICE_DISPLAY_NAME_COLUMN, pp_print_device_get_host_name (device),
1446 /* Translators: This item is a server which needs authentication to show its printers */
1447 DEVICE_DESCRIPTION_COLUMN, _("Server requires authentication"),
1448 SERVER_NEEDS_AUTHENTICATION_COLUMN, TRUE,
1449 DEVICE_VISIBLE_COLUMN, TRUE,
1450 DEVICE_COLUMN, device,
1451 -1);
1452 }
1453 }
1454 }
1455
1456 static void
1457 replace_device (PpNewPrinterDialog *self,
1458 PpPrintDevice *old_device,
1459 PpPrintDevice *new_device)
1460 {
1461 GtkTreeIter iter;
1462 gboolean cont;
1463
1464 if (old_device != NULL && new_device != NULL)
1465 {
1466 cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->devices_liststore), &iter);
1467 while (cont)
1468 {
1469 g_autoptr(PpPrintDevice) device = NULL;
1470
1471 gtk_tree_model_get (GTK_TREE_MODEL (self->devices_liststore), &iter,
1472 DEVICE_COLUMN, &device,
1473 -1);
1474
1475 if (old_device == device)
1476 {
1477 set_device (self, new_device, &iter);
1478 break;
1479 }
1480
1481 cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->devices_liststore), &iter);
1482 }
1483 }
1484 }
1485
1486 static void
1487 cups_get_dests_cb (GObject *source_object,
1488 GAsyncResult *res,
1489 gpointer user_data)
1490 {
1491 PpNewPrinterDialog *self = user_data;
1492 PpCupsDests *dests;
1493 g_autoptr(GError) error = NULL;
1494
1495 dests = pp_cups_get_dests_finish (PP_CUPS (source_object), res, &error);
1496
1497 if (dests)
1498 {
1499 self->dests = dests->dests;
1500 self->num_of_dests = dests->num_of_dests;
1501
1502 get_cups_devices (self);
1503 }
1504 else
1505 {
1506 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1507 {
1508 g_warning ("%s", error->message);
1509
1510 get_cups_devices (self);
1511 }
1512 }
1513 }
1514
1515 static void
1516 row_activated_cb (PpNewPrinterDialog *self)
1517 {
1518 GtkTreeModel *model;
1519 GtkTreeIter iter;
1520 gboolean authentication_needed;
1521 gboolean selected;
1522
1523 selected = gtk_tree_selection_get_selected (gtk_tree_view_get_selection (self->devices_treeview),
1524 &model,
1525 &iter);
1526
1527 if (selected)
1528 {
1529 gtk_tree_model_get (model, &iter, SERVER_NEEDS_AUTHENTICATION_COLUMN, &authentication_needed, -1);
1530
1531 if (authentication_needed)
1532 {
1533 authenticate_samba_server (self);
1534 }
1535 else
1536 {
1537 add_cb (self);
1538 }
1539 }
1540 }
1541
1542 static void
1543 cell_data_func (GtkTreeViewColumn *tree_column,
1544 GtkCellRenderer *cell,
1545 GtkTreeModel *tree_model,
1546 GtkTreeIter *iter,
1547 gpointer user_data)
1548 {
1549 PpNewPrinterDialog *self = user_data;
1550 gboolean selected = FALSE;
1551 g_autofree gchar *name = NULL;
1552 g_autofree gchar *description = NULL;
1553
1554 selected = gtk_tree_selection_iter_is_selected (gtk_tree_view_get_selection (self->devices_treeview), iter);
1555
1556 gtk_tree_model_get (tree_model, iter,
1557 DEVICE_DISPLAY_NAME_COLUMN, &name,
1558 DEVICE_DESCRIPTION_COLUMN, &description,
1559 -1);
1560
1561 if (name != NULL)
1562 {
1563 g_autofree gchar *text = NULL;
1564
1565 if (description != NULL)
1566 {
1567 if (selected)
1568 text = g_markup_printf_escaped ("<b>%s</b>\n<small>%s</small>",
1569 name,
1570 description);
1571 else
1572 text = g_markup_printf_escaped ("<b>%s</b>\n<small><span foreground=\"#555555\">%s</span></small>",
1573 name,
1574 description);
1575 }
1576 else
1577 {
1578 text = g_markup_printf_escaped ("<b>%s</b>\n ",
1579 name);
1580 }
1581
1582 g_object_set (G_OBJECT (cell),
1583 "markup", text,
1584 NULL);
1585 }
1586 }
1587
1588 static void
1589 populate_devices_list (PpNewPrinterDialog *self)
1590 {
1591 GtkTreeViewColumn *column;
1592 g_autoptr(PpSamba) samba = NULL;
1593 g_autoptr(GEmblem) emblem = NULL;
1594 g_autoptr(PpCups) cups = NULL;
1595 g_autoptr(GIcon) icon = NULL;
1596 g_autoptr(GIcon) emblem_icon = NULL;
1597 GtkCellRenderer *text_renderer;
1598 GtkCellRenderer *icon_renderer;
1599
1600 g_signal_connect_object (gtk_tree_view_get_selection (self->devices_treeview),
1601 "changed", G_CALLBACK (device_selection_changed_cb), self, G_CONNECT_SWAPPED);
1602
1603 g_signal_connect_object (self->devices_treeview,
1604 "row-activated", G_CALLBACK (row_activated_cb), self, G_CONNECT_SWAPPED);
1605
1606 self->local_printer_icon = g_themed_icon_new ("printer");
1607 self->remote_printer_icon = g_themed_icon_new ("printer-network");
1608
1609 icon = g_themed_icon_new ("network-server");
1610 emblem_icon = g_themed_icon_new ("changes-prevent");
1611 emblem = g_emblem_new (emblem_icon);
1612
1613 self->authenticated_server_icon = g_emblemed_icon_new (icon, emblem);
1614
1615 icon_renderer = gtk_cell_renderer_pixbuf_new ();
1616 g_object_set (icon_renderer, "icon-size", GTK_ICON_SIZE_LARGE, NULL);
1617 gtk_cell_renderer_set_alignment (icon_renderer, 1.0, 0.5);
1618 gtk_cell_renderer_set_padding (icon_renderer, 4, 4);
1619 column = gtk_tree_view_column_new_with_attributes ("Icon", icon_renderer,
1620 "gicon", DEVICE_GICON_COLUMN, NULL);
1621 gtk_tree_view_column_set_max_width (column, -1);
1622 gtk_tree_view_column_set_min_width (column, 80);
1623 gtk_tree_view_append_column (self->devices_treeview, column);
1624
1625
1626 text_renderer = gtk_cell_renderer_text_new ();
1627 column = gtk_tree_view_column_new_with_attributes ("Devices", text_renderer,
1628 NULL);
1629 gtk_tree_view_column_set_cell_data_func (column, text_renderer, cell_data_func,
1630 self, NULL);
1631 gtk_tree_view_append_column (self->devices_treeview, column);
1632
1633 gtk_tree_model_filter_set_visible_column (self->devices_model_filter, DEVICE_VISIBLE_COLUMN);
1634
1635 cups = pp_cups_new ();
1636 pp_cups_get_dests_async (cups, self->cancellable, cups_get_dests_cb, self);
1637
1638 self->samba_searching = TRUE;
1639 update_dialog_state (self);
1640
1641 samba = pp_samba_new (NULL);
1642 pp_samba_get_devices_async (samba, FALSE, self->cancellable, get_samba_devices_cb, self);
1643 }
1644
1645 static void
1646 ppd_selection_cb (GtkWindow *_dialog,
1647 gint response_id,
1648 gpointer user_data)
1649 {
1650 PpNewPrinterDialog *self = user_data;
1651 GList *original_names_list = NULL;
1652 g_autofree gchar *ppd_name = NULL;
1653 g_autofree gchar *ppd_display_name = NULL;
1654 gint acquisition_method;
1655
1656 if (response_id == GTK_RESPONSE_OK) {
1657 ppd_name = pp_ppd_selection_dialog_get_ppd_name (self->ppd_selection_dialog);
1658 ppd_display_name = pp_ppd_selection_dialog_get_ppd_display_name (self->ppd_selection_dialog);
1659 }
1660
1661 if (ppd_name)
1662 {
1663 g_object_set (self->new_device, "device-ppd", ppd_name, NULL);
1664
1665 acquisition_method = pp_print_device_get_acquisition_method (self->new_device);
1666 if ((acquisition_method == ACQUISITION_METHOD_JETDIRECT ||
1667 acquisition_method == ACQUISITION_METHOD_LPD) &&
1668 ppd_display_name != NULL)
1669 {
1670 g_autofree gchar *printer_name = NULL;
1671
1672 g_object_set (self->new_device,
1673 "device-name", ppd_display_name,
1674 "device-original-name", ppd_display_name,
1675 NULL);
1676
1677 gtk_tree_model_foreach (GTK_TREE_MODEL (self->devices_liststore),
1678 prepend_original_name,
1679 &original_names_list);
1680
1681 original_names_list = g_list_reverse (original_names_list);
1682
1683 printer_name = canonicalize_device_name (original_names_list,
1684 self->local_cups_devices,
1685 self->dests,
1686 self->num_of_dests,
1687 self->new_device);
1688
1689 g_list_free_full (original_names_list, g_free);
1690
1691 g_object_set (self->new_device,
1692 "device-name", printer_name,
1693 "device-original-name", printer_name,
1694 NULL);
1695 }
1696 }
1697
1698 /* This is needed here since parent dialog is destroyed first. */
1699 gtk_window_set_transient_for (GTK_WINDOW (self->ppd_selection_dialog), NULL);
1700
1701 self->user_callback (GTK_WINDOW (self), response_id, self->user_data);
1702 }
1703
1704 static void
1705 cancel_cb (PpNewPrinterDialog *self)
1706 {
1707 self->user_callback (GTK_WINDOW (self), GTK_RESPONSE_CANCEL, self->user_data);
1708 }
1709
1710 static void
1711 add_cb (PpNewPrinterDialog *self)
1712 {
1713 g_autoptr(PpPrintDevice) device = NULL;
1714 GtkTreeModel *model;
1715 GtkTreeIter iter;
1716 gint acquisition_method;
1717
1718 g_cancellable_cancel (self->cancellable);
1719 g_clear_object (&self->cancellable);
1720
1721 if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (self->devices_treeview), &model, &iter))
1722 {
1723 gtk_tree_model_get (model, &iter,
1724 DEVICE_COLUMN, &device,
1725 -1);
1726 }
1727
1728 if (device)
1729 {
1730 acquisition_method = pp_print_device_get_acquisition_method (device);
1731 if (acquisition_method == ACQUISITION_METHOD_SAMBA ||
1732 acquisition_method == ACQUISITION_METHOD_SAMBA_HOST ||
1733 acquisition_method == ACQUISITION_METHOD_JETDIRECT ||
1734 acquisition_method == ACQUISITION_METHOD_LPD)
1735 {
1736 self->new_device = pp_print_device_copy (device);
1737 self->ppd_selection_dialog =
1738 pp_ppd_selection_dialog_new (self->list,
1739 NULL,
1740 ppd_selection_cb,
1741 self);
1742
1743 gtk_window_set_transient_for (GTK_WINDOW (self->ppd_selection_dialog),
1744 GTK_WINDOW (self));
1745
1746 /* New device will be set at return from ppd selection */
1747 gtk_widget_set_visible (GTK_WIDGET (self->ppd_selection_dialog), TRUE);
1748 }
1749 else
1750 {
1751 self->new_device = pp_print_device_copy (device);
1752 self->user_callback (GTK_WINDOW (self), GTK_RESPONSE_OK, self->user_data);
1753 }
1754 }
1755 }
1756
1757 PpNewPrinterDialog *
1758 pp_new_printer_dialog_new (PPDList *ppd_list,
1759 UserResponseCallback user_callback,
1760 gpointer user_data)
1761 {
1762 PpNewPrinterDialog *self;
1763
1764 self = g_object_new (pp_new_printer_dialog_get_type (), NULL);
1765
1766 self->user_callback = user_callback;
1767 self->user_data = user_data;
1768
1769 self->list = ppd_list_copy (ppd_list);
1770
1771 self->local_cups_devices = g_ptr_array_new_with_free_func (g_object_unref);
1772
1773 /* GCancellable for cancelling of async operations */
1774 self->cancellable = g_cancellable_new ();
1775
1776 g_signal_connect_object (self->search_entry, "activate", G_CALLBACK (search_entry_activated_cb), self, G_CONNECT_SWAPPED);
1777 g_signal_connect_object (self->search_entry, "search-changed", G_CALLBACK (search_entry_changed_cb), self, G_CONNECT_SWAPPED);
1778
1779 g_signal_connect_object (self->unlock_button, "clicked", G_CALLBACK (authenticate_samba_server), self, G_CONNECT_SWAPPED);
1780
1781 /* Authentication form widgets */
1782 g_signal_connect_object (self->username_entry, "changed", G_CALLBACK (auth_entries_changed), self, G_CONNECT_SWAPPED);
1783 g_signal_connect_object (self->password_entry, "changed", G_CALLBACK (auth_entries_changed), self, G_CONNECT_SWAPPED);
1784 g_signal_connect_object (self->go_back_button, "clicked", G_CALLBACK (on_go_back_button_clicked), self, G_CONNECT_SWAPPED);
1785
1786 /* Fill with data */
1787 populate_devices_list (self);
1788
1789 return self;
1790 }
1791
1792 static gboolean
1793 pp_new_printer_dialog_close_request (GtkWindow *window)
1794 {
1795 PpNewPrinterDialog *self = PP_NEW_PRINTER_DIALOG (window);
1796
1797 cancel_cb (self);
1798
1799 return GDK_EVENT_STOP;
1800 }
1801
1802 static void
1803 pp_new_printer_dialog_dispose (GObject *object)
1804 {
1805 PpNewPrinterDialog *self = PP_NEW_PRINTER_DIALOG (object);
1806
1807 g_cancellable_cancel (self->remote_host_cancellable);
1808 g_cancellable_cancel (self->cancellable);
1809
1810 g_clear_handle_id (&self->host_search_timeout_id, g_source_remove);
1811 g_clear_object (&self->remote_host_cancellable);
1812 g_clear_object (&self->cancellable);
1813 g_clear_pointer (&self->list, ppd_list_free);
1814 g_clear_pointer (&self->local_cups_devices, g_ptr_array_unref);
1815 g_clear_object (&self->new_device);
1816 g_clear_object (&self->local_printer_icon);
1817 g_clear_object (&self->remote_printer_icon);
1818 g_clear_object (&self->authenticated_server_icon);
1819 g_clear_object (&self->snmp_host);
1820 g_clear_object (&self->socket_host);
1821 g_clear_object (&self->lpd_host);
1822 g_clear_object (&self->remote_cups_host);
1823 g_clear_object (&self->samba_host);
1824
1825 if (self->ppd_selection_dialog != NULL)
1826 {
1827 gtk_window_destroy (GTK_WINDOW (self->ppd_selection_dialog));
1828 self->ppd_selection_dialog = NULL;
1829 }
1830
1831 if (self->num_of_dests > 0)
1832 {
1833 cupsFreeDests (self->num_of_dests, self->dests);
1834 self->num_of_dests = 0;
1835 self->dests = NULL;
1836 }
1837
1838 G_OBJECT_CLASS (pp_new_printer_dialog_parent_class)->dispose (object);
1839 }
1840
1841 void
1842 pp_new_printer_dialog_class_init (PpNewPrinterDialogClass *klass)
1843 {
1844 GtkWindowClass *window_class = GTK_WINDOW_CLASS (klass);
1845 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
1846 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1847
1848 g_type_ensure (PP_TYPE_PRINT_DEVICE);
1849
1850 gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/printers/new-printer-dialog.ui");
1851
1852 gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, devices_liststore);
1853 gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, devices_model_filter);
1854
1855 /* headerbar */
1856 gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, header_title);
1857
1858 /* headerbar topleft buttons */
1859 gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, headerbar_topleft_buttons);
1860 gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, go_back_button);
1861
1862 /* headerbar topright buttons */
1863 gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, headerbar_topright_buttons);
1864 gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, new_printer_add_button);
1865 gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, unlock_button);
1866 gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, authenticate_button);
1867
1868 /* dialogstack */
1869 gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, dialog_stack);
1870 gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, stack);
1871
1872 /* scrolledwindow1 */
1873 gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, scrolledwindow1);
1874 gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, devices_treeview);
1875
1876 gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, search_entry);
1877
1878 /* authentication page */
1879 gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, authentication_title);
1880 gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, authentication_text);
1881 gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, username_entry);
1882 gtk_widget_class_bind_template_child (widget_class, PpNewPrinterDialog, password_entry);
1883
1884 gtk_widget_class_bind_template_callback (widget_class, add_cb);
1885 gtk_widget_class_bind_template_callback (widget_class, cancel_cb);
1886
1887 object_class->dispose = pp_new_printer_dialog_dispose;
1888 window_class->close_request = pp_new_printer_dialog_close_request;
1889
1890 gtk_widget_class_add_binding_action (widget_class, GDK_KEY_Escape, 0, "window.close", NULL);
1891 }
1892
1893
1894 void
1895 pp_new_printer_dialog_init (PpNewPrinterDialog *self)
1896 {
1897 gtk_widget_init_template (GTK_WIDGET (self));
1898 }
1899
1900 void
1901 pp_new_printer_dialog_set_ppd_list (PpNewPrinterDialog *self,
1902 PPDList *list)
1903 {
1904 self->list = ppd_list_copy (list);
1905
1906 if (self->ppd_selection_dialog)
1907 pp_ppd_selection_dialog_set_ppd_list (self->ppd_selection_dialog, self->list);
1908 }
1909
1910 PpNewPrinter *
1911 pp_new_printer_dialog_get_new_printer (PpNewPrinterDialog *self)
1912 {
1913 PpNewPrinter *new_printer = NULL;
1914
1915 new_printer = pp_new_printer_new ();
1916 g_object_set (new_printer,
1917 "name", pp_print_device_get_device_name (self->new_device),
1918 "original-name", pp_print_device_get_device_original_name (self->new_device),
1919 "device-uri", pp_print_device_get_device_uri (self->new_device),
1920 "device-id", pp_print_device_get_device_id (self->new_device),
1921 "ppd-name", pp_print_device_get_device_ppd (self->new_device),
1922 "ppd-file-name", pp_print_device_get_device_ppd (self->new_device),
1923 "info", pp_print_device_get_device_info (self->new_device),
1924 "location", pp_print_device_get_device_location (self->new_device),
1925 "make-and-model", pp_print_device_get_device_make_and_model (self->new_device),
1926 "host-name", pp_print_device_get_host_name (self->new_device),
1927 "host-port", pp_print_device_get_host_port (self->new_device),
1928 "is-network-device", pp_print_device_is_network_device (self->new_device),
1929 "window-id", 0,
1930 NULL);
1931
1932 return new_printer;
1933 }
1934