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