GCC Code Coverage Report


Directory: ./
File: panels/printers/pp-utils.c
Date: 2024-05-04 07:58:27
Exec Total Coverage
Lines: 5 1520 0.3%
Functions: 1 97 1.0%
Branches: 2 1024 0.2%

Line Branch Exec Source
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright 2009-2010 Red Hat, Inc,
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20 #include "config.h"
21
22 #include <glib.h>
23 #include <glib/gi18n.h>
24 #include <glib/gstdio.h>
25 #include <gtk/gtk.h>
26 #include <cups/cups.h>
27 #include <cups/ppd.h>
28
29 #include "pp-utils.h"
30
31 #define DBUS_TIMEOUT 120000
32 #define DBUS_TIMEOUT_LONG 600000
33
34 #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
35 #define HAVE_CUPS_1_6 1
36 #endif
37
38 #ifndef HAVE_CUPS_1_6
39 #define ippGetCount(attr) attr->num_values
40 #define ippGetGroupTag(attr) attr->group_tag
41 #define ippGetValueTag(attr) attr->value_tag
42 #define ippGetName(attr) attr->name
43 #define ippGetStatusCode(ipp) ipp->request.status.status_code
44 #define ippGetInteger(attr, element) attr->values[element].integer
45 #define ippGetString(attr, element, language) attr->values[element].string.text
46 #define ippGetBoolean(attr, element) attr->values[element].boolean
47
48 static int
49 ippGetRange (ipp_attribute_t *attr,
50 int element,
51 int *upper)
52 {
53 *upper = attr->values[element].range.upper;
54 return (attr->values[element].range.lower);
55 }
56
57 static ipp_attribute_t *
58 ippFirstAttribute (ipp_t *ipp)
59 {
60 if (!ipp)
61 return (NULL);
62 return (ipp->current = ipp->attrs);
63 }
64
65 static ipp_attribute_t *
66 ippNextAttribute (ipp_t *ipp)
67 {
68 if (!ipp || !ipp->current)
69 return (NULL);
70 return (ipp->current = ipp->current->next);
71 }
72 #endif
73
74 #if (CUPS_VERSION_MAJOR == 1) && (CUPS_VERSION_MINOR <= 6)
75 #define HTTP_URI_STATUS_OK HTTP_URI_OK
76 #endif
77
78 gchar *
79 get_tag_value (const gchar *tag_string, const gchar *tag_name)
80 {
81 gchar **tag_string_splitted = NULL;
82 gchar *tag_value = NULL;
83 gint tag_name_length;
84 gint i;
85
86 if (tag_string && tag_name)
87 {
88 tag_name_length = strlen (tag_name);
89 tag_string_splitted = g_strsplit (tag_string, ";", 0);
90 if (tag_string_splitted)
91 {
92 for (i = 0; i < g_strv_length (tag_string_splitted); i++)
93 if (g_ascii_strncasecmp (tag_string_splitted[i], tag_name, tag_name_length) == 0)
94 if (strlen (tag_string_splitted[i]) > tag_name_length + 1)
95 tag_value = g_strdup (tag_string_splitted[i] + tag_name_length + 1);
96
97 g_strfreev (tag_string_splitted);
98 }
99 }
100
101 return tag_value;
102 }
103
104
105 /*
106 * Normalize given string so that it is lowercase, doesn't
107 * have trailing or leading whitespaces and digits doesn't
108 * neighbour with alphabetic.
109 * (see cupshelpers/ppds.py from system-config-printer)
110 */
111 static gchar *
112 normalize (const gchar *input_string)
113 {
114 gchar *result = NULL;
115 gint i, j = 0, k = -1;
116
117 if (input_string)
118 {
119 g_autofree gchar *tmp = g_strstrip (g_ascii_strdown (input_string, -1));
120 if (tmp)
121 {
122 g_autofree gchar *res = g_new (gchar, 2 * strlen (tmp) + 1);
123
124 for (i = 0; i < strlen (tmp); i++)
125 {
126 if ((g_ascii_isalpha (tmp[i]) && k >= 0 && g_ascii_isdigit (res[k])) ||
127 (g_ascii_isdigit (tmp[i]) && k >= 0 && g_ascii_isalpha (res[k])))
128 {
129 res[j] = ' ';
130 k = j++;
131 res[j] = tmp[i];
132 k = j++;
133 }
134 else
135 {
136 if (g_ascii_isspace (tmp[i]) || !g_ascii_isalnum (tmp[i]))
137 {
138 if (!(k >= 0 && res[k] == ' '))
139 {
140 res[j] = ' ';
141 k = j++;
142 }
143 }
144 else
145 {
146 res[j] = tmp[i];
147 k = j++;
148 }
149 }
150 }
151
152 res[j] = '\0';
153
154 result = g_strdup (res);
155 }
156 }
157
158 return result;
159 }
160
161
162 char *
163 get_dest_attr (const char *dest_name,
164 const char *attr)
165 {
166 cups_dest_t *dests;
167 int num_dests;
168 cups_dest_t *dest;
169 const char *value;
170 char *ret;
171
172 if (dest_name == NULL)
173 return NULL;
174
175 ret = NULL;
176
177 num_dests = cupsGetDests (&dests);
178 if (num_dests < 1) {
179 g_debug ("Unable to get printer destinations");
180 return NULL;
181 }
182
183 dest = cupsGetDest (dest_name, NULL, num_dests, dests);
184 if (dest == NULL) {
185 g_debug ("Unable to find a printer named '%s'", dest_name);
186 goto out;
187 }
188
189 value = cupsGetOption (attr, dest->num_options, dest->options);
190 if (value == NULL) {
191 g_debug ("Unable to get %s for '%s'", attr, dest_name);
192 goto out;
193 }
194 ret = g_strdup (value);
195 out:
196 cupsFreeDests (num_dests, dests);
197
198 return ret;
199 }
200
201 gchar *
202 get_ppd_attribute (const gchar *ppd_file_name,
203 const gchar *attribute_name)
204 {
205 ppd_file_t *ppd_file = NULL;
206 ppd_attr_t *ppd_attr = NULL;
207 gchar *result = NULL;
208
209 if (ppd_file_name)
210 {
211 ppd_file = ppdOpenFile (ppd_file_name);
212
213 if (ppd_file)
214 {
215 ppd_attr = ppdFindAttr (ppd_file, attribute_name, NULL);
216 if (ppd_attr != NULL)
217 result = g_strdup (ppd_attr->value);
218 ppdClose (ppd_file);
219 }
220 }
221
222 return result;
223 }
224
225 /* Set default destination in ~/.cups/lpoptions.
226 * Unset default destination if "dest" is NULL.
227 */
228 void
229 set_local_default_printer (const gchar *printer_name)
230 {
231 cups_dest_t *dests = NULL;
232 int num_dests = 0;
233 int i;
234
235 num_dests = cupsGetDests (&dests);
236
237 for (i = 0; i < num_dests; i ++)
238 {
239 if (printer_name && g_strcmp0 (dests[i].name, printer_name) == 0)
240 dests[i].is_default = 1;
241 else
242 dests[i].is_default = 0;
243 }
244
245 cupsSetDests (num_dests, dests);
246 }
247
248 /*
249 * This function does something which should be provided by CUPS...
250 * It returns FALSE if the renaming fails.
251 */
252 gboolean
253 printer_rename (const gchar *old_name,
254 const gchar *new_name)
255 {
256 ipp_attribute_t *attr = NULL;
257 cups_ptype_t printer_type = 0;
258 cups_dest_t *dests = NULL;
259 cups_dest_t *dest = NULL;
260 cups_job_t *jobs = NULL;
261 g_autoptr(GDBusConnection) bus = NULL;
262 const gchar *printer_location = NULL;
263 const gchar *printer_info = NULL;
264 const gchar *printer_uri = NULL;
265 const gchar *device_uri = NULL;
266 const gchar *job_sheets = NULL;
267 gboolean result = FALSE;
268 gboolean accepting = TRUE;
269 gboolean printer_paused = FALSE;
270 gboolean default_printer = FALSE;
271 gboolean printer_shared = FALSE;
272 g_autoptr(GError) error = NULL;
273 http_t *http;
274 g_autofree gchar *ppd_link = NULL;
275 g_autofree gchar *ppd_filename = NULL;
276 gchar **sheets = NULL;
277 gchar **users_allowed = NULL;
278 gchar **users_denied = NULL;
279 gchar **member_names = NULL;
280 const gchar *start_sheet = NULL;
281 const gchar *end_sheet = NULL;
282 g_autofree gchar *error_policy = NULL;
283 g_autofree gchar *op_policy = NULL;
284 ipp_t *request;
285 ipp_t *response;
286 gint i;
287 int num_dests = 0;
288 int num_jobs = 0;
289 static const char * const requested_attrs[] = {
290 "printer-error-policy",
291 "printer-op-policy",
292 "requesting-user-name-allowed",
293 "requesting-user-name-denied",
294 "member-names"};
295
296 if (old_name == NULL ||
297 old_name[0] == '\0' ||
298 new_name == NULL ||
299 new_name[0] == '\0' ||
300 g_strcmp0 (old_name, new_name) == 0)
301 return FALSE;
302
303 num_dests = cupsGetDests (&dests);
304
305 dest = cupsGetDest (new_name, NULL, num_dests, dests);
306 if (dest)
307 {
308 cupsFreeDests (num_dests, dests);
309 return FALSE;
310 }
311
312 num_jobs = cupsGetJobs (&jobs, old_name, 0, CUPS_WHICHJOBS_ACTIVE);
313 cupsFreeJobs (num_jobs, jobs);
314 if (num_jobs > 1)
315 {
316 g_warning ("There are queued jobs on printer %s!", old_name);
317 cupsFreeDests (num_dests, dests);
318 return FALSE;
319 }
320
321 /*
322 * Gather some informations about the original printer
323 */
324 dest = cupsGetDest (old_name, NULL, num_dests, dests);
325 if (dest)
326 {
327 for (i = 0; i < dest->num_options; i++)
328 {
329 if (g_strcmp0 (dest->options[i].name, "printer-is-accepting-jobs") == 0)
330 accepting = g_strcmp0 (dest->options[i].value, "true") == 0;
331 else if (g_strcmp0 (dest->options[i].name, "printer-is-shared") == 0)
332 printer_shared = g_strcmp0 (dest->options[i].value, "true") == 0;
333 else if (g_strcmp0 (dest->options[i].name, "device-uri") == 0)
334 device_uri = dest->options[i].value;
335 else if (g_strcmp0 (dest->options[i].name, "printer-uri-supported") == 0)
336 printer_uri = dest->options[i].value;
337 else if (g_strcmp0 (dest->options[i].name, "printer-info") == 0)
338 printer_info = dest->options[i].value;
339 else if (g_strcmp0 (dest->options[i].name, "printer-location") == 0)
340 printer_location = dest->options[i].value;
341 else if (g_strcmp0 (dest->options[i].name, "printer-state") == 0)
342 printer_paused = g_strcmp0 (dest->options[i].value, "5") == 0;
343 else if (g_strcmp0 (dest->options[i].name, "job-sheets") == 0)
344 job_sheets = dest->options[i].value;
345 else if (g_strcmp0 (dest->options[i].name, "printer-type") == 0)
346 printer_type = atoi (dest->options[i].value);
347 }
348 default_printer = dest->is_default;
349 }
350 cupsFreeDests (num_dests, dests);
351
352 if (accepting)
353 {
354 printer_set_accepting_jobs (old_name, FALSE, NULL);
355
356 num_jobs = cupsGetJobs (&jobs, old_name, 0, CUPS_WHICHJOBS_ACTIVE);
357 cupsFreeJobs (num_jobs, jobs);
358 if (num_jobs > 1)
359 {
360 printer_set_accepting_jobs (old_name, accepting, NULL);
361 g_warning ("There are queued jobs on printer %s!", old_name);
362 return FALSE;
363 }
364 }
365
366
367 /*
368 * Gather additional informations about the original printer
369 */
370 #ifdef HAVE_CUPS_HTTPCONNECT2
371 http = httpConnect2 (cupsServer (), ippPort (), NULL, AF_UNSPEC,
372 cupsEncryption (), 1, 30000, NULL);
373 #else
374 http = httpConnectEncrypt (cupsServer (), ippPort (), cupsEncryption ());
375 #endif
376 if (http != NULL)
377 {
378 request = ippNewRequest (IPP_GET_PRINTER_ATTRIBUTES);
379 ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
380 "printer-uri", NULL, printer_uri);
381 ippAddStrings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
382 "requested-attributes", G_N_ELEMENTS (requested_attrs), NULL, requested_attrs);
383 response = cupsDoRequest (http, request, "/");
384
385 if (response)
386 {
387 if (ippGetStatusCode (response) <= IPP_OK_CONFLICT)
388 {
389 attr = ippFindAttribute (response, "printer-error-policy", IPP_TAG_NAME);
390 if (attr)
391 error_policy = g_strdup (ippGetString (attr, 0, NULL));
392
393 attr = ippFindAttribute (response, "printer-op-policy", IPP_TAG_NAME);
394 if (attr)
395 op_policy = g_strdup (ippGetString (attr, 0, NULL));
396
397 attr = ippFindAttribute (response, "requesting-user-name-allowed", IPP_TAG_NAME);
398 if (attr && ippGetCount (attr) > 0)
399 {
400 users_allowed = g_new0 (gchar *, ippGetCount (attr) + 1);
401 for (i = 0; i < ippGetCount (attr); i++)
402 users_allowed[i] = g_strdup (ippGetString (attr, i, NULL));
403 }
404
405 attr = ippFindAttribute (response, "requesting-user-name-denied", IPP_TAG_NAME);
406 if (attr && ippGetCount (attr) > 0)
407 {
408 users_denied = g_new0 (gchar *, ippGetCount (attr) + 1);
409 for (i = 0; i < ippGetCount (attr); i++)
410 users_denied[i] = g_strdup (ippGetString (attr, i, NULL));
411 }
412
413 attr = ippFindAttribute (response, "member-names", IPP_TAG_NAME);
414 if (attr && ippGetCount (attr) > 0)
415 {
416 member_names = g_new0 (gchar *, ippGetCount (attr) + 1);
417 for (i = 0; i < ippGetCount (attr); i++)
418 member_names[i] = g_strdup (ippGetString (attr, i, NULL));
419 }
420 }
421 ippDelete (response);
422 }
423 httpClose (http);
424 }
425
426 if (job_sheets)
427 {
428 sheets = g_strsplit (job_sheets, ",", 0);
429 if (g_strv_length (sheets) > 1)
430 {
431 start_sheet = sheets[0];
432 end_sheet = sheets[1];
433 }
434 }
435
436 ppd_link = g_strdup (cupsGetPPD (old_name));
437 if (ppd_link)
438 {
439 ppd_filename = g_file_read_link (ppd_link, NULL);
440
441 if (!ppd_filename)
442 ppd_filename = g_strdup (ppd_link);
443 }
444
445
446 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
447 if (!bus)
448 {
449 g_warning ("Failed to get system bus: %s", error->message);
450 }
451 else
452 {
453 if (printer_type & CUPS_PRINTER_CLASS)
454 {
455 if (member_names)
456 for (i = 0; i < g_strv_length (member_names); i++)
457 class_add_printer (new_name, member_names[i]);
458 }
459 else
460 {
461 g_autoptr(GVariant) output = NULL;
462 g_autoptr(GError) add_error = NULL;
463
464 output = g_dbus_connection_call_sync (bus,
465 MECHANISM_BUS,
466 "/",
467 MECHANISM_BUS,
468 "PrinterAddWithPpdFile",
469 g_variant_new ("(sssss)",
470 new_name,
471 device_uri ? device_uri : "",
472 ppd_filename ? ppd_filename : "",
473 printer_info ? printer_info : "",
474 printer_location ? printer_location : ""),
475 G_VARIANT_TYPE ("(s)"),
476 G_DBUS_CALL_FLAGS_NONE,
477 -1,
478 NULL,
479 &add_error);
480
481 if (output)
482 {
483 const gchar *ret_error;
484
485 g_variant_get (output, "(&s)", &ret_error);
486 if (ret_error[0] != '\0')
487 g_warning ("cups-pk-helper: rename of printer %s to %s failed: %s", old_name, new_name, ret_error);
488 }
489 else
490 {
491 g_warning ("%s", add_error->message);
492 }
493 }
494 }
495
496 if (ppd_link)
497 {
498 g_unlink (ppd_link);
499 }
500
501 num_dests = cupsGetDests (&dests);
502 dest = cupsGetDest (new_name, NULL, num_dests, dests);
503 if (dest)
504 {
505 printer_set_accepting_jobs (new_name, accepting, NULL);
506 printer_set_enabled (new_name, !printer_paused);
507 printer_set_shared (new_name, printer_shared);
508 printer_set_job_sheets (new_name, start_sheet, end_sheet);
509 printer_set_policy (new_name, op_policy, FALSE);
510 printer_set_policy (new_name, error_policy, TRUE);
511 printer_set_users (new_name, users_allowed, TRUE);
512 printer_set_users (new_name, users_denied, FALSE);
513 if (default_printer)
514 printer_set_default (new_name);
515
516 printer_delete (old_name);
517
518 result = TRUE;
519 }
520 else
521 printer_set_accepting_jobs (old_name, accepting, NULL);
522
523 cupsFreeDests (num_dests, dests);
524 if (sheets)
525 g_strfreev (sheets);
526 if (users_allowed)
527 g_strfreev (users_allowed);
528 if (users_denied)
529 g_strfreev (users_denied);
530
531 return result;
532 }
533
534 gboolean
535 printer_set_location (const gchar *printer_name,
536 const gchar *location)
537 {
538 g_autoptr(GDBusConnection) bus = NULL;
539 g_autoptr(GVariant) output = NULL;
540 const gchar *ret_error;
541 g_autoptr(GError) error = NULL;
542
543 if (!printer_name || !location)
544 return TRUE;
545
546 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
547 if (!bus)
548 {
549 g_warning ("Failed to get system bus: %s", error->message);
550 return TRUE;
551 }
552
553 output = g_dbus_connection_call_sync (bus,
554 MECHANISM_BUS,
555 "/",
556 MECHANISM_BUS,
557 "PrinterSetLocation",
558 g_variant_new ("(ss)", printer_name, location),
559 G_VARIANT_TYPE ("(s)"),
560 G_DBUS_CALL_FLAGS_NONE,
561 -1,
562 NULL,
563 &error);
564
565 if (output == NULL)
566 {
567 g_warning ("%s", error->message);
568 return FALSE;
569 }
570
571 g_variant_get (output, "(&s)", &ret_error);
572 if (ret_error[0] != '\0')
573 {
574 g_warning ("cups-pk-helper: setting of location for printer %s failed: %s", printer_name, ret_error);
575 return FALSE;
576 }
577
578 return TRUE;
579 }
580
581 gboolean
582 printer_set_accepting_jobs (const gchar *printer_name,
583 gboolean accepting_jobs,
584 const gchar *reason)
585 {
586 g_autoptr(GDBusConnection) bus = NULL;
587 g_autoptr(GVariant) output = NULL;
588 const gchar *ret_error;
589 g_autoptr(GError) error = NULL;
590
591 if (!printer_name)
592 return TRUE;
593
594 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
595 if (!bus)
596 {
597 g_warning ("Failed to get system bus: %s", error->message);
598 return TRUE;
599 }
600
601 output = g_dbus_connection_call_sync (bus,
602 MECHANISM_BUS,
603 "/",
604 MECHANISM_BUS,
605 "PrinterSetAcceptJobs",
606 g_variant_new ("(sbs)",
607 printer_name,
608 accepting_jobs,
609 reason ? reason : ""),
610 G_VARIANT_TYPE ("(s)"),
611 G_DBUS_CALL_FLAGS_NONE,
612 -1,
613 NULL,
614 &error);
615
616 if (output == NULL)
617 {
618 g_warning ("%s", error->message);
619 return FALSE;
620 }
621
622 g_variant_get (output, "(&s)", &ret_error);
623 if (ret_error[0] != '\0')
624 {
625 g_warning ("cups-pk-helper: setting of acceptance of jobs for printer %s failed: %s", printer_name, ret_error);
626 return FALSE;
627 }
628
629 return TRUE;
630 }
631
632 gboolean
633 printer_set_enabled (const gchar *printer_name,
634 gboolean enabled)
635 {
636 g_autoptr(GDBusConnection) bus = NULL;
637 g_autoptr(GVariant) output = NULL;
638 const gchar *ret_error;
639 g_autoptr(GError) error = NULL;
640
641 if (!printer_name)
642 return TRUE;
643
644 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
645 if (!bus)
646 {
647 g_warning ("Failed to get system bus: %s", error->message);
648 return TRUE;
649 }
650
651 output = g_dbus_connection_call_sync (bus,
652 MECHANISM_BUS,
653 "/",
654 MECHANISM_BUS,
655 "PrinterSetEnabled",
656 g_variant_new ("(sb)", printer_name, enabled),
657 G_VARIANT_TYPE ("(s)"),
658 G_DBUS_CALL_FLAGS_NONE,
659 -1,
660 NULL,
661 &error);
662
663 if (output == NULL)
664 {
665 g_warning ("%s", error->message);
666 return FALSE;
667 }
668
669 g_variant_get (output, "(&s)", &ret_error);
670 if (ret_error[0] != '\0')
671 {
672 g_warning ("cups-pk-helper: setting of enablement of printer %s failed: %s", printer_name, ret_error);
673 return FALSE;
674 }
675
676 return TRUE;
677 }
678
679 gboolean
680 printer_delete (const gchar *printer_name)
681 {
682 g_autoptr(GDBusConnection) bus = NULL;
683 g_autoptr(GVariant) output = NULL;
684 const gchar *ret_error;
685 g_autoptr(GError) error = NULL;
686
687 if (!printer_name)
688 return TRUE;
689
690 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
691 if (!bus)
692 {
693 g_warning ("Failed to get system bus: %s", error->message);
694 return TRUE;
695 }
696
697 output = g_dbus_connection_call_sync (bus,
698 MECHANISM_BUS,
699 "/",
700 MECHANISM_BUS,
701 "PrinterDelete",
702 g_variant_new ("(s)", printer_name),
703 G_VARIANT_TYPE ("(s)"),
704 G_DBUS_CALL_FLAGS_NONE,
705 -1,
706 NULL,
707 &error);
708
709 if (output == NULL)
710 {
711 g_warning ("%s", error->message);
712 return FALSE;
713 }
714
715 g_variant_get (output, "(&s)", &ret_error);
716 if (ret_error[0] != '\0')
717 {
718 g_warning ("cups-pk-helper: removing of printer %s failed: %s", printer_name, ret_error);
719 return FALSE;
720 }
721
722 return TRUE;
723 }
724
725 gboolean
726 printer_set_default (const gchar *printer_name)
727 {
728 const char *cups_server;
729 g_autoptr(GError) error = NULL;
730
731 if (!printer_name)
732 return TRUE;
733
734 cups_server = cupsServer ();
735 if (g_ascii_strncasecmp (cups_server, "localhost", 9) == 0 ||
736 g_ascii_strncasecmp (cups_server, "127.0.0.1", 9) == 0 ||
737 g_ascii_strncasecmp (cups_server, "::1", 3) == 0 ||
738 cups_server[0] == '/')
739 {
740 g_autoptr(GDBusConnection) bus = NULL;
741 g_autoptr(GVariant) output = NULL;
742 const gchar *ret_error;
743
744 /* Clean .cups/lpoptions before setting
745 * default printer on local CUPS server.
746 */
747 set_local_default_printer (NULL);
748
749 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
750 if (!bus)
751 {
752 g_warning ("Failed to get system bus: %s", error->message);
753 return FALSE;
754 }
755
756 output = g_dbus_connection_call_sync (bus,
757 MECHANISM_BUS,
758 "/",
759 MECHANISM_BUS,
760 "PrinterSetDefault",
761 g_variant_new ("(s)", printer_name),
762 G_VARIANT_TYPE ("(s)"),
763 G_DBUS_CALL_FLAGS_NONE,
764 -1,
765 NULL,
766 &error);
767
768 if (output == NULL)
769 {
770 g_warning ("%s", error->message);
771 return FALSE;
772 }
773
774 g_variant_get (output, "(&s)", &ret_error);
775 if (ret_error[0] != '\0')
776 {
777 g_warning ("cups-pk-helper: setting default printer to %s failed: %s", printer_name, ret_error);
778 return FALSE;
779 }
780
781 return TRUE;
782 }
783 else
784 /* Store default printer to .cups/lpoptions
785 * if we are connected to a remote CUPS server.
786 */
787 {
788 set_local_default_printer (printer_name);
789 return TRUE;
790 }
791 }
792
793 gboolean
794 printer_set_shared (const gchar *printer_name,
795 gboolean shared)
796 {
797 g_autoptr(GDBusConnection) bus = NULL;
798 g_autoptr(GVariant) output = NULL;
799 const gchar *ret_error;
800 g_autoptr(GError) error = NULL;
801
802 if (!printer_name)
803 return TRUE;
804
805 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
806 if (!bus)
807 {
808 g_warning ("Failed to get system bus: %s", error->message);
809 return TRUE;
810 }
811
812 output = g_dbus_connection_call_sync (bus,
813 MECHANISM_BUS,
814 "/",
815 MECHANISM_BUS,
816 "PrinterSetShared",
817 g_variant_new ("(sb)", printer_name, shared),
818 G_VARIANT_TYPE ("(s)"),
819 G_DBUS_CALL_FLAGS_NONE,
820 -1,
821 NULL,
822 &error);
823
824 if (output == NULL)
825 {
826 g_warning ("%s", error->message);
827 return FALSE;
828 }
829
830 g_variant_get (output, "(&s)", &ret_error);
831 if (ret_error[0] != '\0')
832 {
833 g_warning ("cups-pk-helper: setting of sharing of printer %s failed: %s", printer_name, ret_error);
834 return FALSE;
835 }
836
837 return TRUE;
838 }
839
840 gboolean
841 printer_set_job_sheets (const gchar *printer_name,
842 const gchar *start_sheet,
843 const gchar *end_sheet)
844 {
845 g_autoptr(GDBusConnection) bus = NULL;
846 g_autoptr(GVariant) output = NULL;
847 const gchar *ret_error;
848 g_autoptr(GError) error = NULL;
849
850 if (!printer_name || !start_sheet || !end_sheet)
851 return TRUE;
852
853 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
854 if (!bus)
855 {
856 g_warning ("Failed to get system bus: %s", error->message);
857 return TRUE;
858 }
859
860 output = g_dbus_connection_call_sync (bus,
861 MECHANISM_BUS,
862 "/",
863 MECHANISM_BUS,
864 "PrinterSetJobSheets",
865 g_variant_new ("(sss)", printer_name, start_sheet, end_sheet),
866 G_VARIANT_TYPE ("(s)"),
867 G_DBUS_CALL_FLAGS_NONE,
868 -1,
869 NULL,
870 &error);
871
872 if (output == NULL)
873 {
874 g_warning ("%s", error->message);
875 return FALSE;
876 }
877
878 g_variant_get (output, "(&s)", &ret_error);
879 if (ret_error[0] != '\0')
880 {
881 g_warning ("cups-pk-helper: setting of job sheets for printer %s failed: %s", printer_name, ret_error);
882 return FALSE;
883 }
884
885 return TRUE;
886 }
887
888 gboolean
889 printer_set_policy (const gchar *printer_name,
890 const gchar *policy,
891 gboolean error_policy)
892 {
893 g_autoptr(GDBusConnection) bus = NULL;
894 g_autoptr(GVariant) output = NULL;
895 const gchar *ret_error;
896 g_autoptr(GError) error = NULL;
897
898 if (!printer_name || !policy)
899 return TRUE;
900
901 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
902 if (!bus)
903 {
904 g_warning ("Failed to get system bus: %s", error->message);
905 return TRUE;
906 }
907
908 if (error_policy)
909 output = g_dbus_connection_call_sync (bus,
910 MECHANISM_BUS,
911 "/",
912 MECHANISM_BUS,
913 "PrinterSetErrorPolicy",
914 g_variant_new ("(ss)", printer_name, policy),
915 G_VARIANT_TYPE ("(s)"),
916 G_DBUS_CALL_FLAGS_NONE,
917 -1,
918 NULL,
919 &error);
920 else
921 output = g_dbus_connection_call_sync (bus,
922 MECHANISM_BUS,
923 "/",
924 MECHANISM_BUS,
925 "PrinterSetOpPolicy",
926 g_variant_new ("(ss)", printer_name, policy),
927 G_VARIANT_TYPE ("(s)"),
928 G_DBUS_CALL_FLAGS_NONE,
929 -1,
930 NULL,
931 &error);
932
933 if (output == NULL)
934 {
935 g_warning ("%s", error->message);
936 return FALSE;
937 }
938
939 g_variant_get (output, "(&s)", &ret_error);
940 if (ret_error[0] != '\0')
941 {
942 g_warning ("cups-pk-helper: setting of a policy for printer %s failed: %s", printer_name, ret_error);
943 return FALSE;
944 }
945
946 return TRUE;
947 }
948
949 gboolean
950 printer_set_users (const gchar *printer_name,
951 gchar **users,
952 gboolean allowed)
953 {
954 g_autoptr(GDBusConnection) bus = NULL;
955 GVariantBuilder array_builder;
956 gint i;
957 g_autoptr(GVariant) output = NULL;
958 const gchar *ret_error;
959 g_autoptr(GError) error = NULL;
960
961 if (!printer_name || !users)
962 return TRUE;
963
964 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
965 if (!bus)
966 {
967 g_warning ("Failed to get system bus: %s", error->message);
968 return TRUE;
969 }
970
971 g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("as"));
972 for (i = 0; users[i]; i++)
973 g_variant_builder_add (&array_builder, "s", users[i]);
974
975 if (allowed)
976 output = g_dbus_connection_call_sync (bus,
977 MECHANISM_BUS,
978 "/",
979 MECHANISM_BUS,
980 "PrinterSetUsersAllowed",
981 g_variant_new ("(sas)", printer_name, &array_builder),
982 G_VARIANT_TYPE ("(s)"),
983 G_DBUS_CALL_FLAGS_NONE,
984 -1,
985 NULL,
986 &error);
987 else
988 output = g_dbus_connection_call_sync (bus,
989 MECHANISM_BUS,
990 "/",
991 MECHANISM_BUS,
992 "PrinterSetUsersDenied",
993 g_variant_new ("(sas)", printer_name, &array_builder),
994 G_VARIANT_TYPE ("(s)"),
995 G_DBUS_CALL_FLAGS_NONE,
996 -1,
997 NULL,
998 &error);
999
1000 if (output == NULL)
1001 {
1002 g_warning ("%s", error->message);
1003 return FALSE;
1004 }
1005
1006 g_variant_get (output, "(&s)", &ret_error);
1007 if (ret_error[0] != '\0')
1008 {
1009 g_warning ("cups-pk-helper: setting of access list for printer %s failed: %s", printer_name, ret_error);
1010 return FALSE;
1011 }
1012
1013 return TRUE;
1014 }
1015
1016 gboolean
1017 class_add_printer (const gchar *class_name,
1018 const gchar *printer_name)
1019 {
1020 g_autoptr(GDBusConnection) bus = NULL;
1021 g_autoptr(GVariant) output = NULL;
1022 const gchar *ret_error;
1023 g_autoptr(GError) error = NULL;
1024
1025 if (!class_name || !printer_name)
1026 return TRUE;
1027
1028 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
1029 if (!bus)
1030 {
1031 g_warning ("Failed to get system bus: %s", error->message);
1032 return TRUE;
1033 }
1034
1035 output = g_dbus_connection_call_sync (bus,
1036 MECHANISM_BUS,
1037 "/",
1038 MECHANISM_BUS,
1039 "ClassAddPrinter",
1040 g_variant_new ("(ss)", class_name, printer_name),
1041 G_VARIANT_TYPE ("(s)"),
1042 G_DBUS_CALL_FLAGS_NONE,
1043 -1,
1044 NULL,
1045 &error);
1046
1047 if (output == NULL)
1048 {
1049 g_warning ("%s", error->message);
1050 return FALSE;
1051 }
1052
1053 g_variant_get (output, "(&s)", &ret_error);
1054 if (ret_error[0] != '\0')
1055 {
1056 g_warning ("cups-pk-helper: adding of printer %s to class %s failed: %s", printer_name, class_name, ret_error);
1057 return FALSE;
1058 }
1059
1060 return TRUE;
1061 }
1062
1063 gboolean
1064 printer_is_local (cups_ptype_t printer_type,
1065 const gchar *device_uri)
1066 {
1067 gboolean result = TRUE;
1068 char scheme[HTTP_MAX_URI];
1069 char username[HTTP_MAX_URI];
1070 char hostname[HTTP_MAX_URI];
1071 char resource[HTTP_MAX_URI];
1072 int port;
1073
1074 if (printer_type &
1075 (CUPS_PRINTER_DISCOVERED |
1076 CUPS_PRINTER_REMOTE |
1077 CUPS_PRINTER_IMPLICIT))
1078 result = FALSE;
1079
1080 if (device_uri == NULL || !result)
1081 return result;
1082
1083 httpSeparateURI (HTTP_URI_CODING_ALL, device_uri,
1084 scheme, sizeof (scheme),
1085 username, sizeof (username),
1086 hostname, sizeof (hostname),
1087 &port,
1088 resource, sizeof (resource));
1089
1090 if (g_str_equal (scheme, "ipp") ||
1091 g_str_equal (scheme, "smb") ||
1092 g_str_equal (scheme, "socket") ||
1093 g_str_equal (scheme, "lpd"))
1094 result = FALSE;
1095
1096 return result;
1097 }
1098
1099 gchar*
1100 printer_get_hostname (cups_ptype_t printer_type,
1101 const gchar *device_uri,
1102 const gchar *printer_uri)
1103 {
1104 gboolean local = TRUE;
1105 gchar *result = NULL;
1106 char scheme[HTTP_MAX_URI];
1107 char username[HTTP_MAX_URI];
1108 char hostname[HTTP_MAX_URI];
1109 char resource[HTTP_MAX_URI];
1110 int port;
1111
1112 if (device_uri == NULL)
1113 return result;
1114
1115 if (printer_type & (CUPS_PRINTER_DISCOVERED |
1116 CUPS_PRINTER_REMOTE |
1117 CUPS_PRINTER_IMPLICIT))
1118 {
1119 if (printer_uri)
1120 {
1121 httpSeparateURI (HTTP_URI_CODING_ALL, printer_uri,
1122 scheme, sizeof (scheme),
1123 username, sizeof (username),
1124 hostname, sizeof (hostname),
1125 &port,
1126 resource, sizeof (resource));
1127
1128 if (hostname[0] != '\0')
1129 result = g_strdup (hostname);
1130 }
1131
1132 local = FALSE;
1133 }
1134
1135 if (result == NULL && device_uri)
1136 {
1137 httpSeparateURI (HTTP_URI_CODING_ALL, device_uri,
1138 scheme, sizeof (scheme),
1139 username, sizeof (username),
1140 hostname, sizeof (hostname),
1141 &port,
1142 resource, sizeof (resource));
1143
1144 if (g_str_equal (scheme, "ipp") ||
1145 g_str_equal (scheme, "smb") ||
1146 g_str_equal (scheme, "socket") ||
1147 g_str_equal (scheme, "lpd"))
1148 {
1149 if (hostname[0] != '\0')
1150 result = g_strdup (hostname);
1151
1152 local = FALSE;
1153 }
1154 }
1155
1156 if (local)
1157 result = g_strdup ("localhost");
1158
1159 return result;
1160 }
1161
1162 /* Returns default page size for current locale */
1163 const gchar *
1164 get_page_size_from_locale (void)
1165 {
1166 if (g_str_equal (gtk_paper_size_get_default (), GTK_PAPER_NAME_LETTER))
1167 return "Letter";
1168 else
1169 return "A4";
1170 }
1171
1172 typedef struct
1173 {
1174 gchar *printer_name;
1175 gchar **attributes_names;
1176 GHashTable *result;
1177 GIACallback callback;
1178 gpointer user_data;
1179 GMainContext *context;
1180 } GIAData;
1181
1182 static GIAData *
1183 gia_data_new (const gchar *printer_name, gchar **attributes_names, GIACallback callback, gpointer user_data)
1184 {
1185 GIAData *data;
1186
1187 data = g_new0 (GIAData, 1);
1188 data->printer_name = g_strdup (printer_name);
1189 data->attributes_names = g_strdupv (attributes_names);
1190 data->callback = callback;
1191 data->user_data = user_data;
1192 data->context = g_main_context_ref_thread_default ();
1193
1194 return data;
1195 }
1196
1197 static void
1198 gia_data_free (GIAData *data)
1199 {
1200 g_free (data->printer_name);
1201 if (data->attributes_names)
1202 g_strfreev (data->attributes_names);
1203 if (data->result)
1204 g_hash_table_unref (data->result);
1205 if (data->context)
1206 g_main_context_unref (data->context);
1207 g_free (data);
1208 }
1209
1210 static gboolean
1211 get_ipp_attributes_idle_cb (gpointer user_data)
1212 {
1213 GIAData *data = (GIAData *) user_data;
1214
1215 data->callback (data->result, data->user_data);
1216 data->result = NULL;
1217
1218 return FALSE;
1219 }
1220
1221 static void
1222 get_ipp_attributes_cb (gpointer user_data)
1223 {
1224 GIAData *data = user_data;
1225 g_autoptr(GSource) idle_source = NULL;
1226
1227 idle_source = g_idle_source_new ();
1228 g_source_set_callback (idle_source,
1229 get_ipp_attributes_idle_cb,
1230 data,
1231 (GDestroyNotify) gia_data_free);
1232 g_source_attach (idle_source, data->context);
1233 }
1234
1235 static void
1236 ipp_attribute_free2 (gpointer attr)
1237 {
1238 IPPAttribute *attribute = (IPPAttribute *) attr;
1239 ipp_attribute_free (attribute);
1240 }
1241
1242 static gpointer
1243 get_ipp_attributes_func (gpointer user_data)
1244 {
1245 ipp_attribute_t *attr = NULL;
1246 GIAData *data = user_data;
1247 ipp_t *request;
1248 ipp_t *response = NULL;
1249 g_autofree gchar *printer_uri = NULL;
1250 char **requested_attrs = NULL;
1251 gint i, j, length = 0;
1252
1253 printer_uri = g_strdup_printf ("ipp://localhost/printers/%s", data->printer_name);
1254
1255 if (data->attributes_names)
1256 {
1257 length = g_strv_length (data->attributes_names);
1258
1259 requested_attrs = g_new0 (char *, length);
1260 for (i = 0; data->attributes_names[i]; i++)
1261 requested_attrs[i] = g_strdup (data->attributes_names[i]);
1262
1263 request = ippNewRequest (IPP_GET_PRINTER_ATTRIBUTES);
1264 ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
1265 "printer-uri", NULL, printer_uri);
1266 ippAddStrings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1267 "requested-attributes", length, NULL, (const char **) requested_attrs);
1268 response = cupsDoRequest (CUPS_HTTP_DEFAULT, request, "/");
1269 }
1270
1271 if (response)
1272 {
1273 if (ippGetStatusCode (response) <= IPP_OK_CONFLICT)
1274 {
1275 for (j = 0; j < length; j++)
1276 {
1277 attr = ippFindAttribute (response, requested_attrs[j], IPP_TAG_ZERO);
1278 if (attr && ippGetCount (attr) > 0 && ippGetValueTag (attr) != IPP_TAG_NOVALUE)
1279 {
1280 IPPAttribute *attribute;
1281
1282 attribute = g_new0 (IPPAttribute, 1);
1283 attribute->attribute_name = g_strdup (requested_attrs[j]);
1284 attribute->attribute_values = g_new0 (IPPAttributeValue, ippGetCount (attr));
1285 attribute->num_of_values = ippGetCount (attr);
1286
1287 if (ippGetValueTag (attr) == IPP_TAG_INTEGER ||
1288 ippGetValueTag (attr) == IPP_TAG_ENUM)
1289 {
1290 attribute->attribute_type = IPP_ATTRIBUTE_TYPE_INTEGER;
1291
1292 for (i = 0; i < ippGetCount (attr); i++)
1293 attribute->attribute_values[i].integer_value = ippGetInteger (attr, i);
1294 }
1295 else if (ippGetValueTag (attr) == IPP_TAG_NAME ||
1296 ippGetValueTag (attr) == IPP_TAG_STRING ||
1297 ippGetValueTag (attr) == IPP_TAG_TEXT ||
1298 ippGetValueTag (attr) == IPP_TAG_URI ||
1299 ippGetValueTag (attr) == IPP_TAG_KEYWORD ||
1300 ippGetValueTag (attr) == IPP_TAG_URISCHEME)
1301 {
1302 attribute->attribute_type = IPP_ATTRIBUTE_TYPE_STRING;
1303
1304 for (i = 0; i < ippGetCount (attr); i++)
1305 attribute->attribute_values[i].string_value = g_strdup (ippGetString (attr, i, NULL));
1306 }
1307 else if (ippGetValueTag (attr) == IPP_TAG_RANGE)
1308 {
1309 attribute->attribute_type = IPP_ATTRIBUTE_TYPE_RANGE;
1310
1311 for (i = 0; i < ippGetCount (attr); i++)
1312 {
1313 attribute->attribute_values[i].lower_range =
1314 ippGetRange (attr, i, &(attribute->attribute_values[i].upper_range));
1315 }
1316 }
1317 else if (ippGetValueTag (attr) == IPP_TAG_BOOLEAN)
1318 {
1319 attribute->attribute_type = IPP_ATTRIBUTE_TYPE_BOOLEAN;
1320
1321 for (i = 0; i < ippGetCount (attr); i++)
1322 attribute->attribute_values[i].boolean_value = ippGetBoolean (attr, i);
1323 }
1324
1325 if (!data->result)
1326 data->result = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, ipp_attribute_free2);
1327
1328 g_hash_table_insert (data->result, g_strdup (requested_attrs[j]), attribute);
1329 }
1330 }
1331 }
1332
1333 ippDelete (response);
1334 }
1335
1336
1337 for (i = 0; i < length; i++)
1338 g_free (requested_attrs[i]);
1339 g_free (requested_attrs);
1340
1341 get_ipp_attributes_cb (data);
1342
1343 return NULL;
1344 }
1345
1346 void
1347 get_ipp_attributes_async (const gchar *printer_name,
1348 gchar **attributes_names,
1349 GIACallback callback,
1350 gpointer user_data)
1351 {
1352 GIAData *data;
1353 g_autoptr(GThread) thread = NULL;
1354 g_autoptr(GError) error = NULL;
1355
1356 data = gia_data_new (printer_name, attributes_names, callback, user_data);
1357
1358 thread = g_thread_try_new ("get-ipp-attributes",
1359 get_ipp_attributes_func,
1360 data,
1361 &error);
1362
1363 if (!thread)
1364 {
1365 g_warning ("%s", error->message);
1366 callback (NULL, user_data);
1367
1368 gia_data_free (data);
1369 }
1370 }
1371
1372 IPPAttribute *
1373 ipp_attribute_copy (IPPAttribute *attr)
1374 {
1375 IPPAttribute *result = NULL;
1376 gint i;
1377
1378 if (attr)
1379 {
1380 result = g_new0 (IPPAttribute, 1);
1381
1382 *result = *attr;
1383 result->attribute_name = g_strdup (attr->attribute_name);
1384 result->attribute_values = g_new0 (IPPAttributeValue, attr->num_of_values);
1385 for (i = 0; i < attr->num_of_values; i++)
1386 {
1387 result->attribute_values[i] = attr->attribute_values[i];
1388 if (attr->attribute_values[i].string_value)
1389 result->attribute_values[i].string_value = g_strdup (attr->attribute_values[i].string_value);
1390 }
1391 }
1392
1393 return result;
1394 }
1395
1396 void
1397 ipp_attribute_free (IPPAttribute *attr)
1398 {
1399 gint i;
1400
1401 if (attr)
1402 {
1403 for (i = 0; i < attr->num_of_values; i++)
1404 g_free (attr->attribute_values[i].string_value);
1405
1406 g_free (attr->attribute_values);
1407 g_free (attr->attribute_name);
1408 g_free (attr);
1409 }
1410 }
1411
1412 typedef struct
1413 {
1414 gchar *printer_name;
1415 gchar *ppd_copy;
1416 GCancellable *cancellable;
1417 PSPCallback callback;
1418 gpointer user_data;
1419 } PSPData;
1420
1421 static PSPData *
1422 psp_data_new (const gchar *printer_name, const gchar *ppd_copy, GCancellable *cancellable, PSPCallback callback, gpointer user_data)
1423 {
1424 PSPData *data;
1425
1426 data = g_new0 (PSPData, 1);
1427 data->printer_name = g_strdup (printer_name);
1428 data->ppd_copy = g_strdup (ppd_copy);
1429 if (cancellable)
1430 data->cancellable = g_object_ref (cancellable);
1431 data->callback = callback;
1432 data->user_data = user_data;
1433 return data;
1434 }
1435
1436 static void
1437 psp_data_free (PSPData *data)
1438 {
1439 g_free (data->printer_name);
1440 if (data->ppd_copy != NULL)
1441 {
1442 g_unlink (data->ppd_copy);
1443 g_free (data->ppd_copy);
1444 }
1445 g_clear_object (&data->cancellable);
1446 g_free (data);
1447 }
1448
1449 G_DEFINE_AUTOPTR_CLEANUP_FUNC (PSPData, psp_data_free)
1450
1451 static void
1452 printer_set_ppd_async_dbus_cb (GObject *source_object,
1453 GAsyncResult *res,
1454 gpointer user_data)
1455 {
1456 g_autoptr(GVariant) output = NULL;
1457 gboolean result = FALSE;
1458 g_autoptr(PSPData) data = user_data;
1459 g_autoptr(GError) error = NULL;
1460
1461 output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
1462 res,
1463 &error);
1464
1465 if (output)
1466 {
1467 const gchar *ret_error;
1468
1469 g_variant_get (output, "(&s)", &ret_error);
1470 if (ret_error[0] != '\0')
1471 g_warning ("cups-pk-helper: setting of driver for printer %s failed: %s", data->printer_name, ret_error);
1472 else
1473 result = TRUE;
1474 }
1475 else
1476 {
1477 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1478 g_warning ("%s", error->message);
1479 }
1480
1481 /* Don't call callback if cancelled */
1482 if (!data->cancellable ||
1483 !g_cancellable_is_cancelled (data->cancellable))
1484 data->callback (data->printer_name,
1485 result,
1486 data->user_data);
1487 }
1488
1489 /*
1490 * Set ppd for given printer.
1491 * Don't use this for classes, just for printers.
1492 */
1493 void
1494 printer_set_ppd_async (const gchar *printer_name,
1495 const gchar *ppd_name,
1496 GCancellable *cancellable,
1497 PSPCallback callback,
1498 gpointer user_data)
1499 {
1500 g_autoptr(GDBusConnection) bus = NULL;
1501 g_autoptr(GError) error = NULL;
1502
1503 if (printer_name == NULL ||
1504 printer_name[0] == '\0')
1505 {
1506 callback (printer_name, FALSE, user_data);
1507 return;
1508 }
1509
1510 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
1511 if (!bus)
1512 {
1513 g_warning ("Failed to get system bus: %s", error->message);
1514 callback (printer_name, FALSE, user_data);
1515 return;
1516 }
1517
1518 g_dbus_connection_call (bus,
1519 MECHANISM_BUS,
1520 "/",
1521 MECHANISM_BUS,
1522 "PrinterAdd",
1523 g_variant_new ("(sssss)",
1524 printer_name,
1525 "",
1526 ppd_name,
1527 "",
1528 ""),
1529 G_VARIANT_TYPE ("(s)"),
1530 G_DBUS_CALL_FLAGS_NONE,
1531 -1,
1532 cancellable,
1533 printer_set_ppd_async_dbus_cb,
1534 psp_data_new (printer_name, NULL, cancellable, callback, user_data));
1535 }
1536
1537 static void
1538 printer_set_ppd_file_async_scb (GObject *source_object,
1539 GAsyncResult *res,
1540 gpointer user_data)
1541 {
1542 g_autoptr(GDBusConnection) bus = NULL;
1543 gboolean success;
1544 g_autoptr(PSPData) data = user_data;
1545 g_autoptr(GError) error = NULL;
1546
1547 success = g_file_copy_finish (G_FILE (source_object),
1548 res,
1549 &error);
1550
1551 if (!success)
1552 {
1553 g_warning ("%s", error->message);
1554 data->callback (data->printer_name, FALSE, data->user_data);
1555 return;
1556 }
1557
1558 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
1559 if (!bus)
1560 {
1561 g_warning ("Failed to get system bus: %s", error->message);
1562 data->callback (data->printer_name, FALSE, data->user_data);
1563 return;
1564 }
1565
1566 g_dbus_connection_call (bus,
1567 MECHANISM_BUS,
1568 "/",
1569 MECHANISM_BUS,
1570 "PrinterAddWithPpdFile",
1571 g_variant_new ("(sssss)",
1572 data->printer_name,
1573 "",
1574 data->ppd_copy,
1575 "",
1576 ""),
1577 G_VARIANT_TYPE ("(s)"),
1578 G_DBUS_CALL_FLAGS_NONE,
1579 -1,
1580 data->cancellable,
1581 printer_set_ppd_async_dbus_cb,
1582 data);
1583 g_steal_pointer (&data);
1584 }
1585
1586 /*
1587 * Set ppd for given printer.
1588 * Don't use this for classes, just for printers.
1589 */
1590 void
1591 printer_set_ppd_file_async (const gchar *printer_name,
1592 const gchar *ppd_filename,
1593 GCancellable *cancellable,
1594 PSPCallback callback,
1595 gpointer user_data)
1596 {
1597 g_autoptr(GFileIOStream) stream = NULL;
1598 g_autoptr(GFile) source_ppd_file = NULL;
1599 g_autoptr(GFile) destination_ppd_file = NULL;
1600
1601 if (printer_name == NULL ||
1602 printer_name[0] == '\0')
1603 {
1604 callback (printer_name, FALSE, user_data);
1605 return;
1606 }
1607
1608 /*
1609 * We need to copy the PPD to temp directory at first.
1610 * This is needed because of SELinux.
1611 */
1612 source_ppd_file = g_file_new_for_path (ppd_filename);
1613 destination_ppd_file = g_file_new_tmp ("g-c-c-XXXXXX.ppd", &stream, NULL);
1614
1615 g_file_copy_async (source_ppd_file,
1616 destination_ppd_file,
1617 G_FILE_COPY_OVERWRITE,
1618 G_PRIORITY_DEFAULT,
1619 cancellable,
1620 NULL,
1621 NULL,
1622 printer_set_ppd_file_async_scb,
1623 psp_data_new (printer_name, g_file_get_path (destination_ppd_file), cancellable, callback, user_data));
1624 }
1625
1626 typedef void (*GPACallback) (gchar **attribute_values,
1627 gpointer user_data);
1628
1629 typedef struct
1630 {
1631 gchar **ppds_names;
1632 gchar *attribute_name;
1633 gchar **result;
1634 GPACallback callback;
1635 gpointer user_data;
1636 GMainContext *context;
1637 } GPAData;
1638
1639 static GPAData *
1640 gpa_data_new (gchar **ppds_names, gchar *attribute_name, GPACallback callback, gpointer user_data)
1641 {
1642 GPAData *data;
1643
1644 data = g_new0 (GPAData, 1);
1645 data->ppds_names = g_strdupv (ppds_names);
1646 data->attribute_name = g_strdup (attribute_name);
1647 data->callback = callback;
1648 data->user_data = user_data;
1649 data->context = g_main_context_ref_thread_default ();
1650
1651 return data;
1652 }
1653
1654 static void
1655 gpa_data_free (GPAData *data)
1656 {
1657 g_free (data->attribute_name);
1658 g_strfreev (data->ppds_names);
1659 if (data->result != NULL)
1660 g_strfreev (data->result);
1661 if (data->context)
1662 g_main_context_unref (data->context);
1663 g_free (data);
1664 }
1665
1666 static gboolean
1667 get_ppds_attribute_idle_cb (gpointer user_data)
1668 {
1669 GPAData *data = (GPAData *) user_data;
1670
1671 data->callback (data->result, data->user_data);
1672
1673 return FALSE;
1674 }
1675
1676 static void
1677 get_ppds_attribute_cb (gpointer user_data)
1678 {
1679 GPAData *data = (GPAData *) user_data;
1680 g_autoptr(GSource) idle_source = NULL;
1681
1682 idle_source = g_idle_source_new ();
1683 g_source_set_callback (idle_source,
1684 get_ppds_attribute_idle_cb,
1685 data,
1686 (GDestroyNotify) gpa_data_free);
1687 g_source_attach (idle_source, data->context);
1688 }
1689
1690 static gpointer
1691 get_ppds_attribute_func (gpointer user_data)
1692 {
1693 ppd_file_t *ppd_file;
1694 ppd_attr_t *ppd_attr;
1695 GPAData *data = user_data;
1696 gint i;
1697
1698 data->result = g_new0 (gchar *, g_strv_length (data->ppds_names) + 1);
1699 for (i = 0; data->ppds_names[i]; i++)
1700 {
1701 g_autofree gchar *ppd_filename = g_strdup (cupsGetServerPPD (CUPS_HTTP_DEFAULT, data->ppds_names[i]));
1702 if (ppd_filename)
1703 {
1704 ppd_file = ppdOpenFile (ppd_filename);
1705 if (ppd_file)
1706 {
1707 ppd_attr = ppdFindAttr (ppd_file, data->attribute_name, NULL);
1708 if (ppd_attr != NULL)
1709 data->result[i] = g_strdup (ppd_attr->value);
1710
1711 ppdClose (ppd_file);
1712 }
1713
1714 g_unlink (ppd_filename);
1715 }
1716 }
1717
1718 get_ppds_attribute_cb (data);
1719
1720 return NULL;
1721 }
1722
1723 /*
1724 * Get values of requested PPD attribute for given PPDs.
1725 */
1726 static void
1727 get_ppds_attribute_async (gchar **ppds_names,
1728 gchar *attribute_name,
1729 GPACallback callback,
1730 gpointer user_data)
1731 {
1732 GPAData *data;
1733 g_autoptr(GThread) thread = NULL;
1734 g_autoptr(GError) error = NULL;
1735
1736 if (!ppds_names || !attribute_name)
1737 {
1738 callback (NULL, user_data);
1739 return;
1740 }
1741
1742 data = gpa_data_new (ppds_names, attribute_name, callback, user_data);
1743
1744 thread = g_thread_try_new ("get-ppds-attribute",
1745 get_ppds_attribute_func,
1746 data,
1747 &error);
1748
1749 if (!thread)
1750 {
1751 g_warning ("%s", error->message);
1752 callback (NULL, user_data);
1753
1754 gpa_data_free (data);
1755 }
1756 }
1757
1758
1759
1760 typedef void (*GDACallback) (gchar *device_id,
1761 gchar *device_make_and_model,
1762 gchar *device_uri,
1763 gpointer user_data);
1764
1765 typedef struct
1766 {
1767 gchar *printer_name;
1768 gchar *device_uri;
1769 GList *backend_list;
1770 GCancellable *cancellable;
1771 GDACallback callback;
1772 gpointer user_data;
1773 } GDAData;
1774
1775 static GDAData *
1776 gda_data_new (const gchar *printer_name, GCancellable *cancellable, GDACallback callback, gpointer user_data)
1777 {
1778 GDAData *data;
1779
1780 data = g_new0 (GDAData, 1);
1781 data->printer_name = g_strdup (printer_name);
1782 if (cancellable)
1783 data->cancellable = g_object_ref (cancellable);
1784 data->callback = callback;
1785 data->user_data = user_data;
1786
1787 return data;
1788 }
1789
1790 static void
1791 gda_data_free (GDAData *data)
1792 {
1793 g_free (data->printer_name);
1794 g_free (data->device_uri);
1795 g_list_free_full(data->backend_list, g_free);
1796 g_clear_object (&data->cancellable);
1797 g_free (data);
1798 }
1799
1800 G_DEFINE_AUTOPTR_CLEANUP_FUNC (GDAData, gda_data_free)
1801
1802 typedef struct
1803 {
1804 gchar *printer_name;
1805 gint count;
1806 PPDName **result;
1807 GCancellable *cancellable;
1808 GPNCallback callback;
1809 gpointer user_data;
1810 } GPNData;
1811
1812 static GPNData *
1813 gpn_data_new (const gchar *printer_name, gint count, GCancellable *cancellable, GPNCallback callback, gpointer user_data)
1814 {
1815 GPNData *data;
1816
1817 data = g_new0 (GPNData, 1);
1818 data->printer_name = g_strdup (printer_name);
1819 data->count = count;
1820 if (cancellable)
1821 data->cancellable = g_object_ref (cancellable);
1822 data->callback = callback;
1823 data->user_data = user_data;
1824
1825 return data;
1826 }
1827
1828 static void
1829 gpn_data_free (GPNData *data)
1830 {
1831 g_free (data->printer_name);
1832 if (data->result != NULL)
1833 {
1834 for (int i = 0; data->result[i]; i++)
1835 {
1836 g_free (data->result[i]->ppd_name);
1837 g_free (data->result[i]->ppd_display_name);
1838 g_free (data->result[i]);
1839 }
1840 g_free (data->result);
1841 }
1842 g_clear_object (&data->cancellable);
1843 g_free (data);
1844 }
1845
1846 G_DEFINE_AUTOPTR_CLEANUP_FUNC (GPNData, gpn_data_free)
1847
1848 static void
1849 get_ppd_names_async_cb (gchar **attribute_values,
1850 gpointer user_data)
1851 {
1852 g_autoptr(GPNData) data = user_data;
1853 gint i;
1854
1855 if (g_cancellable_is_cancelled (data->cancellable))
1856 {
1857 data->callback (NULL,
1858 data->printer_name,
1859 TRUE,
1860 data->user_data);
1861 return;
1862 }
1863
1864 if (attribute_values)
1865 {
1866 for (i = 0; attribute_values[i]; i++)
1867 data->result[i]->ppd_display_name = g_strdup (attribute_values[i]);
1868 }
1869
1870 data->callback (data->result,
1871 data->printer_name,
1872 FALSE,
1873 data->user_data);
1874 }
1875
1876 static void
1877 get_ppd_names_async_dbus_scb (GObject *source_object,
1878 GAsyncResult *res,
1879 gpointer user_data)
1880 {
1881 g_autoptr(GVariant) output = NULL;
1882 PPDName *ppd_item;
1883 PPDName **result = NULL;
1884 g_autoptr(GPNData) data = user_data;
1885 g_autoptr(GError) error = NULL;
1886 GList *driver_list = NULL;
1887 GList *iter;
1888 gint i, j, n = 0;
1889 static const char * const match_levels[] = {
1890 "exact-cmd",
1891 "exact",
1892 "close",
1893 "generic",
1894 "none"};
1895
1896 output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
1897 res,
1898 &error);
1899
1900 if (output)
1901 {
1902 g_autoptr(GVariant) array = NULL;
1903
1904 g_variant_get (output, "(@a(ss))",
1905 &array);
1906
1907 for (j = 0; j < G_N_ELEMENTS (match_levels) && n < data->count; j++)
1908 {
1909 g_autoptr(GVariantIter) iter = NULL;
1910 const gchar *driver, *match;
1911
1912 g_variant_get (array,
1913 "a(ss)",
1914 &iter);
1915
1916 while (g_variant_iter_next (iter, "(&s&s)", &driver, &match))
1917 {
1918 if (g_str_equal (match, match_levels[j]) && n < data->count)
1919 {
1920 ppd_item = g_new0 (PPDName, 1);
1921 ppd_item->ppd_name = g_strdup (driver);
1922
1923 if (g_strcmp0 (match, "exact-cmd") == 0)
1924 ppd_item->ppd_match_level = PPD_EXACT_CMD_MATCH;
1925 else if (g_strcmp0 (match, "exact") == 0)
1926 ppd_item->ppd_match_level = PPD_EXACT_MATCH;
1927 else if (g_strcmp0 (match, "close") == 0)
1928 ppd_item->ppd_match_level = PPD_CLOSE_MATCH;
1929 else if (g_strcmp0 (match, "generic") == 0)
1930 ppd_item->ppd_match_level = PPD_GENERIC_MATCH;
1931 else if (g_strcmp0 (match, "none") == 0)
1932 ppd_item->ppd_match_level = PPD_NO_MATCH;
1933
1934 driver_list = g_list_append (driver_list, ppd_item);
1935
1936 n++;
1937 }
1938 }
1939 }
1940 }
1941 else
1942 {
1943 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1944 g_warning ("%s", error->message);
1945 }
1946
1947 if (n > 0)
1948 {
1949 result = g_new0 (PPDName *, n + 1);
1950 i = 0;
1951 for (iter = driver_list; iter; iter = iter->next)
1952 {
1953 result[i] = iter->data;
1954 i++;
1955 }
1956 }
1957
1958 if (result)
1959 {
1960 g_auto(GStrv) ppds_names = NULL;
1961
1962 data->result = result;
1963
1964 ppds_names = g_new0 (gchar *, n + 1);
1965 for (i = 0; i < n; i++)
1966 ppds_names[i] = g_strdup (result[i]->ppd_name);
1967
1968 get_ppds_attribute_async (ppds_names,
1969 "NickName",
1970 get_ppd_names_async_cb,
1971 data);
1972 g_steal_pointer (&data);
1973 }
1974 else
1975 {
1976 data->callback (NULL,
1977 data->printer_name,
1978 g_cancellable_is_cancelled (data->cancellable),
1979 data->user_data);
1980 }
1981 }
1982
1983 static void
1984 get_device_attributes_cb (gchar *device_id,
1985 gchar *device_make_and_model,
1986 gchar *device_uri,
1987 gpointer user_data)
1988 {
1989 g_autoptr(GDBusConnection) bus = NULL;
1990 g_autoptr(GError) error = NULL;
1991 g_autoptr(GPNData) data = user_data;
1992
1993 if (g_cancellable_is_cancelled (data->cancellable))
1994 {
1995 data->callback (NULL,
1996 data->printer_name,
1997 TRUE,
1998 data->user_data);
1999 return;
2000 }
2001
2002 if (!device_id || !device_make_and_model || !device_uri)
2003 {
2004 data->callback (NULL,
2005 data->printer_name,
2006 FALSE,
2007 data->user_data);
2008 return;
2009 }
2010
2011 bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
2012 if (!bus)
2013 {
2014 g_warning ("Failed to get system bus: %s", error->message);
2015 data->callback (NULL,
2016 data->printer_name,
2017 FALSE,
2018 data->user_data);
2019 return;
2020 }
2021
2022 g_dbus_connection_call (bus,
2023 SCP_BUS,
2024 SCP_PATH,
2025 SCP_IFACE,
2026 "GetBestDrivers",
2027 g_variant_new ("(sss)",
2028 device_id,
2029 device_make_and_model,
2030 device_uri),
2031 G_VARIANT_TYPE ("(a(ss))"),
2032 G_DBUS_CALL_FLAGS_NONE,
2033 DBUS_TIMEOUT_LONG,
2034 data->cancellable,
2035 get_ppd_names_async_dbus_scb,
2036 data);
2037 g_steal_pointer (&data);
2038 }
2039
2040 /*
2041 * Special item for the list of backends. It represents
2042 * backends not present in the list itself.
2043 */
2044 #define OTHER_BACKENDS "other-backends"
2045
2046 /*
2047 * List of CUPS backends sorted according to their speed,
2048 * the fastest is the first one. The last item represents
2049 * backends not present in the list.
2050 */
2051 const gchar *cups_backends[] = {
2052 "usb",
2053 "socket",
2054 "serial",
2055 "parallel",
2056 "lpd",
2057 "ipp",
2058 "hp",
2059 "dnssd",
2060 "snmp",
2061 "bluetooth",
2062 "beh",
2063 "ncp",
2064 "hpfax",
2065 OTHER_BACKENDS
2066 };
2067
2068 static GList *
2069 create_backends_list ()
2070 {
2071 GList *list = NULL;
2072 gint i;
2073
2074 for (i = 0; i < G_N_ELEMENTS (cups_backends); i++)
2075 list = g_list_prepend (list, g_strdup (cups_backends[i]));
2076 list = g_list_reverse (list);
2077
2078 return list;
2079 }
2080
2081 static GVariantBuilder *
2082 create_other_backends_array ()
2083 {
2084 GVariantBuilder *builder;
2085 gint i;
2086
2087 builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
2088 for (i = 0; i < G_N_ELEMENTS (cups_backends) - 1; i++)
2089 g_variant_builder_add (builder, "s", cups_backends[i]);
2090
2091 return builder;
2092 }
2093
2094 static void
2095 get_device_attributes_async_dbus_cb (GObject *source_object,
2096 GAsyncResult *res,
2097 gpointer user_data)
2098
2099 {
2100 g_autoptr(GVariant) output = NULL;
2101 g_autoptr(GDAData) data = user_data;
2102 g_autoptr(GError) error = NULL;
2103 gchar *device_id = NULL;
2104 gchar *device_make_and_model = NULL;
2105
2106 output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
2107 res,
2108 &error);
2109
2110 if (output)
2111 {
2112 const gchar *ret_error;
2113 g_autoptr(GVariant) devices_variant = NULL;
2114 gint index = -1;
2115
2116 g_variant_get (output, "(&s@a{ss})",
2117 &ret_error,
2118 &devices_variant);
2119
2120 if (ret_error[0] != '\0')
2121 {
2122 g_warning ("cups-pk-helper: getting of attributes for printer %s failed: %s", data->printer_name, ret_error);
2123 }
2124
2125 if (data->device_uri)
2126 {
2127 g_autoptr(GVariantIter) iter = NULL;
2128 const gchar *key, *value;
2129 g_autofree gchar *suffix = NULL;
2130
2131 g_variant_get (devices_variant,
2132 "a{ss}",
2133 &iter);
2134
2135 while (g_variant_iter_next (iter, "{&s&s}", &key, &value))
2136 {
2137 if (g_str_equal (value, data->device_uri))
2138 {
2139 gchar *number = g_strrstr (key, ":");
2140 if (number != NULL)
2141 {
2142 gchar *endptr;
2143
2144 number++;
2145 index = g_ascii_strtoll (number, &endptr, 10);
2146 if (index == 0 && endptr == (number))
2147 index = -1;
2148 }
2149 }
2150 }
2151
2152 suffix = g_strdup_printf (":%d", index);
2153
2154 g_variant_get (devices_variant,
2155 "a{ss}",
2156 &iter);
2157
2158 while (g_variant_iter_next (iter, "{&s&s}", &key, &value))
2159 {
2160 if (g_str_has_suffix (key, suffix))
2161 {
2162 if (g_str_has_prefix (key, "device-id"))
2163 {
2164 device_id = g_strdup (value);
2165 }
2166
2167 if (g_str_has_prefix (key, "device-make-and-model"))
2168 {
2169 device_make_and_model = g_strdup (value);
2170 }
2171 }
2172 }
2173 }
2174 }
2175 else
2176 {
2177 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
2178 g_warning ("%s", error->message);
2179 }
2180
2181 if (!device_id || !device_make_and_model)
2182 {
2183 GVariantBuilder *include_scheme_builder = NULL;
2184 GVariantBuilder *exclude_scheme_builder = NULL;
2185
2186 g_free (device_id);
2187 g_free (device_make_and_model);
2188
2189 device_id = NULL;
2190 device_make_and_model = NULL;
2191
2192 if (data->backend_list && !g_cancellable_is_cancelled (data->cancellable))
2193 {
2194 const gchar *backend_name;
2195
2196 backend_name = data->backend_list->data;
2197
2198 if (g_strcmp0 (backend_name, OTHER_BACKENDS) != 0)
2199 {
2200 include_scheme_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
2201 g_variant_builder_add (include_scheme_builder, "s", backend_name);
2202 }
2203 else
2204 {
2205 exclude_scheme_builder = create_other_backends_array ();
2206 }
2207
2208 data->backend_list = g_list_delete_link (data->backend_list, data->backend_list);
2209
2210 g_dbus_connection_call (G_DBUS_CONNECTION (g_object_ref (source_object)),
2211 MECHANISM_BUS,
2212 "/",
2213 MECHANISM_BUS,
2214 "DevicesGet",
2215 g_variant_new ("(iiasas)",
2216 0,
2217 0,
2218 include_scheme_builder,
2219 exclude_scheme_builder),
2220 G_VARIANT_TYPE ("(sa{ss})"),
2221 G_DBUS_CALL_FLAGS_NONE,
2222 DBUS_TIMEOUT,
2223 data->cancellable,
2224 get_device_attributes_async_dbus_cb,
2225 data);
2226 g_steal_pointer (&data);
2227
2228 if (include_scheme_builder)
2229 g_variant_builder_unref (include_scheme_builder);
2230
2231 if (exclude_scheme_builder)
2232 g_variant_builder_unref (exclude_scheme_builder);
2233
2234 return;
2235 }
2236 }
2237
2238 data->callback (device_id,
2239 device_make_and_model,
2240 data->device_uri,
2241 data->user_data);
2242 }
2243
2244 static void
2245 get_device_attributes_async_scb (GHashTable *result,
2246 gpointer user_data)
2247 {
2248 g_autoptr(GDBusConnection) bus = NULL;
2249 GVariantBuilder include_scheme_builder;
2250 IPPAttribute *attr;
2251 g_autoptr(GDAData) data = user_data;
2252 g_autoptr(GError) error = NULL;
2253
2254 if (result)
2255 {
2256 attr = g_hash_table_lookup (result, "device-uri");
2257 if (attr && attr->attribute_type == IPP_ATTRIBUTE_TYPE_STRING &&
2258 attr->num_of_values > 0)
2259 data->device_uri = g_strdup (attr->attribute_values[0].string_value);
2260 g_hash_table_unref (result);
2261 }
2262
2263 if (g_cancellable_is_cancelled (data->cancellable))
2264 {
2265 data->callback (NULL, NULL, NULL, data->user_data);
2266 return;
2267 }
2268
2269 if (!data->device_uri)
2270 {
2271 data->callback (NULL, NULL, NULL, data->user_data);
2272 return;
2273 }
2274
2275 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
2276 if (!bus)
2277 {
2278 g_warning ("Failed to get system bus: %s", error->message);
2279 data->callback (NULL, NULL, NULL, data->user_data);
2280 return;
2281 }
2282
2283 data->backend_list = create_backends_list ();
2284
2285 g_variant_builder_init (&include_scheme_builder, G_VARIANT_TYPE ("as"));
2286 g_variant_builder_add (&include_scheme_builder, "s", data->backend_list->data);
2287
2288 data->backend_list = g_list_delete_link (data->backend_list, data->backend_list);
2289
2290 g_dbus_connection_call (g_object_ref (bus),
2291 MECHANISM_BUS,
2292 "/",
2293 MECHANISM_BUS,
2294 "DevicesGet",
2295 g_variant_new ("(iiasas)",
2296 0,
2297 0,
2298 &include_scheme_builder,
2299 NULL),
2300 G_VARIANT_TYPE ("(sa{ss})"),
2301 G_DBUS_CALL_FLAGS_NONE,
2302 DBUS_TIMEOUT,
2303 data->cancellable,
2304 get_device_attributes_async_dbus_cb,
2305 data);
2306 g_steal_pointer (&data);
2307 }
2308
2309 /*
2310 * Get device-id, device-make-and-model and device-uri for given printer.
2311 */
2312 static void
2313 get_device_attributes_async (const gchar *printer_name,
2314 GCancellable *cancellable,
2315 GDACallback callback,
2316 gpointer user_data)
2317 {
2318 g_auto(GStrv) attributes = NULL;
2319
2320 if (!printer_name)
2321 {
2322 callback (NULL, NULL, NULL, user_data);
2323 return;
2324 }
2325
2326 attributes = g_new0 (gchar *, 2);
2327 attributes[0] = g_strdup ("device-uri");
2328
2329 get_ipp_attributes_async (printer_name,
2330 attributes,
2331 get_device_attributes_async_scb,
2332 gda_data_new (printer_name, cancellable, callback, user_data));
2333 }
2334
2335 /*
2336 * Return "count" best matching driver names for given printer.
2337 */
2338 void
2339 get_ppd_names_async (gchar *printer_name,
2340 gint count,
2341 GCancellable *cancellable,
2342 GPNCallback callback,
2343 gpointer user_data)
2344 {
2345 if (!printer_name)
2346 {
2347 callback (NULL, NULL, TRUE, user_data);
2348 return;
2349 }
2350
2351 /*
2352 * We have to find out device-id for this printer at first.
2353 */
2354 get_device_attributes_async (printer_name,
2355 cancellable,
2356 get_device_attributes_cb,
2357 gpn_data_new (printer_name, count, cancellable, callback, user_data));
2358 }
2359
2360 typedef struct
2361 {
2362 PPDList *result;
2363 GCancellable *cancellable;
2364 GAPCallback callback;
2365 gpointer user_data;
2366 GMainContext *context;
2367 } GAPData;
2368
2369 static GAPData *
2370 gap_data_new (GCancellable *cancellable, GAPCallback callback, gpointer user_data)
2371 {
2372 GAPData *data;
2373
2374 data = g_new0 (GAPData, 1);
2375 if (cancellable)
2376 data->cancellable = g_object_ref (cancellable);
2377 data->callback = callback;
2378 data->user_data = user_data;
2379 data->context = g_main_context_ref_thread_default ();
2380
2381 return data;
2382 }
2383
2384 static void
2385 gap_data_free (GAPData *data)
2386 {
2387 if (data->result != NULL)
2388 ppd_list_free (data->result);
2389 g_clear_object (&data->cancellable);
2390 if (data->context)
2391 g_main_context_unref (data->context);
2392 g_free (data);
2393 }
2394
2395 static gboolean
2396 get_all_ppds_idle_cb (gpointer user_data)
2397 {
2398 GAPData *data = user_data;
2399
2400 if (!g_cancellable_is_cancelled (data->cancellable))
2401 data->callback (data->result, data->user_data);
2402
2403 return FALSE;
2404 }
2405
2406 static void
2407 get_all_ppds_cb (gpointer user_data)
2408 {
2409 GAPData *data = user_data;
2410 g_autoptr(GSource) idle_source = NULL;
2411
2412 idle_source = g_idle_source_new ();
2413 g_source_set_callback (idle_source,
2414 get_all_ppds_idle_cb,
2415 data,
2416 (GDestroyNotify) gap_data_free);
2417 g_source_attach (idle_source, data->context);
2418 }
2419
2420 static const struct {
2421 const char *normalized_name;
2422 const char *display_name;
2423 } manufacturers_names[] = {
2424 { "alps", "Alps" },
2425 { "anitech", "Anitech" },
2426 { "apple", "Apple" },
2427 { "apollo", "Apollo" },
2428 { "brother", "Brother" },
2429 { "canon", "Canon" },
2430 { "citizen", "Citizen" },
2431 { "citoh", "Citoh" },
2432 { "compaq", "Compaq" },
2433 { "dec", "DEC" },
2434 { "dell", "Dell" },
2435 { "dnp", "DNP" },
2436 { "dymo", "Dymo" },
2437 { "epson", "Epson" },
2438 { "fujifilm", "Fujifilm" },
2439 { "fujitsu", "Fujitsu" },
2440 { "gelsprinter", "Ricoh" },
2441 { "generic", "Generic" },
2442 { "genicom", "Genicom" },
2443 { "gestetner", "Gestetner" },
2444 { "hewlett packard", "Hewlett-Packard" },
2445 { "heidelberg", "Heidelberg" },
2446 { "hitachi", "Hitachi" },
2447 { "hp", "Hewlett-Packard" },
2448 { "ibm", "IBM" },
2449 { "imagen", "Imagen" },
2450 { "imagistics", "Imagistics" },
2451 { "infoprint", "InfoPrint" },
2452 { "infotec", "Infotec" },
2453 { "intellitech", "Intellitech" },
2454 { "kodak", "Kodak" },
2455 { "konica minolta", "Minolta" },
2456 { "kyocera", "Kyocera" },
2457 { "kyocera mita", "Kyocera" },
2458 { "lanier", "Lanier" },
2459 { "lexmark international", "Lexmark" },
2460 { "lexmark", "Lexmark" },
2461 { "minolta", "Minolta" },
2462 { "minolta qms", "Minolta" },
2463 { "mitsubishi", "Mitsubishi" },
2464 { "nec", "NEC" },
2465 { "nrg", "NRG" },
2466 { "oce", "Oce" },
2467 { "oki", "Oki" },
2468 { "oki data corp", "Oki" },
2469 { "olivetti", "Olivetti" },
2470 { "olympus", "Olympus" },
2471 { "panasonic", "Panasonic" },
2472 { "pcpi", "PCPI" },
2473 { "pentax", "Pentax" },
2474 { "qms", "QMS" },
2475 { "raven", "Raven" },
2476 { "raw", "Raw" },
2477 { "ricoh", "Ricoh" },
2478 { "samsung", "Samsung" },
2479 { "savin", "Savin" },
2480 { "seiko", "Seiko" },
2481 { "sharp", "Sharp" },
2482 { "shinko", "Shinko" },
2483 { "sipix", "SiPix" },
2484 { "sony", "Sony" },
2485 { "star", "Star" },
2486 { "tally", "Tally" },
2487 { "tektronix", "Tektronix" },
2488 { "texas instruments", "Texas Instruments" },
2489 { "toshiba", "Toshiba" },
2490 { "toshiba tec corp.", "Toshiba" },
2491 { "xante", "Xante" },
2492 { "xerox", "Xerox" },
2493 { "zebra", "Zebra" },
2494 };
2495
2496 static gpointer
2497 get_all_ppds_func (gpointer user_data)
2498 {
2499 ipp_attribute_t *attr;
2500 GHashTable *ppds_hash = NULL;
2501 GHashTable *manufacturers_hash = NULL;
2502 GAPData *data = user_data;
2503 PPDName *item;
2504 ipp_t *request;
2505 ipp_t *response;
2506 GList *list;
2507 gchar *manufacturer_display_name;
2508 gint i, j;
2509
2510 request = ippNewRequest (CUPS_GET_PPDS);
2511 response = cupsDoRequest (CUPS_HTTP_DEFAULT, request, "/");
2512
2513 if (response &&
2514 ippGetStatusCode (response) <= IPP_OK_CONFLICT)
2515 {
2516 /*
2517 * This hash contains names of manufacturers as keys and
2518 * values are GLists of PPD names.
2519 */
2520 ppds_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
2521
2522 /*
2523 * This hash contains all possible names of manufacturers as keys
2524 * and values are just first occurrences of their equivalents.
2525 * This is for mapping of e.g. "Hewlett Packard" and "HP" to the same name
2526 * (the one which comes first).
2527 */
2528 manufacturers_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
2529
2530 for (i = 0; i < G_N_ELEMENTS (manufacturers_names); i++)
2531 {
2532 g_hash_table_insert (manufacturers_hash,
2533 g_strdup (manufacturers_names[i].normalized_name),
2534 g_strdup (manufacturers_names[i].display_name));
2535 }
2536
2537 for (attr = ippFirstAttribute (response); attr != NULL; attr = ippNextAttribute (response))
2538 {
2539 const gchar *ppd_device_id = NULL;
2540 const gchar *ppd_make_and_model = NULL;
2541 const gchar *ppd_name = NULL;
2542 const gchar *ppd_product = NULL;
2543 const gchar *ppd_make = NULL;
2544 g_autofree gchar *mdl = NULL;
2545 g_autofree gchar *mfg = NULL;
2546 g_autofree gchar *mfg_normalized = NULL;
2547
2548 while (attr != NULL && ippGetGroupTag (attr) != IPP_TAG_PRINTER)
2549 attr = ippNextAttribute (response);
2550
2551 if (attr == NULL)
2552 break;
2553
2554 while (attr != NULL && ippGetGroupTag (attr) == IPP_TAG_PRINTER)
2555 {
2556 if (g_strcmp0 (ippGetName (attr), "ppd-device-id") == 0 &&
2557 ippGetValueTag (attr) == IPP_TAG_TEXT)
2558 ppd_device_id = ippGetString (attr, 0, NULL);
2559 else if (g_strcmp0 (ippGetName (attr), "ppd-make-and-model") == 0 &&
2560 ippGetValueTag (attr) == IPP_TAG_TEXT)
2561 ppd_make_and_model = ippGetString (attr, 0, NULL);
2562 else if (g_strcmp0 (ippGetName (attr), "ppd-name") == 0 &&
2563 ippGetValueTag (attr) == IPP_TAG_NAME)
2564 ppd_name = ippGetString (attr, 0, NULL);
2565 else if (g_strcmp0 (ippGetName (attr), "ppd-product") == 0 &&
2566 ippGetValueTag (attr) == IPP_TAG_TEXT)
2567 ppd_product = ippGetString (attr, 0, NULL);
2568 else if (g_strcmp0 (ippGetName (attr), "ppd-make") == 0 &&
2569 ippGetValueTag (attr) == IPP_TAG_TEXT)
2570 ppd_make = ippGetString (attr, 0, NULL);
2571
2572 attr = ippNextAttribute (response);
2573 }
2574
2575 /* Get manufacturer's name */
2576 if (ppd_device_id && ppd_device_id[0] != '\0')
2577 {
2578 mfg = get_tag_value (ppd_device_id, "mfg");
2579 if (!mfg)
2580 mfg = get_tag_value (ppd_device_id, "manufacturer");
2581 mfg_normalized = normalize (mfg);
2582 }
2583
2584 if (!mfg &&
2585 ppd_make &&
2586 ppd_make[0] != '\0')
2587 {
2588 mfg = g_strdup (ppd_make);
2589 mfg_normalized = normalize (ppd_make);
2590 }
2591
2592 /* Get model */
2593 if (ppd_make_and_model &&
2594 ppd_make_and_model[0] != '\0')
2595 {
2596 mdl = g_strdup (ppd_make_and_model);
2597 }
2598
2599 if (!mdl &&
2600 ppd_product &&
2601 ppd_product[0] != '\0')
2602 {
2603 mdl = g_strdup (ppd_product);
2604 }
2605
2606 if (!mdl &&
2607 ppd_device_id &&
2608 ppd_device_id[0] != '\0')
2609 {
2610 mdl = get_tag_value (ppd_device_id, "mdl");
2611 if (!mdl)
2612 mdl = get_tag_value (ppd_device_id, "model");
2613 }
2614
2615 if (ppd_name && ppd_name[0] != '\0' &&
2616 mdl && mdl[0] != '\0' &&
2617 mfg && mfg[0] != '\0')
2618 {
2619 manufacturer_display_name = g_hash_table_lookup (manufacturers_hash, mfg_normalized);
2620 if (!manufacturer_display_name)
2621 {
2622 g_hash_table_insert (manufacturers_hash, g_strdup (mfg_normalized), g_strdup (mfg));
2623 }
2624 else
2625 {
2626 g_free (mfg_normalized);
2627 mfg_normalized = normalize (manufacturer_display_name);
2628 }
2629
2630 item = g_new0 (PPDName, 1);
2631 item->ppd_name = g_strdup (ppd_name);
2632 item->ppd_display_name = g_strdup (mdl);
2633 item->ppd_match_level = -1;
2634
2635 list = g_hash_table_lookup (ppds_hash, mfg_normalized);
2636 if (list)
2637 {
2638 list = g_list_append (list, item);
2639 }
2640 else
2641 {
2642 list = g_list_append (list, item);
2643 g_hash_table_insert (ppds_hash, g_strdup (mfg_normalized), list);
2644 }
2645 }
2646
2647 if (attr == NULL)
2648 break;
2649 }
2650 }
2651
2652 if (response)
2653 ippDelete(response);
2654
2655 if (ppds_hash &&
2656 manufacturers_hash)
2657 {
2658 GHashTableIter iter;
2659 gpointer key;
2660 gpointer value;
2661 GList *ppd_item;
2662 GList *sort_list = NULL;
2663 GList *list_iter;
2664 gchar *name;
2665
2666 data->result = g_new0 (PPDList, 1);
2667 data->result->num_of_manufacturers = g_hash_table_size (ppds_hash);
2668 data->result->manufacturers = g_new0 (PPDManufacturerItem *, data->result->num_of_manufacturers);
2669
2670 g_hash_table_iter_init (&iter, ppds_hash);
2671 while (g_hash_table_iter_next (&iter, &key, &value))
2672 {
2673 sort_list = g_list_append (sort_list, g_strdup (key));
2674 }
2675
2676 /* Sort list of manufacturers */
2677 sort_list = g_list_sort (sort_list, (GCompareFunc) g_strcmp0);
2678
2679 /*
2680 * Fill resulting list of lists (list of manufacturers where
2681 * each item contains list of PPD names)
2682 */
2683 i = 0;
2684 for (list_iter = sort_list; list_iter; list_iter = list_iter->next)
2685 {
2686 name = (gchar *) list_iter->data;
2687 value = g_hash_table_lookup (ppds_hash, name);
2688
2689 data->result->manufacturers[i] = g_new0 (PPDManufacturerItem, 1);
2690 data->result->manufacturers[i]->manufacturer_name = g_strdup (name);
2691 data->result->manufacturers[i]->manufacturer_display_name = g_strdup (g_hash_table_lookup (manufacturers_hash, name));
2692 data->result->manufacturers[i]->num_of_ppds = g_list_length ((GList *) value);
2693 data->result->manufacturers[i]->ppds = g_new0 (PPDName *, data->result->manufacturers[i]->num_of_ppds);
2694
2695 for (ppd_item = (GList *) value, j = 0; ppd_item; ppd_item = ppd_item->next, j++)
2696 {
2697 data->result->manufacturers[i]->ppds[j] = ppd_item->data;
2698 }
2699
2700 g_list_free ((GList *) value);
2701
2702 i++;
2703 }
2704
2705 g_list_free_full (sort_list, g_free);
2706 g_hash_table_destroy (ppds_hash);
2707 g_hash_table_destroy (manufacturers_hash);
2708 }
2709
2710 get_all_ppds_cb (data);
2711
2712 return NULL;
2713 }
2714
2715 /*
2716 * Get names of all installed PPDs sorted by manufacturers names.
2717 */
2718 void
2719 get_all_ppds_async (GCancellable *cancellable,
2720 GAPCallback callback,
2721 gpointer user_data)
2722 {
2723 GAPData *data;
2724 g_autoptr(GThread) thread = NULL;
2725 g_autoptr(GError) error = NULL;
2726
2727 data = gap_data_new (cancellable, callback, user_data);
2728
2729 thread = g_thread_try_new ("get-all-ppds",
2730 get_all_ppds_func,
2731 data,
2732 &error);
2733
2734 if (!thread)
2735 {
2736 g_warning ("%s", error->message);
2737 callback (NULL, user_data);
2738
2739 gap_data_free (data);
2740 }
2741 }
2742
2743 PPDList *
2744 ppd_list_copy (PPDList *list)
2745 {
2746 PPDList *result = NULL;
2747 gint i, j;
2748
2749 if (list)
2750 {
2751 result = g_new0 (PPDList, 1);
2752 result->num_of_manufacturers = list->num_of_manufacturers;
2753 result->manufacturers = g_new0 (PPDManufacturerItem *, list->num_of_manufacturers);
2754
2755 for (i = 0; i < result->num_of_manufacturers; i++)
2756 {
2757 result->manufacturers[i] = g_new0 (PPDManufacturerItem, 1);
2758 result->manufacturers[i]->num_of_ppds = list->manufacturers[i]->num_of_ppds;
2759 result->manufacturers[i]->ppds = g_new0 (PPDName *, result->manufacturers[i]->num_of_ppds);
2760
2761 result->manufacturers[i]->manufacturer_display_name =
2762 g_strdup (list->manufacturers[i]->manufacturer_display_name);
2763
2764 result->manufacturers[i]->manufacturer_name =
2765 g_strdup (list->manufacturers[i]->manufacturer_name);
2766
2767 for (j = 0; j < result->manufacturers[i]->num_of_ppds; j++)
2768 {
2769 result->manufacturers[i]->ppds[j] = g_new0 (PPDName, 1);
2770
2771 result->manufacturers[i]->ppds[j]->ppd_display_name =
2772 g_strdup (list->manufacturers[i]->ppds[j]->ppd_display_name);
2773
2774 result->manufacturers[i]->ppds[j]->ppd_name =
2775 g_strdup (list->manufacturers[i]->ppds[j]->ppd_name);
2776
2777 result->manufacturers[i]->ppds[j]->ppd_match_level =
2778 list->manufacturers[i]->ppds[j]->ppd_match_level;
2779 }
2780 }
2781 }
2782
2783 return result;
2784 }
2785
2786 void
2787 ppd_list_free (PPDList *list)
2788 {
2789 gint i, j;
2790
2791 if (list)
2792 {
2793 for (i = 0; i < list->num_of_manufacturers; i++)
2794 {
2795 for (j = 0; j < list->manufacturers[i]->num_of_ppds; j++)
2796 {
2797 g_free (list->manufacturers[i]->ppds[j]->ppd_name);
2798 g_free (list->manufacturers[i]->ppds[j]->ppd_display_name);
2799 g_free (list->manufacturers[i]->ppds[j]);
2800 }
2801
2802 g_free (list->manufacturers[i]->manufacturer_name);
2803 g_free (list->manufacturers[i]->manufacturer_display_name);
2804 g_free (list->manufacturers[i]->ppds);
2805 g_free (list->manufacturers[i]);
2806 }
2807
2808 g_free (list->manufacturers);
2809 g_free (list);
2810 }
2811 }
2812
2813 gchar *
2814 get_standard_manufacturers_name (const gchar *name)
2815 {
2816 g_autofree gchar *normalized_name = NULL;
2817 gint i;
2818
2819 if (name == NULL)
2820 return NULL;
2821
2822 normalized_name = normalize (name);
2823
2824 for (i = 0; i < G_N_ELEMENTS (manufacturers_names); i++)
2825 {
2826 if (g_strcmp0 (manufacturers_names[i].normalized_name, normalized_name) == 0)
2827 {
2828 return g_strdup (manufacturers_names[i].display_name);
2829 }
2830 }
2831
2832 return NULL;
2833 }
2834
2835 typedef struct
2836 {
2837 gchar *printer_name;
2838 gchar *host_name;
2839 gint port;
2840 gchar *result;
2841 PGPCallback callback;
2842 gpointer user_data;
2843 GMainContext *context;
2844 } PGPData;
2845
2846 static PGPData *
2847 pgp_data_new (const gchar *printer_name, const gchar *host_name, gint port, PGPCallback callback, gpointer user_data)
2848 {
2849 PGPData *data;
2850
2851 data = g_new0 (PGPData, 1);
2852 data->printer_name = g_strdup (printer_name);
2853 data->host_name = g_strdup (host_name);
2854 data->port = port;
2855 data->callback = callback;
2856 data->user_data = user_data;
2857 data->context = g_main_context_ref_thread_default ();
2858
2859 return data;
2860 }
2861
2862 static void
2863 pgp_data_free (PGPData *data)
2864 {
2865 g_free (data->printer_name);
2866 g_free (data->host_name);
2867 g_free (data->result);
2868 if (data->context)
2869 g_main_context_unref (data->context);
2870 g_free (data);
2871 }
2872
2873 static gboolean
2874 printer_get_ppd_idle_cb (gpointer user_data)
2875 {
2876 PGPData *data = user_data;
2877
2878 data->callback (data->result, data->user_data);
2879
2880 return FALSE;
2881 }
2882
2883 static void
2884 printer_get_ppd_cb (gpointer user_data)
2885 {
2886 PGPData *data = user_data;
2887 g_autoptr(GSource) idle_source = NULL;
2888
2889 idle_source = g_idle_source_new ();
2890 g_source_set_callback (idle_source,
2891 printer_get_ppd_idle_cb,
2892 data,
2893 (GDestroyNotify) pgp_data_free);
2894 g_source_attach (idle_source, data->context);
2895 }
2896
2897 static gpointer
2898 printer_get_ppd_func (gpointer user_data)
2899 {
2900 PGPData *data = user_data;
2901
2902 if (data->host_name)
2903 {
2904 http_t *http;
2905
2906 #ifdef HAVE_CUPS_HTTPCONNECT2
2907 http = httpConnect2 (data->host_name, data->port, NULL, AF_UNSPEC,
2908 HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL);
2909 #else
2910 http = httpConnect (data->host_name, data->port);
2911 #endif
2912 if (http)
2913 {
2914 data->result = g_strdup (cupsGetPPD2 (http, data->printer_name));
2915 httpClose (http);
2916 }
2917 }
2918 else
2919 {
2920 data->result = g_strdup (cupsGetPPD (data->printer_name));
2921 }
2922
2923 printer_get_ppd_cb (data);
2924
2925 return NULL;
2926 }
2927
2928 void
2929 printer_get_ppd_async (const gchar *printer_name,
2930 const gchar *host_name,
2931 gint port,
2932 PGPCallback callback,
2933 gpointer user_data)
2934 {
2935 PGPData *data;
2936 g_autoptr(GThread) thread = NULL;
2937 g_autoptr(GError) error = NULL;
2938
2939 data = pgp_data_new (printer_name, host_name, port, callback, user_data);
2940
2941 thread = g_thread_try_new ("printer-get-ppd",
2942 printer_get_ppd_func,
2943 data,
2944 &error);
2945
2946 if (!thread)
2947 {
2948 g_warning ("%s", error->message);
2949 callback (NULL, user_data);
2950
2951 pgp_data_free (data);
2952 }
2953 }
2954
2955 typedef struct
2956 {
2957 gchar *printer_name;
2958 cups_dest_t *result;
2959 GNDCallback callback;
2960 gpointer user_data;
2961 GMainContext *context;
2962 } GNDData;
2963
2964 static GNDData *
2965 gnd_data_new (const gchar *printer_name, GNDCallback callback, gpointer user_data)
2966 {
2967 GNDData *data;
2968
2969 data = g_new0 (GNDData, 1);
2970 data->printer_name = g_strdup (printer_name);
2971 data->callback = callback;
2972 data->user_data = user_data;
2973 data->context = g_main_context_ref_thread_default ();
2974
2975 return data;
2976 }
2977
2978 static void
2979 gnd_data_free (GNDData *data)
2980 {
2981 g_free (data->printer_name);
2982 if (data->context)
2983 g_main_context_unref (data->context);
2984 g_free (data);
2985 }
2986
2987 static gboolean
2988 get_named_dest_idle_cb (gpointer user_data)
2989 {
2990 GNDData *data = user_data;
2991
2992 data->callback (data->result, data->user_data);
2993
2994 return FALSE;
2995 }
2996
2997 static void
2998 get_named_dest_cb (gpointer user_data)
2999 {
3000 GNDData *data = user_data;
3001 g_autoptr(GSource) idle_source = NULL;
3002
3003 idle_source = g_idle_source_new ();
3004 g_source_set_callback (idle_source,
3005 get_named_dest_idle_cb,
3006 data,
3007 (GDestroyNotify) gnd_data_free);
3008 g_source_attach (idle_source, data->context);
3009 }
3010
3011 static gpointer
3012 get_named_dest_func (gpointer user_data)
3013 {
3014 GNDData *data = user_data;
3015
3016 data->result = cupsGetNamedDest (CUPS_HTTP_DEFAULT, data->printer_name, NULL);
3017
3018 get_named_dest_cb (data);
3019
3020 return NULL;
3021 }
3022
3023 void
3024 get_named_dest_async (const gchar *printer_name,
3025 GNDCallback callback,
3026 gpointer user_data)
3027 {
3028 GNDData *data;
3029 g_autoptr(GThread) thread = NULL;
3030 g_autoptr(GError) error = NULL;
3031
3032 data = gnd_data_new (printer_name, callback, user_data);
3033
3034 thread = g_thread_try_new ("get-named-dest",
3035 get_named_dest_func,
3036 data,
3037 &error);
3038
3039 if (!thread)
3040 {
3041 g_warning ("%s", error->message);
3042 callback (NULL, user_data);
3043
3044 gnd_data_free (data);
3045 }
3046 }
3047
3048 typedef struct
3049 {
3050 GCancellable *cancellable;
3051 PAOCallback callback;
3052 gpointer user_data;
3053 } PAOData;
3054
3055 static PAOData *
3056 pao_data_new (GCancellable *cancellable, PAOCallback callback, gpointer user_data)
3057 {
3058 PAOData *data;
3059
3060 data = g_new0 (PAOData, 1);
3061 if (cancellable)
3062 data->cancellable = g_object_ref (cancellable);
3063 data->callback = callback;
3064 data->user_data = user_data;
3065 return data;
3066 }
3067
3068 static void
3069 pao_data_free (PAOData *data)
3070 {
3071 g_clear_object (&data->cancellable);
3072 g_free (data);
3073 }
3074
3075 G_DEFINE_AUTOPTR_CLEANUP_FUNC (PAOData, pao_data_free)
3076
3077 static void
3078 printer_add_option_async_dbus_cb (GObject *source_object,
3079 GAsyncResult *res,
3080 gpointer user_data)
3081 {
3082 g_autoptr(GVariant) output = NULL;
3083 gboolean success = FALSE;
3084 g_autoptr(PAOData) data = user_data;
3085 g_autoptr(GError) error = NULL;
3086
3087 output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
3088 res,
3089 &error);
3090
3091 if (output)
3092 {
3093 const gchar *ret_error;
3094
3095 g_variant_get (output, "(&s)", &ret_error);
3096 if (ret_error[0] != '\0')
3097 g_warning ("cups-pk-helper: setting of an option failed: %s", ret_error);
3098 else
3099 success = TRUE;
3100 }
3101 else
3102 {
3103 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
3104 g_warning ("%s", error->message);
3105 }
3106
3107 if (!g_cancellable_is_cancelled (data->cancellable))
3108 data->callback (success, data->user_data);
3109 }
3110
3111 void
3112 printer_add_option_async (const gchar *printer_name,
3113 const gchar *option_name,
3114 gchar **values,
3115 gboolean set_default,
3116 GCancellable *cancellable,
3117 PAOCallback callback,
3118 gpointer user_data)
3119 {
3120 GVariantBuilder array_builder;
3121 g_autoptr(GDBusConnection) bus = NULL;
3122 g_autoptr(GError) error = NULL;
3123 gint i;
3124
3125 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
3126 if (!bus)
3127 {
3128 g_warning ("Failed to get system bus: %s", error->message);
3129 callback (FALSE, user_data);
3130 return;
3131 }
3132
3133 g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("as"));
3134 if (values)
3135 {
3136 for (i = 0; values[i]; i++)
3137 g_variant_builder_add (&array_builder, "s", values[i]);
3138 }
3139
3140 g_dbus_connection_call (bus,
3141 MECHANISM_BUS,
3142 "/",
3143 MECHANISM_BUS,
3144 set_default ? "PrinterAddOptionDefault" :
3145 "PrinterAddOption",
3146 g_variant_new ("(ssas)",
3147 printer_name,
3148 option_name,
3149 &array_builder),
3150 G_VARIANT_TYPE ("(s)"),
3151 G_DBUS_CALL_FLAGS_NONE,
3152 DBUS_TIMEOUT,
3153 cancellable,
3154 printer_add_option_async_dbus_cb,
3155 pao_data_new (cancellable, callback, user_data));
3156 }
3157
3158 typedef struct
3159 {
3160 GList *backend_list;
3161 GCancellable *cancellable;
3162 GCDCallback callback;
3163 gpointer user_data;
3164 } GCDData;
3165
3166 static GCDData *
3167 gcd_data_new (GList *backend_list, GCancellable *cancellable, GCDCallback callback, gpointer user_data)
3168 {
3169 GCDData *data;
3170
3171 data = g_new0 (GCDData, 1);
3172 data->backend_list = backend_list;
3173 if (cancellable)
3174 data->cancellable = g_object_ref (cancellable);
3175 data->callback = callback;
3176 data->user_data = user_data;
3177
3178 return data;
3179 }
3180
3181 static void
3182 gcd_data_free (GCDData *data)
3183 {
3184 g_list_free_full (data->backend_list, g_free);
3185 g_clear_object (&data->cancellable);
3186 g_free (data);
3187 }
3188
3189 G_DEFINE_AUTOPTR_CLEANUP_FUNC (GCDData, gcd_data_free)
3190
3191 static gint
3192 get_suffix_index (const gchar *string)
3193 {
3194 gchar *number;
3195 gchar *endptr;
3196 gint index = -1;
3197
3198 number = g_strrstr (string, ":");
3199 if (number)
3200 {
3201 number++;
3202 index = g_ascii_strtoll (number, &endptr, 10);
3203 if (index == 0 && endptr == number)
3204 index = -1;
3205 }
3206
3207 return index;
3208 }
3209
3210 static void
3211 get_cups_devices_async_dbus_cb (GObject *source_object,
3212 GAsyncResult *res,
3213 gpointer user_data)
3214
3215 {
3216 g_autoptr(GPtrArray) devices = NULL;
3217 g_autoptr(GVariant) output = NULL;
3218 g_autoptr(GCDData) data = user_data;
3219 g_autoptr(GError) error = NULL;
3220 gint num_of_devices = 0;
3221
3222 output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
3223 res,
3224 &error);
3225
3226 if (output)
3227 {
3228 const gchar *ret_error;
3229 g_autoptr(GVariant) devices_variant = NULL;
3230 gboolean is_network_device;
3231 g_autoptr(GVariantIter) iter = NULL;
3232 const gchar *key, *value;
3233 gint index = -1, max_index = -1, i;
3234
3235 g_variant_get (output, "(&s@a{ss})",
3236 &ret_error,
3237 &devices_variant);
3238
3239 if (ret_error[0] != '\0')
3240 {
3241 g_warning ("cups-pk-helper: getting of CUPS devices failed: %s", ret_error);
3242 }
3243
3244 g_variant_get (devices_variant, "a{ss}", &iter);
3245 while (g_variant_iter_next (iter, "{&s&s}", &key, &value))
3246 {
3247 index = get_suffix_index (key);
3248 if (index > max_index)
3249 max_index = index;
3250 }
3251
3252 if (max_index >= 0)
3253 {
3254 g_autoptr(GVariantIter) iter2 = NULL;
3255
3256 num_of_devices = max_index + 1;
3257 devices = g_ptr_array_new_with_free_func (g_object_unref);
3258 for (i = 0; i < num_of_devices; i++)
3259 g_ptr_array_add (devices, pp_print_device_new ());
3260
3261 g_variant_get (devices_variant, "a{ss}", &iter2);
3262 while (g_variant_iter_next (iter2, "{&s&s}", &key, &value))
3263 {
3264 PpPrintDevice *device;
3265
3266 index = get_suffix_index (key);
3267 if (index >= 0)
3268 {
3269 device = g_ptr_array_index (devices, index);
3270 if (g_str_has_prefix (key, "device-class"))
3271 {
3272 is_network_device = g_strcmp0 (value, "network") == 0;
3273 g_object_set (device, "is-network-device", is_network_device, NULL);
3274 }
3275 else if (g_str_has_prefix (key, "device-id"))
3276 g_object_set (device, "device-id", value, NULL);
3277 else if (g_str_has_prefix (key, "device-info"))
3278 g_object_set (device, "device-info", value, NULL);
3279 else if (g_str_has_prefix (key, "device-make-and-model"))
3280 {
3281 g_object_set (device,
3282 "device-make-and-model", value,
3283 "device-name", value,
3284 NULL);
3285 }
3286 else if (g_str_has_prefix (key, "device-uri"))
3287 g_object_set (device, "device-uri", value, NULL);
3288 else if (g_str_has_prefix (key, "device-location"))
3289 g_object_set (device, "device-location", value, NULL);
3290
3291 g_object_set (device, "acquisition-method", ACQUISITION_METHOD_DEFAULT_CUPS_SERVER, NULL);
3292 }
3293 }
3294 }
3295 }
3296 else
3297 {
3298 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
3299 g_warning ("%s", error->message);
3300
3301 data->callback (devices,
3302 TRUE,
3303 g_cancellable_is_cancelled (data->cancellable),
3304 data->user_data);
3305 return;
3306 }
3307
3308 if (data->backend_list)
3309 {
3310 if (!g_cancellable_is_cancelled (data->cancellable))
3311 {
3312 GVariantBuilder *include_scheme_builder = NULL;
3313 GVariantBuilder *exclude_scheme_builder = NULL;
3314 g_autofree gchar *backend_name = NULL;
3315
3316 backend_name = data->backend_list->data;
3317
3318 data->callback (devices,
3319 FALSE,
3320 FALSE,
3321 data->user_data);
3322
3323 if (g_strcmp0 (backend_name, OTHER_BACKENDS) != 0)
3324 {
3325 include_scheme_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
3326 g_variant_builder_add (include_scheme_builder, "s", backend_name);
3327 }
3328 else
3329 {
3330 exclude_scheme_builder = create_other_backends_array ();
3331 }
3332
3333 data->backend_list = g_list_delete_link (data->backend_list, data->backend_list);
3334
3335 g_dbus_connection_call (G_DBUS_CONNECTION (g_object_ref (source_object)),
3336 MECHANISM_BUS,
3337 "/",
3338 MECHANISM_BUS,
3339 "DevicesGet",
3340 g_variant_new ("(iiasas)",
3341 0,
3342 0,
3343 include_scheme_builder,
3344 exclude_scheme_builder),
3345 G_VARIANT_TYPE ("(sa{ss})"),
3346 G_DBUS_CALL_FLAGS_NONE,
3347 DBUS_TIMEOUT,
3348 data->cancellable,
3349 get_cups_devices_async_dbus_cb,
3350 data);
3351 g_steal_pointer (&data);
3352
3353 if (include_scheme_builder)
3354 g_variant_builder_unref (include_scheme_builder);
3355
3356 if (exclude_scheme_builder)
3357 g_variant_builder_unref (exclude_scheme_builder);
3358
3359 return;
3360 }
3361 else
3362 {
3363 data->callback (devices,
3364 TRUE,
3365 TRUE,
3366 data->user_data);
3367 }
3368 }
3369 else
3370 {
3371 data->callback (devices,
3372 TRUE,
3373 g_cancellable_is_cancelled (data->cancellable),
3374 data->user_data);
3375 }
3376 }
3377
3378 void
3379 get_cups_devices_async (GCancellable *cancellable,
3380 GCDCallback callback,
3381 gpointer user_data)
3382 {
3383 g_autoptr(GDBusConnection) bus = NULL;
3384 GVariantBuilder include_scheme_builder;
3385 GList *backend_list;
3386 g_autoptr(GError) error = NULL;
3387 g_autofree gchar *backend_name = NULL;
3388
3389 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
3390 if (!bus)
3391 {
3392 g_warning ("Failed to get system bus: %s", error->message);
3393 callback (NULL, TRUE, FALSE, user_data);
3394 return;
3395 }
3396
3397 backend_list = create_backends_list ();
3398
3399 backend_name = backend_list->data;
3400
3401 g_variant_builder_init (&include_scheme_builder, G_VARIANT_TYPE ("as"));
3402 g_variant_builder_add (&include_scheme_builder, "s", backend_name);
3403
3404 backend_list = g_list_delete_link (backend_list, backend_list);
3405
3406 g_dbus_connection_call (bus,
3407 MECHANISM_BUS,
3408 "/",
3409 MECHANISM_BUS,
3410 "DevicesGet",
3411 g_variant_new ("(iiasas)",
3412 0,
3413 0,
3414 &include_scheme_builder,
3415 NULL),
3416 G_VARIANT_TYPE ("(sa{ss})"),
3417 G_DBUS_CALL_FLAGS_NONE,
3418 DBUS_TIMEOUT,
3419 cancellable,
3420 get_cups_devices_async_dbus_cb,
3421 gcd_data_new (backend_list, cancellable, callback, user_data));
3422 }
3423
3424 gchar *
3425 guess_device_hostname (PpPrintDevice *device)
3426 {
3427 http_uri_status_t status;
3428 char scheme[HTTP_MAX_URI];
3429 char username[HTTP_MAX_URI];
3430 char hostname[HTTP_MAX_URI];
3431 char resource[HTTP_MAX_URI];
3432 int port;
3433 gchar *result = NULL;
3434 gchar *hostname_begin;
3435 gchar *hostname_end = NULL;
3436
3437 if (device != NULL && pp_print_device_get_device_uri (device) != NULL)
3438 {
3439 if (g_str_has_prefix (pp_print_device_get_device_uri (device), "socket") ||
3440 g_str_has_prefix (pp_print_device_get_device_uri (device), "lpd") ||
3441 g_str_has_prefix (pp_print_device_get_device_uri (device), "ipp") ||
3442 g_str_has_prefix (pp_print_device_get_device_uri (device), "smb"))
3443 {
3444 status = httpSeparateURI (HTTP_URI_CODING_ALL,
3445 pp_print_device_get_device_uri (device),
3446 scheme, HTTP_MAX_URI,
3447 username, HTTP_MAX_URI,
3448 hostname, HTTP_MAX_URI,
3449 &port,
3450 resource, HTTP_MAX_URI);
3451
3452 if (status >= HTTP_URI_STATUS_OK &&
3453 hostname[0] != '\0')
3454 result = g_strdup (hostname);
3455 }
3456 else if ((g_str_has_prefix (pp_print_device_get_device_uri (device), "dnssd") ||
3457 g_str_has_prefix (pp_print_device_get_device_uri (device), "mdns")) &&
3458 pp_print_device_get_device_info (device) != NULL)
3459 {
3460 /*
3461 * CUPS browses its printers as
3462 * "PrinterName @ ComputerName" or "PrinterInfo @ ComputerName"
3463 * through DNS-SD.
3464 */
3465 hostname_begin = g_strrstr (pp_print_device_get_device_info (device), " @ ");
3466 if (hostname_begin != NULL)
3467 result = g_strdup (hostname_begin + 3);
3468 }
3469 else if (g_str_has_prefix (pp_print_device_get_device_uri (device), "hp:/net/") ||
3470 g_str_has_prefix (pp_print_device_get_device_uri (device), "hpfax:/net/"))
3471 {
3472 /*
3473 * HPLIP printers have URI of form hp:/net/%s?ip=%s&port=%d
3474 * or hp:/net/%s?ip=%s.
3475 */
3476 hostname_begin = g_strrstr (pp_print_device_get_device_uri (device), "ip=");
3477 if (hostname_begin != NULL)
3478 {
3479 hostname_begin += 3;
3480 hostname_end = strstr (hostname_begin, "&");
3481 }
3482
3483 if (hostname_end != NULL)
3484 result = g_strndup (hostname_begin, hostname_end - hostname_begin);
3485 else
3486 result = g_strdup (hostname_begin);
3487 }
3488 }
3489
3490 return result;
3491 }
3492
3493 gchar *
3494 canonicalize_device_name (GList *device_names,
3495 GPtrArray *local_cups_devices,
3496 cups_dest_t *dests,
3497 gint num_of_dests,
3498 PpPrintDevice *device)
3499 {
3500 PpPrintDevice *item;
3501 gboolean already_present;
3502 GList *iter;
3503 gsize len;
3504 g_autofree gchar *name = NULL;
3505 gchar *occurrence;
3506 gint name_index, j;
3507 static const char * const residues[] = {
3508 "-foomatic",
3509 "-hpijs",
3510 "-hpcups",
3511 "-cups",
3512 "-gutenprint",
3513 "-series",
3514 "-label-printer",
3515 "-dot-matrix",
3516 "-ps3",
3517 "-ps2",
3518 "-br-script",
3519 "-kpdl",
3520 "-pcl3",
3521 "-pcl",
3522 "-zxs",
3523 "-pxl"};
3524
3525 if (pp_print_device_get_device_id (device) != NULL)
3526 {
3527 name = get_tag_value (pp_print_device_get_device_id (device), "mdl");
3528 if (name == NULL)
3529 name = get_tag_value (pp_print_device_get_device_id (device), "model");
3530 }
3531
3532 if (name == NULL &&
3533 pp_print_device_get_device_make_and_model (device) != NULL &&
3534 pp_print_device_get_device_make_and_model (device)[0] != '\0')
3535 {
3536 name = g_strdup (pp_print_device_get_device_make_and_model (device));
3537 }
3538
3539 if (name == NULL &&
3540 pp_print_device_get_device_original_name (device) != NULL &&
3541 pp_print_device_get_device_original_name (device)[0] != '\0')
3542 {
3543 name = g_strdup (pp_print_device_get_device_original_name (device));
3544 }
3545
3546 if (name == NULL &&
3547 pp_print_device_get_device_info (device) != NULL &&
3548 pp_print_device_get_device_info (device)[0] != '\0')
3549 {
3550 name = g_strdup (pp_print_device_get_device_info (device));
3551 }
3552
3553 if (name == NULL)
3554 return NULL;
3555
3556 g_strstrip (name);
3557 g_strcanon (name, ALLOWED_CHARACTERS, '-');
3558
3559 /* Remove common strings found in driver names */
3560 for (j = 0; j < G_N_ELEMENTS (residues); j++)
3561 {
3562 g_autofree gchar *lower_name = g_ascii_strdown (name, -1);
3563
3564 occurrence = g_strrstr (lower_name, residues[j]);
3565 if (occurrence != NULL)
3566 {
3567 occurrence[0] = '\0';
3568 name[strlen (lower_name)] = '\0';
3569 }
3570 }
3571
3572 /* Remove trailing "-" */
3573 len = strlen (name);
3574 while (len-- && name[len] == '-')
3575 name[len] = '\0';
3576
3577 /* Merge "--" to "-" */
3578 occurrence = g_strrstr (name, "--");
3579 while (occurrence != NULL)
3580 {
3581 shift_string_left (occurrence);
3582 occurrence = g_strrstr (name, "--");
3583 }
3584
3585 /* Remove leading "-" */
3586 if (name[0] == '-')
3587 shift_string_left (name);
3588
3589 name_index = 2;
3590 already_present = FALSE;
3591 while (TRUE)
3592 {
3593 g_autofree gchar *new_name = NULL;
3594
3595 if (already_present)
3596 {
3597 new_name = g_strdup_printf ("%s-%d", name, name_index);
3598 name_index++;
3599 }
3600 else
3601 {
3602 new_name = g_strdup (name);
3603 }
3604
3605 already_present = FALSE;
3606 for (j = 0; j < num_of_dests; j++)
3607 if (g_strcmp0 (dests[j].name, new_name) == 0)
3608 already_present = TRUE;
3609
3610 for (iter = device_names; iter; iter = iter->next)
3611 {
3612 gchar *device_original_name = iter->data;
3613 if (g_strcmp0 (device_original_name, new_name) == 0)
3614 already_present = TRUE;
3615 }
3616
3617 for (guint i = 0; i < local_cups_devices->len; i++)
3618 {
3619 item = g_ptr_array_index (local_cups_devices, i);
3620 if (g_strcmp0 (pp_print_device_get_device_original_name (item), new_name) == 0)
3621 already_present = TRUE;
3622 }
3623
3624 if (!already_present)
3625 return g_steal_pointer (&new_name);
3626 }
3627 }
3628
3629 void
3630 7 shift_string_left (gchar *str)
3631 {
3632 gchar *next;
3633
3634
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 if (str != NULL && str[0] != '\0')
3635 {
3636 7 next = g_utf8_find_next_char (str, NULL);
3637 7 memmove (str, next, strlen (next) + 1);
3638 }
3639 7 }
3640
3641 gboolean
3642 printer_name_is_valid (const gchar *str)
3643 {
3644 const gchar *invalid_chars = " \t#/";
3645 return strlen(str) == strcspn(str, invalid_chars);
3646 }
3647