1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2011 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, or (at your option)
8 * 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 #include <gio/gio.h>
22 #include <stdlib.h>
23 #include <libnotify/notify.h>
24 #include <glib/gi18n.h>
25 #include <glib/gstdio.h>
26 #include <gtk/gtk.h>
27 #include <cups/cups.h>
28 #include <cups/ppd.h>
29
30 static GDBusNodeInfo *npn_introspection_data = NULL;
31 static GDBusNodeInfo *pdi_introspection_data = NULL;
32
33 #define SCP_DBUS_NPN_NAME "com.redhat.NewPrinterNotification"
34 #define SCP_DBUS_NPN_PATH "/com/redhat/NewPrinterNotification"
35 #define SCP_DBUS_NPN_INTERFACE "com.redhat.NewPrinterNotification"
36
37 #define SCP_DBUS_PDI_NAME "com.redhat.PrinterDriversInstaller"
38 #define SCP_DBUS_PDI_PATH "/com/redhat/PrinterDriversInstaller"
39 #define SCP_DBUS_PDI_INTERFACE "com.redhat.PrinterDriversInstaller"
40
41 #define PACKAGE_KIT_BUS "org.freedesktop.PackageKit"
42 #define PACKAGE_KIT_PATH "/org/freedesktop/PackageKit"
43 #define PACKAGE_KIT_MODIFY_IFACE "org.freedesktop.PackageKit.Modify"
44 #define PACKAGE_KIT_QUERY_IFACE "org.freedesktop.PackageKit.Query"
45
46 #define SCP_BUS "org.fedoraproject.Config.Printing"
47 #define SCP_PATH "/org/fedoraproject/Config/Printing"
48 #define SCP_IFACE "org.fedoraproject.Config.Printing"
49
50 #define MECHANISM_BUS "org.opensuse.CupsPkHelper.Mechanism"
51
52 #define ALLOWED_CHARACTERS "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
53
54 #define DBUS_TIMEOUT 60000
55 #define DBUS_INSTALL_TIMEOUT 3600000
56
57 #define GNOME_SESSION_DBUS_NAME "org.gnome.SessionManager"
58 #define GNOME_SESSION_DBUS_PATH "/org/gnome/SessionManager"
59 #define GNOME_SESSION_DBUS_IFACE "org.gnome.SessionManager"
60 #define GNOME_SESSION_CLIENT_PRIVATE_DBUS_IFACE "org.gnome.SessionManager.ClientPrivate"
61
62 #define GNOME_SESSION_PRESENCE_DBUS_PATH "/org/gnome/SessionManager/Presence"
63 #define GNOME_SESSION_PRESENCE_DBUS_IFACE "org.gnome.SessionManager.Presence"
64
65 #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
66 #define HAVE_CUPS_1_6 1
67 #endif
68
69 #ifndef HAVE_CUPS_1_6
70 #define ippGetState(ipp) ipp->state
71 #endif
72
73 enum {
74 PRESENCE_STATUS_AVAILABLE = 0,
75 PRESENCE_STATUS_INVISIBLE,
76 PRESENCE_STATUS_BUSY,
77 PRESENCE_STATUS_IDLE,
78 PRESENCE_STATUS_UNKNOWN
79 };
80
81 static const gchar npn_introspection_xml[] =
82 "<node name='/com/redhat/NewPrinterNotification'>"
83 " <interface name='com.redhat.NewPrinterNotification'>"
84 " <method name='GetReady'>"
85 " </method>"
86 " <method name='NewPrinter'>"
87 " <arg type='i' name='status' direction='in'/>"
88 " <arg type='s' name='name' direction='in'/>"
89 " <arg type='s' name='mfg' direction='in'/>"
90 " <arg type='s' name='mdl' direction='in'/>"
91 " <arg type='s' name='des' direction='in'/>"
92 " <arg type='s' name='cmd' direction='in'/>"
93 " </method>"
94 " </interface>"
95 "</node>";
96
97 static const gchar pdi_introspection_xml[] =
98 "<node name='/com/redhat/PrinterDriversInstaller'>"
99 " <interface name='com.redhat.PrinterDriversInstaller'>"
100 " <method name='InstallDrivers'>"
101 " <arg type='s' name='mfg' direction='in'/>"
102 " <arg type='s' name='mdl' direction='in'/>"
103 " <arg type='s' name='cmd' direction='in'/>"
104 " </method>"
105 " </interface>"
106 "</node>";
107
108 static GMainLoop *main_loop;
109 static guint npn_registration_id;
110 static guint pdi_registration_id;
111 static guint npn_owner_id;
112 static guint pdi_owner_id;
113
114 static GHashTable *
get_missing_executables(const gchar * ppd_file_name)115 get_missing_executables (const gchar *ppd_file_name)
116 {
117 GHashTable *executables = NULL;
118 GDBusProxy *proxy;
119 GVariant *output;
120 GVariant *array;
121 GError *error = NULL;
122 gint i;
123
124 if (!ppd_file_name)
125 return NULL;
126
127 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
128 G_DBUS_PROXY_FLAGS_NONE,
129 NULL,
130 SCP_BUS,
131 SCP_PATH,
132 SCP_IFACE,
133 NULL,
134 &error);
135
136 if (!proxy) {
137 g_warning ("%s", error->message);
138 g_error_free (error);
139 return NULL;
140 }
141
142 output = g_dbus_proxy_call_sync (proxy,
143 "MissingExecutables",
144 g_variant_new ("(s)",
145 ppd_file_name),
146 G_DBUS_CALL_FLAGS_NONE,
147 DBUS_TIMEOUT,
148 NULL,
149 &error);
150
151 if (output && g_variant_n_children (output) == 1) {
152 array = g_variant_get_child_value (output, 0);
153 if (array) {
154 executables = g_hash_table_new_full (g_str_hash, g_str_equal,
155 g_free, NULL);
156 for (i = 0; i < g_variant_n_children (array); i++) {
157 g_hash_table_insert (executables,
158 g_strdup (g_variant_get_string (
159 g_variant_get_child_value (array, i),
160 NULL)),
161 NULL);
162 }
163 }
164 }
165
166 if (output) {
167 g_variant_unref (output);
168 } else {
169 g_warning ("%s", error->message);
170 g_error_free (error);
171 }
172
173 g_object_unref (proxy);
174
175 return executables;
176 }
177
178 static GHashTable *
find_packages_for_executables(GHashTable * executables)179 find_packages_for_executables (GHashTable *executables)
180 {
181 GHashTableIter exec_iter;
182 GHashTable *packages = NULL;
183 GDBusProxy *proxy;
184 GVariant *output;
185 gpointer key, value;
186 GError *error = NULL;
187
188 if (!executables || g_hash_table_size (executables) <= 0)
189 return NULL;
190
191 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
192 G_DBUS_PROXY_FLAGS_NONE,
193 NULL,
194 PACKAGE_KIT_BUS,
195 PACKAGE_KIT_PATH,
196 PACKAGE_KIT_QUERY_IFACE,
197 NULL,
198 &error);
199
200 if (!proxy) {
201 g_warning ("%s", error->message);
202 g_error_free (error);
203 return NULL;
204 }
205
206 packages = g_hash_table_new_full (g_str_hash, g_str_equal,
207 g_free, NULL);
208
209 g_hash_table_iter_init (&exec_iter, executables);
210 while (g_hash_table_iter_next (&exec_iter, &key, &value)) {
211 output = g_dbus_proxy_call_sync (proxy,
212 "SearchFile",
213 g_variant_new ("(ss)",
214 (gchar *) key,
215 ""),
216 G_DBUS_CALL_FLAGS_NONE,
217 DBUS_TIMEOUT,
218 NULL,
219 &error);
220
221 if (output) {
222 gboolean installed;
223 gchar *package;
224
225 g_variant_get (output,
226 "(bs)",
227 &installed,
228 &package);
229 if (!installed)
230 g_hash_table_insert (packages, g_strdup (package), NULL);
231
232 g_variant_unref (output);
233 } else {
234 g_warning ("%s", error->message);
235 g_error_free (error);
236 }
237 }
238
239 g_object_unref (proxy);
240
241 return packages;
242 }
243
244 static void
install_packages(GHashTable * packages)245 install_packages (GHashTable *packages)
246 {
247 GVariantBuilder array_builder;
248 GHashTableIter pkg_iter;
249 GDBusProxy *proxy;
250 GVariant *output;
251 gpointer key, value;
252 GError *error = NULL;
253
254 if (!packages || g_hash_table_size (packages) <= 0)
255 return;
256
257 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
258 G_DBUS_PROXY_FLAGS_NONE,
259 NULL,
260 PACKAGE_KIT_BUS,
261 PACKAGE_KIT_PATH,
262 PACKAGE_KIT_MODIFY_IFACE,
263 NULL,
264 &error);
265
266 if (!proxy) {
267 g_warning ("%s", error->message);
268 g_error_free (error);
269 return;
270 }
271
272 g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("as"));
273
274 g_hash_table_iter_init (&pkg_iter, packages);
275 while (g_hash_table_iter_next (&pkg_iter, &key, &value)) {
276 g_variant_builder_add (&array_builder,
277 "s",
278 (gchar *) key);
279 }
280
281 output = g_dbus_proxy_call_sync (proxy,
282 "InstallPackageNames",
283 g_variant_new ("(uass)",
284 0,
285 &array_builder,
286 "hide-finished"),
287 G_DBUS_CALL_FLAGS_NONE,
288 DBUS_INSTALL_TIMEOUT,
289 NULL,
290 &error);
291
292 if (output) {
293 g_variant_unref (output);
294 } else {
295 g_warning ("%s", error->message);
296 g_error_free (error);
297 }
298
299 g_object_unref (proxy);
300 }
301
302 static gchar *
get_best_ppd(gchar * device_id,gchar * device_make_and_model,gchar * device_uri)303 get_best_ppd (gchar *device_id,
304 gchar *device_make_and_model,
305 gchar *device_uri)
306 {
307 GDBusProxy *proxy;
308 GVariant *output;
309 GVariant *array;
310 GVariant *tuple;
311 GError *error = NULL;
312 gchar *ppd_name = NULL;
313 gint i, j;
314 static const char * const match_levels[] = {
315 "exact-cmd",
316 "exact",
317 "close",
318 "generic",
319 "none"};
320
321 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
322 G_DBUS_PROXY_FLAGS_NONE,
323 NULL,
324 SCP_BUS,
325 SCP_PATH,
326 SCP_IFACE,
327 NULL,
328 &error);
329
330 if (!proxy) {
331 g_warning ("%s", error->message);
332 g_error_free (error);
333 return NULL;
334 }
335
336 output = g_dbus_proxy_call_sync (proxy,
337 "GetBestDrivers",
338 g_variant_new ("(sss)",
339 device_id ? device_id : "",
340 device_make_and_model ? device_make_and_model : "",
341 device_uri ? device_uri : ""),
342 G_DBUS_CALL_FLAGS_NONE,
343 DBUS_TIMEOUT,
344 NULL,
345 &error);
346
347 if (output && g_variant_n_children (output) >= 1) {
348 array = g_variant_get_child_value (output, 0);
349 if (array)
350 for (j = 0; j < G_N_ELEMENTS (match_levels) && ppd_name == NULL; j++)
351 for (i = 0; i < g_variant_n_children (array) && ppd_name == NULL; i++) {
352 tuple = g_variant_get_child_value (array, i);
353 if (tuple && g_variant_n_children (tuple) == 2) {
354 if (g_strcmp0 (g_variant_get_string (
355 g_variant_get_child_value (tuple, 1),
356 NULL), match_levels[j]) == 0)
357 ppd_name = g_strdup (g_variant_get_string (
358 g_variant_get_child_value (tuple, 0),
359 NULL));
360 }
361 }
362 }
363
364 if (output) {
365 g_variant_unref (output);
366 } else {
367 g_warning ("%s", error->message);
368 g_error_free (error);
369 }
370
371 g_object_unref (proxy);
372
373 return ppd_name;
374 }
375
376 static gchar *
get_tag_value(const gchar * tag_string,const gchar * tag_name)377 get_tag_value (const gchar *tag_string,
378 const gchar *tag_name)
379 {
380 gchar **tag_string_splitted;
381 gchar *tag_value = NULL;
382 gint tag_name_length;
383 gint i;
384
385 if (!tag_string ||
386 !tag_name)
387 return NULL;
388
389 tag_name_length = strlen (tag_name);
390 tag_string_splitted = g_strsplit (tag_string, ";", 0);
391 if (tag_string_splitted) {
392 for (i = 0; i < g_strv_length (tag_string_splitted); i++)
393 if (g_ascii_strncasecmp (tag_string_splitted[i], tag_name, tag_name_length) == 0)
394 if (strlen (tag_string_splitted[i]) > tag_name_length + 1)
395 tag_value = g_strdup (tag_string_splitted[i] + tag_name_length + 1);
396
397 g_strfreev (tag_string_splitted);
398 }
399
400 return tag_value;
401 }
402
403 static gchar *
create_name(gchar * device_id)404 create_name (gchar *device_id)
405 {
406 cups_dest_t *dests;
407 gboolean already_present = FALSE;
408 gchar *name = NULL;
409 gchar *new_name = NULL;
410 gint num_dests;
411 gint name_index = 2;
412 gint j;
413
414 g_return_val_if_fail (device_id != NULL, NULL);
415
416 name = get_tag_value (device_id, "mdl");
417 if (!name)
418 name = get_tag_value (device_id, "model");
419
420 if (name)
421 name = g_strcanon (name, ALLOWED_CHARACTERS, '-');
422
423 num_dests = cupsGetDests (&dests);
424 do {
425 if (already_present) {
426 new_name = g_strdup_printf ("%s-%d", name, name_index);
427 name_index++;
428 } else {
429 new_name = g_strdup (name);
430 }
431
432 already_present = FALSE;
433 for (j = 0; j < num_dests; j++)
434 if (g_strcmp0 (dests[j].name, new_name) == 0)
435 already_present = TRUE;
436
437 if (already_present) {
438 g_free (new_name);
439 } else {
440 g_free (name);
441 name = new_name;
442 }
443 } while (already_present);
444 cupsFreeDests (num_dests, dests);
445
446 return name;
447 }
448
449 static gboolean
add_printer(gchar * printer_name,gchar * device_uri,gchar * ppd_name,gchar * info,gchar * location)450 add_printer (gchar *printer_name,
451 gchar *device_uri,
452 gchar *ppd_name,
453 gchar *info,
454 gchar *location)
455 {
456 cups_dest_t *dests;
457 GDBusProxy *proxy;
458 gboolean success = FALSE;
459 GVariant *output;
460 GError *error = NULL;
461 gint num_dests;
462 gint i;
463
464 if (!printer_name || !device_uri || !ppd_name)
465 return FALSE;
466
467 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
468 G_DBUS_PROXY_FLAGS_NONE,
469 NULL,
470 MECHANISM_BUS,
471 "/",
472 MECHANISM_BUS,
473 NULL,
474 &error);
475
476 if (!proxy) {
477 g_warning ("%s", error->message);
478 g_error_free (error);
479 return FALSE;
480 }
481
482 output = g_dbus_proxy_call_sync (proxy,
483 "PrinterAdd",
484 g_variant_new ("(sssss)",
485 printer_name,
486 device_uri,
487 ppd_name,
488 info ? info : "",
489 location ? location : ""),
490 G_DBUS_CALL_FLAGS_NONE,
491 DBUS_TIMEOUT,
492 NULL,
493 &error);
494
495 if (output) {
496 g_variant_unref (output);
497 } else {
498 g_warning ("%s", error->message);
499 g_error_free (error);
500 }
501
502 g_object_unref (proxy);
503
504 num_dests = cupsGetDests (&dests);
505 for (i = 0; i < num_dests; i++)
506 if (g_strcmp0 (dests[i].name, printer_name) == 0)
507 success = TRUE;
508 cupsFreeDests (num_dests, dests);
509
510 return success;
511 }
512
513 static gboolean
printer_set_enabled(const gchar * printer_name,gboolean enabled)514 printer_set_enabled (const gchar *printer_name,
515 gboolean enabled)
516 {
517 GDBusProxy *proxy;
518 gboolean result = TRUE;
519 GVariant *output;
520 GError *error = NULL;
521
522 if (!printer_name)
523 return FALSE;
524
525 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
526 G_DBUS_PROXY_FLAGS_NONE,
527 NULL,
528 MECHANISM_BUS,
529 "/",
530 MECHANISM_BUS,
531 NULL,
532 &error);
533
534 if (!proxy) {
535 g_warning ("%s", error->message);
536 g_error_free (error);
537 return FALSE;
538 }
539
540 output = g_dbus_proxy_call_sync (proxy,
541 "PrinterSetEnabled",
542 g_variant_new ("(sb)",
543 printer_name,
544 enabled),
545 G_DBUS_CALL_FLAGS_NONE,
546 DBUS_TIMEOUT,
547 NULL,
548 &error);
549
550 if (output) {
551 g_variant_unref (output);
552 } else {
553 g_warning ("%s", error->message);
554 g_error_free (error);
555 result = FALSE;
556 }
557
558 g_object_unref (proxy);
559
560 return result;
561 }
562
563 static gboolean
printer_set_accepting_jobs(const gchar * printer_name,gboolean accepting_jobs,const gchar * reason)564 printer_set_accepting_jobs (const gchar *printer_name,
565 gboolean accepting_jobs,
566 const gchar *reason)
567 {
568 GDBusProxy *proxy;
569 gboolean result = TRUE;
570 GVariant *output;
571 GError *error = NULL;
572
573 if (!printer_name)
574 return FALSE;
575
576 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
577 G_DBUS_PROXY_FLAGS_NONE,
578 NULL,
579 MECHANISM_BUS,
580 "/",
581 MECHANISM_BUS,
582 NULL,
583 &error);
584
585 if (!proxy) {
586 g_warning ("%s", error->message);
587 g_error_free (error);
588 return FALSE;
589 }
590
591 output = g_dbus_proxy_call_sync (proxy,
592 "PrinterSetAcceptJobs",
593 g_variant_new ("(sbs)",
594 printer_name,
595 accepting_jobs,
596 reason ? reason : ""),
597 G_DBUS_CALL_FLAGS_NONE,
598 DBUS_TIMEOUT,
599 NULL,
600 &error);
601
602 if (output) {
603 g_variant_unref (output);
604 } else {
605 g_warning ("%s", error->message);
606 g_error_free (error);
607 result = FALSE;
608 }
609
610 g_object_unref (proxy);
611
612 return result;
613 }
614
615 static ipp_t *
execute_maintenance_command(const char * printer_name,const char * command,const char * title)616 execute_maintenance_command (const char *printer_name,
617 const char *command,
618 const char *title)
619 {
620 http_t *http;
621 GError *error = NULL;
622 ipp_t *request = NULL;
623 ipp_t *response = NULL;
624 gchar *file_name = NULL;
625 char *uri;
626 int fd = -1;
627
628 http = httpConnectEncrypt (cupsServer (),
629 ippPort (),
630 cupsEncryption ());
631
632 if (!http)
633 return NULL;
634
635 request = ippNewRequest (IPP_PRINT_JOB);
636
637 uri = g_strdup_printf ("ipp://localhost/printers/%s",
638 printer_name);
639
640 ippAddString (request,
641 IPP_TAG_OPERATION,
642 IPP_TAG_URI,
643 "printer-uri",
644 NULL,
645 uri);
646
647 g_free (uri);
648
649 ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
650 NULL, title);
651
652 ippAddString (request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format",
653 NULL, "application/vnd.cups-command");
654
655 fd = g_file_open_tmp ("ccXXXXXX", &file_name, &error);
656
657 if (fd != -1) {
658 FILE *file;
659
660 file = fdopen (fd, "w");
661 fprintf (file, "#CUPS-COMMAND\n");
662 fprintf (file, "%s\n", command);
663 fclose (file);
664
665 response = cupsDoFileRequest (http, request, "/", file_name);
666 g_unlink (file_name);
667 } else {
668 g_warning ("%s", error->message);
669 g_error_free (error);
670 }
671
672 g_free (file_name);
673 httpClose (http);
674
675 return response;
676 }
677
678 static char *
get_dest_attr(const char * dest_name,const char * attr)679 get_dest_attr (const char *dest_name,
680 const char *attr)
681 {
682 cups_dest_t *dests;
683 int num_dests;
684 cups_dest_t *dest;
685 const char *value;
686 char *ret;
687
688 if (dest_name == NULL)
689 return NULL;
690
691 ret = NULL;
692
693 num_dests = cupsGetDests (&dests);
694 if (num_dests < 1) {
695 g_debug ("Unable to get printer destinations");
696 return NULL;
697 }
698
699 dest = cupsGetDest (dest_name, NULL, num_dests, dests);
700 if (dest == NULL) {
701 g_debug ("Unable to find a printer named '%s'", dest_name);
702 goto out;
703 }
704
705 value = cupsGetOption (attr, dest->num_options, dest->options);
706 if (value == NULL) {
707 g_debug ("Unable to get %s for '%s'", attr, dest_name);
708 goto out;
709 }
710 ret = g_strdup (value);
711 out:
712 cupsFreeDests (num_dests, dests);
713
714 return ret;
715 }
716
717 static void
printer_autoconfigure(gchar * printer_name)718 printer_autoconfigure (gchar *printer_name)
719 {
720 gchar *commands;
721 gchar *commands_lowercase;
722 ipp_t *response = NULL;
723
724 if (!printer_name)
725 return;
726
727 commands = get_dest_attr (printer_name, "printer-commands");
728 commands_lowercase = g_ascii_strdown (commands, -1);
729
730 if (g_strrstr (commands_lowercase, "autoconfigure")) {
731 response = execute_maintenance_command (printer_name,
732 "AutoConfigure",
733 ("Automatic configuration"));
734 if (response) {
735 if (ippGetState (response) == IPP_ERROR)
736 g_warning ("An error has occured during automatic configuration of new printer.");
737 ippDelete (response);
738 }
739 }
740 g_free (commands);
741 g_free (commands_lowercase);
742 }
743
744 /* Returns default page size for current locale */
745 static const gchar *
get_page_size_from_locale(void)746 get_page_size_from_locale (void)
747 {
748 if (g_str_equal (gtk_paper_size_get_default (), GTK_PAPER_NAME_LETTER))
749 return "Letter";
750 else
751 return "A4";
752 }
753
754 static void
set_default_paper_size(const gchar * printer_name,const gchar * ppd_file_name)755 set_default_paper_size (const gchar *printer_name,
756 const gchar *ppd_file_name)
757 {
758 GDBusProxy *proxy;
759 GVariant *output;
760 GError *error = NULL;
761 GVariantBuilder *builder;
762
763 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
764 G_DBUS_PROXY_FLAGS_NONE,
765 NULL,
766 MECHANISM_BUS,
767 "/",
768 MECHANISM_BUS,
769 NULL,
770 &error);
771
772 if (!proxy) {
773 g_warning ("%s", error->message);
774 g_error_free (error);
775 return;
776 }
777
778 /* Set default media size according to the locale
779 * FIXME: Handle more than A4 and Letter:
780 * https://bugzilla.gnome.org/show_bug.cgi?id=660769 */
781 builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
782 g_variant_builder_add (builder, "s", get_page_size_from_locale ());
783
784 output = g_dbus_proxy_call_sync (proxy,
785 "PrinterAddOption",
786 g_variant_new ("(ssas)",
787 printer_name ? printer_name : "",
788 "PageSize",
789 builder),
790 G_DBUS_CALL_FLAGS_NONE,
791 DBUS_TIMEOUT,
792 NULL,
793 &error);
794
795 if (output) {
796 g_variant_unref (output);
797 } else {
798 if (!(error->domain == G_DBUS_ERROR &&
799 (error->code == G_DBUS_ERROR_SERVICE_UNKNOWN ||
800 error->code == G_DBUS_ERROR_UNKNOWN_METHOD)))
801 g_warning ("%s", error->message);
802 g_error_free (error);
803 }
804
805 g_object_unref (proxy);
806 }
807
808 /*
809 * Setup new printer and returns TRUE if successful.
810 */
811 static gboolean
setup_printer(gchar * device_id,gchar * device_make_and_model,gchar * device_uri)812 setup_printer (gchar *device_id,
813 gchar *device_make_and_model,
814 gchar *device_uri)
815 {
816 gboolean success = FALSE;
817 gchar *ppd_name;
818 gchar *printer_name;
819
820 ppd_name = get_best_ppd (device_id, device_make_and_model, device_uri);
821 printer_name = create_name (device_id);
822
823 if (!ppd_name || !printer_name || !device_uri) {
824 g_free (ppd_name);
825 g_free (printer_name);
826 return FALSE;
827 }
828
829 success = add_printer (printer_name, device_uri,
830 ppd_name, NULL, NULL);
831
832 /* Set some options of the new printer */
833 if (success) {
834 const char *ppd_file_name;
835
836 printer_set_accepting_jobs (printer_name, TRUE, NULL);
837 printer_set_enabled (printer_name, TRUE);
838 printer_autoconfigure (printer_name);
839
840 ppd_file_name = cupsGetPPD (printer_name);
841
842 if (ppd_file_name) {
843 GHashTable *executables;
844 GHashTable *packages;
845
846 set_default_paper_size (printer_name, ppd_file_name);
847
848 executables = get_missing_executables (ppd_file_name);
849 packages = find_packages_for_executables (executables);
850 install_packages (packages);
851
852 if (executables)
853 g_hash_table_destroy (executables);
854 if (packages)
855 g_hash_table_destroy (packages);
856 g_unlink (ppd_file_name);
857 }
858 }
859
860 g_free (printer_name);
861 g_free (ppd_name);
862
863 return success;
864 }
865
866 static void
handle_method_call(GDBusConnection * connection,const gchar * sender,const gchar * object_path,const gchar * interface_name,const gchar * method_name,GVariant * parameters,GDBusMethodInvocation * invocation,gpointer user_data)867 handle_method_call (GDBusConnection *connection,
868 const gchar *sender,
869 const gchar *object_path,
870 const gchar *interface_name,
871 const gchar *method_name,
872 GVariant *parameters,
873 GDBusMethodInvocation *invocation,
874 gpointer user_data)
875 {
876 gchar *primary_text = NULL;
877 gchar *secondary_text = NULL;
878 gchar *name = NULL;
879 gchar *mfg = NULL;
880 gchar *mdl = NULL;
881 gchar *des = NULL;
882 gchar *cmd = NULL;
883 gchar *device = NULL;
884 gchar *device_id;
885 gchar *make_and_model;
886 gint status = 0;
887
888 if (g_strcmp0 (method_name, "GetReady") == 0) {
889 /* Translators: We are configuring new printer */
890 primary_text = g_strdup (_("Configuring new printer"));
891 /* Translators: Just wait */
892 secondary_text = g_strdup (_("Please wait…"));
893
894 g_dbus_method_invocation_return_value (invocation,
895 NULL);
896 }
897 else if (g_strcmp0 (method_name, "NewPrinter") == 0) {
898 if (g_variant_n_children (parameters) == 6) {
899 g_variant_get (parameters, "(i&s&s&s&s&s)",
900 &status,
901 &name,
902 &mfg,
903 &mdl,
904 &des,
905 &cmd);
906 }
907
908 if (g_strrstr (name, "/")) {
909 /* name is a URI, no queue was generated, because no suitable
910 * driver was found
911 */
912
913 device_id = g_strdup_printf ("MFG:%s;MDL:%s;DES:%s;CMD:%s;", mfg, mdl, des, cmd);
914 make_and_model = g_strdup_printf ("%s %s", mfg, mdl);
915
916 if (!setup_printer (device_id, make_and_model, name)) {
917
918 /* Translators: We have no driver installed for this printer */
919 primary_text = g_strdup (_("Missing printer driver"));
920
921 if ((mfg && mdl) || des) {
922 if (mfg && mdl)
923 device = g_strdup_printf ("%s %s", mfg, mdl);
924 else
925 device = g_strdup (des);
926
927 /* Translators: We have no driver installed for the device */
928 secondary_text = g_strdup_printf (_("No printer driver for %s."), device);
929 g_free (device);
930 }
931 else
932 /* Translators: We have no driver installed for this printer */
933 secondary_text = g_strdup (_("No driver for this printer."));
934 }
935
936 g_free (make_and_model);
937 g_free (device_id);
938 }
939 else {
940 /* name is the name of the queue which hal_lpadmin has set up
941 * automatically.
942 */
943
944 const char *ppd_file_name;
945
946 ppd_file_name = cupsGetPPD (name);
947 if (ppd_file_name) {
948 GHashTable *executables;
949 GHashTable *packages;
950
951 executables = get_missing_executables (ppd_file_name);
952 packages = find_packages_for_executables (executables);
953 install_packages (packages);
954
955 if (executables)
956 g_hash_table_destroy (executables);
957 if (packages)
958 g_hash_table_destroy (packages);
959 g_unlink (ppd_file_name);
960 }
961 }
962
963 g_dbus_method_invocation_return_value (invocation,
964 NULL);
965 }
966 else if (g_strcmp0 (method_name, "InstallDrivers") == 0) {
967 GDBusProxy *proxy;
968 GError *error = NULL;
969
970 if (g_variant_n_children (parameters) == 3) {
971 g_variant_get (parameters, "(&s&s&s)",
972 &mfg,
973 &mdl,
974 &cmd);
975 }
976
977 if (mfg && mdl)
978 device = g_strdup_printf ("MFG:%s;MDL:%s;", mfg, mdl);
979
980 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
981 G_DBUS_PROXY_FLAGS_NONE,
982 NULL,
983 PACKAGE_KIT_BUS,
984 PACKAGE_KIT_PATH,
985 PACKAGE_KIT_MODIFY_IFACE,
986 NULL,
987 &error);
988
989 if (!proxy) {
990 g_warning ("%s", error->message);
991 g_error_free (error);
992 }
993
994 if (proxy && device) {
995 GVariantBuilder *builder;
996 GVariant *output;
997
998 builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
999 g_variant_builder_add (builder, "s", device);
1000
1001 output = g_dbus_proxy_call_sync (proxy,
1002 "InstallPrinterDrivers",
1003 g_variant_new ("(uass)",
1004 0,
1005 builder,
1006 "hide-finished"),
1007 G_DBUS_CALL_FLAGS_NONE,
1008 DBUS_INSTALL_TIMEOUT,
1009 NULL,
1010 &error);
1011
1012 if (output) {
1013 g_variant_unref (output);
1014 } else {
1015 g_warning ("%s", error->message);
1016 g_error_free (error);
1017 }
1018
1019 g_object_unref (proxy);
1020 }
1021
1022 g_dbus_method_invocation_return_value (invocation,
1023 NULL);
1024 }
1025
1026 if (primary_text) {
1027 NotifyNotification *notification;
1028 notification = notify_notification_new (primary_text,
1029 secondary_text,
1030 "printer-symbolic");
1031 notify_notification_set_app_name (notification, _("Printers"));
1032 notify_notification_set_hint_string (notification, "desktop-entry", "gnome-printers-panel");
1033 notify_notification_set_hint (notification, "transient", g_variant_new_boolean (TRUE));
1034
1035 notify_notification_show (notification, NULL);
1036 g_object_unref (notification);
1037 g_free (primary_text);
1038 g_free (secondary_text);
1039 }
1040 }
1041
1042 static const GDBusInterfaceVTable interface_vtable =
1043 {
1044 handle_method_call,
1045 NULL,
1046 NULL
1047 };
1048
1049 static void
unregister_objects()1050 unregister_objects ()
1051 {
1052 GDBusConnection *system_connection;
1053 GError *error = NULL;
1054
1055 system_connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
1056
1057 if (npn_registration_id > 0) {
1058 g_dbus_connection_unregister_object (system_connection, npn_registration_id);
1059 npn_registration_id = 0;
1060 }
1061
1062 if (pdi_registration_id > 0) {
1063 g_dbus_connection_unregister_object (system_connection, pdi_registration_id);
1064 pdi_registration_id = 0;
1065 }
1066 }
1067
1068 static void
unown_names()1069 unown_names ()
1070 {
1071 if (npn_owner_id > 0) {
1072 g_bus_unown_name (npn_owner_id);
1073 npn_owner_id = 0;
1074 }
1075
1076 if (pdi_owner_id > 0) {
1077 g_bus_unown_name (pdi_owner_id);
1078 pdi_owner_id = 0;
1079 }
1080 }
1081
1082 static void
on_npn_bus_acquired(GDBusConnection * connection,const gchar * name,gpointer user_data)1083 on_npn_bus_acquired (GDBusConnection *connection,
1084 const gchar *name,
1085 gpointer user_data)
1086 {
1087 GError *error = NULL;
1088
1089 npn_registration_id = g_dbus_connection_register_object (connection,
1090 SCP_DBUS_NPN_PATH,
1091 npn_introspection_data->interfaces[0],
1092 &interface_vtable,
1093 NULL,
1094 NULL,
1095 &error);
1096
1097 if (npn_registration_id == 0) {
1098 g_warning ("Failed to register object: %s\n", error->message);
1099 g_error_free (error);
1100 }
1101 }
1102
1103 static void
on_pdi_bus_acquired(GDBusConnection * connection,const gchar * name,gpointer user_data)1104 on_pdi_bus_acquired (GDBusConnection *connection,
1105 const gchar *name,
1106 gpointer user_data)
1107 {
1108 GError *error = NULL;
1109
1110 pdi_registration_id = g_dbus_connection_register_object (connection,
1111 SCP_DBUS_PDI_PATH,
1112 pdi_introspection_data->interfaces[0],
1113 &interface_vtable,
1114 NULL,
1115 NULL,
1116 &error);
1117
1118 if (pdi_registration_id == 0) {
1119 g_warning ("Failed to register object: %s\n", error->message);
1120 g_error_free (error);
1121 }
1122 }
1123
1124 static void
on_name_acquired(GDBusConnection * connection,const gchar * name,gpointer user_data)1125 on_name_acquired (GDBusConnection *connection,
1126 const gchar *name,
1127 gpointer user_data)
1128 {
1129 }
1130
1131 static void
on_name_lost(GDBusConnection * connection,const gchar * name,gpointer user_data)1132 on_name_lost (GDBusConnection *connection,
1133 const gchar *name,
1134 gpointer user_data)
1135 {
1136 unregister_objects ();
1137 }
1138
1139 static void
session_signal_handler(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)1140 session_signal_handler (GDBusConnection *connection,
1141 const gchar *sender_name,
1142 const gchar *object_path,
1143 const gchar *interface_name,
1144 const gchar *signal_name,
1145 GVariant *parameters,
1146 gpointer user_data)
1147 {
1148 guint new_status;
1149
1150 g_variant_get (parameters, "(u)", &new_status);
1151
1152 if (new_status == PRESENCE_STATUS_IDLE ||
1153 new_status == PRESENCE_STATUS_AVAILABLE) {
1154 unregister_objects ();
1155 unown_names ();
1156
1157 if (new_status == PRESENCE_STATUS_AVAILABLE) {
1158 npn_owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
1159 SCP_DBUS_NPN_NAME,
1160 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
1161 G_BUS_NAME_OWNER_FLAGS_REPLACE,
1162 on_npn_bus_acquired,
1163 on_name_acquired,
1164 on_name_lost,
1165 NULL,
1166 NULL);
1167
1168 pdi_owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
1169 SCP_DBUS_PDI_NAME,
1170 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
1171 G_BUS_NAME_OWNER_FLAGS_REPLACE,
1172 on_pdi_bus_acquired,
1173 on_name_acquired,
1174 on_name_lost,
1175 NULL,
1176 NULL);
1177 }
1178 }
1179 }
1180
1181 static void
client_signal_handler(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)1182 client_signal_handler (GDBusConnection *connection,
1183 const gchar *sender_name,
1184 const gchar *object_path,
1185 const gchar *interface_name,
1186 const gchar *signal_name,
1187 GVariant *parameters,
1188 gpointer user_data)
1189 {
1190 GDBusProxy *proxy;
1191 GError *error = NULL;
1192 GVariant *output;
1193
1194 if (g_strcmp0 (signal_name, "QueryEndSession") == 0 ||
1195 g_strcmp0 (signal_name, "EndSession") == 0) {
1196 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
1197 G_DBUS_PROXY_FLAGS_NONE,
1198 NULL,
1199 sender_name,
1200 object_path,
1201 interface_name,
1202 NULL,
1203 &error);
1204
1205 if (proxy) {
1206 output = g_dbus_proxy_call_sync (proxy,
1207 "EndSessionResponse",
1208 g_variant_new ("(bs)", TRUE, ""),
1209 G_DBUS_CALL_FLAGS_NONE,
1210 -1,
1211 NULL,
1212 &error);
1213
1214 if (output) {
1215 g_variant_unref (output);
1216 }
1217 else {
1218 g_warning ("%s", error->message);
1219 g_error_free (error);
1220 }
1221
1222 g_object_unref (proxy);
1223 }
1224 else {
1225 g_warning ("%s", error->message);
1226 g_error_free (error);
1227 }
1228
1229 if (g_strcmp0 (signal_name, "EndSession") == 0) {
1230 g_main_loop_quit (main_loop);
1231 g_debug ("Exiting gsd-printer");
1232 }
1233 }
1234 }
1235
1236 static gchar *
register_gnome_session_client(const gchar * app_id,const gchar * client_startup_id)1237 register_gnome_session_client (const gchar *app_id,
1238 const gchar *client_startup_id)
1239 {
1240 GDBusProxy *proxy;
1241 GVariant *output = NULL;
1242 GError *error = NULL;
1243 const gchar *client_id = NULL;
1244 gchar *result = NULL;
1245
1246 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
1247 G_DBUS_PROXY_FLAGS_NONE,
1248 NULL,
1249 GNOME_SESSION_DBUS_NAME,
1250 GNOME_SESSION_DBUS_PATH,
1251 GNOME_SESSION_DBUS_IFACE,
1252 NULL,
1253 &error);
1254
1255 if (proxy) {
1256 output = g_dbus_proxy_call_sync (proxy,
1257 "RegisterClient",
1258 g_variant_new ("(ss)", app_id, client_startup_id),
1259 G_DBUS_CALL_FLAGS_NONE,
1260 -1,
1261 NULL,
1262 &error);
1263
1264 if (output) {
1265 g_variant_get (output, "(o)", &client_id);
1266 if (client_id)
1267 result = g_strdup (client_id);
1268 g_variant_unref (output);
1269 }
1270 else {
1271 g_warning ("%s", error->message);
1272 g_error_free (error);
1273 }
1274
1275 g_object_unref (proxy);
1276 }
1277 else {
1278 g_warning ("%s", error->message);
1279 g_error_free (error);
1280 }
1281
1282 return result;
1283 }
1284
1285 int
main(int argc,char * argv[])1286 main (int argc, char *argv[])
1287 {
1288 GDBusConnection *connection;
1289 gboolean client_signal_subscription_set = FALSE;
1290 GError *error = NULL;
1291 guint client_signal_subscription_id;
1292 guint session_signal_subscription_id;
1293 gchar *object_path;
1294
1295 bindtextdomain (GETTEXT_PACKAGE, GNOME_SETTINGS_LOCALEDIR);
1296 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1297 textdomain (GETTEXT_PACKAGE);
1298 setlocale (LC_ALL, "");
1299
1300 npn_registration_id = 0;
1301 pdi_registration_id = 0;
1302 npn_owner_id = 0;
1303 pdi_owner_id = 0;
1304
1305 notify_init ("gnome-settings-daemon-printer");
1306
1307 npn_introspection_data =
1308 g_dbus_node_info_new_for_xml (npn_introspection_xml, &error);
1309
1310 if (npn_introspection_data == NULL) {
1311 g_warning ("Error parsing introspection XML: %s\n", error->message);
1312 g_error_free (error);
1313 goto error;
1314 }
1315
1316 pdi_introspection_data =
1317 g_dbus_node_info_new_for_xml (pdi_introspection_xml, &error);
1318
1319 if (pdi_introspection_data == NULL) {
1320 g_warning ("Error parsing introspection XML: %s\n", error->message);
1321 g_error_free (error);
1322 goto error;
1323 }
1324
1325 connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
1326
1327 session_signal_subscription_id =
1328 g_dbus_connection_signal_subscribe (connection,
1329 NULL,
1330 GNOME_SESSION_PRESENCE_DBUS_IFACE,
1331 "StatusChanged",
1332 GNOME_SESSION_PRESENCE_DBUS_PATH,
1333 NULL,
1334 G_DBUS_SIGNAL_FLAGS_NONE,
1335 session_signal_handler,
1336 NULL,
1337 NULL);
1338
1339 object_path = register_gnome_session_client ("gsd-printer", "");
1340 if (object_path) {
1341 client_signal_subscription_id =
1342 g_dbus_connection_signal_subscribe (connection,
1343 NULL,
1344 GNOME_SESSION_CLIENT_PRIVATE_DBUS_IFACE,
1345 NULL,
1346 object_path,
1347 NULL,
1348 G_DBUS_SIGNAL_FLAGS_NONE,
1349 client_signal_handler,
1350 NULL,
1351 NULL);
1352 client_signal_subscription_set = TRUE;
1353 }
1354
1355 if (npn_owner_id == 0)
1356 npn_owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
1357 SCP_DBUS_NPN_NAME,
1358 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
1359 G_BUS_NAME_OWNER_FLAGS_REPLACE,
1360 on_npn_bus_acquired,
1361 on_name_acquired,
1362 on_name_lost,
1363 NULL,
1364 NULL);
1365
1366 if (pdi_owner_id == 0)
1367 pdi_owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
1368 SCP_DBUS_PDI_NAME,
1369 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
1370 G_BUS_NAME_OWNER_FLAGS_REPLACE,
1371 on_pdi_bus_acquired,
1372 on_name_acquired,
1373 on_name_lost,
1374 NULL,
1375 NULL);
1376
1377 main_loop = g_main_loop_new (NULL, FALSE);
1378 g_main_loop_run (main_loop);
1379
1380 unregister_objects ();
1381 unown_names ();
1382
1383 if (client_signal_subscription_set)
1384 g_dbus_connection_signal_unsubscribe (connection, client_signal_subscription_id);
1385 g_dbus_connection_signal_unsubscribe (connection, session_signal_subscription_id);
1386
1387 g_free (object_path);
1388
1389 g_dbus_node_info_unref (npn_introspection_data);
1390 g_dbus_node_info_unref (pdi_introspection_data);
1391
1392 return 0;
1393
1394 error:
1395
1396 if (npn_introspection_data)
1397 g_dbus_node_info_unref (npn_introspection_data);
1398
1399 if (pdi_introspection_data)
1400 g_dbus_node_info_unref (pdi_introspection_data);
1401
1402 return 1;
1403 }
1404