Bug Summary

File:modules/printbackends/cups/ctkprintbackendcups.c
Warning:line 1774, column 3
Value stored to 'state' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ctkprintbackendcups.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/modules/printbackends/cups -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I ../../.. -I ../../.. -I ../../../ctk -I ../../../ctk -I ../../../cdk -I ../../../cdk -I /usr/include/colord-1 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/libmount -I /usr/include/blkid -D CTK_COMPILATION -D CTK_PRINT_BACKEND_ENABLE_UNSUPPORTED -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/atk-1.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gio-unix-2.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/pango-1.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/modules/printbackends/cups -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-172619-43637-1 -x c ctkprintbackendcups.c
1/* CTK - The GIMP Toolkit
2 * ctkprintbackendcups.h: Default implementation of CtkPrintBackend
3 * for the Common Unix Print System (CUPS)
4 * Copyright (C) 2006, 2007 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "config.h"
21#include <ctype.h>
22#include <unistd.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <stdlib.h>
26#include <time.h>
27
28/* Cups 1.6 deprecates ppdFindAttr(), ppdFindCustomOption(),
29 * ppdFirstCustomParam(), and ppdNextCustomParam() among others. This
30 * turns off the warning so that it will compile.
31 */
32#define _PPD_DEPRECATED
33
34#include <cups/cups.h>
35#include <cups/language.h>
36#include <cups/http.h>
37#include <cups/ipp.h>
38#include <errno(*__errno_location ()).h>
39#include <cairo.h>
40#include <cairo-pdf.h>
41#include <cairo-ps.h>
42
43#include <glib/gstdio.h>
44#include <glib/gi18n-lib.h>
45#include <gmodule.h>
46
47#include <ctk/ctk.h>
48#include <ctk/ctkprintbackend.h>
49#include <ctk/ctkunixprint.h>
50#include <ctk/ctkprinter-private.h>
51
52#include "ctkprintbackendcups.h"
53#include "ctkprintercups.h"
54
55#include "ctkcupsutils.h"
56#include "ctkcupssecretsutils.h"
57
58#include <ctkprintutils.h>
59
60#ifdef HAVE_COLORD1
61#include <colord.h>
62#endif
63
64#if ((CUPS_VERSION_MAJOR2 == 2 && CUPS_VERSION_MINOR4 >= 2) || CUPS_VERSION_MAJOR2 > 2)
65#define HAVE_CUPS_2_2
66#endif
67
68typedef struct _CtkPrintBackendCupsClass CtkPrintBackendCupsClass;
69
70#define CTK_PRINT_BACKEND_CUPS_CLASS(klass)((((CtkPrintBackendCupsClass*) (void *) g_type_check_class_cast
((GTypeClass*) ((klass)), ((ctk_print_backend_cups_get_type (
)))))))
(G_TYPE_CHECK_CLASS_CAST ((klass), CTK_TYPE_PRINT_BACKEND_CUPS, CtkPrintBackendCupsClass)(((CtkPrintBackendCupsClass*) (void *) g_type_check_class_cast
((GTypeClass*) ((klass)), ((ctk_print_backend_cups_get_type (
))))))
)
71#define CTK_IS_PRINT_BACKEND_CUPS_CLASS(klass)(((__extension__ ({ GTypeClass *__class = (GTypeClass*) ((klass
)); GType __t = ((ctk_print_backend_cups_get_type ())); gboolean
__r; if (!__class) __r = (0); else if (__class->g_type ==
__t) __r = (!(0)); else __r = g_type_check_class_is_a (__class
, __t); __r; }))))
(G_TYPE_CHECK_CLASS_TYPE ((klass), CTK_TYPE_PRINT_BACKEND_CUPS)((__extension__ ({ GTypeClass *__class = (GTypeClass*) ((klass
)); GType __t = ((ctk_print_backend_cups_get_type ())); gboolean
__r; if (!__class) __r = (0); else if (__class->g_type ==
__t) __r = (!(0)); else __r = g_type_check_class_is_a (__class
, __t); __r; })))
)
72#define CTK_PRINT_BACKEND_CUPS_GET_CLASS(obj)((((CtkPrintBackendCupsClass*) (((GTypeInstance*) ((obj)))->
g_class))))
(G_TYPE_INSTANCE_GET_CLASS ((obj), CTK_TYPE_PRINT_BACKEND_CUPS, CtkPrintBackendCupsClass)(((CtkPrintBackendCupsClass*) (((GTypeInstance*) ((obj)))->
g_class)))
)
73
74#define _CUPS_MAX_ATTEMPTS10 10
75#define _CUPS_MAX_CHUNK_SIZE8192 8192
76
77#define AVAHI_IF_UNSPEC-1 -1
78#define AVAHI_PROTO_INET0 0
79#define AVAHI_PROTO_INET61 1
80#define AVAHI_PROTO_UNSPEC-1 -1
81
82#define AVAHI_BUS"org.freedesktop.Avahi" "org.freedesktop.Avahi"
83#define AVAHI_SERVER_IFACE"org.freedesktop.Avahi.Server" "org.freedesktop.Avahi.Server"
84#define AVAHI_SERVICE_BROWSER_IFACE"org.freedesktop.Avahi.ServiceBrowser" "org.freedesktop.Avahi.ServiceBrowser"
85#define AVAHI_SERVICE_RESOLVER_IFACE"org.freedesktop.Avahi.ServiceResolver" "org.freedesktop.Avahi.ServiceResolver"
86
87#define PRINTER_NAME_ALLOWED_CHARACTERS"abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_" "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
88/* define this to see warnings about ignored ppd options */
89#undef PRINT_IGNORED_OPTIONS
90
91#define _CUPS_MAP_ATTR_INT(attr, v, a){if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values
[0].integer;}
{if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].integer;}
92#define _CUPS_MAP_ATTR_STR(attr, v, a){if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values
[0].string.text;}
{if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].string.text;}
93
94static GType print_backend_cups_type = 0;
95
96typedef void (* CtkPrintCupsResponseCallbackFunc) (CtkPrintBackend *print_backend,
97 CtkCupsResult *result,
98 gpointer user_data);
99
100typedef enum
101{
102 DISPATCH_SETUP,
103 DISPATCH_REQUEST,
104 DISPATCH_SEND,
105 DISPATCH_CHECK,
106 DISPATCH_READ,
107 DISPATCH_ERROR
108} CtkPrintCupsDispatchState;
109
110typedef struct
111{
112 GSource source;
113
114 http_t *http;
115 CtkCupsRequest *request;
116 CtkCupsPollState poll_state;
117 GPollFD *data_poll;
118 CtkPrintBackendCups *backend;
119 CtkPrintCupsResponseCallbackFunc callback;
120 gpointer callback_data;
121
122} CtkPrintCupsDispatchWatch;
123
124struct _CtkPrintBackendCupsClass
125{
126 CtkPrintBackendClass parent_class;
127};
128
129struct _CtkPrintBackendCups
130{
131 CtkPrintBackend parent_instance;
132
133 char *default_printer;
134
135 guint list_printers_poll;
136 guint list_printers_pending : 1;
137 gint list_printers_attempts;
138 guint got_default_printer : 1;
139 guint default_printer_poll;
140 CtkCupsConnectionTest *cups_connection_test;
141 gint reading_ppds;
142
143 GList *requests;
144 GHashTable *auth;
145 gchar *username;
146 gboolean authentication_lock;
147#ifdef HAVE_COLORD1
148 CdClient *colord_client;
149#endif
150
151 GDBusConnection *dbus_connection;
152 char *avahi_default_printer;
153 guint avahi_service_browser_subscription_id;
154 guint avahi_service_browser_subscription_ids[2];
155 char *avahi_service_browser_paths[2];
156 GCancellable *avahi_cancellable;
157 guint unsubscribe_general_subscription_id;
158
159 gboolean secrets_service_available;
160 guint secrets_service_watch_id;
161 GCancellable *secrets_service_cancellable;
162
163 GList *temporary_queues_in_construction;
164 GList *temporary_queues_removed;
165};
166
167static GObjectClass *backend_parent_class;
168
169static void ctk_print_backend_cups_class_init (CtkPrintBackendCupsClass *class);
170static void ctk_print_backend_cups_init (CtkPrintBackendCups *impl);
171static void ctk_print_backend_cups_finalize (GObject *object);
172static void ctk_print_backend_cups_dispose (GObject *object);
173static void cups_get_printer_list (CtkPrintBackend *print_backend);
174static void cups_get_default_printer (CtkPrintBackendCups *print_backend);
175static void cups_get_local_default_printer (CtkPrintBackendCups *print_backend);
176static void cups_request_execute (CtkPrintBackendCups *print_backend,
177 CtkCupsRequest *request,
178 CtkPrintCupsResponseCallbackFunc callback,
179 gpointer user_data,
180 GDestroyNotify notify);
181static void cups_printer_get_settings_from_options (CtkPrinter *printer,
182 CtkPrinterOptionSet *options,
183 CtkPrintSettings *settings);
184static gboolean cups_printer_mark_conflicts (CtkPrinter *printer,
185 CtkPrinterOptionSet *options);
186static CtkPrinterOptionSet *cups_printer_get_options (CtkPrinter *printer,
187 CtkPrintSettings *settings,
188 CtkPageSetup *page_setup,
189 CtkPrintCapabilities capabilities);
190static void cups_printer_prepare_for_print (CtkPrinter *printer,
191 CtkPrintJob *print_job,
192 CtkPrintSettings *settings,
193 CtkPageSetup *page_setup);
194static GList * cups_printer_list_papers (CtkPrinter *printer);
195static CtkPageSetup * cups_printer_get_default_page_size (CtkPrinter *printer);
196static void cups_printer_request_details (CtkPrinter *printer);
197static gboolean cups_request_default_printer (CtkPrintBackendCups *print_backend);
198static gboolean cups_request_ppd (CtkPrinter *printer);
199static gboolean cups_printer_get_hard_margins (CtkPrinter *printer,
200 gdouble *top,
201 gdouble *bottom,
202 gdouble *left,
203 gdouble *right);
204static gboolean cups_printer_get_hard_margins_for_paper_size (CtkPrinter *printer,
205 CtkPaperSize *paper_size,
206 gdouble *top,
207 gdouble *bottom,
208 gdouble *left,
209 gdouble *right);
210static CtkPrintCapabilities cups_printer_get_capabilities (CtkPrinter *printer);
211static void set_option_from_settings (CtkPrinterOption *option,
212 CtkPrintSettings *setting);
213static void cups_begin_polling_info (CtkPrintBackendCups *print_backend,
214 CtkPrintJob *job,
215 int job_id);
216static gboolean cups_job_info_poll_timeout (gpointer user_data);
217static void ctk_print_backend_cups_print_stream (CtkPrintBackend *backend,
218 CtkPrintJob *job,
219 GIOChannel *data_io,
220 CtkPrintJobCompleteFunc callback,
221 gpointer user_data,
222 GDestroyNotify dnotify);
223static cairo_surface_t * cups_printer_create_cairo_surface (CtkPrinter *printer,
224 CtkPrintSettings *settings,
225 gdouble width,
226 gdouble height,
227 GIOChannel *cache_io);
228
229static void ctk_print_backend_cups_set_password (CtkPrintBackend *backend,
230 gchar **auth_info_required,
231 gchar **auth_info,
232 gboolean store_auth_info);
233
234void overwrite_and_free (gpointer data);
235static gboolean is_address_local (const gchar *address);
236static gboolean request_auth_info (gpointer data);
237static void lookup_auth_info (gpointer data);
238
239static void avahi_request_printer_list (CtkPrintBackendCups *cups_backend);
240
241static void secrets_service_appeared_cb (GDBusConnection *connection,
242 const gchar *name,
243 const gchar *name_owner,
244 gpointer user_data);
245static void secrets_service_vanished_cb (GDBusConnection *connection,
246 const gchar *name,
247 gpointer user_data);
248
249#ifdef HAVE_CUPS_2_2
250static void create_temporary_queue (CtkPrintBackendCups *backend,
251 const gchar *printer_name,
252 const gchar *printer_uri,
253 const gchar *device_uri);
254#endif
255
256static void
257ctk_print_backend_cups_register_type (GTypeModule *module)
258{
259 const GTypeInfo print_backend_cups_info =
260 {
261 .class_size = sizeof (CtkPrintBackendCupsClass),
262 .class_init = (GClassInitFunc) ctk_print_backend_cups_class_init,
263 .instance_size = sizeof (CtkPrintBackendCups),
264 .n_preallocs = 0,
265 .instance_init = (GInstanceInitFunc) ctk_print_backend_cups_init
266 };
267
268 print_backend_cups_type = g_type_module_register_type (module,
269 CTK_TYPE_PRINT_BACKEND(ctk_print_backend_get_type ()),
270 "CtkPrintBackendCups",
271 &print_backend_cups_info, 0);
272}
273
274G_MODULE_EXPORT__attribute__((visibility("default"))) void
275pb_module_init (GTypeModule *module)
276{
277 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Initializing the CUPS print backend module\n"
); }; } while (0)
278 g_print ("CUPS Backend: Initializing the CUPS print backend module\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Initializing the CUPS print backend module\n"
); }; } while (0)
;
279
280 ctk_print_backend_cups_register_type (module);
281 ctk_printer_cups_register_type (module);
282}
283
284G_MODULE_EXPORT__attribute__((visibility("default"))) void
285pb_module_exit (void)
286{
287
288}
289
290G_MODULE_EXPORT__attribute__((visibility("default"))) CtkPrintBackend *
291pb_module_create (void)
292{
293 return ctk_print_backend_cups_new ();
294}
295/*
296 * CtkPrintBackendCups
297 */
298GType
299ctk_print_backend_cups_get_type (void)
300{
301 return print_backend_cups_type;
302}
303
304/**
305 * ctk_print_backend_cups_new:
306 *
307 * Creates a new #CtkPrintBackendCups object. #CtkPrintBackendCups
308 * implements the #CtkPrintBackend interface with direct access to
309 * the filesystem using Unix/Linux API calls
310 *
311 * Returns: the new #CtkPrintBackendCups object
312 */
313CtkPrintBackend *
314ctk_print_backend_cups_new (void)
315{
316 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Creating a new CUPS print backend object\n"
); }; } while (0)
317 g_print ("CUPS Backend: Creating a new CUPS print backend object\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Creating a new CUPS print backend object\n"
); }; } while (0)
;
318
319 return g_object_new (CTK_TYPE_PRINT_BACKEND_CUPS(ctk_print_backend_cups_get_type ()), NULL((void*)0));
320}
321
322static void
323ctk_print_backend_cups_class_init (CtkPrintBackendCupsClass *class)
324{
325 GObjectClass *gobject_class = G_OBJECT_CLASS (class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), (((GType) ((20) << (2))))))))
;
326 CtkPrintBackendClass *backend_class = CTK_PRINT_BACKEND_CLASS (class)((((CtkPrintBackendClass*) (void *) g_type_check_class_cast (
(GTypeClass*) ((class)), ((ctk_print_backend_get_type ())))))
)
;
327
328 backend_parent_class = g_type_class_peek_parent (class);
329
330 gobject_class->finalize = ctk_print_backend_cups_finalize;
331 gobject_class->dispose = ctk_print_backend_cups_dispose;
332
333 backend_class->request_printer_list = cups_get_printer_list;
334 backend_class->print_stream = ctk_print_backend_cups_print_stream;
335 backend_class->printer_request_details = cups_printer_request_details;
336 backend_class->printer_create_cairo_surface = cups_printer_create_cairo_surface;
337 backend_class->printer_get_options = cups_printer_get_options;
338 backend_class->printer_mark_conflicts = cups_printer_mark_conflicts;
339 backend_class->printer_get_settings_from_options = cups_printer_get_settings_from_options;
340 backend_class->printer_prepare_for_print = cups_printer_prepare_for_print;
341 backend_class->printer_list_papers = cups_printer_list_papers;
342 backend_class->printer_get_default_page_size = cups_printer_get_default_page_size;
343 backend_class->printer_get_hard_margins = cups_printer_get_hard_margins;
344 backend_class->printer_get_hard_margins_for_paper_size = cups_printer_get_hard_margins_for_paper_size;
345 backend_class->printer_get_capabilities = cups_printer_get_capabilities;
346 backend_class->set_password = ctk_print_backend_cups_set_password;
347}
348
349static gboolean
350option_is_ipp_option (CtkPrinterOption *option)
351{
352 gpointer data = g_object_get_data (G_OBJECT (option)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((option)), (((GType) ((20) << (2))))))))
, "is-ipp-option");
353
354 if (data != NULL((void*)0))
355 return GPOINTER_TO_UINT (data)((guint) (gulong) (data)) != 0;
356 else
357 return FALSE(0);
358}
359
360static void
361option_set_is_ipp_option (CtkPrinterOption *option,
362 gboolean is_ipp_option)
363{
364 g_object_set_data (G_OBJECT (option)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((option)), (((GType) ((20) << (2))))))))
,
365 "is-ipp-option",
366 GUINT_TO_POINTER (is_ipp_option ? 1 : 0)((gpointer) (gulong) (is_ipp_option ? 1 : 0)));
367}
368
369static cairo_status_t
370_cairo_write_to_cups (void *closure,
371 const unsigned char *data,
372 unsigned int length)
373{
374 GIOChannel *io = (GIOChannel *)closure;
375 gsize written;
376 GError *error;
377
378 error = NULL((void*)0);
379
380 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Writing %i byte chunk to temp file\n"
, length); }; } while (0)
381 g_print ("CUPS Backend: Writing %i byte chunk to temp file\n", length))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Writing %i byte chunk to temp file\n"
, length); }; } while (0)
;
382
383 while (length > 0)
384 {
385 g_io_channel_write_chars (io, (gchar *)data, length, &written, &error);
386
387 if (error != NULL((void*)0))
388 {
389 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Error writing to temp file, %s\n", error
->message); }; } while (0)
390 g_print ("CUPS Backend: Error writing to temp file, %s\n",do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Error writing to temp file, %s\n", error
->message); }; } while (0)
391 error->message))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Error writing to temp file, %s\n", error
->message); }; } while (0)
;
392
393 g_error_free (error);
394 return CAIRO_STATUS_WRITE_ERROR;
395 }
396
397 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Wrote %""lu"" bytes to temp file\n",
written); }; } while (0)
398 g_print ("CUPS Backend: Wrote %"G_GSIZE_FORMAT" bytes to temp file\n", written))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Wrote %""lu"" bytes to temp file\n",
written); }; } while (0)
;
399
400 data += written;
401 length -= written;
402 }
403
404 return CAIRO_STATUS_SUCCESS;
405}
406
407static cairo_surface_t *
408cups_printer_create_cairo_surface (CtkPrinter *printer,
409 CtkPrintSettings *settings,
410 gdouble width,
411 gdouble height,
412 GIOChannel *cache_io)
413{
414 cairo_surface_t *surface;
415 ppd_file_t *ppd_file = NULL((void*)0);
416 ppd_attr_t *ppd_attr = NULL((void*)0);
417 ppd_attr_t *ppd_attr_res = NULL((void*)0);
418 ppd_attr_t *ppd_attr_screen_freq = NULL((void*)0);
419 ppd_attr_t *ppd_attr_res_screen_freq = NULL((void*)0);
420 gchar *res_string = NULL((void*)0);
421 gint level = 2;
422
423 if (ctk_printer_accepts_pdf (printer))
424 surface = cairo_pdf_surface_create_for_stream (_cairo_write_to_cups, cache_io, width, height);
425 else
426 surface = cairo_ps_surface_create_for_stream (_cairo_write_to_cups, cache_io, width, height);
427
428 ppd_file = ctk_printer_cups_get_ppd (CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
);
429
430 if (ppd_file != NULL((void*)0))
431 {
432 ppd_attr = ppdFindAttr (ppd_file, "LanguageLevel", NULL((void*)0));
433
434 if (ppd_attr != NULL((void*)0))
435 level = atoi (ppd_attr->value);
436
437 if (ctk_print_settings_get_resolution (settings) == 0)
438 {
439 ppd_attr_res = ppdFindAttr (ppd_file, "DefaultResolution", NULL((void*)0));
440
441 if (ppd_attr_res != NULL((void*)0))
442 {
443 int res, res_x, res_y;
444
445 if (sscanf (ppd_attr_res->value, "%dx%ddpi", &res_x, &res_y) == 2)
446 {
447 if (res_x > 0 && res_y > 0)
448 ctk_print_settings_set_resolution_xy (settings, res_x, res_y);
449 }
450 else if (sscanf (ppd_attr_res->value, "%ddpi", &res) == 1)
451 {
452 if (res > 0)
453 ctk_print_settings_set_resolution (settings, res);
454 }
455 }
456 }
457
458 res_string = g_strdup_printf ("%ddpi",
459 ctk_print_settings_get_resolution (settings));
460 ppd_attr_res_screen_freq = ppdFindAttr (ppd_file, "ResScreenFreq", res_string);
461 g_free (res_string);
462
463 if (ppd_attr_res_screen_freq == NULL((void*)0))
464 {
465 res_string = g_strdup_printf ("%dx%ddpi",
466 ctk_print_settings_get_resolution_x (settings),
467 ctk_print_settings_get_resolution_y (settings));
468 ppd_attr_res_screen_freq = ppdFindAttr (ppd_file, "ResScreenFreq", res_string);
469 g_free (res_string);
470 }
471
472 ppd_attr_screen_freq = ppdFindAttr (ppd_file, "ScreenFreq", NULL((void*)0));
473
474 if (ppd_attr_res_screen_freq != NULL((void*)0) && atof (ppd_attr_res_screen_freq->value) > 0.0)
475 ctk_print_settings_set_printer_lpi (settings, atof (ppd_attr_res_screen_freq->value));
476 else if (ppd_attr_screen_freq != NULL((void*)0) && atof (ppd_attr_screen_freq->value) > 0.0)
477 ctk_print_settings_set_printer_lpi (settings, atof (ppd_attr_screen_freq->value));
478 }
479
480 if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_PS)
481 {
482 if (level == 2)
483 cairo_ps_surface_restrict_to_level (surface, CAIRO_PS_LEVEL_2);
484
485 if (level == 3)
486 cairo_ps_surface_restrict_to_level (surface, CAIRO_PS_LEVEL_3);
487 }
488
489 cairo_surface_set_fallback_resolution (surface,
490 2.0 * ctk_print_settings_get_printer_lpi (settings),
491 2.0 * ctk_print_settings_get_printer_lpi (settings));
492
493 return surface;
494}
495
496typedef struct {
497 CtkPrintJobCompleteFunc callback;
498 CtkPrintJob *job;
499 gpointer user_data;
500 GDestroyNotify dnotify;
501 http_t *http;
502} CupsPrintStreamData;
503
504static void
505cups_free_print_stream_data (CupsPrintStreamData *data)
506{
507 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
508 g_print ("CUPS Backend: %s\n", G_STRFUNC))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
;
509
510 if (data->dnotify)
511 data->dnotify (data->user_data);
512 g_object_unref (data->job);
513 if (data->http != NULL((void*)0))
514 httpClose (data->http);
515 g_free (data);
516}
517
518static void
519cups_print_cb (CtkPrintBackendCups *print_backend,
520 CtkCupsResult *result,
521 gpointer user_data)
522{
523 GError *error = NULL((void*)0);
524 CupsPrintStreamData *ps = user_data;
525
526 cdk_threads_enter ();
527
528 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
529 g_print ("CUPS Backend: %s\n", G_STRFUNC))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
;
530
531 if (ctk_cups_result_is_error (result))
532 error = g_error_new_literal (ctk_print_error_quark (),
533 CTK_PRINT_ERROR_INTERNAL_ERROR,
534 ctk_cups_result_get_error_string (result));
535
536 if (ps->callback)
537 ps->callback (ps->job, ps->user_data, error);
538
539 if (error == NULL((void*)0))
540 {
541 int job_id = 0;
542 ipp_attribute_t *attr; /* IPP job-id attribute */
543 ipp_t *response = ctk_cups_result_get_response (result);
544
545 if ((attr = ippFindAttribute (response, "job-id", IPP_TAG_INTEGER)) != NULL((void*)0))
546 job_id = ippGetInteger (attr, 0);
547
548 if (!ctk_print_job_get_track_print_status (ps->job) || job_id == 0)
549 ctk_print_job_set_status (ps->job, CTK_PRINT_STATUS_FINISHED);
550 else
551 {
552 ctk_print_job_set_status (ps->job, CTK_PRINT_STATUS_PENDING);
553 cups_begin_polling_info (print_backend, ps->job, job_id);
554 }
555 }
556 else
557 ctk_print_job_set_status (ps->job, CTK_PRINT_STATUS_FINISHED_ABORTED);
558
559
560 if (error)
561 g_error_free (error);
562
563 cdk_threads_leave ();
564}
565
566typedef struct {
567 CtkCupsRequest *request;
568 CtkPageSetup *page_setup;
569 CtkPrinterCups *printer;
570} CupsOptionsData;
571
572#define UNSIGNED_FLOAT_REGEX"([0-9]+([.,][0-9]*)?|[.,][0-9]+)([e][+-]?[0-9]+)?" "([0-9]+([.,][0-9]*)?|[.,][0-9]+)([e][+-]?[0-9]+)?"
573#define SIGNED_FLOAT_REGEX"[+-]?""([0-9]+([.,][0-9]*)?|[.,][0-9]+)([e][+-]?[0-9]+)?" "[+-]?"UNSIGNED_FLOAT_REGEX"([0-9]+([.,][0-9]*)?|[.,][0-9]+)([e][+-]?[0-9]+)?"
574#define SIGNED_INTEGER_REGEX"[+-]?([0-9]+)" "[+-]?([0-9]+)"
575
576static void
577add_cups_options (const gchar *key,
578 const gchar *value,
579 gpointer user_data)
580{
581 CupsOptionsData *data = (CupsOptionsData *) user_data;
582 CtkCupsRequest *request = data->request;
583 CtkPrinterCups *printer = data->printer;
584 gboolean custom_value = FALSE(0);
585 gchar *new_value = NULL((void*)0);
586 gint i;
587
588 if (!key || !value)
589 return;
590
591 if (!g_str_has_prefix (key, "cups-")(__builtin_constant_p ("cups-")? __extension__ ({ const char *
const __str = (key); const char * const __prefix = ("cups-")
; gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (key, "cups-") )
)
592 return;
593
594 if (strcmp (value, "ctk-ignore-value") == 0)
595 return;
596
597 key = key + strlen ("cups-");
598
599 if (printer && printer->ppd_file && !g_str_has_prefix (value, "Custom.")(__builtin_constant_p ("Custom.")? __extension__ ({ const char
* const __str = (value); const char * const __prefix = ("Custom."
); gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (value, "Custom.") )
)
600 {
601 ppd_coption_t *coption;
602 gboolean found = FALSE(0);
603 gboolean custom_values_enabled = FALSE(0);
604
605 coption = ppdFindCustomOption (printer->ppd_file, key);
606 if (coption && coption->option)
607 {
608 for (i = 0; i < coption->option->num_choices; i++)
609 {
610 /* Are custom values enabled ? */
611 if (g_str_equal (coption->option->choices[i].choice, "Custom")(strcmp ((const char *) (coption->option->choices[i].choice
), (const char *) ("Custom")) == 0)
)
612 custom_values_enabled = TRUE(!(0));
613
614 /* Is the value among available choices ? */
615 if (g_str_equal (coption->option->choices[i].choice, value)(strcmp ((const char *) (coption->option->choices[i].choice
), (const char *) (value)) == 0)
)
616 found = TRUE(!(0));
617 }
618
619 if (custom_values_enabled && !found)
620 {
621 /* Check syntax of the invalid choice to see whether
622 it could be a custom value */
623 if (g_str_equal (key, "PageSize")(strcmp ((const char *) (key), (const char *) ("PageSize")) ==
0)
||
624 g_str_equal (key, "PageRegion")(strcmp ((const char *) (key), (const char *) ("PageRegion"))
== 0)
)
625 {
626 /* Handle custom page sizes... */
627 if (g_regex_match_simple ("^" UNSIGNED_FLOAT_REGEX"([0-9]+([.,][0-9]*)?|[.,][0-9]+)([e][+-]?[0-9]+)?" "x" UNSIGNED_FLOAT_REGEX"([0-9]+([.,][0-9]*)?|[.,][0-9]+)([e][+-]?[0-9]+)?" "(cm|mm|m|in|ft|pt)?$", value, G_REGEX_CASELESS, 0))
628 custom_value = TRUE(!(0));
629 else
630 {
631 if (data->page_setup != NULL((void*)0))
632 {
633 custom_value = TRUE(!(0));
634 new_value =
635 g_strdup_printf ("Custom.%.2fx%.2fmm",
636 ctk_paper_size_get_width (ctk_page_setup_get_paper_size (data->page_setup), CTK_UNIT_MM),
637 ctk_paper_size_get_height (ctk_page_setup_get_paper_size (data->page_setup), CTK_UNIT_MM));
638 }
639 }
640 }
641 else
642 {
643 /* Handle other custom options... */
644 ppd_cparam_t *cparam;
645
646 cparam = (ppd_cparam_t *) cupsArrayFirst (coption->params);
647 if (cparam != NULL((void*)0))
648 {
649 switch (cparam->type)
650 {
651 case PPD_CUSTOM_CURVE :
652 case PPD_CUSTOM_INVCURVE :
653 case PPD_CUSTOM_REAL :
654 if (g_regex_match_simple ("^" SIGNED_FLOAT_REGEX"[+-]?""([0-9]+([.,][0-9]*)?|[.,][0-9]+)([e][+-]?[0-9]+)?" "$", value, G_REGEX_CASELESS, 0))
655 custom_value = TRUE(!(0));
656 break;
657
658 case PPD_CUSTOM_POINTS :
659 if (g_regex_match_simple ("^" SIGNED_FLOAT_REGEX"[+-]?""([0-9]+([.,][0-9]*)?|[.,][0-9]+)([e][+-]?[0-9]+)?" "(cm|mm|m|in|ft|pt)?$", value, G_REGEX_CASELESS, 0))
660 custom_value = TRUE(!(0));
661 break;
662
663 case PPD_CUSTOM_INT :
664 if (g_regex_match_simple ("^" SIGNED_INTEGER_REGEX"[+-]?([0-9]+)" "$", value, G_REGEX_CASELESS, 0))
665 custom_value = TRUE(!(0));
666 break;
667
668 case PPD_CUSTOM_PASSCODE :
669 case PPD_CUSTOM_PASSWORD :
670 case PPD_CUSTOM_STRING :
671 custom_value = TRUE(!(0));
672 break;
673
674 default :
675 custom_value = FALSE(0);
676 }
677 }
678 }
679 }
680 }
681 }
682
683 /* Add "Custom." prefix to custom values if not already added. */
684 if (custom_value)
685 {
686 if (new_value == NULL((void*)0))
687 new_value = g_strdup_printf ("Custom.%s", value);
688 ctk_cups_request_encode_option (request, key, new_value);
689 g_free (new_value);
690 }
691 else
692 ctk_cups_request_encode_option (request, key, value);
693}
694
695static void
696ctk_print_backend_cups_print_stream (CtkPrintBackend *print_backend,
697 CtkPrintJob *job,
698 GIOChannel *data_io,
699 CtkPrintJobCompleteFunc callback,
700 gpointer user_data,
701 GDestroyNotify dnotify)
702{
703 CtkPrinterCups *cups_printer;
704 CupsPrintStreamData *ps;
705 CupsOptionsData *options_data;
706 CtkPageSetup *page_setup;
707 CtkCupsRequest *request = NULL((void*)0);
708 CtkPrintSettings *settings;
709 const gchar *title;
710 char printer_absolute_uri[HTTP_MAX_URI1024];
711 http_t *http = NULL((void*)0);
712
713 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
714 g_print ("CUPS Backend: %s\n", G_STRFUNC))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
;
715
716 cups_printer = CTK_PRINTER_CUPS (ctk_print_job_get_printer (job))((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ctk_print_job_get_printer (job))), ((ctk_printer_cups_get_type
()))))))
;
717 settings = ctk_print_job_get_settings (job);
718
719 if (cups_printer->avahi_browsed)
720 {
721 http = httpConnect2 (cups_printer->hostname, cups_printer->port,
722 NULL((void*)0), AF_UNSPEC0,
723 HTTP_ENCRYPTION_IF_REQUESTED,
724 1, 30000,
725 NULL((void*)0));
726 if (http)
727 {
728 request = ctk_cups_request_new_with_username (http,
729 CTK_CUPS_POST,
730 IPP_PRINT_JOBIPP_OP_PRINT_JOB,
731 data_io,
732 cups_printer->hostname,
733 cups_printer->device_uri,
734 CTK_PRINT_BACKEND_CUPS (print_backend)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((print_backend)), ((ctk_print_backend_cups_get_type
()))))))
->username);
735 g_snprintf (printer_absolute_uri, HTTP_MAX_URI1024, "%s", cups_printer->printer_uri);
736 }
737 else
738 {
739 GError *error = NULL((void*)0);
740
741 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Error connecting to %s:%d", cups_printer
->hostname, cups_printer->port); }; } while (0)
742 g_warning ("CUPS Backend: Error connecting to %s:%d",do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Error connecting to %s:%d", cups_printer
->hostname, cups_printer->port); }; } while (0)
743 cups_printer->hostname,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Error connecting to %s:%d", cups_printer
->hostname, cups_printer->port); }; } while (0)
744 cups_printer->port))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Error connecting to %s:%d", cups_printer
->hostname, cups_printer->port); }; } while (0)
;
745
746 error = g_error_new (ctk_print_error_quark (),
747 CTK_CUPS_ERROR_GENERAL,
748 "Error connecting to %s",
749 cups_printer->hostname);
750
751 ctk_print_job_set_status (job, CTK_PRINT_STATUS_FINISHED_ABORTED);
752
753 if (callback)
754 {
755 callback (job, user_data, error);
756 }
757
758 g_clear_error (&error);
759
760 return;
761 }
762 }
763 else
764 {
765 request = ctk_cups_request_new_with_username (NULL((void*)0),
766 CTK_CUPS_POST,
767 IPP_PRINT_JOBIPP_OP_PRINT_JOB,
768 data_io,
769 NULL((void*)0),
770 cups_printer->device_uri,
771 CTK_PRINT_BACKEND_CUPS (print_backend)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((print_backend)), ((ctk_print_backend_cups_get_type
()))))))
->username);
772
773 httpAssembleURIf (HTTP_URI_CODING_ALL,
774 printer_absolute_uri,
775 sizeof (printer_absolute_uri),
776 "ipp",
777 NULL((void*)0),
778 "localhost",
779 ippPort (),
780 "/printers/%s",
781 ctk_printer_get_name (ctk_print_job_get_printer (job)));
782 }
783
784 ctk_cups_request_set_ipp_version (request,
785 cups_printer->ipp_version_major,
786 cups_printer->ipp_version_minor);
787
788 ctk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION,
789 IPP_TAG_URI, "printer-uri",
790 NULL((void*)0), printer_absolute_uri);
791
792 title = ctk_print_job_get_title (job);
793 if (title) {
794 char *title_truncated = NULL((void*)0);
795 size_t title_bytes = strlen (title);
796
797 if (title_bytes >= IPP_MAX_NAME256)
798 {
799 gchar *end;
800
801 end = g_utf8_find_prev_char (title, title + IPP_MAX_NAME256 - 1);
802 title_truncated = g_utf8_substring (title,
803 0,
804 g_utf8_pointer_to_offset (title, end));
805 }
806
807 ctk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION,
808 IPP_TAG_NAME, "job-name",
809 NULL((void*)0),
810 title_truncated ? title_truncated : title);
811 g_free (title_truncated);
812 }
813
814 g_object_get (job,
815 "page-setup", &page_setup,
816 NULL((void*)0));
817
818 options_data = g_new0 (CupsOptionsData, 1)((CupsOptionsData *) g_malloc0_n ((1), sizeof (CupsOptionsData
)))
;
819 options_data->request = request;
820 options_data->printer = cups_printer;
821 options_data->page_setup = page_setup;
822 ctk_print_settings_foreach (settings, add_cups_options, options_data);
823 g_clear_object (&page_setup)do { _Static_assert (sizeof *((&page_setup)) == sizeof (gpointer
), "Expression evaluates to false"); __typeof__ (((&page_setup
))) _pp = ((&page_setup)); __typeof__ (*((&page_setup
))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref
) (_ptr); } while (0)
;
824 g_free (options_data);
825
826 ps = g_new0 (CupsPrintStreamData, 1)((CupsPrintStreamData *) g_malloc0_n ((1), sizeof (CupsPrintStreamData
)))
;
827 ps->callback = callback;
828 ps->user_data = user_data;
829 ps->dnotify = dnotify;
830 ps->job = g_object_ref (job)((__typeof__ (job)) (g_object_ref) (job));
831 ps->http = http;
832
833 request->need_auth_info = FALSE(0);
834 request->auth_info_required = NULL((void*)0);
835
836 /* Check if auth_info_required is set and if it should be handled.
837 * The cups libraries handle the ticket exchange for "negotiate". */
838 if (cups_printer->auth_info_required != NULL((void*)0) &&
839 g_strv_length (cups_printer->auth_info_required) == 1 &&
840 g_strcmp0 (cups_printer->auth_info_required[0], "negotiate") == 0)
841 {
842 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Ignoring auth-info-required \"%s\"\n"
, cups_printer->auth_info_required[0]); }; } while (0)
843 g_print ("CUPS Backend: Ignoring auth-info-required \"%s\"\n",do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Ignoring auth-info-required \"%s\"\n"
, cups_printer->auth_info_required[0]); }; } while (0)
844 cups_printer->auth_info_required[0]))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Ignoring auth-info-required \"%s\"\n"
, cups_printer->auth_info_required[0]); }; } while (0)
;
845 }
846 else if (cups_printer->auth_info_required != NULL((void*)0))
847 {
848 request->need_auth_info = TRUE(!(0));
849 request->auth_info_required = g_strdupv (cups_printer->auth_info_required);
850 }
851
852 cups_request_execute (CTK_PRINT_BACKEND_CUPS (print_backend)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((print_backend)), ((ctk_print_backend_cups_get_type
()))))))
,
853 request,
854 (CtkPrintCupsResponseCallbackFunc) cups_print_cb,
855 ps,
856 (GDestroyNotify)cups_free_print_stream_data);
857}
858
859void overwrite_and_free (gpointer data)
860{
861 gchar *password = (gchar *) data;
862
863 if (password != NULL((void*)0))
864 {
865 memset (password, 0, strlen (password));
866 g_free (password);
867 }
868}
869
870static void
871ctk_print_backend_cups_init (CtkPrintBackendCups *backend_cups)
872{
873 int i;
874
875 backend_cups->list_printers_poll = FALSE(0);
876 backend_cups->got_default_printer = FALSE(0);
877 backend_cups->list_printers_pending = FALSE(0);
878 backend_cups->list_printers_attempts = 0;
879 backend_cups->reading_ppds = 0;
880
881 backend_cups->requests = NULL((void*)0);
882 backend_cups->auth = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, overwrite_and_free);
883 backend_cups->authentication_lock = FALSE(0);
884
885 backend_cups->default_printer_poll = 0;
886 backend_cups->cups_connection_test = NULL((void*)0);
887
888 backend_cups->username = NULL((void*)0);
889
890#ifdef HAVE_COLORD1
891 backend_cups->colord_client = cd_client_new ();
892#endif
893
894 backend_cups->dbus_connection = NULL((void*)0);
895 backend_cups->avahi_default_printer = NULL((void*)0);
896 backend_cups->avahi_service_browser_subscription_id = 0;
897 for (i = 0; i < 2; i++)
898 {
899 backend_cups->avahi_service_browser_paths[i] = NULL((void*)0);
900 backend_cups->avahi_service_browser_subscription_ids[i] = 0;
901 }
902
903 cups_get_local_default_printer (backend_cups);
904
905 backend_cups->secrets_service_available = FALSE(0);
906 backend_cups->secrets_service_cancellable = g_cancellable_new ();
907 backend_cups->secrets_service_watch_id =
908 ctk_cups_secrets_service_watch (secrets_service_appeared_cb,
909 secrets_service_vanished_cb,
910 backend_cups);
911
912 backend_cups->temporary_queues_in_construction = NULL((void*)0);
913 backend_cups->temporary_queues_removed = NULL((void*)0);
914}
915
916static void
917ctk_print_backend_cups_finalize (GObject *object)
918{
919 CtkPrintBackendCups *backend_cups;
920
921 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: finalizing CUPS backend module\n"); }
; } while (0)
922 g_print ("CUPS Backend: finalizing CUPS backend module\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: finalizing CUPS backend module\n"); }
; } while (0)
;
923
924 backend_cups = CTK_PRINT_BACKEND_CUPS (object)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((object)), ((ctk_print_backend_cups_get_type
()))))))
;
925
926 g_free (backend_cups->default_printer);
927 backend_cups->default_printer = NULL((void*)0);
928
929 ctk_cups_connection_test_free (backend_cups->cups_connection_test);
930 backend_cups->cups_connection_test = NULL((void*)0);
931
932 g_hash_table_destroy (backend_cups->auth);
933
934 g_free (backend_cups->username);
935
936#ifdef HAVE_COLORD1
937 g_object_unref (backend_cups->colord_client);
938#endif
939
940 g_clear_object (&backend_cups->avahi_cancellable)do { _Static_assert (sizeof *((&backend_cups->avahi_cancellable
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&backend_cups->avahi_cancellable))) _pp = ((&backend_cups
->avahi_cancellable)); __typeof__ (*((&backend_cups->
avahi_cancellable))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr
) (g_object_unref) (_ptr); } while (0)
;
941 g_clear_pointer (&backend_cups->avahi_default_printer, g_free)do { _Static_assert (sizeof *(&backend_cups->avahi_default_printer
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
((&backend_cups->avahi_default_printer)) _pp = (&
backend_cups->avahi_default_printer); __typeof__ (*(&backend_cups
->avahi_default_printer)) _ptr = *_pp; *_pp = ((void*)0); if
(_ptr) (g_free) (_ptr); } while (0)
;
942 g_clear_object (&backend_cups->dbus_connection)do { _Static_assert (sizeof *((&backend_cups->dbus_connection
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&backend_cups->dbus_connection))) _pp = ((&backend_cups
->dbus_connection)); __typeof__ (*((&backend_cups->
dbus_connection))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (
g_object_unref) (_ptr); } while (0)
;
943
944 g_clear_object (&backend_cups->secrets_service_cancellable)do { _Static_assert (sizeof *((&backend_cups->secrets_service_cancellable
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&backend_cups->secrets_service_cancellable))) _pp =
((&backend_cups->secrets_service_cancellable)); __typeof__
(*((&backend_cups->secrets_service_cancellable))) _ptr
= *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr)
; } while (0)
;
945 if (backend_cups->secrets_service_watch_id != 0)
946 {
947 g_bus_unwatch_name (backend_cups->secrets_service_watch_id);
948 }
949
950 g_list_free_full (backend_cups->temporary_queues_in_construction, g_free);
951 backend_cups->temporary_queues_in_construction = NULL((void*)0);
952
953 g_list_free_full (backend_cups->temporary_queues_removed, g_free);
954 backend_cups->temporary_queues_removed = NULL((void*)0);
955
956 backend_parent_class->finalize (object);
957}
958
959static void
960ctk_print_backend_cups_dispose (GObject *object)
961{
962 CtkPrintBackendCups *backend_cups;
963 int i;
964
965 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
966 g_print ("CUPS Backend: %s\n", G_STRFUNC))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
;
967
968 backend_cups = CTK_PRINT_BACKEND_CUPS (object)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((object)), ((ctk_print_backend_cups_get_type
()))))))
;
969
970 if (backend_cups->list_printers_poll > 0)
971 g_source_remove (backend_cups->list_printers_poll);
972 backend_cups->list_printers_poll = 0;
973 backend_cups->list_printers_attempts = 0;
974
975 if (backend_cups->default_printer_poll > 0)
976 g_source_remove (backend_cups->default_printer_poll);
977 backend_cups->default_printer_poll = 0;
978
979 g_cancellable_cancel (backend_cups->avahi_cancellable);
980
981 for (i = 0; i < 2; i++)
982 {
983 if (backend_cups->avahi_service_browser_subscription_ids[i] > 0)
984 {
985 g_dbus_connection_signal_unsubscribe (backend_cups->dbus_connection,
986 backend_cups->avahi_service_browser_subscription_ids[i]);
987 backend_cups->avahi_service_browser_subscription_ids[i] = 0;
988 }
989
990 if (backend_cups->avahi_service_browser_paths[i])
991 {
992 g_dbus_connection_call (backend_cups->dbus_connection,
993 AVAHI_BUS"org.freedesktop.Avahi",
994 backend_cups->avahi_service_browser_paths[i],
995 AVAHI_SERVICE_BROWSER_IFACE"org.freedesktop.Avahi.ServiceBrowser",
996 "Free",
997 NULL((void*)0),
998 NULL((void*)0),
999 G_DBUS_CALL_FLAGS_NONE,
1000 -1,
1001 NULL((void*)0),
1002 NULL((void*)0),
1003 NULL((void*)0));
1004 g_clear_pointer (&backend_cups->avahi_service_browser_paths[i], g_free)do { _Static_assert (sizeof *(&backend_cups->avahi_service_browser_paths
[i]) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
((&backend_cups->avahi_service_browser_paths[i])) _pp
= (&backend_cups->avahi_service_browser_paths[i]); __typeof__
(*(&backend_cups->avahi_service_browser_paths[i])) _ptr
= *_pp; *_pp = ((void*)0); if (_ptr) (g_free) (_ptr); } while
(0)
;
1005 }
1006 }
1007
1008 if (backend_cups->avahi_service_browser_subscription_id > 0)
1009 {
1010 g_dbus_connection_signal_unsubscribe (backend_cups->dbus_connection,
1011 backend_cups->avahi_service_browser_subscription_id);
1012 backend_cups->avahi_service_browser_subscription_id = 0;
1013 }
1014
1015 if (backend_cups->unsubscribe_general_subscription_id > 0)
1016 {
1017 g_source_remove (backend_cups->unsubscribe_general_subscription_id);
1018 backend_cups->unsubscribe_general_subscription_id = 0;
1019 }
1020
1021 backend_parent_class->dispose (object);
1022}
1023
1024static gboolean
1025is_address_local (const gchar *address)
1026{
1027 if (address[0] == '/' ||
1028 strcmp (address, "127.0.0.1") == 0 ||
1029 strcmp (address, "[::1]") == 0)
1030 return TRUE(!(0));
1031 else
1032 return FALSE(0);
1033}
1034
1035static void
1036ctk_print_backend_cups_set_password (CtkPrintBackend *backend,
1037 gchar **auth_info_required,
1038 gchar **auth_info,
1039 gboolean store_auth_info)
1040{
1041 CtkPrintBackendCups *cups_backend = CTK_PRINT_BACKEND_CUPS (backend)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((backend)), ((ctk_print_backend_cups_get_type
()))))))
;
1042 GList *l;
1043 char dispatch_hostname[HTTP_MAX_URI1024];
1044 gchar *username = NULL((void*)0);
1045 gchar *hostname = NULL((void*)0);
1046 gchar *password = NULL((void*)0);
1047 gint length;
1048 gint i;
1049
1050 length = g_strv_length (auth_info_required);
1051
1052 if (auth_info != NULL((void*)0))
1053 for (i = 0; i < length; i++)
1054 {
1055 if (g_strcmp0 (auth_info_required[i], "username") == 0)
1056 username = g_strdup (auth_info[i])g_strdup_inline (auth_info[i]);
1057 else if (g_strcmp0 (auth_info_required[i], "hostname") == 0)
1058 hostname = g_strdup (auth_info[i])g_strdup_inline (auth_info[i]);
1059 else if (g_strcmp0 (auth_info_required[i], "password") == 0)
1060 password = g_strdup (auth_info[i])g_strdup_inline (auth_info[i]);
1061 }
1062
1063 if (hostname != NULL((void*)0) && username != NULL((void*)0) && password != NULL((void*)0))
1064 {
1065 gchar *key = g_strconcat (username, "@", hostname, NULL((void*)0));
1066 g_hash_table_insert (cups_backend->auth, key, g_strdup (password)g_strdup_inline (password));
1067 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS backend: caching password for %s\n", key); };
} while (0)
1068 g_print ("CUPS backend: caching password for %s\n", key))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS backend: caching password for %s\n", key); };
} while (0)
;
1069 }
1070
1071 g_free (cups_backend->username);
1072 cups_backend->username = g_strdup (username)g_strdup_inline (username);
1073
1074
1075 for (l = cups_backend->requests; l; l = l->next)
1076 {
1077 CtkPrintCupsDispatchWatch *dispatch = l->data;
1078
1079 httpGetHostname (dispatch->request->http, dispatch_hostname, sizeof (dispatch_hostname));
1080 if (is_address_local (dispatch_hostname))
1081 strcpy (dispatch_hostname, "localhost");
1082
1083 if (dispatch->request->need_auth_info)
1084 {
1085 if (auth_info != NULL((void*)0))
1086 {
1087 dispatch->request->auth_info = g_new0 (gchar *, length + 1)((gchar * *) g_malloc0_n ((length + 1), sizeof (gchar *)));
1088 for (i = 0; i < length; i++)
1089 dispatch->request->auth_info[i] = g_strdup (auth_info[i])g_strdup_inline (auth_info[i]);
1090 }
1091 /* Save the password if the user requested it */
1092 if (password != NULL((void*)0) && store_auth_info)
1093 {
1094 const gchar *printer_uri =
1095 ctk_cups_request_ipp_get_string (dispatch->request,
1096 IPP_TAG_URI,
1097 "printer-uri");
1098
1099 ctk_cups_secrets_service_store (auth_info, auth_info_required,
1100 printer_uri);
1101 }
1102 dispatch->backend->authentication_lock = FALSE(0);
1103 dispatch->request->need_auth_info = FALSE(0);
1104 }
1105 else if (dispatch->request->password_state == CTK_CUPS_PASSWORD_REQUESTED || auth_info == NULL((void*)0))
1106 {
1107 overwrite_and_free (dispatch->request->password);
1108 dispatch->request->password = g_strdup (password)g_strdup_inline (password);
1109 g_free (dispatch->request->username);
1110 dispatch->request->username = g_strdup (username)g_strdup_inline (username);
1111 dispatch->request->password_state = CTK_CUPS_PASSWORD_HAS;
1112 dispatch->backend->authentication_lock = FALSE(0);
1113 }
1114 }
1115}
1116
1117static gboolean
1118request_password (gpointer data)
1119{
1120 CtkPrintCupsDispatchWatch *dispatch = data;
1121 const gchar *username;
1122 gchar *password;
1123 gchar *prompt = NULL((void*)0);
1124 gchar *key = NULL((void*)0);
1125 char hostname[HTTP_MAX_URI1024];
1126 gchar **auth_info_required;
1127 gchar **auth_info_default;
1128 gchar **auth_info_display;
1129 gboolean *auth_info_visible;
1130 gint length = 3;
1131 gint i;
1132
1133 if (dispatch->backend->authentication_lock)
1134 return G_SOURCE_REMOVE(0);
1135
1136 httpGetHostname (dispatch->request->http, hostname, sizeof (hostname));
1137 if (is_address_local (hostname))
1138 strcpy (hostname, "localhost");
1139
1140 if (dispatch->backend->username != NULL((void*)0))
1141 username = dispatch->backend->username;
1142 else
1143 username = cupsUser ();
1144
1145 auth_info_required = g_new0 (gchar*, length + 1)((gchar* *) g_malloc0_n ((length + 1), sizeof (gchar*)));
1146 auth_info_required[0] = g_strdup ("hostname")g_strdup_inline ("hostname");
1147 auth_info_required[1] = g_strdup ("username")g_strdup_inline ("username");
1148 auth_info_required[2] = g_strdup ("password")g_strdup_inline ("password");
1149
1150 auth_info_default = g_new0 (gchar*, length + 1)((gchar* *) g_malloc0_n ((length + 1), sizeof (gchar*)));
1151 auth_info_default[0] = g_strdup (hostname)g_strdup_inline (hostname);
1152 auth_info_default[1] = g_strdup (username)g_strdup_inline (username);
1153
1154 auth_info_display = g_new0 (gchar*, length + 1)((gchar* *) g_malloc0_n ((length + 1), sizeof (gchar*)));
1155 auth_info_display[1] = g_strdup (_("Username:"))g_strdup_inline (((char *) g_dgettext ("ctk30", "Username:"))
)
;
1156 auth_info_display[2] = g_strdup (_("Password:"))g_strdup_inline (((char *) g_dgettext ("ctk30", "Password:"))
)
;
1157
1158 auth_info_visible = g_new0 (gboolean, length + 1)((gboolean *) g_malloc0_n ((length + 1), sizeof (gboolean)));
1159 auth_info_visible[1] = TRUE(!(0));
1160
1161 key = g_strconcat (username, "@", hostname, NULL((void*)0));
1162 password = g_hash_table_lookup (dispatch->backend->auth, key);
1163
1164 if (password && dispatch->request->password_state != CTK_CUPS_PASSWORD_NOT_VALID)
1165 {
1166 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS backend: using stored password for %s\n", key
); }; } while (0)
1167 g_print ("CUPS backend: using stored password for %s\n", key))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS backend: using stored password for %s\n", key
); }; } while (0)
;
1168
1169 overwrite_and_free (dispatch->request->password);
1170 dispatch->request->password = g_strdup (password)g_strdup_inline (password);
1171 g_free (dispatch->request->username);
1172 dispatch->request->username = g_strdup (username)g_strdup_inline (username);
1173 dispatch->request->password_state = CTK_CUPS_PASSWORD_HAS;
1174 }
1175 else
1176 {
1177 const char *job_title = ctk_cups_request_ipp_get_string (dispatch->request, IPP_TAG_NAME, "job-name");
1178 const char *printer_uri = ctk_cups_request_ipp_get_string (dispatch->request, IPP_TAG_URI, "printer-uri");
1179 char *printer_name = NULL((void*)0);
1180
1181 if (printer_uri != NULL((void*)0) && strrchr (printer_uri, '/') != NULL((void*)0))
1182 printer_name = g_strdup (strrchr (printer_uri, '/') + 1)g_strdup_inline (strrchr (printer_uri, '/') + 1);
1183
1184 if (dispatch->request->password_state == CTK_CUPS_PASSWORD_NOT_VALID)
1185 g_hash_table_remove (dispatch->backend->auth, key);
1186
1187 dispatch->request->password_state = CTK_CUPS_PASSWORD_REQUESTED;
1188
1189 dispatch->backend->authentication_lock = TRUE(!(0));
1190
1191 switch (ippGetOperation (dispatch->request->ipp_request))
1192 {
1193 case IPP_PRINT_JOBIPP_OP_PRINT_JOB:
1194 if (job_title != NULL((void*)0) && printer_name != NULL((void*)0))
1195 prompt = g_strdup_printf ( _("Authentication is required to print document “%s” on printer %s")((char *) g_dgettext ("ctk30", "Authentication is required to print document “%s” on printer %s"
))
, job_title, printer_name);
1196 else
1197 prompt = g_strdup_printf ( _("Authentication is required to print a document on %s")((char *) g_dgettext ("ctk30", "Authentication is required to print a document on %s"
))
, hostname);
1198 break;
1199 case IPP_GET_JOB_ATTRIBUTESIPP_OP_GET_JOB_ATTRIBUTES:
1200 if (job_title != NULL((void*)0))
1201 prompt = g_strdup_printf ( _("Authentication is required to get attributes of job “%s”")((char *) g_dgettext ("ctk30", "Authentication is required to get attributes of job “%s”"
))
, job_title);
1202 else
1203 prompt = g_strdup ( _("Authentication is required to get attributes of a job"))g_strdup_inline (((char *) g_dgettext ("ctk30", "Authentication is required to get attributes of a job"
)))
;
1204 break;
1205 case IPP_GET_PRINTER_ATTRIBUTESIPP_OP_GET_PRINTER_ATTRIBUTES:
1206 if (printer_name != NULL((void*)0))
1207 prompt = g_strdup_printf ( _("Authentication is required to get attributes of printer %s")((char *) g_dgettext ("ctk30", "Authentication is required to get attributes of printer %s"
))
, printer_name);
1208 else
1209 prompt = g_strdup ( _("Authentication is required to get attributes of a printer"))g_strdup_inline (((char *) g_dgettext ("ctk30", "Authentication is required to get attributes of a printer"
)))
;
1210 break;
1211 case CUPS_GET_DEFAULTIPP_OP_CUPS_GET_DEFAULT:
1212 prompt = g_strdup_printf ( _("Authentication is required to get default printer of %s")((char *) g_dgettext ("ctk30", "Authentication is required to get default printer of %s"
))
, hostname);
1213 break;
1214 case CUPS_GET_PRINTERSIPP_OP_CUPS_GET_PRINTERS:
1215 prompt = g_strdup_printf ( _("Authentication is required to get printers from %s")((char *) g_dgettext ("ctk30", "Authentication is required to get printers from %s"
))
, hostname);
1216 break;
1217 default:
1218 /* work around gcc warning about 0 not being a value for this enum */
1219 if (ippGetOperation (dispatch->request->ipp_request) == 0)
1220 prompt = g_strdup_printf ( _("Authentication is required to get a file from %s")((char *) g_dgettext ("ctk30", "Authentication is required to get a file from %s"
))
, hostname);
1221 else
1222 prompt = g_strdup_printf ( _("Authentication is required on %s")((char *) g_dgettext ("ctk30", "Authentication is required on %s"
))
, hostname);
1223 break;
1224 }
1225
1226 g_free (printer_name);
1227
1228 g_signal_emit_by_name (dispatch->backend, "request-password",
1229 auth_info_required, auth_info_default,
1230 auth_info_display, auth_info_visible, prompt,
1231 FALSE(0)); /* Cups password is only cached not stored. */
1232
1233 g_free (prompt);
1234 }
1235
1236 for (i = 0; i < length; i++)
1237 {
1238 g_free (auth_info_required[i]);
1239 g_free (auth_info_default[i]);
1240 g_free (auth_info_display[i]);
1241 }
1242
1243 g_free (auth_info_required);
1244 g_free (auth_info_default);
1245 g_free (auth_info_display);
1246 g_free (auth_info_visible);
1247 g_free (key);
1248
1249 return G_SOURCE_REMOVE(0);
1250}
1251
1252static void
1253cups_dispatch_add_poll (GSource *source)
1254{
1255 CtkPrintCupsDispatchWatch *dispatch;
1256 CtkCupsPollState poll_state;
1257
1258 dispatch = (CtkPrintCupsDispatchWatch *) source;
1259
1260 poll_state = ctk_cups_request_get_poll_state (dispatch->request);
1261
1262 /* Remove the old source if the poll state changed. */
1263 if (poll_state != dispatch->poll_state && dispatch->data_poll != NULL((void*)0))
1264 {
1265 g_source_remove_poll (source, dispatch->data_poll);
1266 g_free (dispatch->data_poll);
1267 dispatch->data_poll = NULL((void*)0);
1268 }
1269
1270 if (dispatch->request->http != NULL((void*)0))
1271 {
1272 if (dispatch->data_poll == NULL((void*)0))
1273 {
1274 dispatch->data_poll = g_new0 (GPollFD, 1)((GPollFD *) g_malloc0_n ((1), sizeof (GPollFD)));
1275 dispatch->poll_state = poll_state;
1276
1277 if (poll_state == CTK_CUPS_HTTP_READ)
1278 dispatch->data_poll->events = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
1279 else if (poll_state == CTK_CUPS_HTTP_WRITE)
1280 dispatch->data_poll->events = G_IO_OUT | G_IO_ERR;
1281 else
1282 dispatch->data_poll->events = 0;
1283
1284 dispatch->data_poll->fd = httpGetFd (dispatch->request->http);
1285 g_source_add_poll (source, dispatch->data_poll);
1286 }
1287 }
1288}
1289
1290static gboolean
1291check_auth_info (gpointer user_data)
1292{
1293 CtkPrintCupsDispatchWatch *dispatch;
1294 dispatch = (CtkPrintCupsDispatchWatch *) user_data;
1295
1296 if (!dispatch->request->need_auth_info)
1297 {
1298 if (dispatch->request->auth_info == NULL((void*)0))
1299 {
1300 dispatch->callback (CTK_PRINT_BACKEND (dispatch->backend)((((CtkPrintBackend*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dispatch->backend)), ((ctk_print_backend_get_type ())
)))))
,
1301 ctk_cups_request_get_result (dispatch->request),
1302 dispatch->callback_data);
1303 g_source_destroy ((GSource *) dispatch);
1304 }
1305 else
1306 {
1307 gint length;
1308 gint i;
1309
1310 length = g_strv_length (dispatch->request->auth_info_required);
1311
1312 ctk_cups_request_ipp_add_strings (dispatch->request,
1313 IPP_TAG_JOB,
1314 IPP_TAG_TEXT,
1315 "auth-info",
1316 length,
1317 NULL((void*)0),
1318 (const char * const *) dispatch->request->auth_info);
1319
1320 g_source_attach ((GSource *) dispatch, NULL((void*)0));
1321 g_source_unref ((GSource *) dispatch);
1322
1323 for (i = 0; i < length; i++)
1324 overwrite_and_free (dispatch->request->auth_info[i]);
1325 g_free (dispatch->request->auth_info);
1326 dispatch->request->auth_info = NULL((void*)0);
1327 }
1328
1329 return G_SOURCE_REMOVE(0);
1330 }
1331
1332 return G_SOURCE_CONTINUE(!(0));
1333}
1334
1335static void
1336lookup_auth_info_cb (GObject *source_object G_GNUC_UNUSED__attribute__ ((__unused__)),
1337 GAsyncResult *res,
1338 gpointer user_data)
1339{
1340 GTask *task;
1341 CtkPrintCupsDispatchWatch *dispatch;
1342 gchar **auth_info;
1343 GError *error = NULL((void*)0);
1344 gint i;
1345
1346 task = (GTask *) res;
1347 dispatch = user_data;
1348 auth_info = g_task_propagate_pointer (task, &error);
1349
1350 if (auth_info == NULL((void*)0))
1351 {
1352 if (error != NULL((void*)0))
1353 {
1354 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("Failed to look up auth info: %s\n", error->message
); }; } while (0)
1355 g_print ("Failed to look up auth info: %s\n", error->message))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("Failed to look up auth info: %s\n", error->message
); }; } while (0)
;
1356 g_error_free (error);
1357 }
1358 else
1359 {
1360 /* Error note should have been shown by the function causing this */
1361 CTK_NOTE (PRINTING, g_print ("Failed to look up auth info.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("Failed to look up auth info.\n"); }; } while (0)
;
1362 }
1363 dispatch->backend->authentication_lock = FALSE(0);
1364 g_object_unref (task);
1365 request_auth_info (dispatch);
1366 return;
1367 }
1368
1369 ctk_print_backend_cups_set_password (CTK_PRINT_BACKEND (dispatch->backend)((((CtkPrintBackend*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dispatch->backend)), ((ctk_print_backend_get_type ())
)))))
,
1370 dispatch->request->auth_info_required, auth_info,
1371 FALSE(0));
1372 for (i = 0; auth_info[i] != NULL((void*)0); i++)
1373 {
1374 overwrite_and_free (auth_info[i]);
1375 auth_info[i] = NULL((void*)0);
1376 }
1377 g_clear_pointer (auth_info, g_free)do { _Static_assert (sizeof *(auth_info) == sizeof (gpointer)
, "Expression evaluates to false"); __typeof__ ((auth_info)) _pp
= (auth_info); __typeof__ (*(auth_info)) _ptr = *_pp; *_pp =
((void*)0); if (_ptr) (g_free) (_ptr); } while (0)
;
1378
1379 g_object_unref (task);
1380}
1381
1382static void
1383lookup_auth_info (gpointer user_data)
1384{
1385 CtkPrintCupsDispatchWatch *dispatch;
1386 gsize length,
1387 i;
1388 gboolean need_secret_auth_info = FALSE(0);
1389
1390 dispatch = user_data;
1391
1392 if (dispatch->backend->authentication_lock)
1393 return;
1394
1395 length = g_strv_length (dispatch->request->auth_info_required);
1396
1397 for (i = 0; i < length; i++)
1398 {
1399 if (g_strcmp0 (dispatch->request->auth_info_required[i], "password") == 0)
1400 {
1401 need_secret_auth_info = TRUE(!(0));
1402 break;
1403 }
1404 }
1405
1406 g_idle_add (check_auth_info, user_data);
1407
1408 if (dispatch->backend->secrets_service_available && need_secret_auth_info)
1409 {
1410 const gchar *printer_uri;
1411
1412 dispatch->backend->authentication_lock = TRUE(!(0));
1413 printer_uri = ctk_cups_request_ipp_get_string (dispatch->request,
1414 IPP_TAG_URI,
1415 "printer-uri");
1416 ctk_cups_secrets_service_query_task (dispatch->backend,
1417 dispatch->backend->secrets_service_cancellable,
1418 lookup_auth_info_cb,
1419 dispatch,
1420 printer_uri,
1421 dispatch->request->auth_info_required);
1422 return;
1423 }
1424
1425 request_auth_info (user_data);
1426}
1427
1428static gboolean
1429request_auth_info (gpointer user_data)
1430{
1431 CtkPrintCupsDispatchWatch *dispatch;
1432 const char *job_title;
1433 const char *printer_uri;
1434 gchar *prompt = NULL((void*)0);
1435 char *printer_name = NULL((void*)0);
1436 gint length;
1437 gint i;
1438 gboolean *auth_info_visible = NULL((void*)0);
1439 gchar **auth_info_default = NULL((void*)0);
1440 gchar **auth_info_display = NULL((void*)0);
1441
1442 dispatch = (CtkPrintCupsDispatchWatch *) user_data;
1443
1444 if (dispatch->backend->authentication_lock)
1445 return FALSE(0);
1446
1447 job_title = ctk_cups_request_ipp_get_string (dispatch->request, IPP_TAG_NAME, "job-name");
1448 printer_uri = ctk_cups_request_ipp_get_string (dispatch->request, IPP_TAG_URI, "printer-uri");
1449 length = g_strv_length (dispatch->request->auth_info_required);
1450
1451 auth_info_visible = g_new0 (gboolean, length)((gboolean *) g_malloc0_n ((length), sizeof (gboolean)));
1452 auth_info_default = g_new0 (gchar *, length + 1)((gchar * *) g_malloc0_n ((length + 1), sizeof (gchar *)));
1453 auth_info_display = g_new0 (gchar *, length + 1)((gchar * *) g_malloc0_n ((length + 1), sizeof (gchar *)));
1454
1455 for (i = 0; i < length; i++)
1456 {
1457 if (g_strcmp0 (dispatch->request->auth_info_required[i], "domain") == 0)
1458 {
1459 auth_info_display[i] = g_strdup (_("Domain:"))g_strdup_inline (((char *) g_dgettext ("ctk30", "Domain:")));
1460 auth_info_default[i] = g_strdup ("WORKGROUP")g_strdup_inline ("WORKGROUP");
1461 auth_info_visible[i] = TRUE(!(0));
1462 }
1463 else if (g_strcmp0 (dispatch->request->auth_info_required[i], "username") == 0)
1464 {
1465 auth_info_display[i] = g_strdup (_("Username:"))g_strdup_inline (((char *) g_dgettext ("ctk30", "Username:"))
)
;
1466 if (dispatch->backend->username != NULL((void*)0))
1467 auth_info_default[i] = g_strdup (dispatch->backend->username)g_strdup_inline (dispatch->backend->username);
1468 else
1469 auth_info_default[i] = g_strdup (cupsUser ())g_strdup_inline (cupsUser ());
1470 auth_info_visible[i] = TRUE(!(0));
1471 }
1472 else if (g_strcmp0 (dispatch->request->auth_info_required[i], "password") == 0)
1473 {
1474 auth_info_display[i] = g_strdup (_("Password:"))g_strdup_inline (((char *) g_dgettext ("ctk30", "Password:"))
)
;
1475 auth_info_visible[i] = FALSE(0);
1476 }
1477 }
1478
1479 if (printer_uri != NULL((void*)0) && strrchr (printer_uri, '/') != NULL((void*)0))
1480 printer_name = g_strdup (strrchr (printer_uri, '/') + 1)g_strdup_inline (strrchr (printer_uri, '/') + 1);
1481
1482 dispatch->backend->authentication_lock = TRUE(!(0));
1483
1484 if (job_title != NULL((void*)0))
1485 {
1486 if (printer_name != NULL((void*)0))
1487 prompt = g_strdup_printf ( _("Authentication is required to print document “%s” on printer %s")((char *) g_dgettext ("ctk30", "Authentication is required to print document “%s” on printer %s"
))
, job_title, printer_name);
1488 else
1489 prompt = g_strdup_printf ( _("Authentication is required to print document “%s”")((char *) g_dgettext ("ctk30", "Authentication is required to print document “%s”"
))
, job_title);
1490 }
1491 else
1492 {
1493 if (printer_name != NULL((void*)0))
1494 prompt = g_strdup_printf ( _("Authentication is required to print this document on printer %s")((char *) g_dgettext ("ctk30", "Authentication is required to print this document on printer %s"
))
, printer_name);
1495 else
1496 prompt = g_strdup ( _("Authentication is required to print this document"))g_strdup_inline (((char *) g_dgettext ("ctk30", "Authentication is required to print this document"
)))
;
1497 }
1498
1499 g_signal_emit_by_name (dispatch->backend, "request-password",
1500 dispatch->request->auth_info_required,
1501 auth_info_default,
1502 auth_info_display,
1503 auth_info_visible,
1504 prompt,
1505 dispatch->backend->secrets_service_available);
1506
1507 for (i = 0; i < length; i++)
1508 {
1509 g_free (auth_info_default[i]);
1510 g_free (auth_info_display[i]);
1511 }
1512
1513 g_free (auth_info_default);
1514 g_free (auth_info_display);
1515 g_free (printer_name);
1516 g_free (prompt);
1517
1518 return FALSE(0);
1519}
1520
1521static gboolean
1522cups_dispatch_watch_check (GSource *source)
1523{
1524 CtkPrintCupsDispatchWatch *dispatch;
1525 CtkCupsPollState poll_state;
1526 gboolean result;
1527
1528 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s <source %p>\n", ((const char
*) (__func__)), source); }; } while (0)
1529 g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s <source %p>\n", ((const char
*) (__func__)), source); }; } while (0)
;
1530
1531 dispatch = (CtkPrintCupsDispatchWatch *) source;
1532
1533 poll_state = ctk_cups_request_get_poll_state (dispatch->request);
1534
1535 if (poll_state != CTK_CUPS_HTTP_IDLE && !dispatch->request->need_password)
1536 if (!(dispatch->data_poll->revents & dispatch->data_poll->events))
1537 return FALSE(0);
1538
1539 result = ctk_cups_request_read_write (dispatch->request, FALSE(0));
1540 if (result && dispatch->data_poll != NULL((void*)0))
1541 {
1542 g_source_remove_poll (source, dispatch->data_poll);
1543 g_free (dispatch->data_poll);
1544 dispatch->data_poll = NULL((void*)0);
1545 }
1546
1547 if (dispatch->request->need_password && dispatch->request->password_state != CTK_CUPS_PASSWORD_REQUESTED)
1548 {
1549 dispatch->request->need_password = FALSE(0);
1550 g_idle_add (request_password, dispatch);
1551 result = FALSE(0);
1552 }
1553
1554 return result;
1555}
1556
1557static gboolean
1558cups_dispatch_watch_prepare (GSource *source,
1559 gint *timeout_)
1560{
1561 CtkPrintCupsDispatchWatch *dispatch;
1562 gboolean result;
1563
1564 dispatch = (CtkPrintCupsDispatchWatch *) source;
1565
1566 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s <source %p>\n", ((const char
*) (__func__)), source); }; } while (0)
1567 g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s <source %p>\n", ((const char
*) (__func__)), source); }; } while (0)
;
1568
1569 *timeout_ = -1;
1570
1571 result = ctk_cups_request_read_write (dispatch->request, TRUE(!(0)));
1572
1573 cups_dispatch_add_poll (source);
1574
1575 return result;
1576}
1577
1578static gboolean
1579cups_dispatch_watch_dispatch (GSource *source,
1580 GSourceFunc callback,
1581 gpointer user_data)
1582{
1583 CtkPrintCupsDispatchWatch *dispatch;
1584 CtkPrintCupsResponseCallbackFunc ep_callback;
1585 CtkCupsResult *result;
1586
1587 g_assert (callback != NULL)do { if (callback != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "ctkprintbackendcups.c", 1587, ((const char*)
(__func__)), "callback != NULL"); } while (0)
;
1588
1589 ep_callback = (CtkPrintCupsResponseCallbackFunc) callback;
1590
1591 dispatch = (CtkPrintCupsDispatchWatch *) source;
1592
1593 result = ctk_cups_request_get_result (dispatch->request);
1594
1595 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s <source %p>\n", ((const char
*) (__func__)), source); }; } while (0)
1596 g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s <source %p>\n", ((const char
*) (__func__)), source); }; } while (0)
;
1597
1598 if (ctk_cups_result_is_error (result))
1599 {
1600 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print("Error result: %s (type %i, status %i, code %i)\n", ctk_cups_result_get_error_string
(result), ctk_cups_result_get_error_type (result), ctk_cups_result_get_error_status
(result), ctk_cups_result_get_error_code (result)); }; } while
(0)
1601 g_print("Error result: %s (type %i, status %i, code %i)\n",do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print("Error result: %s (type %i, status %i, code %i)\n", ctk_cups_result_get_error_string
(result), ctk_cups_result_get_error_type (result), ctk_cups_result_get_error_status
(result), ctk_cups_result_get_error_code (result)); }; } while
(0)
1602 ctk_cups_result_get_error_string (result),do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print("Error result: %s (type %i, status %i, code %i)\n", ctk_cups_result_get_error_string
(result), ctk_cups_result_get_error_type (result), ctk_cups_result_get_error_status
(result), ctk_cups_result_get_error_code (result)); }; } while
(0)
1603 ctk_cups_result_get_error_type (result),do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print("Error result: %s (type %i, status %i, code %i)\n", ctk_cups_result_get_error_string
(result), ctk_cups_result_get_error_type (result), ctk_cups_result_get_error_status
(result), ctk_cups_result_get_error_code (result)); }; } while
(0)
1604 ctk_cups_result_get_error_status (result),do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print("Error result: %s (type %i, status %i, code %i)\n", ctk_cups_result_get_error_string
(result), ctk_cups_result_get_error_type (result), ctk_cups_result_get_error_status
(result), ctk_cups_result_get_error_code (result)); }; } while
(0)
1605 ctk_cups_result_get_error_code (result)))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print("Error result: %s (type %i, status %i, code %i)\n", ctk_cups_result_get_error_string
(result), ctk_cups_result_get_error_type (result), ctk_cups_result_get_error_status
(result), ctk_cups_result_get_error_code (result)); }; } while
(0)
;
1606 }
1607
1608 ep_callback (CTK_PRINT_BACKEND (dispatch->backend)((((CtkPrintBackend*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dispatch->backend)), ((ctk_print_backend_get_type ())
)))))
, result, user_data);
1609
1610 return FALSE(0);
1611}
1612
1613static void
1614cups_dispatch_watch_finalize (GSource *source)
1615{
1616 CtkPrintCupsDispatchWatch *dispatch;
1617 CtkCupsResult *result;
1618
1619 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s <source %p>\n", ((const char
*) (__func__)), source); }; } while (0)
1620 g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s <source %p>\n", ((const char
*) (__func__)), source); }; } while (0)
;
1621
1622 dispatch = (CtkPrintCupsDispatchWatch *) source;
1623
1624 result = ctk_cups_request_get_result (dispatch->request);
1625 if (ctk_cups_result_get_error_type (result) == CTK_CUPS_ERROR_AUTH)
1626 {
1627 const gchar *username;
1628 gchar hostname[HTTP_MAX_URI1024];
1629 gchar *key;
1630
1631 httpGetHostname (dispatch->request->http, hostname, sizeof (hostname));
1632 if (is_address_local (hostname))
1633 strcpy (hostname, "localhost");
1634
1635 if (dispatch->backend->username != NULL((void*)0))
1636 username = dispatch->backend->username;
1637 else
1638 username = cupsUser ();
1639
1640 key = g_strconcat (username, "@", hostname, NULL((void*)0));
1641 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS backend: removing stored password for %s\n", key
); }; } while (0)
1642 g_print ("CUPS backend: removing stored password for %s\n", key))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS backend: removing stored password for %s\n", key
); }; } while (0)
;
1643 g_hash_table_remove (dispatch->backend->auth, key);
1644 g_free (key);
1645
1646 if (dispatch->backend)
1647 dispatch->backend->authentication_lock = FALSE(0);
1648 }
1649
1650 ctk_cups_request_free (dispatch->request);
1651
1652 if (dispatch->backend)
1653 {
1654 /* We need to unref this at idle time, because it might be the
1655 * last reference to this module causing the code to be
1656 * unloaded (including this particular function!)
1657 * Update: Doing this at idle caused a deadlock taking the
1658 * mainloop context lock while being in a GSource callout for
1659 * multithreaded apps. So, for now we just disable unloading
1660 * of print backends. See _ctk_print_backend_create for the
1661 * disabling.
1662 */
1663
1664 dispatch->backend->requests = g_list_remove (dispatch->backend->requests, dispatch);
1665
1666
1667 g_object_unref (dispatch->backend);
1668 dispatch->backend = NULL((void*)0);
1669 }
1670
1671 if (dispatch->data_poll)
1672 {
1673 g_source_remove_poll (source, dispatch->data_poll);
1674 g_free (dispatch->data_poll);
1675 dispatch->data_poll = NULL((void*)0);
1676 }
1677}
1678
1679static GSourceFuncs _cups_dispatch_watch_funcs = {
1680 .prepare = cups_dispatch_watch_prepare,
1681 .check = cups_dispatch_watch_check,
1682 .dispatch = cups_dispatch_watch_dispatch,
1683 .finalize = cups_dispatch_watch_finalize
1684};
1685
1686
1687static void
1688cups_request_execute (CtkPrintBackendCups *print_backend,
1689 CtkCupsRequest *request,
1690 CtkPrintCupsResponseCallbackFunc callback,
1691 gpointer user_data,
1692 GDestroyNotify notify)
1693{
1694 CtkPrintCupsDispatchWatch *dispatch;
1695
1696 dispatch = (CtkPrintCupsDispatchWatch *) g_source_new (&_cups_dispatch_watch_funcs,
1697 sizeof (CtkPrintCupsDispatchWatch));
1698 g_source_set_name (&dispatch->source, "CTK+ CUPS backend");
1699
1700 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s <source %p> - Executing cups request on server '%s' and resource '%s'\n"
, ((const char*) (__func__)), dispatch, request->server, request
->resource); }; } while (0)
1701 g_print ("CUPS Backend: %s <source %p> - Executing cups request on server '%s' and resource '%s'\n", G_STRFUNC, dispatch, request->server, request->resource))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s <source %p> - Executing cups request on server '%s' and resource '%s'\n"
, ((const char*) (__func__)), dispatch, request->server, request
->resource); }; } while (0)
;
1702
1703 dispatch->request = request;
1704 dispatch->backend = g_object_ref (print_backend)((__typeof__ (print_backend)) (g_object_ref) (print_backend));
1705 dispatch->poll_state = CTK_CUPS_HTTP_IDLE;
1706 dispatch->data_poll = NULL((void*)0);
1707 dispatch->callback = NULL((void*)0);
1708 dispatch->callback_data = NULL((void*)0);
1709
1710 print_backend->requests = g_list_prepend (print_backend->requests, dispatch);
1711
1712 g_source_set_callback ((GSource *) dispatch, (GSourceFunc) callback, user_data, notify);
1713
1714 if (request->need_auth_info)
1715 {
1716 dispatch->callback = callback;
1717 dispatch->callback_data = user_data;
1718 lookup_auth_info (dispatch);
1719 }
1720 else
1721 {
1722 g_source_attach ((GSource *) dispatch, NULL((void*)0));
1723 g_source_unref ((GSource *) dispatch);
1724 }
1725}
1726
1727typedef struct {
1728 CtkPrintBackendCups *print_backend;
1729 CtkPrintJob *job;
1730 int job_id;
1731 int counter;
1732} CupsJobPollData;
1733
1734static void
1735job_object_died (gpointer user_data,
1736 GObject *where_the_object_was G_GNUC_UNUSED__attribute__ ((__unused__)))
1737{
1738 CupsJobPollData *data = user_data;
1739 data->job = NULL((void*)0);
1740}
1741
1742static void
1743cups_job_poll_data_free (CupsJobPollData *data)
1744{
1745 if (data->job)
1746 g_object_weak_unref (G_OBJECT (data->job)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data->job)), (((GType) ((20) << (2))))))))
, job_object_died, data);
1747
1748 g_free (data);
1749}
1750
1751static void
1752cups_request_job_info_cb (CtkPrintBackendCups *print_backend G_GNUC_UNUSED__attribute__ ((__unused__)),
1753 CtkCupsResult *result,
1754 gpointer user_data)
1755{
1756 CupsJobPollData *data = user_data;
1757 ipp_attribute_t *attr;
1758 ipp_t *response;
1759 int state;
1760 gboolean done;
1761
1762 cdk_threads_enter ();
1763
1764 if (data->job == NULL((void*)0))
1765 {
1766 cups_job_poll_data_free (data);
1767 goto done;
1768 }
1769
1770 data->counter++;
1771
1772 response = ctk_cups_result_get_response (result);
1773
1774 state = 0;
Value stored to 'state' is never read
1775
1776 attr = ippFindAttribute (response, "job-state", IPP_TAG_ENUM);
1777 state = ippGetInteger (attr, 0);
1778
1779 done = FALSE(0);
1780 switch (state)
1781 {
1782 case IPP_JOB_PENDINGIPP_JSTATE_PENDING:
1783 case IPP_JOB_HELDIPP_JSTATE_HELD:
1784 case IPP_JOB_STOPPEDIPP_JSTATE_STOPPED:
1785 ctk_print_job_set_status (data->job,
1786 CTK_PRINT_STATUS_PENDING);
1787 break;
1788 case IPP_JOB_PROCESSINGIPP_JSTATE_PROCESSING:
1789 ctk_print_job_set_status (data->job,
1790 CTK_PRINT_STATUS_PRINTING);
1791 break;
1792 default:
1793 case IPP_JOB_CANCELLEDIPP_JSTATE_CANCELED:
1794 case IPP_JOB_ABORTEDIPP_JSTATE_ABORTED:
1795 ctk_print_job_set_status (data->job,
1796 CTK_PRINT_STATUS_FINISHED_ABORTED);
1797 done = TRUE(!(0));
1798 break;
1799 case 0:
1800 case IPP_JOB_COMPLETEDIPP_JSTATE_COMPLETED:
1801 ctk_print_job_set_status (data->job,
1802 CTK_PRINT_STATUS_FINISHED);
1803 done = TRUE(!(0));
1804 break;
1805 }
1806
1807 if (!done && data->job != NULL((void*)0))
1808 {
1809 guint32 timeout;
1810 guint id;
1811
1812 if (data->counter < 5)
1813 timeout = 100;
1814 else if (data->counter < 10)
1815 timeout = 500;
1816 else
1817 timeout = 1000;
1818
1819 id = g_timeout_add (timeout, cups_job_info_poll_timeout, data);
1820 g_source_set_name_by_id (id, "[ctk+] cups_job_info_poll_timeout");
1821 }
1822 else
1823 cups_job_poll_data_free (data);
1824
1825done:
1826 cdk_threads_leave ();
1827}
1828
1829static void
1830cups_request_job_info (CupsJobPollData *data)
1831{
1832 CtkCupsRequest *request;
1833 gchar *job_uri;
1834
1835 request = ctk_cups_request_new_with_username (NULL((void*)0),
1836 CTK_CUPS_POST,
1837 IPP_GET_JOB_ATTRIBUTESIPP_OP_GET_JOB_ATTRIBUTES,
1838 NULL((void*)0),
1839 NULL((void*)0),
1840 NULL((void*)0),
1841 data->print_backend->username);
1842
1843 job_uri = g_strdup_printf ("ipp://localhost/jobs/%d", data->job_id);
1844 ctk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
1845 "job-uri", NULL((void*)0), job_uri);
1846 g_free (job_uri);
1847
1848 cups_request_execute (data->print_backend,
1849 request,
1850 (CtkPrintCupsResponseCallbackFunc) cups_request_job_info_cb,
1851 data,
1852 NULL((void*)0));
1853}
1854
1855static gboolean
1856cups_job_info_poll_timeout (gpointer user_data)
1857{
1858 CupsJobPollData *data = user_data;
1859
1860 if (data->job == NULL((void*)0))
1861 cups_job_poll_data_free (data);
1862 else
1863 cups_request_job_info (data);
1864
1865 return G_SOURCE_REMOVE(0);
1866}
1867
1868static void
1869cups_begin_polling_info (CtkPrintBackendCups *print_backend,
1870 CtkPrintJob *job,
1871 gint job_id)
1872{
1873 CupsJobPollData *data;
1874
1875 data = g_new0 (CupsJobPollData, 1)((CupsJobPollData *) g_malloc0_n ((1), sizeof (CupsJobPollData
)))
;
1876
1877 data->print_backend = print_backend;
1878 data->job = job;
1879 data->job_id = job_id;
1880 data->counter = 0;
1881
1882 g_object_weak_ref (G_OBJECT (job)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((job)), (((GType) ((20) << (2))))))))
, job_object_died, data);
1883
1884 cups_request_job_info (data);
1885}
1886
1887static void
1888mark_printer_inactive (CtkPrinter *printer,
1889 CtkPrintBackend *backend)
1890{
1891 CtkPrinterCups *cups_printer = CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
;
1892
1893 if (cups_printer->is_temporary)
1894 {
1895 GList *iter;
1896
1897 /* Do not recreate printers which disappeared from Avahi. */
1898 iter = g_list_find_custom (CTK_PRINT_BACKEND_CUPS (backend)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((backend)), ((ctk_print_backend_cups_get_type
()))))))
->temporary_queues_removed,
1899 ctk_printer_get_name (printer), (GCompareFunc) g_strcmp0);
1900 if (iter == NULL((void*)0))
1901 {
1902 /* Recreate temporary queue since they are created for 60 seconds only. */
1903#ifdef HAVE_CUPS_2_2
1904 create_temporary_queue (CTK_PRINT_BACKEND_CUPS (backend)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((backend)), ((ctk_print_backend_cups_get_type
()))))))
,
1905 ctk_printer_get_name (printer),
1906 cups_printer->printer_uri,
1907 cups_printer->temporary_queue_device_uri);
1908#endif
1909 }
1910 }
1911 else
1912 {
1913 ctk_printer_set_is_active (printer, FALSE(0));
1914 g_signal_emit_by_name (backend, "printer-removed", printer);
1915 }
1916}
1917
1918static gint
1919find_printer (CtkPrinter *printer,
1920 const gchar *find_name)
1921{
1922 const gchar *printer_name;
1923
1924 printer_name = ctk_printer_get_name (printer);
1925 return g_ascii_strcasecmp (printer_name, find_name);
1926}
1927/* Printer messages we're interested in */
1928static const char * const printer_messages[] =
1929 {
1930 "toner-low",
1931 "toner-empty",
1932 "developer-low",
1933 "developer-empty",
1934 "marker-supply-low",
1935 "marker-supply-empty",
1936 "cover-open",
1937 "door-open",
1938 "media-low",
1939 "media-empty",
1940 "offline",
1941 "other"
1942 };
1943
1944/* Attributes we're interested in for printers */
1945static const char * const printer_attrs[] =
1946 {
1947 "printer-name",
1948 "printer-uri-supported",
1949 "member-uris",
1950 "printer-location",
1951 "printer-info",
1952 "printer-state-message",
1953 "printer-state-reasons",
1954 "printer-state",
1955 "queued-job-count",
1956 "printer-is-accepting-jobs",
1957 "job-sheets-supported",
1958 "job-sheets-default",
1959 "printer-type",
1960 "auth-info-required",
1961 "number-up-default",
1962 "ipp-versions-supported",
1963 "multiple-document-handling-supported",
1964 "copies-supported",
1965 "number-up-supported",
1966 "device-uri",
1967 "printer-is-temporary"
1968 };
1969
1970/* Attributes we're interested in for printers without PPD */
1971static const char * const printer_attrs_detailed[] =
1972 {
1973 "printer-name",
1974 "printer-uri-supported",
1975 "member-uris",
1976 "printer-location",
1977 "printer-info",
1978 "printer-state-message",
1979 "printer-state-reasons",
1980 "printer-state",
1981 "queued-job-count",
1982 "printer-is-accepting-jobs",
1983 "job-sheets-supported",
1984 "job-sheets-default",
1985 "printer-type",
1986 "auth-info-required",
1987 "number-up-default",
1988 "ipp-versions-supported",
1989 "multiple-document-handling-supported",
1990 "copies-supported",
1991 "number-up-supported",
1992 "media-col-default",
1993 "media-col-supported",
1994 "media-default",
1995 "media-size-supported",
1996 "media-supported",
1997 "media-left-margin-supported",
1998 "media-right-margin-supported",
1999 "media-bottom-margin-supported",
2000 "media-top-margin-supported",
2001 "sides-default",
2002 "sides-supported",
2003 "output-bin-default",
2004 "output-bin-supported",
2005 };
2006
2007typedef enum
2008 {
2009 CTK_PRINTER_STATE_LEVEL_NONE = 0,
2010 CTK_PRINTER_STATE_LEVEL_INFO = 1,
2011 CTK_PRINTER_STATE_LEVEL_WARNING = 2,
2012 CTK_PRINTER_STATE_LEVEL_ERROR = 3
2013 } PrinterStateLevel;
2014
2015typedef struct
2016{
2017 float x_dimension;
2018 float y_dimension;
2019} MediaSize;
2020
2021typedef struct
2022{
2023 const gchar *printer_name;
2024 const gchar *printer_uri;
2025 const gchar *member_uris;
2026 const gchar *location;
2027 const gchar *description;
2028 gchar *state_msg;
2029 const gchar *reason_msg;
2030 PrinterStateLevel reason_level;
2031 gint state;
2032 gint job_count;
2033 gboolean is_paused;
2034 gboolean is_accepting_jobs;
2035 const gchar *default_cover_before;
2036 const gchar *default_cover_after;
2037 gboolean default_printer;
2038 gboolean got_printer_type;
2039 gboolean remote_printer;
2040 gboolean avahi_printer;
2041 gchar *avahi_resource_path;
2042 gchar **auth_info_required;
2043 gint default_number_up;
2044 guchar ipp_version_major;
2045 guchar ipp_version_minor;
2046 gboolean supports_copies;
2047 gboolean supports_collate;
2048 gboolean supports_number_up;
2049 gchar *media_default;
2050 GList *media_supported;
2051 GList *media_size_supported;
2052 float media_bottom_margin_default;
2053 float media_top_margin_default;
2054 float media_left_margin_default;
2055 float media_right_margin_default;
2056 gboolean media_margin_default_set;
2057 gchar *sides_default;
2058 GList *sides_supported;
2059 char **covers;
2060 int number_of_covers;
2061 gchar *output_bin_default;
2062 GList *output_bin_supported;
2063 gchar *original_device_uri;
2064 gboolean is_temporary;
2065} PrinterSetupInfo;
2066
2067static void
2068printer_setup_info_free (PrinterSetupInfo *info)
2069{
2070 g_free (info->original_device_uri);
2071 g_free (info->state_msg);
2072 g_strfreev (info->covers);
2073 g_slice_free (PrinterSetupInfo, info)do { if (1) g_slice_free1 (sizeof (PrinterSetupInfo), (info))
; else (void) ((PrinterSetupInfo*) 0 == (info)); } while (0)
;
2074}
2075
2076static void
2077get_ipp_version (const char *ipp_version_string,
2078 guchar *ipp_version_major,
2079 guchar *ipp_version_minor)
2080{
2081 gchar *endptr;
2082
2083 *ipp_version_major = 1;
2084 *ipp_version_minor = 1;
2085
2086 if (ipp_version_string)
2087 {
2088 gchar **ipp_version_strv;
2089
2090 ipp_version_strv = g_strsplit (ipp_version_string, ".", 0);
2091
2092 if (ipp_version_strv)
2093 {
2094 if (g_strv_length (ipp_version_strv) == 2)
2095 {
2096 *ipp_version_major = (guchar) g_ascii_strtoull (ipp_version_strv[0], &endptr, 10);
2097 if (endptr == ipp_version_strv[0])
2098 *ipp_version_major = 1;
2099
2100 *ipp_version_minor = (guchar) g_ascii_strtoull (ipp_version_strv[1], &endptr, 10);
2101 if (endptr == ipp_version_strv[1])
2102 *ipp_version_minor = 1;
2103 }
2104
2105 g_strfreev (ipp_version_strv);
2106 }
2107 }
2108}
2109
2110static void
2111get_server_ipp_version (guchar *ipp_version_major,
2112 guchar *ipp_version_minor)
2113{
2114 *ipp_version_major = 1;
2115 *ipp_version_minor = 1;
2116
2117 if (IPP_VERSION"\002\001" && strlen (IPP_VERSION"\002\001") == 2)
2118 {
2119 *ipp_version_major = (unsigned char) IPP_VERSION"\002\001"[0];
2120 *ipp_version_minor = (unsigned char) IPP_VERSION"\002\001"[1];
2121 }
2122}
2123
2124static gint
2125ipp_version_cmp (guchar ipp_version_major1,
2126 guchar ipp_version_minor1,
2127 guchar ipp_version_major2,
2128 guchar ipp_version_minor2)
2129{
2130 if (ipp_version_major1 == ipp_version_major2 &&
2131 ipp_version_minor1 == ipp_version_minor2)
2132 {
2133 return 0;
2134 }
2135 else if (ipp_version_major1 < ipp_version_major2 ||
2136 (ipp_version_major1 == ipp_version_major2 &&
2137 ipp_version_minor1 < ipp_version_minor2))
2138 {
2139 return -1;
2140 }
2141 else
2142 {
2143 return 1;
2144 }
2145}
2146
2147static void
2148cups_printer_handle_attribute (CtkPrintBackendCups *cups_backend G_GNUC_UNUSED__attribute__ ((__unused__)),
2149 ipp_attribute_t *attr,
2150 PrinterSetupInfo *info)
2151{
2152 gint i, j;
2153 if (strcmp (ippGetName (attr), "printer-name") == 0 &&
2154 ippGetValueTag (attr) == IPP_TAG_NAME)
2155 info->printer_name = ippGetString (attr, 0, NULL((void*)0));
2156 else if (strcmp (ippGetName (attr), "printer-uri-supported") == 0 &&
2157 ippGetValueTag (attr) == IPP_TAG_URI)
2158 info->printer_uri = ippGetString (attr, 0, NULL((void*)0));
2159 else if (strcmp (ippGetName (attr), "member-uris") == 0 &&
2160 ippGetValueTag (attr) == IPP_TAG_URI)
2161 info->member_uris = ippGetString (attr, 0, NULL((void*)0));
2162 else if (strcmp (ippGetName (attr), "printer-location") == 0)
2163 info->location = ippGetString (attr, 0, NULL((void*)0));
2164 else if (strcmp (ippGetName (attr), "printer-info") == 0)
2165 info->description = ippGetString (attr, 0, NULL((void*)0));
2166 else if (strcmp (ippGetName (attr), "printer-state-message") == 0)
2167 info->state_msg = g_strdup (ippGetString (attr, 0, NULL))g_strdup_inline (ippGetString (attr, 0, ((void*)0)));
2168 else if (strcmp (ippGetName (attr), "printer-state-reasons") == 0)
2169 /* Store most important reason to reason_msg and set
2170 its importance at printer_state_reason_level */
2171 {
2172 for (i = 0; i < ippGetCount (attr); i++)
2173 {
2174 if (strcmp (ippGetString (attr, i, NULL((void*)0)), "none") != 0)
2175 {
2176 gboolean interested_in = FALSE(0);
2177 /* Sets is_paused flag for paused printer. */
2178 if (strcmp (ippGetString (attr, i, NULL((void*)0)), "paused") == 0)
2179 {
2180 info->is_paused = TRUE(!(0));
2181 }
2182
2183 for (j = 0; j < G_N_ELEMENTS (printer_messages)(sizeof (printer_messages) / sizeof ((printer_messages)[0])); j++)
2184 if (strncmp (ippGetString (attr, i, NULL((void*)0)), printer_messages[j],
2185 strlen (printer_messages[j])) == 0)
2186 {
2187 interested_in = TRUE(!(0));
2188 break;
2189 }
2190
2191 if (interested_in)
2192 {
2193 if (g_str_has_suffix (ippGetString (attr, i, NULL), "-report")(__builtin_constant_p ("-report")? __extension__ ({ const char
* const __str = (ippGetString (attr, i, ((void*)0))); const char
* const __suffix = ("-report"); gboolean __result = (0); if (
__str == ((void*)0) || __suffix == ((void*)0)) __result = (g_str_has_suffix
) (__str, __suffix); else { const size_t __str_len = strlen (
((__str) + !(__str))); const size_t __suffix_len = strlen (((
__suffix) + !(__suffix))); if (__str_len >= __suffix_len) __result
= memcmp (__str + __str_len - __suffix_len, ((__suffix) + !(
__suffix)), __suffix_len) == 0; } __result; }) : (g_str_has_suffix
) (ippGetString (attr, i, ((void*)0)), "-report") )
)
2194 {
2195 if (info->reason_level <= CTK_PRINTER_STATE_LEVEL_INFO)
2196 {
2197 info->reason_msg = ippGetString (attr, i, NULL((void*)0));
2198 info->reason_level = CTK_PRINTER_STATE_LEVEL_INFO;
2199 }
2200 }
2201 else if (g_str_has_suffix (ippGetString (attr, i, NULL), "-warning")(__builtin_constant_p ("-warning")? __extension__ ({ const char
* const __str = (ippGetString (attr, i, ((void*)0))); const char
* const __suffix = ("-warning"); gboolean __result = (0); if
(__str == ((void*)0) || __suffix == ((void*)0)) __result = (
g_str_has_suffix) (__str, __suffix); else { const size_t __str_len
= strlen (((__str) + !(__str))); const size_t __suffix_len =
strlen (((__suffix) + !(__suffix))); if (__str_len >= __suffix_len
) __result = memcmp (__str + __str_len - __suffix_len, ((__suffix
) + !(__suffix)), __suffix_len) == 0; } __result; }) : (g_str_has_suffix
) (ippGetString (attr, i, ((void*)0)), "-warning") )
)
2202 {
2203 if (info->reason_level <= CTK_PRINTER_STATE_LEVEL_WARNING)
2204 {
2205 info->reason_msg = ippGetString (attr, i, NULL((void*)0));
2206 info->reason_level = CTK_PRINTER_STATE_LEVEL_WARNING;
2207 }
2208 }
2209 else /* It is error in the case of no suffix. */
2210 {
2211 info->reason_msg = ippGetString (attr, i, NULL((void*)0));
2212 info->reason_level = CTK_PRINTER_STATE_LEVEL_ERROR;
2213 }
2214 }
2215 }
2216 }
2217 }
2218 else if (strcmp (ippGetName (attr), "printer-state") == 0)
2219 info->state = ippGetInteger (attr, 0);
2220 else if (strcmp (ippGetName (attr), "queued-job-count") == 0)
2221 info->job_count = ippGetInteger (attr, 0);
2222 else if (strcmp (ippGetName (attr), "printer-is-accepting-jobs") == 0)
2223 {
2224 if (ippGetBoolean (attr, 0) == 1)
2225 info->is_accepting_jobs = TRUE(!(0));
2226 else
2227 info->is_accepting_jobs = FALSE(0);
2228 }
2229 else if (strcmp (ippGetName (attr), "job-sheets-supported") == 0)
2230 {
2231 info->number_of_covers = ippGetCount (attr);
2232 info->covers = g_new (char *, info->number_of_covers + 1)((char * *) g_malloc_n ((info->number_of_covers + 1), sizeof
(char *)))
;
2233 for (i = 0; i < info->number_of_covers; i++)
2234 info->covers[i] = g_strdup (ippGetString (attr, i, NULL))g_strdup_inline (ippGetString (attr, i, ((void*)0)));
2235 info->covers[info->number_of_covers] = NULL((void*)0);
2236 }
2237 else if (strcmp (ippGetName (attr), "job-sheets-default") == 0)
2238 {
2239 if (ippGetCount (attr) == 2)
2240 {
2241 info->default_cover_before = ippGetString (attr, 0, NULL((void*)0));
2242 info->default_cover_after = ippGetString (attr, 1, NULL((void*)0));
2243 }
2244 }
2245 else if (strcmp (ippGetName (attr), "printer-type") == 0)
2246 {
2247 info->got_printer_type = TRUE(!(0));
2248 if (ippGetInteger (attr, 0) & 0x00020000)
2249 info->default_printer = TRUE(!(0));
2250 else
2251 info->default_printer = FALSE(0);
2252
2253 if (ippGetInteger (attr, 0) & 0x00000002)
2254 info->remote_printer = TRUE(!(0));
2255 else
2256 info->remote_printer = FALSE(0);
2257 }
2258 else if (strcmp (ippGetName (attr), "auth-info-required") == 0)
2259 {
2260 if (strcmp (ippGetString (attr, 0, NULL((void*)0)), "none") != 0)
2261 {
2262 info->auth_info_required = g_new0 (gchar *, ippGetCount (attr) + 1)((gchar * *) g_malloc0_n ((ippGetCount (attr) + 1), sizeof (gchar
*)))
;
2263 for (i = 0; i < ippGetCount (attr); i++)
2264 info->auth_info_required[i] = g_strdup (ippGetString (attr, i, NULL))g_strdup_inline (ippGetString (attr, i, ((void*)0)));
2265 }
2266 }
2267 else if (strcmp (ippGetName (attr), "number-up-default") == 0)
2268 {
2269 info->default_number_up = ippGetInteger (attr, 0);
2270 }
2271 else if (g_strcmp0 (ippGetName (attr), "ipp-versions-supported") == 0)
2272 {
2273 guchar server_ipp_version_major;
2274 guchar server_ipp_version_minor;
2275 guchar ipp_version_major;
2276 guchar ipp_version_minor;
2277
2278 get_server_ipp_version (&server_ipp_version_major,
2279 &server_ipp_version_minor);
2280
2281 for (i = 0; i < ippGetCount (attr); i++)
2282 {
2283 get_ipp_version (ippGetString (attr, i, NULL((void*)0)),
2284 &ipp_version_major,
2285 &ipp_version_minor);
2286
2287 if (ipp_version_cmp (ipp_version_major,
2288 ipp_version_minor,
2289 info->ipp_version_major,
2290 info->ipp_version_minor) > 0 &&
2291 ipp_version_cmp (ipp_version_major,
2292 ipp_version_minor,
2293 server_ipp_version_major,
2294 server_ipp_version_minor) <= 0)
2295 {
2296 info->ipp_version_major = ipp_version_major;
2297 info->ipp_version_minor = ipp_version_minor;
2298 }
2299 }
2300 }
2301 else if (g_strcmp0 (ippGetName (attr), "number-up-supported") == 0)
2302 {
2303 if (ippGetCount (attr) == 6)
2304 {
2305 info->supports_number_up = TRUE(!(0));
2306 }
2307 }
2308 else if (g_strcmp0 (ippGetName (attr), "copies-supported") == 0)
2309 {
2310 int upper = 1;
2311
2312 ippGetRange (attr, 0, &upper);
2313 if (upper > 1)
2314 {
2315 info->supports_copies = TRUE(!(0));
2316 }
2317 }
2318 else if (g_strcmp0 (ippGetName (attr), "multiple-document-handling-supported") == 0)
2319 {
2320 for (i = 0; i < ippGetCount (attr); i++)
2321 {
2322 if (g_strcmp0 (ippGetString (attr, i, NULL((void*)0)), "separate-documents-collated-copies") == 0)
2323 {
2324 info->supports_collate = TRUE(!(0));
2325 }
2326 }
2327 }
2328 else if (g_strcmp0 (ippGetName (attr), "sides-default") == 0)
2329 {
2330 info->sides_default = g_strdup (ippGetString (attr, 0, NULL))g_strdup_inline (ippGetString (attr, 0, ((void*)0)));
2331 }
2332 else if (g_strcmp0 (ippGetName (attr), "sides-supported") == 0)
2333 {
2334 for (i = 0; i < ippGetCount (attr); i++)
2335 info->sides_supported = g_list_prepend (info->sides_supported, g_strdup (ippGetString (attr, i, NULL))g_strdup_inline (ippGetString (attr, i, ((void*)0))));
2336
2337 info->sides_supported = g_list_reverse (info->sides_supported);
2338 }
2339 else if (g_strcmp0 (ippGetName (attr), "media-default") == 0)
2340 {
2341 if (ippGetValueTag (attr) == IPP_TAG_KEYWORD ||
2342 ippGetValueTag (attr) == IPP_TAG_NAME)
2343 info->media_default = g_strdup (ippGetString (attr, 0, NULL))g_strdup_inline (ippGetString (attr, 0, ((void*)0)));
2344 }
2345 else if (g_strcmp0 (ippGetName (attr), "media-col-default") == 0)
2346 {
2347 ipp_attribute_t *iter;
2348 gint num_of_margins = 0;
2349
2350 for (i = 0; i < ippGetCount (attr); i++)
2351 {
2352 ipp_t *col;
2353
2354 col = ippGetCollection (attr, i);
2355 for (iter = ippFirstAttribute (col); iter != NULL((void*)0); iter = ippNextAttribute (col))
2356 {
2357 switch (ippGetValueTag (iter))
2358 {
2359 case IPP_TAG_INTEGER:
2360 if (g_strcmp0 (ippGetName (iter), "media-bottom-margin") == 0)
2361 {
2362 info->media_bottom_margin_default = ippGetInteger (iter, 0) / 100.0;
2363 num_of_margins++;
2364 }
2365 else if (g_strcmp0 (ippGetName (iter), "media-top-margin") == 0)
2366 {
2367 info->media_top_margin_default = ippGetInteger (iter, 0) / 100.0;
2368 num_of_margins++;
2369 }
2370 else if (g_strcmp0 (ippGetName (iter), "media-left-margin") == 0)
2371 {
2372 info->media_left_margin_default = ippGetInteger (iter, 0) / 100.0;
2373 num_of_margins++;
2374 }
2375 else if (g_strcmp0 (ippGetName (iter), "media-right-margin") == 0)
2376 {
2377 info->media_right_margin_default = ippGetInteger (iter, 0) / 100.0;
2378 num_of_margins++;
2379 }
2380 break;
2381
2382 default:
2383 break;
2384 }
2385 }
2386 }
2387
2388 if (num_of_margins == 4)
2389 info->media_margin_default_set = TRUE(!(0));
2390 }
2391 else if (g_strcmp0 (ippGetName (attr), "media-supported") == 0)
2392 {
2393 for (i = 0; i < ippGetCount (attr); i++)
2394 info->media_supported = g_list_prepend (info->media_supported, g_strdup (ippGetString (attr, i, NULL))g_strdup_inline (ippGetString (attr, i, ((void*)0))));
2395
2396 info->media_supported = g_list_reverse (info->media_supported);
2397 }
2398 else if (g_strcmp0 (ippGetName (attr), "media-size-supported") == 0)
2399 {
2400 ipp_attribute_t *iter;
2401 gboolean number_of_dimensions;
2402
2403 for (i = 0; i < ippGetCount (attr); i++)
2404 {
2405 MediaSize *media_size;
2406 ipp_t *media_size_collection;
2407
2408 media_size_collection = ippGetCollection (attr, i);
2409 media_size = g_new0 (MediaSize, 1)((MediaSize *) g_malloc0_n ((1), sizeof (MediaSize)));
2410 number_of_dimensions = 0;
2411
2412 for (iter = ippFirstAttribute (media_size_collection);
2413 iter != NULL((void*)0);
2414 iter = ippNextAttribute (media_size_collection))
2415 {
2416 if (g_strcmp0 (ippGetName (iter), "x-dimension") == 0 &&
2417 ippGetValueTag (iter) == IPP_TAG_INTEGER)
2418 {
2419 media_size->x_dimension = ippGetInteger (iter, 0) / 100.0;
2420 number_of_dimensions++;
2421 }
2422 else if (g_strcmp0 (ippGetName (iter), "y-dimension") == 0 &&
2423 ippGetValueTag (iter) == IPP_TAG_INTEGER)
2424 {
2425 media_size->y_dimension = ippGetInteger (iter, 0) / 100.0;
2426 number_of_dimensions++;
2427 }
2428 }
2429
2430 if (number_of_dimensions == 2)
2431 info->media_size_supported = g_list_prepend (info->media_size_supported, media_size);
2432 else
2433 g_free (media_size);
2434 }
2435
2436 info->media_size_supported = g_list_reverse (info->media_size_supported);
2437 }
2438 else if (g_strcmp0 (ippGetName (attr), "output-bin-default") == 0)
2439 {
2440 info->output_bin_default = g_strdup (ippGetString (attr, 0, NULL))g_strdup_inline (ippGetString (attr, 0, ((void*)0)));
2441 }
2442 else if (g_strcmp0 (ippGetName (attr), "output-bin-supported") == 0)
2443 {
2444 for (i = 0; i < ippGetCount (attr); i++)
2445 info->output_bin_supported = g_list_prepend (info->output_bin_supported, g_strdup (ippGetString (attr, i, NULL))g_strdup_inline (ippGetString (attr, i, ((void*)0))));
2446
2447 info->output_bin_supported = g_list_reverse (info->output_bin_supported);
2448 }
2449 else if (g_strcmp0 (ippGetName (attr), "device-uri") == 0)
2450 {
2451 info->original_device_uri = g_strdup (ippGetString (attr, 0, NULL))g_strdup_inline (ippGetString (attr, 0, ((void*)0)));
2452 }
2453 else if (strcmp (ippGetName (attr), "printer-is-temporary") == 0)
2454 {
2455 if (ippGetBoolean (attr, 0) == 1)
2456 info->is_temporary = TRUE(!(0));
2457 else
2458 info->is_temporary = FALSE(0);
2459 }
2460 else
2461 {
2462 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Attribute %s ignored\n", ippGetName (
attr)); }; } while (0)
2463 g_print ("CUPS Backend: Attribute %s ignored\n", ippGetName (attr)))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Attribute %s ignored\n", ippGetName (
attr)); }; } while (0)
;
2464 }
2465}
2466
2467static CtkPrinter*
2468cups_create_printer (CtkPrintBackendCups *cups_backend,
2469 PrinterSetupInfo *info)
2470{
2471 CtkPrinterCups *cups_printer;
2472 CtkPrinter *printer;
2473 CtkPrintBackend *backend = CTK_PRINT_BACKEND (cups_backend)((((CtkPrintBackend*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((cups_backend)), ((ctk_print_backend_get_type ()))))))
;
2474 char uri[HTTP_MAX_URI1024]; /* Printer URI */
2475 char method[HTTP_MAX_URI1024]; /* Method/scheme name */
2476 char username[HTTP_MAX_URI1024]; /* Username:password */
2477 char hostname[HTTP_MAX_URI1024]; /* Hostname */
2478 char resource[HTTP_MAX_URI1024]; /* Resource name */
2479 int port; /* Port number */
2480 char *cups_server; /* CUPS server */
2481
2482#ifdef HAVE_COLORD1
2483 if (info->avahi_printer)
2484 cups_printer = ctk_printer_cups_new (info->printer_name,
2485 backend,
2486 NULL((void*)0));
2487 else
2488 cups_printer = ctk_printer_cups_new (info->printer_name,
2489 backend,
2490 cups_backend->colord_client);
2491#else
2492 cups_printer = ctk_printer_cups_new (info->printer_name, backend, NULL((void*)0));
2493#endif
2494
2495 if (!info->avahi_printer)
2496 {
2497 cups_printer->device_uri = g_strdup_printf ("/printers/%s",
2498 info->printer_name);
2499 }
2500
2501 /* Check to see if we are looking at a class */
2502 if (info->member_uris)
2503 {
2504 cups_printer->printer_uri = g_strdup (info->member_uris)g_strdup_inline (info->member_uris);
2505 /* TODO if member_uris is a class we need to recursivly find a printer */
2506 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Found class with printer %s\n", info
->member_uris); }; } while (0)
2507 g_print ("CUPS Backend: Found class with printer %s\n",do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Found class with printer %s\n", info
->member_uris); }; } while (0)
2508 info->member_uris))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Found class with printer %s\n", info
->member_uris); }; } while (0)
;
2509 }
2510 else
2511 {
2512 cups_printer->printer_uri = g_strdup (info->printer_uri)g_strdup_inline (info->printer_uri);
2513 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Found printer %s\n", info->printer_uri
); }; } while (0)
2514 g_print ("CUPS Backend: Found printer %s\n",do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Found printer %s\n", info->printer_uri
); }; } while (0)
2515 info->printer_uri))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Found printer %s\n", info->printer_uri
); }; } while (0)
;
2516 }
2517
2518 httpSeparateURI (HTTP_URI_CODING_ALL, cups_printer->printer_uri,
2519 method, sizeof (method),
2520 username, sizeof (username),
2521 hostname, sizeof (hostname),
2522 &port,
2523 resource, sizeof (resource));
2524
2525 if (strncmp (resource, "/printers/", 10) == 0)
2526 {
2527 cups_printer->ppd_name = g_strdup (resource + 10)g_strdup_inline (resource + 10);
2528 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Setting ppd name '%s' for printer/class '%s'\n"
, cups_printer->ppd_name, info->printer_name); }; } while
(0)
2529 g_print ("CUPS Backend: Setting ppd name '%s' for printer/class '%s'\n", cups_printer->ppd_name, info->printer_name))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Setting ppd name '%s' for printer/class '%s'\n"
, cups_printer->ppd_name, info->printer_name); }; } while
(0)
;
2530 }
2531
2532 gethostname (uri, sizeof (uri));
2533 cups_server = g_strdup (cupsServer())g_strdup_inline (cupsServer());
2534
2535 if (strcasecmp (uri, hostname) == 0)
2536 strcpy (hostname, "localhost");
2537
2538 /* if the cups server is local and listening at a unix domain socket
2539 * then use the socket connection
2540 */
2541 if ((strstr (hostname, "localhost") != NULL((void*)0)) &&
2542 (cups_server[0] == '/'))
2543 strcpy (hostname, cups_server);
2544
2545 g_free (cups_server);
2546
2547 cups_printer->default_cover_before = g_strdup (info->default_cover_before)g_strdup_inline (info->default_cover_before);
2548 cups_printer->default_cover_after = g_strdup (info->default_cover_after)g_strdup_inline (info->default_cover_after);
2549 cups_printer->original_device_uri = g_strdup (info->original_device_uri)g_strdup_inline (info->original_device_uri);
2550 cups_printer->hostname = g_strdup (hostname)g_strdup_inline (hostname);
2551 cups_printer->port = port;
2552
2553 if (cups_printer->original_device_uri != NULL((void*)0))
2554 {
2555 httpSeparateURI (HTTP_URI_CODING_ALL, cups_printer->original_device_uri,
2556 method, sizeof (method),
2557 username, sizeof (username),
2558 hostname, sizeof (hostname),
2559 &port,
2560 resource, sizeof (resource));
2561 cups_printer->original_hostname = g_strdup (hostname)g_strdup_inline (hostname);
2562 cups_printer->original_resource = g_strdup (resource)g_strdup_inline (resource);
2563 cups_printer->original_port = port;
2564 }
2565
2566 if (info->default_number_up > 0)
2567 cups_printer->default_number_up = info->default_number_up;
2568
2569 cups_printer->auth_info_required = g_strdupv (info->auth_info_required);
2570 g_strfreev (info->auth_info_required);
2571
2572 printer = CTK_PRINTER (cups_printer)((((CtkPrinter*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((cups_printer)), ((ctk_printer_get_type ()))))))
;
2573
2574 if (cups_backend->default_printer != NULL((void*)0) &&
2575 strcmp (cups_backend->default_printer, ctk_printer_get_name (printer)) == 0)
2576 ctk_printer_set_is_default (printer, TRUE(!(0)));
2577
2578 cups_printer->avahi_browsed = info->avahi_printer;
2579
2580 ctk_print_backend_add_printer (backend, printer);
2581 return printer;
2582}
2583
2584static void
2585set_printer_icon_name_from_info (CtkPrinter *printer,
2586 PrinterSetupInfo *info)
2587{
2588 /* Set printer icon according to importance
2589 (none, report, warning, error - report is omitted). */
2590 if (info->reason_level == CTK_PRINTER_STATE_LEVEL_ERROR)
2591 ctk_printer_set_icon_name (printer, "printer-error");
2592 else if (info->reason_level == CTK_PRINTER_STATE_LEVEL_WARNING)
2593 ctk_printer_set_icon_name (printer, "printer-warning");
2594 else if (ctk_printer_is_paused (printer))
2595 ctk_printer_set_icon_name (printer, "printer-paused");
2596 else
2597 ctk_printer_set_icon_name (printer, "printer");
2598}
2599
2600static gchar *
2601get_reason_msg_desc (guint i,
2602 const gchar *printer_name)
2603{
2604 gchar *reason_msg_desc;
2605
2606 /* The numbers must match the indices in the printer_messages array */
2607 switch (i)
2608 {
2609 case 0:
2610 reason_msg_desc = g_strdup_printf (_("Printer “%s” is low on toner.")((char *) g_dgettext ("ctk30", "Printer “%s” is low on toner."
))
,
2611 printer_name);
2612 break;
2613 case 1:
2614 reason_msg_desc = g_strdup_printf (_("Printer “%s” has no toner left.")((char *) g_dgettext ("ctk30", "Printer “%s” has no toner left."
))
,
2615 printer_name);
2616 break;
2617 case 2:
2618 /* Translators: "Developer" like on photo development context */
2619 reason_msg_desc = g_strdup_printf (_("Printer “%s” is low on developer.")((char *) g_dgettext ("ctk30", "Printer “%s” is low on developer."
))
,
2620 printer_name);
2621 break;
2622 case 3:
2623 /* Translators: "Developer" like on photo development context */
2624 reason_msg_desc = g_strdup_printf (_("Printer “%s” is out of developer.")((char *) g_dgettext ("ctk30", "Printer “%s” is out of developer."
))
,
2625 printer_name);
2626 break;
2627 case 4:
2628 /* Translators: "marker" is one color bin of the printer */
2629 reason_msg_desc = g_strdup_printf (_("Printer “%s” is low on at least one marker supply.")((char *) g_dgettext ("ctk30", "Printer “%s” is low on at least one marker supply."
))
,
2630 printer_name);
2631 break;
2632 case 5:
2633 /* Translators: "marker" is one color bin of the printer */
2634 reason_msg_desc = g_strdup_printf (_("Printer “%s” is out of at least one marker supply.")((char *) g_dgettext ("ctk30", "Printer “%s” is out of at least one marker supply."
))
,
2635 printer_name);
2636 break;
2637 case 6:
2638 reason_msg_desc = g_strdup_printf (_("The cover is open on printer “%s”.")((char *) g_dgettext ("ctk30", "The cover is open on printer “%s”."
))
,
2639 printer_name);
2640 break;
2641 case 7:
2642 reason_msg_desc = g_strdup_printf (_("The door is open on printer “%s”.")((char *) g_dgettext ("ctk30", "The door is open on printer “%s”."
))
,
2643 printer_name);
2644 break;
2645 case 8:
2646 reason_msg_desc = g_strdup_printf (_("Printer “%s” is low on paper.")((char *) g_dgettext ("ctk30", "Printer “%s” is low on paper."
))
,
2647 printer_name);
2648 break;
2649 case 9:
2650 reason_msg_desc = g_strdup_printf (_("Printer “%s” is out of paper.")((char *) g_dgettext ("ctk30", "Printer “%s” is out of paper."
))
,
2651 printer_name);
2652 break;
2653 case 10:
2654 reason_msg_desc = g_strdup_printf (_("Printer “%s” is currently offline.")((char *) g_dgettext ("ctk30", "Printer “%s” is currently offline."
))
,
2655 printer_name);
2656 break;
2657 case 11:
2658 reason_msg_desc = g_strdup_printf (_("There is a problem on printer “%s”.")((char *) g_dgettext ("ctk30", "There is a problem on printer “%s”."
))
,
2659 printer_name);
2660 break;
2661 default:
2662 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "ctkprintbackendcups.c"
, 2662, ((const char*) (__func__)), ((void*)0)); } while (0)
;
2663 }
2664
2665 return reason_msg_desc;
2666}
2667
2668static void
2669set_info_state_message (PrinterSetupInfo *info)
2670{
2671 gint i;
2672
2673 if (info->state_msg == NULL((void*)0) || strlen (info->state_msg) == 0)
2674 {
2675 gchar *tmp_msg2 = NULL((void*)0);
2676 if (info->is_paused && !info->is_accepting_jobs)
2677 /* Translators: this is a printer status. */
2678 tmp_msg2 = g_strdup ( _("Paused; Rejecting Jobs"))g_strdup_inline (((char *) g_dgettext ("ctk30", "Paused; Rejecting Jobs"
)))
;
2679 if (info->is_paused && info->is_accepting_jobs)
2680 /* Translators: this is a printer status. */
2681 tmp_msg2 = g_strdup ( _("Paused"))g_strdup_inline (((char *) g_dgettext ("ctk30", "Paused")));
2682 if (!info->is_paused && !info->is_accepting_jobs)
2683 /* Translators: this is a printer status. */
2684 tmp_msg2 = g_strdup ( _("Rejecting Jobs"))g_strdup_inline (((char *) g_dgettext ("ctk30", "Rejecting Jobs"
)))
;
2685
2686 if (tmp_msg2 != NULL((void*)0))
2687 {
2688 g_free (info->state_msg);
2689 info->state_msg = tmp_msg2;
2690 }
2691 }
2692
2693 /* Set description of the reason and combine it with printer-state-message. */
2694 if (info->reason_msg)
2695 {
2696 gchar *reason_msg_desc = NULL((void*)0);
2697 gboolean found = FALSE(0);
2698
2699 for (i = 0; i < G_N_ELEMENTS (printer_messages)(sizeof (printer_messages) / sizeof ((printer_messages)[0])); i++)
2700 {
2701 if (strncmp (info->reason_msg, printer_messages[i],
2702 strlen (printer_messages[i])) == 0)
2703 {
2704 reason_msg_desc = get_reason_msg_desc (i, info->printer_name);
2705 found = TRUE(!(0));
2706 break;
2707 }
2708 }
2709
2710 if (!found)
2711 info->reason_level = CTK_PRINTER_STATE_LEVEL_NONE;
2712
2713 if (info->reason_level >= CTK_PRINTER_STATE_LEVEL_WARNING)
2714 {
2715 if (info->state_msg == NULL((void*)0) || info->state_msg[0] == '\0')
2716 {
2717 g_free (info->state_msg);
2718 info->state_msg = reason_msg_desc;
2719 reason_msg_desc = NULL((void*)0);
2720 }
2721 else
2722 {
2723 gchar *tmp_msg = NULL((void*)0);
2724 /* Translators: this string connects multiple printer states together. */
2725 tmp_msg = g_strjoin ( _("; ")((char *) g_dgettext ("ctk30", "; ")), info->state_msg,
2726 reason_msg_desc, NULL((void*)0));
2727 g_free (info->state_msg);
2728 info->state_msg = tmp_msg;
2729 }
2730 }
2731
2732 g_free (reason_msg_desc);
2733 }
2734}
2735
2736static void
2737set_default_printer (CtkPrintBackendCups *cups_backend,
2738 const gchar *default_printer_name)
2739{
2740 cups_backend->default_printer = g_strdup (default_printer_name)g_strdup_inline (default_printer_name);
2741 cups_backend->got_default_printer = TRUE(!(0));
2742
2743 if (cups_backend->default_printer != NULL((void*)0))
2744 {
2745 CtkPrinter *default_printer = NULL((void*)0);
2746 default_printer = ctk_print_backend_find_printer (CTK_PRINT_BACKEND (cups_backend)((((CtkPrintBackend*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((cups_backend)), ((ctk_print_backend_get_type ()))))))
,
2747 cups_backend->default_printer);
2748 if (default_printer != NULL((void*)0))
2749 {
2750 ctk_printer_set_is_default (default_printer, TRUE(!(0)));
2751 g_signal_emit_by_name (CTK_PRINT_BACKEND (cups_backend)((((CtkPrintBackend*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((cups_backend)), ((ctk_print_backend_get_type ()))))))
,
2752 "printer-status-changed", default_printer);
2753 }
2754 }
2755}
2756
2757typedef struct {
2758 CtkPrinterCups *printer;
2759 http_t *http;
2760} RequestPrinterInfoData;
2761
2762static void
2763request_printer_info_data_free (RequestPrinterInfoData *data)
2764{
2765 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
2766 g_print ("CUPS Backend: %s\n", G_STRFUNC))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
;
2767 httpClose (data->http);
2768 g_object_unref (data->printer);
2769 g_free (data);
2770}
2771
2772static void
2773cups_request_printer_info_cb (CtkPrintBackendCups *cups_backend,
2774 CtkCupsResult *result,
2775 gpointer user_data)
2776{
2777 RequestPrinterInfoData *data = (RequestPrinterInfoData *) user_data;
2778 PrinterSetupInfo *info = g_slice_new0 (PrinterSetupInfo)((PrinterSetupInfo*) g_slice_alloc0 (sizeof (PrinterSetupInfo
)))
;
2779 CtkPrintBackend *backend = CTK_PRINT_BACKEND (cups_backend)((((CtkPrintBackend*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((cups_backend)), ((ctk_print_backend_get_type ()))))))
;
2780 ipp_attribute_t *attr;
2781 CtkPrinter *printer = g_object_ref (CTK_PRINTER (data->printer))((__typeof__ (((((CtkPrinter*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((data->printer)), ((ctk_printer_get_type
())))))))) (g_object_ref) (((((CtkPrinter*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((data->printer)), ((ctk_printer_get_type
()))))))))
;
2782 gboolean status_changed = FALSE(0);
2783 ipp_t *response;
2784
2785 cdk_threads_enter ();
2786
2787 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
2788 g_print ("CUPS Backend: %s\n", G_STRFUNC))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
;
2789
2790 if (ctk_cups_result_is_error (result))
2791 {
2792 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Error getting printer info: %s %d %d"
, ctk_cups_result_get_error_string (result), ctk_cups_result_get_error_type
(result), ctk_cups_result_get_error_code (result)); }; } while
(0)
2793 g_warning ("CUPS Backend: Error getting printer info: %s %d %d",do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Error getting printer info: %s %d %d"
, ctk_cups_result_get_error_string (result), ctk_cups_result_get_error_type
(result), ctk_cups_result_get_error_code (result)); }; } while
(0)
2794 ctk_cups_result_get_error_string (result),do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Error getting printer info: %s %d %d"
, ctk_cups_result_get_error_string (result), ctk_cups_result_get_error_type
(result), ctk_cups_result_get_error_code (result)); }; } while
(0)
2795 ctk_cups_result_get_error_type (result),do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Error getting printer info: %s %d %d"
, ctk_cups_result_get_error_string (result), ctk_cups_result_get_error_type
(result), ctk_cups_result_get_error_code (result)); }; } while
(0)
2796 ctk_cups_result_get_error_code (result)))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Error getting printer info: %s %d %d"
, ctk_cups_result_get_error_string (result), ctk_cups_result_get_error_type
(result), ctk_cups_result_get_error_code (result)); }; } while
(0)
;
2797
2798 goto done;
2799 }
2800
2801 response = ctk_cups_result_get_response (result);
2802 attr = ippFirstAttribute (response);
2803 while (attr && ippGetGroupTag (attr) != IPP_TAG_PRINTER)
2804 attr = ippNextAttribute (response);
2805
2806 if (attr)
2807 {
2808 while (attr && ippGetGroupTag (attr) == IPP_TAG_PRINTER)
2809 {
2810 cups_printer_handle_attribute (cups_backend, attr, info);
2811 attr = ippNextAttribute (response);
2812 }
2813
2814 if (info->printer_name && info->printer_uri)
2815 {
2816 set_info_state_message (info);
2817
2818 if (info->got_printer_type &&
2819 info->default_printer &&
2820 cups_backend->avahi_default_printer == NULL((void*)0))
2821 cups_backend->avahi_default_printer = g_strdup (info->printer_name)g_strdup_inline (info->printer_name);
2822
2823 ctk_printer_set_is_paused (printer, info->is_paused);
2824 ctk_printer_set_is_accepting_jobs (printer, info->is_accepting_jobs);
2825
2826 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->remote = info->remote_printer;
2827 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->state = info->state;
2828 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->ipp_version_major = info->ipp_version_major;
2829 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->ipp_version_minor = info->ipp_version_minor;
2830 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->supports_copies = info->supports_copies;
2831 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->supports_collate = info->supports_collate;
2832 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->supports_number_up = info->supports_number_up;
2833 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->number_of_covers = info->number_of_covers;
2834 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->covers = g_strdupv (info->covers);
2835 status_changed = ctk_printer_set_job_count (printer, info->job_count);
2836 status_changed |= ctk_printer_set_location (printer, info->location);
2837 status_changed |= ctk_printer_set_description (printer, info->description);
2838 status_changed |= ctk_printer_set_state_message (printer, info->state_msg);
2839 status_changed |= ctk_printer_set_is_accepting_jobs (printer, info->is_accepting_jobs);
2840
2841 set_printer_icon_name_from_info (printer, info);
2842
2843 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->media_default = info->media_default;
2844 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->media_supported = info->media_supported;
2845 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->media_size_supported = info->media_size_supported;
2846 if (info->media_margin_default_set)
2847 {
2848 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->media_margin_default_set = TRUE(!(0));
2849 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->media_bottom_margin_default = info->media_bottom_margin_default;
2850 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->media_top_margin_default = info->media_top_margin_default;
2851 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->media_left_margin_default = info->media_left_margin_default;
2852 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->media_right_margin_default = info->media_right_margin_default;
2853 }
2854 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->sides_default = info->sides_default;
2855 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->sides_supported = info->sides_supported;
2856 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->output_bin_default = info->output_bin_default;
2857 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->output_bin_supported = info->output_bin_supported;
2858
2859 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->is_temporary = info->is_temporary;
2860
2861 ctk_printer_set_has_details (printer, TRUE(!(0)));
2862 g_signal_emit_by_name (printer, "details-acquired", TRUE(!(0)));
2863
2864 if (status_changed)
2865 g_signal_emit_by_name (CTK_PRINT_BACKEND (backend)((((CtkPrintBackend*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((backend)), ((ctk_print_backend_get_type ()))))))
,
2866 "printer-status-changed", printer);
2867 }
2868 }
2869
2870done:
2871 g_object_unref (printer);
2872
2873 if (!cups_backend->got_default_printer &&
2874 ctk_print_backend_printer_list_is_done (backend) &&
2875 cups_backend->avahi_default_printer != NULL((void*)0))
2876 {
2877 set_default_printer (cups_backend, cups_backend->avahi_default_printer);
2878 }
2879
2880 printer_setup_info_free (info);
2881
2882 cdk_threads_leave ();
2883}
2884
2885static void
2886cups_request_printer_info (CtkPrinterCups *printer)
2887{
2888 CtkPrintBackendCups *backend = CTK_PRINT_BACKEND_CUPS (ctk_printer_get_backend (CTK_PRINTER (printer)))((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((ctk_printer_get_backend (((((CtkPrinter*
) (void *) g_type_check_instance_cast ((GTypeInstance*) ((printer
)), ((ctk_printer_get_type ()))))))))), ((ctk_print_backend_cups_get_type
()))))))
;
2889 http_t *http;
2890
2891 http = httpConnect2 (printer->hostname, printer->port, NULL((void*)0), AF_UNSPEC0, HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL((void*)0));
2892 if (http)
2893 {
2894 RequestPrinterInfoData *data;
2895 CtkCupsRequest *request;
2896
2897 data = g_new0 (RequestPrinterInfoData, 1)((RequestPrinterInfoData *) g_malloc0_n ((1), sizeof (RequestPrinterInfoData
)))
;
2898 data->http = http;
2899 data->printer = g_object_ref (printer)((__typeof__ (printer)) (g_object_ref) (printer));
2900
2901 request = ctk_cups_request_new_with_username (http,
2902 CTK_CUPS_POST,
2903 IPP_GET_PRINTER_ATTRIBUTESIPP_OP_GET_PRINTER_ATTRIBUTES,
2904 NULL((void*)0),
2905 NULL((void*)0),
2906 NULL((void*)0),
2907 backend->username);
2908
2909 ctk_cups_request_set_ipp_version (request, 1, 1);
2910
2911 ctk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
2912 "printer-uri", NULL((void*)0), printer->printer_uri);
2913
2914 ctk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2915 "requested-attributes", G_N_ELEMENTS (printer_attrs_detailed)(sizeof (printer_attrs_detailed) / sizeof ((printer_attrs_detailed
)[0]))
,
2916 NULL((void*)0), printer_attrs_detailed);
2917
2918 cups_request_execute (backend,
2919 request,
2920 (CtkPrintCupsResponseCallbackFunc) cups_request_printer_info_cb,
2921 data,
2922 (GDestroyNotify) request_printer_info_data_free);
2923 }
2924}
2925
2926typedef struct
2927{
2928 gchar *printer_uri;
2929 gchar *device_uri;
2930 gchar *location;
2931 gchar *address;
2932 gchar *hostname;
2933 gint port;
2934 gchar *printer_name;
2935 gchar *name;
2936 gchar *resource_path;
2937 gboolean got_printer_type;
2938 guint printer_type;
2939 gboolean got_printer_state;
2940 guint printer_state;
2941 gchar *type;
2942 gchar *domain;
2943 gchar *UUID;
2944 CtkPrintBackendCups *backend;
2945} AvahiConnectionTestData;
2946
2947static CtkPrinter *
2948find_printer_by_uuid (CtkPrintBackendCups *backend,
2949 const gchar *UUID)
2950{
2951 CtkPrinter *result = NULL((void*)0);
2952 GList *printers;
2953 GList *iter;
2954 gchar *printer_uuid;
2955
2956 printers = ctk_print_backend_get_printer_list (CTK_PRINT_BACKEND (backend)((((CtkPrintBackend*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((backend)), ((ctk_print_backend_get_type ()))))))
);
2957 for (iter = printers; iter != NULL((void*)0); iter = iter->next)
2958 {
2959 CtkPrinterCups *printer;
2960
2961 printer = CTK_PRINTER_CUPS (iter->data)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((iter->data)), ((ctk_printer_cups_get_type ()))))))
;
2962
2963 if (printer->original_device_uri != NULL((void*)0))
2964 {
2965 printer_uuid = g_strrstr (printer->original_device_uri, "uuid=");
2966 if (printer_uuid != NULL((void*)0) && strlen (printer_uuid) >= 41)
2967 {
2968 printer_uuid += 5;
2969 printer_uuid = g_strndup (printer_uuid, 36);
2970
2971 if (g_uuid_string_is_valid (printer_uuid))
2972 {
2973 if (g_strcmp0 (printer_uuid, UUID) == 0)
2974 {
2975 result = CTK_PRINTER (printer)((((CtkPrinter*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_get_type ()))))))
;
2976 g_free (printer_uuid);
2977 break;
2978 }
2979 }
2980
2981 g_free (printer_uuid);
2982 }
2983 }
2984 }
2985
2986 g_list_free (printers);
2987
2988 return result;
2989}
2990
2991static void
2992cups_create_local_printer_cb (CtkPrintBackendCups *print_backend,
2993 CtkCupsResult *result,
2994 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
2995{
2996 gchar *printer_name = NULL((void*)0);
2997 ipp_t *response;
2998 GList *iter;
2999
3000 response = ctk_cups_result_get_response (result);
3001
3002 if (ippGetStatusCode (response) <= IPP_OK_CONFLICTIPP_STATUS_OK_CONFLICTING)
3003 {
3004 ipp_attribute_t *attr;
3005
3006 if ((attr = ippFindAttribute (response, "printer-uri-supported", IPP_TAG_URI)) != NULL((void*)0))
3007 {
3008 printer_name = g_strdup (g_strrstr (ippGetString (attr, 0, NULL), "/") + 1)g_strdup_inline (g_strrstr (ippGetString (attr, 0, ((void*)0)
), "/") + 1)
;
3009 }
3010
3011 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Created local printer %s\n", printer_name
); }; } while (0)
3012 g_print ("CUPS Backend: Created local printer %s\n", printer_name))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Created local printer %s\n", printer_name
); }; } while (0)
;
3013 }
3014 else
3015 {
3016 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Creating of local printer failed: %d\n"
, ippGetStatusCode (response)); }; } while (0)
3017 g_print ("CUPS Backend: Creating of local printer failed: %d\n", ippGetStatusCode (response)))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Creating of local printer failed: %d\n"
, ippGetStatusCode (response)); }; } while (0)
;
3018 }
3019
3020 iter = g_list_find_custom (print_backend->temporary_queues_in_construction, printer_name, (GCompareFunc) g_strcmp0);
3021 if (iter != NULL((void*)0))
3022 {
3023 g_free (iter->data);
3024 print_backend->temporary_queues_in_construction = g_list_delete_link (print_backend->temporary_queues_in_construction, iter);
3025 }
3026
3027 g_free (printer_name);
3028}
3029
3030/*
3031 * Create CUPS temporary queue.
3032 */
3033#ifdef HAVE_CUPS_2_2
3034static void
3035create_temporary_queue (CtkPrintBackendCups *backend,
3036 const gchar *printer_name,
3037 const gchar *printer_uri,
3038 const gchar *device_uri)
3039{
3040 CtkCupsRequest *request;
3041 GList *iter;
3042
3043 /* There can be several queues with the same name (ipp and ipps versions of the same printer) */
3044 iter = g_list_find_custom (backend->temporary_queues_in_construction, printer_name, (GCompareFunc) g_strcmp0);
3045 if (iter != NULL((void*)0))
3046 return;
3047
3048 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Creating local printer %s\n", printer_name
); }; } while (0)
3049 g_print ("CUPS Backend: Creating local printer %s\n", printer_name))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Creating local printer %s\n", printer_name
); }; } while (0)
;
3050
3051 backend->temporary_queues_in_construction = g_list_prepend (backend->temporary_queues_in_construction, g_strdup (printer_name)g_strdup_inline (printer_name));
3052
3053 request = ctk_cups_request_new_with_username (NULL((void*)0),
3054 CTK_CUPS_POST,
3055 IPP_OP_CUPS_CREATE_LOCAL_PRINTER,
3056 NULL((void*)0),
3057 NULL((void*)0),
3058 NULL((void*)0),
3059 NULL((void*)0));
3060
3061 ctk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
3062 "printer-uri", NULL((void*)0), printer_uri);
3063 ctk_cups_request_ipp_add_string (request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3064 "printer-name", NULL((void*)0), printer_name);
3065 ctk_cups_request_ipp_add_string (request, IPP_TAG_PRINTER, IPP_TAG_URI,
3066 "device-uri", NULL((void*)0), device_uri);
3067
3068 cups_request_execute (backend,
3069 request,
3070 (CtkPrintCupsResponseCallbackFunc) cups_create_local_printer_cb,
3071 NULL((void*)0),
3072 NULL((void*)0));
3073}
3074#endif
3075/*
3076 * Create new CtkPrinter from informations included in TXT records.
3077 */
3078static void
3079create_cups_printer_from_avahi_data (AvahiConnectionTestData *data)
3080{
3081 PrinterSetupInfo *info = g_slice_new0 (PrinterSetupInfo)((PrinterSetupInfo*) g_slice_alloc0 (sizeof (PrinterSetupInfo
)))
;
3082 CtkPrinter *printer;
3083
3084 printer = ctk_print_backend_find_printer (CTK_PRINT_BACKEND (data->backend)((((CtkPrintBackend*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data->backend)), ((ctk_print_backend_get_type ())))))
)
, data->printer_name);
3085 if (printer != NULL((void*)0))
3086 {
3087 /* A printer with this name is already present in this backend. It is probably the same printer
3088 * on another protocol (IPv4 vs IPv6).
3089 */
3090 return;
3091 }
3092
3093 info->avahi_printer = TRUE(!(0));
3094 info->printer_name = data->printer_name;
3095 info->printer_uri = data->printer_uri;
3096 info->avahi_resource_path = data->resource_path;
3097 info->default_printer = FALSE(0);
3098 info->remote_printer = TRUE(!(0));
3099 info->is_accepting_jobs = TRUE(!(0));
3100
3101 if (data->got_printer_state)
3102 {
3103 info->state = data->printer_state;
3104 info->is_paused = info->state == IPP_PRINTER_STOPPEDIPP_PSTATE_STOPPED;
3105 }
3106
3107 info->got_printer_type = data->got_printer_type;
3108 if (data->got_printer_type)
3109 {
3110 if (data->printer_type & CUPS_PRINTER_DEFAULT)
3111 info->default_printer = TRUE(!(0));
3112 else
3113 info->default_printer = FALSE(0);
3114
3115 if (data->printer_type & CUPS_PRINTER_REMOTE)
3116 info->remote_printer = TRUE(!(0));
3117 else
3118 info->remote_printer = FALSE(0);
3119
3120 if (data->printer_type & CUPS_PRINTER_REJECTING)
3121 info->is_accepting_jobs = FALSE(0);
3122 else
3123 info->is_accepting_jobs = TRUE(!(0));
3124
3125 if (info->default_printer &&
3126 data->backend->avahi_default_printer == NULL((void*)0))
3127 data->backend->avahi_default_printer = g_strdup (info->printer_name)g_strdup_inline (info->printer_name);
3128 }
3129
3130 set_info_state_message (info);
3131
3132 printer = ctk_print_backend_find_printer (CTK_PRINT_BACKEND (data->backend)((((CtkPrintBackend*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data->backend)), ((ctk_print_backend_get_type ())))))
)
, data->printer_name);
3133 if (printer == NULL((void*)0) && data->UUID != NULL((void*)0))
3134 printer = find_printer_by_uuid (data->backend, data->UUID);
3135
3136 if (printer == NULL((void*)0))
3137 {
3138 printer = cups_create_printer (data->backend, info);
3139
3140 if (data->got_printer_type)
3141 {
3142 ctk_printer_set_is_accepting_jobs (printer, info->is_accepting_jobs);
3143 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->remote = info->remote_printer;
3144
3145 if (info->default_printer &&
3146 data->backend->avahi_default_printer == NULL((void*)0))
3147 data->backend->avahi_default_printer = g_strdup (info->printer_name)g_strdup_inline (info->printer_name);
3148 }
3149
3150 if (data->got_printer_state)
3151 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->state = info->state;
3152
3153 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->avahi_name = g_strdup (data->name)g_strdup_inline (data->name);
3154 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->avahi_type = g_strdup (data->type)g_strdup_inline (data->type);
3155 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->avahi_domain = g_strdup (data->domain)g_strdup_inline (data->domain);
3156 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->printer_uri = g_strdup (data->printer_uri)g_strdup_inline (data->printer_uri);
3157 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->temporary_queue_device_uri = g_strdup (data->device_uri)g_strdup_inline (data->device_uri);
3158 g_free (CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->hostname);
3159 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->hostname = g_strdup (data->hostname)g_strdup_inline (data->hostname);
3160 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->port = data->port;
3161 ctk_printer_set_location (printer, data->location);
3162 ctk_printer_set_state_message (printer, info->state_msg);
3163
3164 set_printer_icon_name_from_info (printer, info);
3165
3166 if (!ctk_printer_is_active (printer))
3167 ctk_printer_set_is_active (printer, TRUE(!(0)));
3168
3169 g_signal_emit_by_name (data->backend, "printer-added", printer);
3170 ctk_printer_set_is_new (printer, FALSE(0));
3171 g_signal_emit_by_name (data->backend, "printer-list-changed");
3172
3173 if (!data->backend->got_default_printer &&
3174 ctk_print_backend_printer_list_is_done (CTK_PRINT_BACKEND (data->backend)((((CtkPrintBackend*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data->backend)), ((ctk_print_backend_get_type ())))))
)
) &&
3175 data->backend->avahi_default_printer != NULL((void*)0))
3176 set_default_printer (data->backend, data->backend->avahi_default_printer);
3177
3178 /* The ref is held by CtkPrintBackend, in add_printer() */
3179 g_object_unref (printer);
3180 }
3181
3182 printer_setup_info_free (info);
3183}
3184
3185static void
3186avahi_connection_test_cb (GObject *source_object,
3187 GAsyncResult *res,
3188 gpointer user_data)
3189{
3190 AvahiConnectionTestData *data = (AvahiConnectionTestData *) user_data;
3191 GSocketConnection *connection;
3192 GError *error = NULL((void*)0);
3193
3194 connection = g_socket_client_connect_to_host_finish (G_SOCKET_CLIENT (source_object)((((GSocketClient*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((source_object)), ((g_socket_client_get_type ()))))))
,
3195 res,
3196 &error);
3197 g_object_unref (source_object);
3198
3199 if (connection != NULL((void*)0))
3200 {
3201 g_io_stream_close (G_IO_STREAM (connection)((((GIOStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((connection)), ((g_io_stream_get_type ()))))))
, NULL((void*)0), NULL((void*)0));
3202 g_object_unref (connection);
3203
3204 create_cups_printer_from_avahi_data (data);
3205 }
3206 else
3207 {
3208 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Can not connect to %s: %s\n", data
->address, error->message); }; } while (0)
3209 g_warning ("CUPS Backend: Can not connect to %s: %s\n",do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Can not connect to %s: %s\n", data
->address, error->message); }; } while (0)
3210 data->address,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Can not connect to %s: %s\n", data
->address, error->message); }; } while (0)
3211 error->message))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Can not connect to %s: %s\n", data
->address, error->message); }; } while (0)
;
3212 g_error_free (error);
3213 }
3214
3215 g_free (data->printer_uri);
3216 g_free (data->location);
3217 g_free (data->address);
3218 g_free (data->hostname);
3219 g_free (data->printer_name);
3220 g_free (data->name);
3221 g_free (data->resource_path);
3222 g_free (data->type);
3223 g_free (data->domain);
3224 g_free (data->device_uri);
3225 g_free (data);
3226}
3227
3228gboolean
3229avahi_txt_get_key_value_pair (const gchar *entry,
3230 gchar **key,
3231 gchar **value)
3232{
3233 *key = NULL((void*)0);
3234 *value = NULL((void*)0);
3235
3236 if (entry != NULL((void*)0))
3237 {
3238 const gchar *equal_sign;
3239
3240 /* See RFC 6763 section 6.3 */
3241 equal_sign = strstr (entry, "=");
3242
3243 if (equal_sign != NULL((void*)0))
3244 {
3245 *key = g_strndup (entry, equal_sign - entry);
3246 *value = g_strdup (equal_sign + 1)g_strdup_inline (equal_sign + 1);
3247
3248 return TRUE(!(0));
3249 }
3250 }
3251
3252 return FALSE(0);
3253}
3254
3255static void
3256avahi_service_resolver_cb (GObject *source_object,
3257 GAsyncResult *res,
3258 gpointer user_data)
3259{
3260 CtkPrintBackendCups *backend;
3261 const gchar *name;
3262 const gchar *hostname;
3263 const gchar *type;
3264 const gchar *domain;
3265 const gchar *address;
3266 GVariant *output;
3267 GVariant *txt;
3268 guint32 flags;
3269 guint16 port;
3270 GError *error = NULL((void*)0);
3271 gchar **printer_name_strv;
3272 gchar *endptr;
3273 gchar *key;
3274 gchar *value;
3275 gsize length;
3276 gint interface;
3277 gint protocol;
3278 gint aprotocol;
3279 gint i, j;
3280
3281 output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object)((((GDBusConnection*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((source_object)), ((g_dbus_connection_get_type ()))))))
,
3282 res,
3283 &error);
3284 if (output)
3285 {
3286 AvahiConnectionTestData *data;
3287
3288 backend = CTK_PRINT_BACKEND_CUPS (user_data)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((user_data)), ((ctk_print_backend_cups_get_type
()))))))
;
3289
3290 g_variant_get (output, "(ii&s&s&s&si&sq@aayu)",
3291 &interface,
3292 &protocol,
3293 &name,
3294 &type,
3295 &domain,
3296 &hostname,
3297 &aprotocol,
3298 &address,
3299 &port,
3300 &txt,
3301 &flags);
3302
3303 data = g_new0 (AvahiConnectionTestData, 1)((AvahiConnectionTestData *) g_malloc0_n ((1), sizeof (AvahiConnectionTestData
)))
;
3304
3305 for (i = 0; i < g_variant_n_children (txt); i++)
3306 {
3307 GVariant *child;
3308
3309 child = g_variant_get_child_value (txt, i);
3310
3311 length = g_variant_get_size (child);
3312 if (length > 0)
3313 {
3314 gchar *tmp;
3315
3316 tmp = g_strndup (g_variant_get_data (child), length);
3317 g_variant_unref (child);
3318
3319 if (!avahi_txt_get_key_value_pair (tmp, &key, &value))
3320 {
3321 g_free (tmp);
3322 continue;
3323 }
3324
3325 if (g_strcmp0 (key, "rp") == 0)
3326 {
3327 data->resource_path = g_strdup (value)g_strdup_inline (value);
3328 }
3329 else if (g_strcmp0 (key, "note") == 0)
3330 {
3331 data->location = g_strdup (value)g_strdup_inline (value);
3332 }
3333 else if (g_strcmp0 (key, "printer-type") == 0)
3334 {
3335 endptr = NULL((void*)0);
3336 data->printer_type = g_ascii_strtoull (value, &endptr, 16);
3337 if (data->printer_type != 0 || endptr != value)
3338 data->got_printer_type = TRUE(!(0));
3339 }
3340 else if (g_strcmp0 (key, "printer-state") == 0)
3341 {
3342 endptr = NULL((void*)0);
3343 data->printer_state = g_ascii_strtoull (value, &endptr, 10);
3344 if (data->printer_state != 0 || endptr != value)
3345 data->got_printer_state = TRUE(!(0));
3346 }
3347 else if (g_strcmp0 (key, "UUID") == 0)
3348 {
3349 if (*value != '\0')
3350 data->UUID = g_strdup (value)g_strdup_inline (value);
3351 }
3352
3353 g_clear_pointer (&key, g_free)do { _Static_assert (sizeof *(&key) == sizeof (gpointer),
"Expression evaluates to false"); __typeof__ ((&key)) _pp
= (&key); __typeof__ (*(&key)) _ptr = *_pp; *_pp = (
(void*)0); if (_ptr) (g_free) (_ptr); } while (0)
;
3354 g_clear_pointer (&value, g_free)do { _Static_assert (sizeof *(&value) == sizeof (gpointer
), "Expression evaluates to false"); __typeof__ ((&value)
) _pp = (&value); __typeof__ (*(&value)) _ptr = *_pp;
*_pp = ((void*)0); if (_ptr) (g_free) (_ptr); } while (0)
;
3355 g_free (tmp);
3356 }
3357 else
3358 {
3359 g_variant_unref (child);
3360 }
3361 }
3362
3363 if (data->resource_path != NULL((void*)0))
3364 {
3365 gchar **printer_name_compressed_strv;
3366 gchar *printer_name;
3367 GList *iter;
3368
3369 /*
3370 * Create name of temporary queue from the name of the discovered service.
3371 * This emulates the way how CUPS creates the name.
3372 */
3373 printer_name = g_strdup_printf ("%s", name);
3374 g_strcanon (printer_name, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", '_');
3375
3376 printer_name_strv = g_strsplit_set (printer_name, "_", -1);
3377 printer_name_compressed_strv = g_new0 (gchar *, g_strv_length (printer_name_strv) + 1)((gchar * *) g_malloc0_n ((g_strv_length (printer_name_strv) +
1), sizeof (gchar *)))
;
3378 for (i = 0, j = 0; printer_name_strv[i] != NULL((void*)0); i++)
3379 {
3380 /*
3381 * Keep an empty segment at the beginning or end, if any.
3382 * This emulates the way cups-browsed in Debian 11 created
3383 * printer names (before 1.28.11), for example:
3384 * "Some Printer (123456)" -> Some_Printer_123456_
3385 * and hypothetically
3386 * "(Really) Working Printer" -> _Really_Working_Printer
3387 */
3388 if (printer_name_strv[i][0] != '\0' || i == 0 || printer_name_strv[i + 1] == NULL((void*)0))
3389 {
3390 printer_name_compressed_strv[j] = printer_name_strv[i];
3391 j++;
3392 }
3393 }
3394
3395 data->printer_name = g_strjoinv ("_", printer_name_compressed_strv);
3396
3397 g_strfreev (printer_name_strv);
3398 g_free (printer_name_compressed_strv);
3399 g_free (printer_name);
3400
3401 iter = g_list_find_custom (backend->temporary_queues_removed, data->printer_name, (GCompareFunc) g_strcmp0);
3402 if (iter != NULL((void*)0))
3403 {
3404 g_free (iter->data);
3405 backend->temporary_queues_removed = g_list_delete_link (backend->temporary_queues_removed, iter);
3406 }
3407
3408 if (g_strcmp0 (type, "_ipp._tcp") == 0)
3409 {
3410 data->printer_uri = g_strdup_printf ("ipp://localhost/printers/%s", data->printer_name);
3411 data->device_uri = g_strdup_printf ("ipp://%s:%d/%s", hostname, port, data->resource_path);
3412 }
3413 else
3414 {
3415 data->printer_uri = g_strdup_printf ("ipps://localhost/printers/%s", data->printer_name);
3416 data->device_uri = g_strdup_printf ("ipps://%s:%d/%s", hostname, port, data->resource_path);
3417 }
3418
3419 data->address = g_strdup (address)g_strdup_inline (address);
3420 data->hostname = g_strdup (hostname)g_strdup_inline (hostname);
3421 data->port = port;
3422
3423 data->name = g_strdup (name)g_strdup_inline (name);
3424 data->type = g_strdup (type)g_strdup_inline (type);
3425 data->domain = g_strdup (domain)g_strdup_inline (domain);
3426 data->backend = backend;
3427
3428 /* It can happen that the address is not reachable */
3429 g_socket_client_connect_to_host_async (g_socket_client_new (),
3430 address,
3431 port,
3432 backend->avahi_cancellable,
3433 avahi_connection_test_cb,
3434 data);
3435 }
3436 else
3437 {
3438 g_free (data->printer_name);
3439 g_free (data->location);
3440 g_free (data);
3441 }
3442
3443 g_variant_unref (txt);
3444 g_variant_unref (output);
3445 }
3446 else
3447 {
3448 if (!g_error_matches (error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_CANCELLED))
3449 g_warning ("%s", error->message);
3450 g_error_free (error);
3451 }
3452}
3453
3454static void
3455avahi_service_browser_signal_handler (GDBusConnection *connection G_GNUC_UNUSED__attribute__ ((__unused__)),
3456 const gchar *sender_name G_GNUC_UNUSED__attribute__ ((__unused__)),
3457 const gchar *object_path G_GNUC_UNUSED__attribute__ ((__unused__)),
3458 const gchar *interface_name G_GNUC_UNUSED__attribute__ ((__unused__)),
3459 const gchar *signal_name,
3460 GVariant *parameters,
3461 gpointer user_data)
3462{
3463 CtkPrintBackendCups *backend = CTK_PRINT_BACKEND_CUPS (user_data)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((user_data)), ((ctk_print_backend_cups_get_type
()))))))
;
3464 gchar *name;
3465 gchar *type;
3466 gchar *domain;
3467 guint flags;
3468 gint interface;
3469 gint protocol;
3470
3471 if (g_strcmp0 (signal_name, "ItemNew") == 0)
3472 {
3473 g_variant_get (parameters, "(ii&s&s&su)",
3474 &interface,
3475 &protocol,
3476 &name,
3477 &type,
3478 &domain,
3479 &flags);
3480
3481 if (g_strcmp0 (type, "_ipp._tcp") == 0 ||
3482 g_strcmp0 (type, "_ipps._tcp") == 0)
3483 {
3484 g_dbus_connection_call (backend->dbus_connection,
3485 AVAHI_BUS"org.freedesktop.Avahi",
3486 "/",
3487 AVAHI_SERVER_IFACE"org.freedesktop.Avahi.Server",
3488 "ResolveService",
3489 g_variant_new ("(iisssiu)",
3490 interface,
3491 protocol,
3492 name,
3493 type,
3494 domain,
3495 AVAHI_PROTO_UNSPEC-1,
3496 0),
3497 G_VARIANT_TYPE ("(iissssisqaayu)")(g_variant_type_checked_ (("(iissssisqaayu)"))),
3498 G_DBUS_CALL_FLAGS_NONE,
3499 -1,
3500 backend->avahi_cancellable,
3501 avahi_service_resolver_cb,
3502 user_data);
3503 }
3504 }
3505 else if (g_strcmp0 (signal_name, "ItemRemove") == 0)
3506 {
3507 g_variant_get (parameters, "(ii&s&s&su)",
3508 &interface,
3509 &protocol,
3510 &name,
3511 &type,
3512 &domain,
3513 &flags);
3514
3515 if (g_strcmp0 (type, "_ipp._tcp") == 0 ||
3516 g_strcmp0 (type, "_ipps._tcp") == 0)
3517 {
3518 GList *list;
3519 GList *iter;
3520
3521 list = ctk_print_backend_get_printer_list (CTK_PRINT_BACKEND (backend)((((CtkPrintBackend*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((backend)), ((ctk_print_backend_get_type ()))))))
);
3522 for (iter = list; iter; iter = iter->next)
3523 {
3524 CtkPrinterCups *printer;
3525
3526 printer = CTK_PRINTER_CUPS (iter->data)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((iter->data)), ((ctk_printer_cups_get_type ()))))))
;
3527 if (g_strcmp0 (printer->avahi_name, name) == 0 &&
3528 g_strcmp0 (printer->avahi_type, type) == 0 &&
3529 g_strcmp0 (printer->avahi_domain, domain) == 0)
3530 {
3531 if (g_strcmp0 (ctk_printer_get_name (CTK_PRINTER (printer)((((CtkPrinter*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_get_type ()))))))
),
3532 backend->avahi_default_printer) == 0)
3533 g_clear_pointer (&backend->avahi_default_printer, g_free)do { _Static_assert (sizeof *(&backend->avahi_default_printer
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
((&backend->avahi_default_printer)) _pp = (&backend
->avahi_default_printer); __typeof__ (*(&backend->avahi_default_printer
)) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_free) (_ptr);
} while (0)
;
3534
3535 backend->temporary_queues_removed = g_list_prepend (backend->temporary_queues_removed,
3536 g_strdup (ctk_printer_get_name (CTK_PRINTER (printer)))g_strdup_inline (ctk_printer_get_name (((((CtkPrinter*) (void
*) g_type_check_instance_cast ((GTypeInstance*) ((printer)),
((ctk_printer_get_type ()))))))))
);
3537
3538 g_signal_emit_by_name (backend, "printer-removed", printer);
3539 ctk_print_backend_remove_printer (CTK_PRINT_BACKEND (backend)((((CtkPrintBackend*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((backend)), ((ctk_print_backend_get_type ()))))))
,
3540 CTK_PRINTER (printer)((((CtkPrinter*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_get_type ()))))))
);
3541 g_signal_emit_by_name (backend, "printer-list-changed");
3542 break;
3543 }
3544 }
3545
3546 g_list_free (list);
3547 }
3548 }
3549}
3550
3551static gboolean
3552unsubscribe_general_subscription_cb (gpointer user_data)
3553{
3554 CtkPrintBackendCups *cups_backend = user_data;
3555
3556 g_dbus_connection_signal_unsubscribe (cups_backend->dbus_connection,
3557 cups_backend->avahi_service_browser_subscription_id);
3558 cups_backend->avahi_service_browser_subscription_id = 0;
3559 cups_backend->unsubscribe_general_subscription_id = 0;
3560
3561 return G_SOURCE_REMOVE(0);
3562}
3563
3564static void
3565avahi_service_browser_new_cb (GObject *source_object,
3566 GAsyncResult *res,
3567 gpointer user_data)
3568{
3569 CtkPrintBackendCups *cups_backend;
3570 GVariant *output;
3571 GError *error = NULL((void*)0);
3572 gint i;
3573
3574 output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object)((((GDBusConnection*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((source_object)), ((g_dbus_connection_get_type ()))))))
,
3575 res,
3576 &error);
3577 if (output)
3578 {
3579 cups_backend = CTK_PRINT_BACKEND_CUPS (user_data)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((user_data)), ((ctk_print_backend_cups_get_type
()))))))
;
3580 i = cups_backend->avahi_service_browser_paths[0] ? 1 : 0;
3581
3582 g_variant_get (output, "(o)", &cups_backend->avahi_service_browser_paths[i]);
3583
3584 cups_backend->avahi_service_browser_subscription_ids[i] =
3585 g_dbus_connection_signal_subscribe (cups_backend->dbus_connection,
3586 NULL((void*)0),
3587 AVAHI_SERVICE_BROWSER_IFACE"org.freedesktop.Avahi.ServiceBrowser",
3588 NULL((void*)0),
3589 cups_backend->avahi_service_browser_paths[i],
3590 NULL((void*)0),
3591 G_DBUS_SIGNAL_FLAGS_NONE,
3592 avahi_service_browser_signal_handler,
3593 user_data,
3594 NULL((void*)0));
3595
3596 /*
3597 * The general subscription for all service browsers is not needed
3598 * now because we are already subscribed to service browsers
3599 * specific to _ipp._tcp and _ipps._tcp services.
3600 */
3601 if (cups_backend->avahi_service_browser_paths[0] &&
3602 cups_backend->avahi_service_browser_paths[1] &&
3603 cups_backend->avahi_service_browser_subscription_id > 0)
3604 {
3605 /* We need to unsubscribe in idle since signals in queue destined for emit
3606 * are emitted in idle and check whether the subscriber is still subscribed.
3607 */
3608 cups_backend->unsubscribe_general_subscription_id = g_idle_add (unsubscribe_general_subscription_cb, cups_backend);
3609 }
3610
3611 g_variant_unref (output);
3612 }
3613 else
3614 {
3615 /*
3616 * The creation of ServiceBrowser fails with G_IO_ERROR_DBUS_ERROR
3617 * if Avahi is disabled.
3618 */
3619 if (!g_error_matches (error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_DBUS_ERROR) &&
3620 !g_error_matches (error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_CANCELLED))
3621 g_warning ("%s", error->message);
3622 g_error_free (error);
3623 }
3624}
3625
3626static void
3627avahi_create_browsers (GObject *source_object G_GNUC_UNUSED__attribute__ ((__unused__)),
3628 GAsyncResult *res,
3629 gpointer user_data)
3630{
3631 GDBusConnection *dbus_connection;
3632 CtkPrintBackendCups *cups_backend;
3633 GError *error = NULL((void*)0);
3634
3635 dbus_connection = g_bus_get_finish (res, &error);
3636 if (!dbus_connection)
3637 {
3638 if (!g_error_matches (error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_CANCELLED))
3639 g_warning ("Couldn't connect to D-Bus system bus, %s", error->message);
3640
3641 g_error_free (error);
3642 return;
3643 }
3644
3645 cups_backend = CTK_PRINT_BACKEND_CUPS (user_data)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((user_data)), ((ctk_print_backend_cups_get_type
()))))))
;
3646 cups_backend->dbus_connection = dbus_connection;
3647
3648 /*
3649 * We need to subscribe to signals of service browser before
3650 * we actually create it because it starts to emit them right
3651 * after its creation.
3652 */
3653 cups_backend->avahi_service_browser_subscription_id =
3654 g_dbus_connection_signal_subscribe (cups_backend->dbus_connection,
3655 NULL((void*)0),
3656 AVAHI_SERVICE_BROWSER_IFACE"org.freedesktop.Avahi.ServiceBrowser",
3657 NULL((void*)0),
3658 NULL((void*)0),
3659 NULL((void*)0),
3660 G_DBUS_SIGNAL_FLAGS_NONE,
3661 avahi_service_browser_signal_handler,
3662 cups_backend,
3663 NULL((void*)0));
3664
3665 /*
3666 * Create service browsers for _ipp._tcp and _ipps._tcp services.
3667 */
3668 g_dbus_connection_call (cups_backend->dbus_connection,
3669 AVAHI_BUS"org.freedesktop.Avahi",
3670 "/",
3671 AVAHI_SERVER_IFACE"org.freedesktop.Avahi.Server",
3672 "ServiceBrowserNew",
3673 g_variant_new ("(iissu)",
3674 AVAHI_IF_UNSPEC-1,
3675 AVAHI_PROTO_UNSPEC-1,
3676 "_ipp._tcp",
3677 "",
3678 0),
3679 G_VARIANT_TYPE ("(o)")(g_variant_type_checked_ (("(o)"))),
3680 G_DBUS_CALL_FLAGS_NONE,
3681 -1,
3682 cups_backend->avahi_cancellable,
3683 avahi_service_browser_new_cb,
3684 cups_backend);
3685
3686 g_dbus_connection_call (cups_backend->dbus_connection,
3687 AVAHI_BUS"org.freedesktop.Avahi",
3688 "/",
3689 AVAHI_SERVER_IFACE"org.freedesktop.Avahi.Server",
3690 "ServiceBrowserNew",
3691 g_variant_new ("(iissu)",
3692 AVAHI_IF_UNSPEC-1,
3693 AVAHI_PROTO_UNSPEC-1,
3694 "_ipps._tcp",
3695 "",
3696 0),
3697 G_VARIANT_TYPE ("(o)")(g_variant_type_checked_ (("(o)"))),
3698 G_DBUS_CALL_FLAGS_NONE,
3699 -1,
3700 cups_backend->avahi_cancellable,
3701 avahi_service_browser_new_cb,
3702 cups_backend);
3703}
3704
3705static void
3706avahi_request_printer_list (CtkPrintBackendCups *cups_backend)
3707{
3708 cups_backend->avahi_cancellable = g_cancellable_new ();
3709 g_bus_get (G_BUS_TYPE_SYSTEM, cups_backend->avahi_cancellable, avahi_create_browsers, cups_backend);
3710}
3711
3712static void
3713cups_request_printer_list_cb (CtkPrintBackendCups *cups_backend,
3714 CtkCupsResult *result,
3715 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
3716{
3717 CtkPrintBackend *backend = CTK_PRINT_BACKEND (cups_backend)((((CtkPrintBackend*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((cups_backend)), ((ctk_print_backend_get_type ()))))))
;
3718 ipp_attribute_t *attr;
3719 ipp_t *response;
3720 gboolean list_has_changed;
3721 GList *removed_printer_checklist;
3722 gchar *remote_default_printer = NULL((void*)0);
3723 GList *iter;
3724
3725 cdk_threads_enter ();
3726
3727 list_has_changed = FALSE(0);
3728
3729 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
3730 g_print ("CUPS Backend: %s\n", G_STRFUNC))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
;
3731
3732 cups_backend->list_printers_pending = FALSE(0);
3733
3734 if (ctk_cups_result_is_error (result))
3735 {
3736 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Error getting printer list: %s %d %d"
, ctk_cups_result_get_error_string (result), ctk_cups_result_get_error_type
(result), ctk_cups_result_get_error_code (result)); }; } while
(0)
3737 g_warning ("CUPS Backend: Error getting printer list: %s %d %d",do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Error getting printer list: %s %d %d"
, ctk_cups_result_get_error_string (result), ctk_cups_result_get_error_type
(result), ctk_cups_result_get_error_code (result)); }; } while
(0)
3738 ctk_cups_result_get_error_string (result),do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Error getting printer list: %s %d %d"
, ctk_cups_result_get_error_string (result), ctk_cups_result_get_error_type
(result), ctk_cups_result_get_error_code (result)); }; } while
(0)
3739 ctk_cups_result_get_error_type (result),do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Error getting printer list: %s %d %d"
, ctk_cups_result_get_error_string (result), ctk_cups_result_get_error_type
(result), ctk_cups_result_get_error_code (result)); }; } while
(0)
3740 ctk_cups_result_get_error_code (result)))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Error getting printer list: %s %d %d"
, ctk_cups_result_get_error_string (result), ctk_cups_result_get_error_type
(result), ctk_cups_result_get_error_code (result)); }; } while
(0)
;
3741
3742 if (ctk_cups_result_get_error_type (result) == CTK_CUPS_ERROR_AUTH &&
3743 ctk_cups_result_get_error_code (result) == 1)
3744 {
3745 /* Canceled by user, stop popping up more password dialogs */
3746 if (cups_backend->list_printers_poll > 0)
3747 g_source_remove (cups_backend->list_printers_poll);
3748 cups_backend->list_printers_poll = 0;
3749 cups_backend->list_printers_attempts = 0;
3750 }
3751
3752 goto done;
3753 }
3754
3755 /* Gather the names of the printers in the current queue
3756 * so we may check to see if they were removed
3757 */
3758 removed_printer_checklist = ctk_print_backend_get_printer_list (backend);
3759
3760 response = ctk_cups_result_get_response (result);
3761 for (attr = ippFirstAttribute (response); attr != NULL((void*)0);
3762 attr = ippNextAttribute (response))
3763 {
3764 CtkPrinter *printer;
3765 gboolean status_changed = FALSE(0);
3766 GList *node;
3767 PrinterSetupInfo *info = g_slice_new0 (PrinterSetupInfo)((PrinterSetupInfo*) g_slice_alloc0 (sizeof (PrinterSetupInfo
)))
;
3768
3769 /* Skip leading attributes until we hit a printer...
3770 */
3771 while (attr != NULL((void*)0) && ippGetGroupTag (attr) != IPP_TAG_PRINTER)
3772 attr = ippNextAttribute (response);
3773
3774 if (attr == NULL((void*)0))
3775 break;
3776
3777 while (attr != NULL((void*)0) && ippGetGroupTag (attr) == IPP_TAG_PRINTER)
3778 {
3779 cups_printer_handle_attribute (cups_backend, attr, info);
3780 attr = ippNextAttribute (response);
3781 }
3782
3783 if (info->printer_name == NULL((void*)0) ||
3784 (info->printer_uri == NULL((void*)0) && info->member_uris == NULL((void*)0)))
3785 {
3786 if (attr == NULL((void*)0))
3787 break;
3788 else
3789 continue;
3790 }
3791
3792 /* Do not show printer for queue which was removed from Avahi. */
3793 iter = g_list_find_custom (CTK_PRINT_BACKEND_CUPS (backend)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((backend)), ((ctk_print_backend_cups_get_type
()))))))
->temporary_queues_removed,
3794 info->printer_name, (GCompareFunc) g_strcmp0);
3795 if (iter != NULL((void*)0))
3796 continue;
3797
3798 if (info->got_printer_type)
3799 {
3800 if (info->default_printer && !cups_backend->got_default_printer)
3801 {
3802 if (!info->remote_printer)
3803 {
3804 cups_backend->got_default_printer = TRUE(!(0));
3805 cups_backend->default_printer = g_strdup (info->printer_name)g_strdup_inline (info->printer_name);
3806 }
3807 else
3808 {
3809 if (remote_default_printer == NULL((void*)0))
3810 remote_default_printer = g_strdup (info->printer_name)g_strdup_inline (info->printer_name);
3811 }
3812 }
3813 }
3814 else
3815 {
3816 if (!cups_backend->got_default_printer)
3817 cups_get_default_printer (cups_backend);
3818 }
3819
3820 /* remove name from checklist if it was found */
3821 node = g_list_find_custom (removed_printer_checklist,
3822 info->printer_name,
3823 (GCompareFunc) find_printer);
3824 removed_printer_checklist = g_list_delete_link (removed_printer_checklist,
3825 node);
3826
3827 printer = ctk_print_backend_find_printer (backend, info->printer_name);
3828 if (!printer)
3829 {
3830 printer = cups_create_printer (cups_backend, info);
3831 list_has_changed = TRUE(!(0));
3832 }
3833 else if (CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->avahi_browsed && info->is_temporary)
3834 {
3835 /*
3836 * A temporary queue was created for a printer found via Avahi.
3837 * We modify the placeholder CtkPrinter to point to the temporary queue
3838 * instead of removing the placeholder CtkPrinter and creating new CtkPrinter.
3839 */
3840
3841 g_object_ref (printer)((__typeof__ (printer)) (g_object_ref) (printer));
3842
3843 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->avahi_browsed = FALSE(0);
3844 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->is_temporary = TRUE(!(0));
3845 g_free (CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->device_uri);
3846 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->device_uri = g_strdup_printf ("/printers/%s",
3847 info->printer_name);
3848 ctk_printer_set_has_details (printer, FALSE(0));
3849 cups_printer_request_details (printer);
3850 }
3851 else
3852 g_object_ref (printer)((__typeof__ (printer)) (g_object_ref) (printer));
3853
3854 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->remote = info->remote_printer;
3855
3856 ctk_printer_set_is_paused (printer, info->is_paused);
3857 ctk_printer_set_is_accepting_jobs (printer, info->is_accepting_jobs);
3858
3859 if (!ctk_printer_is_active (printer))
3860 {
3861 ctk_printer_set_is_active (printer, TRUE(!(0)));
3862 ctk_printer_set_is_new (printer, TRUE(!(0)));
3863 list_has_changed = TRUE(!(0));
3864 }
3865
3866 if (ctk_printer_is_new (printer))
3867 {
3868 g_signal_emit_by_name (backend, "printer-added", printer);
3869
3870 ctk_printer_set_is_new (printer, FALSE(0));
3871 }
3872
3873 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->state = info->state;
3874 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->ipp_version_major = info->ipp_version_major;
3875 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->ipp_version_minor = info->ipp_version_minor;
3876 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->supports_copies = info->supports_copies;
3877 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->supports_collate = info->supports_collate;
3878 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->supports_number_up = info->supports_number_up;
3879 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->number_of_covers = info->number_of_covers;
3880 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->covers = g_strdupv (info->covers);
3881 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->is_temporary = info->is_temporary;
3882 status_changed = ctk_printer_set_job_count (printer, info->job_count);
3883 status_changed |= ctk_printer_set_location (printer, info->location);
3884 status_changed |= ctk_printer_set_description (printer,
3885 info->description);
3886
3887 set_info_state_message (info);
3888
3889 status_changed |= ctk_printer_set_state_message (printer, info->state_msg);
3890 status_changed |= ctk_printer_set_is_accepting_jobs (printer, info->is_accepting_jobs);
3891
3892 set_printer_icon_name_from_info (printer, info);
3893
3894 if (status_changed)
3895 g_signal_emit_by_name (CTK_PRINT_BACKEND (backend)((((CtkPrintBackend*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((backend)), ((ctk_print_backend_get_type ()))))))
,
3896 "printer-status-changed", printer);
3897
3898 /* The ref is held by CtkPrintBackend, in add_printer() */
3899 g_object_unref (printer);
3900 printer_setup_info_free (info);
3901
3902 if (attr == NULL((void*)0))
3903 break;
3904 }
3905
3906 /* look at the removed printers checklist and mark any printer
3907 as inactive if it is in the list, emitting a printer_removed signal */
3908 if (removed_printer_checklist != NULL((void*)0))
3909 {
3910 for (iter = removed_printer_checklist; iter; iter = iter->next)
3911 {
3912 if (!CTK_PRINTER_CUPS (iter->data)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((iter->data)), ((ctk_printer_cups_get_type ()))))))
->avahi_browsed)
3913 {
3914 mark_printer_inactive (CTK_PRINTER (iter->data)((((CtkPrinter*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((iter->data)), ((ctk_printer_get_type ()))))))
, backend);
3915 list_has_changed = TRUE(!(0));
3916 }
3917 }
3918
3919 g_list_free (removed_printer_checklist);
3920 }
3921
3922done:
3923 if (list_has_changed)
3924 g_signal_emit_by_name (backend, "printer-list-changed");
3925
3926 ctk_print_backend_set_list_done (backend);
3927
3928 if (!cups_backend->got_default_printer && remote_default_printer != NULL((void*)0))
3929 {
3930 set_default_printer (cups_backend, remote_default_printer);
3931 g_free (remote_default_printer);
3932 }
3933
3934 if (!cups_backend->got_default_printer && cups_backend->avahi_default_printer != NULL((void*)0))
3935 set_default_printer (cups_backend, cups_backend->avahi_default_printer);
3936
3937 cdk_threads_leave ();
3938}
3939
3940static void
3941update_backend_status (CtkPrintBackendCups *cups_backend,
3942 CtkCupsConnectionState state)
3943{
3944 switch (state)
3945 {
3946 case CTK_CUPS_CONNECTION_NOT_AVAILABLE:
3947 g_object_set (cups_backend, "status", CTK_PRINT_BACKEND_STATUS_UNAVAILABLE, NULL((void*)0));
3948 break;
3949 case CTK_CUPS_CONNECTION_AVAILABLE:
3950 g_object_set (cups_backend, "status", CTK_PRINT_BACKEND_STATUS_OK, NULL((void*)0));
3951 break;
3952 default: ;
3953 }
3954}
3955
3956static gboolean
3957cups_request_printer_list (CtkPrintBackendCups *cups_backend)
3958{
3959 CtkCupsConnectionState state;
3960 CtkCupsRequest *request;
3961
3962 if (cups_backend->reading_ppds > 0 || cups_backend->list_printers_pending)
3963 return TRUE(!(0));
3964
3965 state = ctk_cups_connection_test_get_state (cups_backend->cups_connection_test);
3966 update_backend_status (cups_backend, state);
3967
3968 if (cups_backend->list_printers_attempts == 60)
3969 {
3970 cups_backend->list_printers_attempts = -1;
3971 if (cups_backend->list_printers_poll > 0)
3972 g_source_remove (cups_backend->list_printers_poll);
3973 cups_backend->list_printers_poll = cdk_threads_add_timeout (200,
3974 (GSourceFunc) cups_request_printer_list,
3975 cups_backend);
3976 g_source_set_name_by_id (cups_backend->list_printers_poll, "[ctk+] cups_request_printer_list");
3977 }
3978 else if (cups_backend->list_printers_attempts != -1)
3979 cups_backend->list_printers_attempts++;
3980
3981 if (state == CTK_CUPS_CONNECTION_IN_PROGRESS || state == CTK_CUPS_CONNECTION_NOT_AVAILABLE)
3982 return TRUE(!(0));
3983 else
3984 if (cups_backend->list_printers_attempts > 0)
3985 cups_backend->list_printers_attempts = 60;
3986
3987 cups_backend->list_printers_pending = TRUE(!(0));
3988
3989 request = ctk_cups_request_new_with_username (NULL((void*)0),
3990 CTK_CUPS_POST,
3991 CUPS_GET_PRINTERSIPP_OP_CUPS_GET_PRINTERS,
3992 NULL((void*)0),
3993 NULL((void*)0),
3994 NULL((void*)0),
3995 cups_backend->username);
3996
3997 ctk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
3998 "requested-attributes", G_N_ELEMENTS (printer_attrs)(sizeof (printer_attrs) / sizeof ((printer_attrs)[0])),
3999 NULL((void*)0), printer_attrs);
4000
4001 cups_request_execute (cups_backend,
4002 request,
4003 (CtkPrintCupsResponseCallbackFunc) cups_request_printer_list_cb,
4004 request,
4005 NULL((void*)0));
4006
4007 return TRUE(!(0));
4008}
4009
4010static void
4011cups_get_printer_list (CtkPrintBackend *backend)
4012{
4013 CtkPrintBackendCups *cups_backend;
4014
4015 cups_backend = CTK_PRINT_BACKEND_CUPS (backend)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((backend)), ((ctk_print_backend_cups_get_type
()))))))
;
4016
4017 if (cups_backend->cups_connection_test == NULL((void*)0))
4018 cups_backend->cups_connection_test = ctk_cups_connection_test_new (NULL((void*)0), -1);
4019
4020 if (cups_backend->list_printers_poll == 0)
4021 {
4022 if (cups_request_printer_list (cups_backend))
4023 {
4024 cups_backend->list_printers_poll = cdk_threads_add_timeout (50,
4025 (GSourceFunc) cups_request_printer_list,
4026 backend);
4027 g_source_set_name_by_id (cups_backend->list_printers_poll, "[ctk+] cups_request_printer_list");
4028 }
4029
4030 avahi_request_printer_list (cups_backend);
4031 }
4032}
4033
4034typedef struct {
4035 CtkPrinterCups *printer;
4036 GIOChannel *ppd_io;
4037 http_t *http;
4038} GetPPDData;
4039
4040static void
4041get_ppd_data_free (GetPPDData *data)
4042{
4043 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
4044 g_print ("CUPS Backend: %s\n", G_STRFUNC))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
;
4045 httpClose (data->http);
4046 g_io_channel_unref (data->ppd_io);
4047 g_object_unref (data->printer);
4048 g_free (data);
4049}
4050
4051static void
4052cups_request_ppd_cb (CtkPrintBackendCups *print_backend,
4053 CtkCupsResult *result,
4054 GetPPDData *data)
4055{
4056 CtkPrinter *printer;
4057 struct stat data_info;
4058
4059 cdk_threads_enter ();
4060
4061 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
4062 g_print ("CUPS Backend: %s\n", G_STRFUNC))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
;
4063
4064 printer = CTK_PRINTER (data->printer)((((CtkPrinter*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data->printer)), ((ctk_printer_get_type ()))))))
;
4065 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->reading_ppd = FALSE(0);
4066 print_backend->reading_ppds--;
4067
4068 if (!ctk_cups_result_is_error (result))
4069 {
4070 /* let ppdOpenFd take over the ownership of the open file */
4071 g_io_channel_seek_position (data->ppd_io, 0, G_SEEK_SET, NULL((void*)0));
4072 data->printer->ppd_file = ppdOpenFd (dup (g_io_channel_unix_get_fd (data->ppd_io)));
4073 ppdLocalize (data->printer->ppd_file);
4074 ppdMarkDefaults (data->printer->ppd_file);
4075 }
4076
4077 fstat (g_io_channel_unix_get_fd (data->ppd_io), &data_info);
4078 /*
4079 * Standalone Avahi printers and raw printers don't have PPD files or have
4080 * empty PPD files. Try to get printer details via IPP.
4081 * Always do this for Avahi printers.
4082 */
4083 if (data_info.st_size == 0 ||
4084 CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
->avahi_browsed ||
4085 (ctk_cups_result_is_error (result) &&
4086 ((ctk_cups_result_get_error_type (result) == CTK_CUPS_ERROR_HTTP) &&
4087 (ctk_cups_result_get_error_status (result) == HTTP_NOT_FOUNDHTTP_STATUS_NOT_FOUND))))
4088 {
4089 CtkPrinterCups *cups_printer = CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
;
4090
4091 /* Try to get the PPD from original host if it is not
4092 * available on current CUPS server.
4093 */
4094 if (!cups_printer->avahi_browsed &&
4095 (ctk_cups_result_is_error (result) &&
4096 ((ctk_cups_result_get_error_type (result) == CTK_CUPS_ERROR_HTTP) &&
4097 (ctk_cups_result_get_error_status (result) == HTTP_NOT_FOUNDHTTP_STATUS_NOT_FOUND))) &&
4098 cups_printer->remote &&
4099 !cups_printer->request_original_uri &&
4100 cups_printer->original_device_uri != NULL((void*)0) &&
4101 (g_str_has_prefix (cups_printer->original_device_uri, "ipp://")(__builtin_constant_p ("ipp://")? __extension__ ({ const char
* const __str = (cups_printer->original_device_uri); const
char * const __prefix = ("ipp://"); gboolean __result = (0);
if (__str == ((void*)0) || __prefix == ((void*)0)) __result =
(g_str_has_prefix) (__str, __prefix); else { const size_t __str_len
= strlen (((__str) + !(__str))); const size_t __prefix_len =
strlen (((__prefix) + !(__prefix))); if (__str_len >= __prefix_len
) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix
)), __prefix_len) == 0; } __result; }) : (g_str_has_prefix) (
cups_printer->original_device_uri, "ipp://") )
||
4102 g_str_has_prefix (cups_printer->original_device_uri, "ipps://")(__builtin_constant_p ("ipps://")? __extension__ ({ const char
* const __str = (cups_printer->original_device_uri); const
char * const __prefix = ("ipps://"); gboolean __result = (0)
; if (__str == ((void*)0) || __prefix == ((void*)0)) __result
= (g_str_has_prefix) (__str, __prefix); else { const size_t __str_len
= strlen (((__str) + !(__str))); const size_t __prefix_len =
strlen (((__prefix) + !(__prefix))); if (__str_len >= __prefix_len
) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix
)), __prefix_len) == 0; } __result; }) : (g_str_has_prefix) (
cups_printer->original_device_uri, "ipps://") )
))
4103 {
4104 cups_printer->request_original_uri = TRUE(!(0));
4105
4106 ctk_cups_connection_test_free (cups_printer->remote_cups_connection_test);
4107 g_clear_handle_id (&cups_printer->get_remote_ppd_poll, g_source_remove)do { _Static_assert (sizeof *(&cups_printer->get_remote_ppd_poll
) == sizeof (guint), "Expression evaluates to false"); guint *
_tag_ptr = (guint *) (&cups_printer->get_remote_ppd_poll
); guint _handle_id; _handle_id = *_tag_ptr; if (_handle_id >
0) { *_tag_ptr = 0; g_source_remove (_handle_id); } } while (
0)
;
4108 cups_printer->get_remote_ppd_attempts = 0;
4109
4110 cups_printer->remote_cups_connection_test =
4111 ctk_cups_connection_test_new (cups_printer->original_hostname,
4112 cups_printer->original_port);
4113
4114 if (cups_request_ppd (printer))
4115 {
4116 cups_printer->get_remote_ppd_poll = g_timeout_add (50, (GSourceFunc) cups_request_ppd, printer);
4117 g_source_set_name_by_id (cups_printer->get_remote_ppd_poll, "[ctk] cups_request_ppd");
4118 }
4119 }
4120 else
4121 {
4122 if (cups_printer->request_original_uri)
4123 cups_printer->request_original_uri = FALSE(0);
4124
4125 cups_request_printer_info (cups_printer);
4126 }
4127
4128 goto done;
4129 }
4130
4131 ctk_printer_set_has_details (printer, TRUE(!(0)));
4132 g_signal_emit_by_name (printer, "details-acquired", TRUE(!(0)));
4133
4134done:
4135 cdk_threads_leave ();
4136}
4137
4138static gboolean
4139cups_request_ppd (CtkPrinter *printer)
4140{
4141 GError *error;
4142 CtkPrintBackend *print_backend;
4143 CtkPrinterCups *cups_printer;
4144 CtkCupsRequest *request;
4145 char *ppd_filename = NULL((void*)0);
4146 gchar *resource;
4147 http_t *http;
4148 GetPPDData *data;
4149 int fd;
4150 const gchar *hostname;
4151 gint port;
4152
4153 cups_printer = CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
;
4154
4155 error = NULL((void*)0);
4156
4157 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
4158 g_print ("CUPS Backend: %s\n", G_STRFUNC))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: %s\n", ((const char*) (__func__))); }
; } while (0)
;
4159
4160 if (cups_printer->remote && !cups_printer->avahi_browsed)
4161 {
4162 CtkCupsConnectionState state;
4163
4164 state = ctk_cups_connection_test_get_state (cups_printer->remote_cups_connection_test);
4165
4166 if (state == CTK_CUPS_CONNECTION_IN_PROGRESS)
4167 {
4168 if (cups_printer->get_remote_ppd_attempts == 60)
4169 {
4170 cups_printer->get_remote_ppd_attempts = -1;
4171 if (cups_printer->get_remote_ppd_poll > 0)
4172 g_source_remove (cups_printer->get_remote_ppd_poll);
4173 cups_printer->get_remote_ppd_poll = cdk_threads_add_timeout (200,
4174 (GSourceFunc) cups_request_ppd,
4175 printer);
4176 g_source_set_name_by_id (cups_printer->get_remote_ppd_poll, "[ctk+] cups_request_ppd");
4177 }
4178 else if (cups_printer->get_remote_ppd_attempts != -1)
4179 cups_printer->get_remote_ppd_attempts++;
4180
4181 return TRUE(!(0));
4182 }
4183
4184 ctk_cups_connection_test_free (cups_printer->remote_cups_connection_test);
4185 cups_printer->remote_cups_connection_test = NULL((void*)0);
4186 cups_printer->get_remote_ppd_poll = 0;
4187 cups_printer->get_remote_ppd_attempts = 0;
4188
4189 if (state == CTK_CUPS_CONNECTION_NOT_AVAILABLE)
4190 {
4191 g_signal_emit_by_name (printer, "details-acquired", FALSE(0));
4192 return FALSE(0);
4193 }
4194 }
4195
4196 if (cups_printer->request_original_uri)
4197 {
4198 hostname = cups_printer->original_hostname;
4199 port = cups_printer->original_port;
4200 resource = g_strdup_printf ("%s.ppd", cups_printer->original_resource);
4201 }
4202 else
4203 {
4204 if (cups_printer->is_temporary)
4205 hostname = cupsServer ();
4206 else
4207 hostname = cups_printer->hostname;
4208
4209 port = cups_printer->port;
4210 resource = g_strdup_printf ("/printers/%s.ppd",
4211 ctk_printer_cups_get_ppd_name (CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
));
4212 }
4213
4214 http = httpConnect2 (hostname, port,
4215 NULL((void*)0), AF_UNSPEC0,
4216 cupsEncryption (),
4217 1, 30000, NULL((void*)0));
4218
4219 data = g_new0 (GetPPDData, 1)((GetPPDData *) g_malloc0_n ((1), sizeof (GetPPDData)));
4220
4221 fd = g_file_open_tmp ("ctkprint_ppd_XXXXXX",
4222 &ppd_filename,
4223 &error);
4224
4225#ifdef G_ENABLE_DEBUG1
4226 /* If we are debugging printing don't delete the tmp files */
4227 if (!(ctk_get_debug_flags () & CTK_DEBUG_PRINTING))
4228 unlink (ppd_filename);
4229#else
4230 unlink (ppd_filename);
4231#endif /* G_ENABLE_DEBUG */
4232
4233 if (error != NULL((void*)0))
4234 {
4235 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Failed to create temp file, %s\n",
error->message); }; } while (0)
4236 g_warning ("CUPS Backend: Failed to create temp file, %s\n",do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Failed to create temp file, %s\n",
error->message); }; } while (0)
4237 error->message))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Failed to create temp file, %s\n",
error->message); }; } while (0)
;
4238 g_error_free (error);
4239 httpClose (http);
4240 g_free (ppd_filename);
4241 g_free (data);
4242
4243 g_signal_emit_by_name (printer, "details-acquired", FALSE(0));
4244 return FALSE(0);
4245 }
4246
4247 data->http = http;
4248 fchmod (fd, S_IRUSR0400 | S_IWUSR0200);
4249 data->ppd_io = g_io_channel_unix_new (fd);
4250 g_io_channel_set_encoding (data->ppd_io, NULL((void*)0), NULL((void*)0));
4251 g_io_channel_set_close_on_unref (data->ppd_io, TRUE(!(0)));
4252
4253 data->printer = (CtkPrinterCups *) g_object_ref (printer)((__typeof__ (printer)) (g_object_ref) (printer));
4254
4255 print_backend = ctk_printer_get_backend (printer);
4256
4257 request = ctk_cups_request_new_with_username (data->http,
4258 CTK_CUPS_GET,
4259 0,
4260 data->ppd_io,
4261 hostname,
4262 resource,
4263 CTK_PRINT_BACKEND_CUPS (print_backend)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((print_backend)), ((ctk_print_backend_cups_get_type
()))))))
->username);
4264
4265 ctk_cups_request_set_ipp_version (request,
4266 cups_printer->ipp_version_major,
4267 cups_printer->ipp_version_minor);
4268
4269 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Requesting resource %s to be written to temp file %s\n"
, resource, ppd_filename); }; } while (0)
4270 g_print ("CUPS Backend: Requesting resource %s to be written to temp file %s\n", resource, ppd_filename))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_print ("CUPS Backend: Requesting resource %s to be written to temp file %s\n"
, resource, ppd_filename); }; } while (0)
;
4271
4272
4273 cups_printer->reading_ppd = TRUE(!(0));
4274 CTK_PRINT_BACKEND_CUPS (print_backend)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((print_backend)), ((ctk_print_backend_cups_get_type
()))))))
->reading_ppds++;
4275
4276 cups_request_execute (CTK_PRINT_BACKEND_CUPS (print_backend)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((print_backend)), ((ctk_print_backend_cups_get_type
()))))))
,
4277 request,
4278 (CtkPrintCupsResponseCallbackFunc) cups_request_ppd_cb,
4279 data,
4280 (GDestroyNotify)get_ppd_data_free);
4281
4282 g_free (resource);
4283 g_free (ppd_filename);
4284
4285 return FALSE(0);
4286}
4287
4288/* Ordering matters for default preference */
4289static const char *lpoptions_locations[] = {
4290 "/etc/cups/lpoptions",
4291 ".lpoptions",
4292 ".cups/lpoptions"
4293};
4294
4295static void
4296cups_parse_user_default_printer (const char *filename,
4297 char **printer_name)
4298{
4299 FILE *fp;
4300 char line[1024], *lineptr, *defname = NULL((void*)0);
4301
4302 if ((fp = g_fopenfopen (filename, "r")) == NULL((void*)0))
4303 return;
4304
4305 while (fgets (line, sizeof (line), fp) != NULL((void*)0))
4306 {
4307 if (strncasecmp (line, "default", 7) != 0 || !isspace (line[7])((*__ctype_b_loc ())[(int) ((line[7]))] & (unsigned short
int) _ISspace)
)
4308 continue;
4309
4310 lineptr = line + 8;
4311 while (isspace (*lineptr)((*__ctype_b_loc ())[(int) ((*lineptr))] & (unsigned short
int) _ISspace)
)
4312 lineptr++;
4313
4314 if (!*lineptr)
4315 continue;
4316
4317 defname = lineptr;
4318 while (!isspace (*lineptr)((*__ctype_b_loc ())[(int) ((*lineptr))] & (unsigned short
int) _ISspace)
&& *lineptr && *lineptr != '/')
4319 lineptr++;
4320
4321 *lineptr = '\0';
4322
4323 g_free (*printer_name);
4324
4325 *printer_name = g_strdup (defname)g_strdup_inline (defname);
4326 }
4327
4328 fclose (fp);
4329}
4330
4331static void
4332cups_get_user_default_printer (char **printer_name)
4333{
4334 int i;
4335
4336 for (i = 0; i < G_N_ELEMENTS (lpoptions_locations)(sizeof (lpoptions_locations) / sizeof ((lpoptions_locations)
[0]))
; i++)
4337 {
4338 if (g_path_is_absolute (lpoptions_locations[i]))
4339 {
4340 cups_parse_user_default_printer (lpoptions_locations[i],
4341 printer_name);
4342 }
4343 else
4344 {
4345 char *filename;
4346
4347 filename = g_build_filename (g_get_home_dir (),
4348 lpoptions_locations[i], NULL((void*)0));
4349 cups_parse_user_default_printer (filename, printer_name);
4350 g_free (filename);
4351 }
4352 }
4353}
4354
4355static int
4356cups_parse_user_options (const char *filename,
4357 const char *printer_name,
4358 int num_options,
4359 cups_option_t **options)
4360{
4361 FILE *fp;
4362 gchar line[1024], *lineptr, *name;
4363
4364 if ((fp = g_fopenfopen (filename, "r")) == NULL((void*)0))
4365 return num_options;
4366
4367 while (fgets (line, sizeof (line), fp) != NULL((void*)0))
4368 {
4369 if (strncasecmp (line, "dest", 4) == 0 && isspace (line[4])((*__ctype_b_loc ())[(int) ((line[4]))] & (unsigned short
int) _ISspace)
)
4370 lineptr = line + 4;
4371 else if (strncasecmp (line, "default", 7) == 0 && isspace (line[7])((*__ctype_b_loc ())[(int) ((line[7]))] & (unsigned short
int) _ISspace)
)
4372 lineptr = line + 7;
4373 else
4374 continue;
4375
4376 /* Skip leading whitespace */
4377 while (isspace (*lineptr)((*__ctype_b_loc ())[(int) ((*lineptr))] & (unsigned short
int) _ISspace)
)
4378 lineptr++;
4379
4380 if (!*lineptr)
4381 continue;
4382
4383 name = lineptr;
4384 while (!isspace (*lineptr)((*__ctype_b_loc ())[(int) ((*lineptr))] & (unsigned short
int) _ISspace)
&& *lineptr)
4385 {
4386 lineptr++;
4387 }
4388
4389 if (!*lineptr)
4390 continue;
4391
4392 *lineptr++ = '\0';
4393
4394 if (strcasecmp (name, printer_name) != 0)
4395 continue;
4396
4397 /* We found our printer, parse the options */
4398 num_options = cupsParseOptions (lineptr, num_options, options);
4399 }
4400
4401 fclose (fp);
4402
4403 return num_options;
4404}
4405
4406static int
4407cups_get_user_options (const char *printer_name,
4408 int num_options,
4409 cups_option_t **options)
4410{
4411 int i;
4412
4413 for (i = 0; i < G_N_ELEMENTS (lpoptions_locations)(sizeof (lpoptions_locations) / sizeof ((lpoptions_locations)
[0]))
; i++)
4414 {
4415 if (g_path_is_absolute (lpoptions_locations[i]))
4416 {
4417 num_options = cups_parse_user_options (lpoptions_locations[i],
4418 printer_name,
4419 num_options,
4420 options);
4421 }
4422 else
4423 {
4424 char *filename;
4425
4426 filename = g_build_filename (g_get_home_dir (),
4427 lpoptions_locations[i], NULL((void*)0));
4428 num_options = cups_parse_user_options (filename, printer_name,
4429 num_options, options);
4430 g_free (filename);
4431 }
4432 }
4433
4434 return num_options;
4435}
4436
4437/* This function requests default printer from a CUPS server in regular intervals.
4438 * In the case of unreachable CUPS server the request is repeated later.
4439 * The default printer is not requested in the case of previous success.
4440 */
4441static void
4442cups_get_default_printer (CtkPrintBackendCups *backend)
4443{
4444 CtkPrintBackendCups *cups_backend;
4445
4446 cups_backend = backend;
4447
4448 if (cups_backend->cups_connection_test == NULL((void*)0))
4449 cups_backend->cups_connection_test = ctk_cups_connection_test_new (NULL((void*)0), -1);
4450
4451 if (cups_backend->default_printer_poll == 0)
4452 {
4453 if (cups_request_default_printer (cups_backend))
4454 {
4455 cups_backend->default_printer_poll = cdk_threads_add_timeout (200,
4456 (GSourceFunc) cups_request_default_printer,
4457 backend);
4458 g_source_set_name_by_id (cups_backend->default_printer_poll, "[ctk+] cups_request_default_printer");
4459 }
4460 }
4461}
4462
4463/* This function gets default printer from local settings.*/
4464static void
4465cups_get_local_default_printer (CtkPrintBackendCups *backend)
4466{
4467 const char *str;
4468 char *name = NULL((void*)0);
4469
4470 if ((str = g_getenv ("LPDEST")) != NULL((void*)0))
4471 {
4472 backend->default_printer = g_strdup (str)g_strdup_inline (str);
4473 backend->got_default_printer = TRUE(!(0));
4474 return;
4475 }
4476 else if ((str = g_getenv ("PRINTER")) != NULL((void*)0) &&
4477 strcmp (str, "lp") != 0)
4478 {
4479 backend->default_printer = g_strdup (str)g_strdup_inline (str);
4480 backend->got_default_printer = TRUE(!(0));
4481 return;
4482 }
4483
4484 /* Figure out user setting for default printer */
4485 cups_get_user_default_printer (&name);
4486 if (name != NULL((void*)0))
4487 {
4488 backend->default_printer = name;
4489 backend->got_default_printer = TRUE(!(0));
4490 return;
4491 }
4492}
4493
4494static void
4495cups_request_default_printer_cb (CtkPrintBackendCups *print_backend,
4496 CtkCupsResult *result,
4497 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
4498{
4499 ipp_t *response;
4500 ipp_attribute_t *attr;
4501
4502 cdk_threads_enter ();
4503
4504 if (ctk_cups_result_is_error (result))
4505 {
4506 if (ctk_cups_result_get_error_type (result) == CTK_CUPS_ERROR_AUTH &&
4507 ctk_cups_result_get_error_code (result) == 1)
4508 {
4509 /* Canceled by user, stop popping up more password dialogs */
4510 if (print_backend->list_printers_poll > 0)
4511 g_source_remove (print_backend->list_printers_poll);
4512 print_backend->list_printers_poll = 0;
4513 }
4514
4515 return;
4516 }
4517
4518 response = ctk_cups_result_get_response (result);
4519
4520 if ((attr = ippFindAttribute (response, "printer-name", IPP_TAG_NAME)) != NULL((void*)0))
4521 print_backend->default_printer = g_strdup (ippGetString (attr, 0, NULL))g_strdup_inline (ippGetString (attr, 0, ((void*)0)));
4522
4523 print_backend->got_default_printer = TRUE(!(0));
4524
4525 if (print_backend->default_printer != NULL((void*)0))
4526 {
4527 CtkPrinter *printer;
4528
4529 printer = ctk_print_backend_find_printer (CTK_PRINT_BACKEND (print_backend)((((CtkPrintBackend*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((print_backend)), ((ctk_print_backend_get_type ()))))))
,
4530 print_backend->default_printer);
4531 if (printer != NULL((void*)0))
4532 {
4533 ctk_printer_set_is_default (printer, TRUE(!(0)));
4534 g_signal_emit_by_name (CTK_PRINT_BACKEND (print_backend)((((CtkPrintBackend*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((print_backend)), ((ctk_print_backend_get_type ()))))))
, "printer-status-changed", printer);
4535 }
4536 }
4537
4538 /* Make sure to kick off get_printers if we are polling it,
4539 * as we could have blocked this reading the default printer
4540 */
4541 if (print_backend->list_printers_poll != 0)
4542 cups_request_printer_list (print_backend);
4543
4544 cdk_threads_leave ();
4545}
4546
4547static gboolean
4548cups_request_default_printer (CtkPrintBackendCups *print_backend)
4549{
4550 CtkCupsConnectionState state;
4551 CtkCupsRequest *request;
4552
4553 state = ctk_cups_connection_test_get_state (print_backend->cups_connection_test);
4554 update_backend_status (print_backend, state);
4555
4556 if (state == CTK_CUPS_CONNECTION_IN_PROGRESS || state == CTK_CUPS_CONNECTION_NOT_AVAILABLE)
4557 return TRUE(!(0));
4558
4559 request = ctk_cups_request_new_with_username (NULL((void*)0),
4560 CTK_CUPS_POST,
4561 CUPS_GET_DEFAULTIPP_OP_CUPS_GET_DEFAULT,
4562 NULL((void*)0),
4563 NULL((void*)0),
4564 NULL((void*)0),
4565 print_backend->username);
4566
4567 cups_request_execute (print_backend,
4568 request,
4569 (CtkPrintCupsResponseCallbackFunc) cups_request_default_printer_cb,
4570 g_object_ref (print_backend)((__typeof__ (print_backend)) (g_object_ref) (print_backend)),
4571 g_object_unref);
4572
4573 return FALSE(0);
4574}
4575
4576static void
4577cups_printer_request_details (CtkPrinter *printer)
4578{
4579 CtkPrinterCups *cups_printer;
4580
4581 cups_printer = CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
;
4582
4583 if (cups_printer->avahi_browsed)
4584 {
4585#ifdef HAVE_CUPS_2_2
4586 create_temporary_queue (CTK_PRINT_BACKEND_CUPS (ctk_printer_get_backend (printer))((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((ctk_printer_get_backend (printer))), ((ctk_print_backend_cups_get_type
()))))))
,
4587 ctk_printer_get_name (printer),
4588 cups_printer->printer_uri,
4589 cups_printer->temporary_queue_device_uri);
4590#endif
4591 }
4592 else if (!cups_printer->reading_ppd &&
4593 ctk_printer_cups_get_ppd (cups_printer) == NULL((void*)0))
4594 {
4595 if (cups_printer->remote && !cups_printer->avahi_browsed)
4596 {
4597 if (cups_printer->get_remote_ppd_poll == 0)
4598 {
4599 cups_printer->remote_cups_connection_test =
4600 ctk_cups_connection_test_new (cups_printer->hostname,
4601 cups_printer->port);
4602
4603 if (cups_request_ppd (printer))
4604 {
4605 cups_printer->get_remote_ppd_poll = cdk_threads_add_timeout (50,
4606 (GSourceFunc) cups_request_ppd,
4607 printer);
4608 g_source_set_name_by_id (cups_printer->get_remote_ppd_poll, "[ctk+] cups_request_ppd");
4609 }
4610 }
4611 }
4612 else
4613 cups_request_ppd (printer);
4614 }
4615}
4616
4617static char *
4618ppd_text_to_utf8 (ppd_file_t *ppd_file,
4619 const char *text)
4620{
4621 const char *encoding = NULL((void*)0);
4622 char *res;
4623
4624 if (g_ascii_strcasecmp (ppd_file->lang_encoding, "UTF-8") == 0)
4625 {
4626 return g_strdup (text)g_strdup_inline (text);
4627 }
4628 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin1") == 0)
4629 {
4630 encoding = "ISO-8859-1";
4631 }
4632 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin2") == 0)
4633 {
4634 encoding = "ISO-8859-2";
4635 }
4636 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin5") == 0)
4637 {
4638 encoding = "ISO-8859-5";
4639 }
4640 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "JIS83-RKSJ") == 0)
4641 {
4642 encoding = "SHIFT-JIS";
4643 }
4644 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "MacStandard") == 0)
4645 {
4646 encoding = "MACINTOSH";
4647 }
4648 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "WindowsANSI") == 0)
4649 {
4650 encoding = "WINDOWS-1252";
4651 }
4652 else
4653 {
4654 /* Fallback, try iso-8859-1... */
4655 encoding = "ISO-8859-1";
4656 }
4657
4658 res = g_convert (text, -1, "UTF-8", encoding, NULL((void*)0), NULL((void*)0), NULL((void*)0));
4659
4660 if (res == NULL((void*)0))
4661 {
4662 CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Unable to convert PPD text\n"); };
} while (0)
4663 g_warning ("CUPS Backend: Unable to convert PPD text\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) {
g_warning ("CUPS Backend: Unable to convert PPD text\n"); };
} while (0)
;
4664 res = g_strdup ("???")g_strdup_inline ("???");
4665 }
4666
4667 return res;
4668}
4669
4670/* TODO: Add more translations for common settings here */
4671
4672static const struct {
4673 const char *keyword;
4674 const char *translation;
4675} cups_option_translations[] = {
4676 { "Duplex", NC_("printing option", "Two Sided")("Two Sided") },
4677 { "MediaType", NC_("printing option", "Paper Type")("Paper Type") },
4678 { "InputSlot", NC_("printing option", "Paper Source")("Paper Source") },
4679 { "OutputBin", NC_("printing option", "Output Tray")("Output Tray") },
4680 { "Resolution", NC_("printing option", "Resolution")("Resolution") },
4681 { "PreFilter", NC_("printing option", "GhostScript pre-filtering")("GhostScript pre-filtering") }
4682};
4683
4684
4685static const struct {
4686 const char *keyword;
4687 const char *choice;
4688 const char *translation;
4689} cups_choice_translations[] = {
4690 { "Duplex", "None", NC_("printing option value", "One Sided")("One Sided") },
4691 /* Translators: this is an option of "Two Sided" */
4692 { "Duplex", "DuplexNoTumble", NC_("printing option value", "Long Edge (Standard)")("Long Edge (Standard)") },
4693 /* Translators: this is an option of "Two Sided" */
4694 { "Duplex", "DuplexTumble", NC_("printing option value", "Short Edge (Flip)")("Short Edge (Flip)") },
4695 /* Translators: this is an option of "Paper Source" */
4696 { "InputSlot", "Auto", NC_("printing option value", "Auto Select")("Auto Select") },
4697 /* Translators: this is an option of "Paper Source" */
4698 { "InputSlot", "AutoSelect", NC_("printing option value", "Auto Select")("Auto Select") },
4699 /* Translators: this is an option of "Paper Source" */
4700 { "InputSlot", "Default", NC_("printing option value", "Printer Default")("Printer Default") },
4701 /* Translators: this is an option of "Paper Source" */
4702 { "InputSlot", "None", NC_("printing option value", "Printer Default")("Printer Default") },
4703 /* Translators: this is an option of "Paper Source" */
4704 { "InputSlot", "PrinterDefault", NC_("printing option value", "Printer Default")("Printer Default") },
4705 /* Translators: this is an option of "Paper Source" */
4706 { "InputSlot", "Unspecified", NC_("printing option value", "Auto Select")("Auto Select") },
4707 /* Translators: this is an option of "Resolution" */
4708 { "Resolution", "default", NC_("printing option value", "Printer Default")("Printer Default") },
4709 /* Translators: this is an option of "GhostScript" */
4710 { "PreFilter", "EmbedFonts", NC_("printing option value", "Embed GhostScript fonts only")("Embed GhostScript fonts only") },
4711 /* Translators: this is an option of "GhostScript" */
4712 { "PreFilter", "Level1", NC_("printing option value", "Convert to PS level 1")("Convert to PS level 1") },
4713 /* Translators: this is an option of "GhostScript" */
4714 { "PreFilter", "Level2", NC_("printing option value", "Convert to PS level 2")("Convert to PS level 2") },
4715 /* Translators: this is an option of "GhostScript" */
4716 { "PreFilter", "No", NC_("printing option value", "No pre-filtering")("No pre-filtering") }
4717};
4718
4719static const struct {
4720 const char *name;
4721 const char *translation;
4722} cups_group_translations[] = {
4723/* Translators: "Miscellaneous" is the label for a button, that opens
4724 up an extra panel of settings in a print dialog. */
4725 { "Miscellaneous", NC_("printing option group", "Miscellaneous")("Miscellaneous") }
4726};
4727
4728static const struct {
4729 const char *ppd_keyword;
4730 const char *name;
4731} ppd_option_names[] = {
4732 { "Duplex", "ctk-duplex" },
4733 { "MediaType", "ctk-paper-type" },
4734 { "InputSlot", "ctk-paper-source" },
4735 { "OutputBin", "ctk-output-tray" }
4736};
4737
4738static const struct {
4739 const char *ipp_option_name;
4740 const char *ctk_option_name;
4741 const char *translation;
4742} ipp_option_translations[] = {
4743 { "sides", "ctk-duplex", NC_("printing option", "Two Sided")("Two Sided") },
4744 { "output-bin", "ctk-output-tray", NC_("printing option", "Output Tray")("Output Tray") }
4745};
4746
4747static const struct {
4748 const char *ipp_option_name;
4749 const char *ipp_choice;
4750 const char *translation;
4751} ipp_choice_translations[] = {
4752 { "sides", "one-sided", NC_("sides", "One Sided")("One Sided") },
4753 /* Translators: this is an option of "Two Sided" */
4754 { "sides", "two-sided-long-edge", NC_("sides", "Long Edge (Standard)")("Long Edge (Standard)") },
4755 /* Translators: this is an option of "Two Sided" */
4756 { "sides", "two-sided-short-edge", NC_("sides", "Short Edge (Flip)")("Short Edge (Flip)") },
4757
4758 /* Translators: Top output bin */
4759 { "output-bin", "top", NC_("output-bin", "Top Bin")("Top Bin") },
4760 /* Translators: Middle output bin */
4761 { "output-bin", "middle", NC_("output-bin", "Middle Bin")("Middle Bin") },
4762 /* Translators: Bottom output bin */
4763 { "output-bin", "bottom", NC_("output-bin", "Bottom Bin")("Bottom Bin") },
4764 /* Translators: Side output bin */
4765 { "output-bin", "side", NC_("output-bin", "Side Bin")("Side Bin") },
4766 /* Translators: Left output bin */
4767 { "output-bin", "left", NC_("output-bin", "Left Bin")("Left Bin") },
4768 /* Translators: Right output bin */
4769 { "output-bin", "right", NC_("output-bin", "Right Bin")("Right Bin") },
4770 /* Translators: Center output bin */
4771 { "output-bin", "center", NC_("output-bin", "Center Bin")("Center Bin") },
4772 /* Translators: Rear output bin */
4773 { "output-bin", "rear", NC_("output-bin", "Rear Bin")("Rear Bin") },
4774 /* Translators: Output bin where one sided output is oriented in the face-up position */
4775 { "output-bin", "face-up", NC_("output-bin", "Face Up Bin")("Face Up Bin") },
4776 /* Translators: Output bin where one sided output is oriented in the face-down position */
4777 { "output-bin", "face-down", NC_("output-bin", "Face Down Bin")("Face Down Bin") },
4778 /* Translators: Large capacity output bin */
4779 { "output-bin", "large-capacity", NC_("output-bin", "Large Capacity Bin")("Large Capacity Bin") },
4780 { NULL((void*)0), NULL((void*)0), NULL((void*)0) }
4781};
4782
4783/*
4784 * Handles "format not a string literal" error
4785 * https://mail.gnome.org/archives/desktop-devel-list/2016-March/msg00075.html
4786 */
4787static gchar *
4788get_ipp_choice_translation_string (gint index,
4789 guint i)
4790{
4791 gchar *translation;
4792
4793 if (i < G_N_ELEMENTS (ipp_choice_translations)(sizeof (ipp_choice_translations) / sizeof ((ipp_choice_translations
)[0]))
)
4794 translation = g_strdup (_(ipp_choice_translations[i].translation))g_strdup_inline (((char *) g_dgettext ("ctk30", ipp_choice_translations
[i].translation)))
;
4795 else
4796 {
4797 switch (i)
4798 {
4799 case 14:
4800 /* Translators: Output stacker number %d */
4801 translation = g_strdup_printf (C_("output-bin", "Stacker %d")g_dpgettext ("ctk30", "output-bin" "\004" "Stacker %d", strlen
("output-bin") + 1)
, index);
4802 break;
4803 case 15:
4804 /* Translators: Output mailbox number %d */
4805 translation = g_strdup_printf (C_("output-bin", "Mailbox %d")g_dpgettext ("ctk30", "output-bin" "\004" "Mailbox %d", strlen
("output-bin") + 1)
, index);
4806 break;
4807 case 16:
4808 /* Translators: Private mailbox */
4809 translation = g_strdup (C_("output-bin", "My Mailbox"))g_strdup_inline (g_dpgettext ("ctk30", "output-bin" "\004" "My Mailbox"
, strlen ("output-bin") + 1))
;
4810 break;
4811 case 17:
4812 /* Translators: Output tray number %d */
4813 translation = g_strdup_printf (C_("output-bin", "Tray %d")g_dpgettext ("ctk30", "output-bin" "\004" "Tray %d", strlen (
"output-bin") + 1)
, index);
4814 break;
4815 default:
4816 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "ctkprintbackendcups.c"
, 4816, ((const char*) (__func__)), ((void*)0)); } while (0)
;
4817 }
4818 }
4819
4820 return translation;
4821}
4822
4823static const struct {
4824 const char *lpoption;
4825 const char *name;
4826} lpoption_names[] = {
4827 { "number-up", "ctk-n-up" },
4828 { "number-up-layout", "ctk-n-up-layout" },
4829 { "job-billing", "ctk-billing-info" },
4830 { "job-priority", "ctk-job-prio" }
4831};
4832
4833/* keep sorted when changing */
4834static const char *color_option_whitelist[] = {
4835 "BRColorEnhancement",
4836 "BRColorMatching",
4837 "BRColorMatching",
4838 "BRColorMode",
4839 "BRGammaValue",
4840 "BRImprovedGray",
4841 "BlackSubstitution",
4842 "ColorModel",
4843 "HPCMYKInks",
4844 "HPCSGraphics",
4845 "HPCSImages",
4846 "HPCSText",
4847 "HPColorSmart",
4848 "RPSBlackMode",
4849 "RPSBlackOverPrint",
4850 "Rcmyksimulation",
4851};
4852
4853/* keep sorted when changing */
4854static const char *color_group_whitelist[] = {
4855 "ColorPage",
4856 "FPColorWise1",
4857 "FPColorWise2",
4858 "FPColorWise3",
4859 "FPColorWise4",
4860 "FPColorWise5",
4861 "HPColorOptionsPanel",
4862};
4863
4864/* keep sorted when changing */
4865static const char *image_quality_option_whitelist[] = {
4866 "BRDocument",
4867 "BRHalfTonePattern",
4868 "BRNormalPrt",
4869 "BRPrintQuality",
4870 "BitsPerPixel",
4871 "Darkness",
4872 "Dithering",
4873 "EconoMode",
4874 "Economode",
4875 "HPEconoMode",
4876 "HPEdgeControl",
4877 "HPGraphicsHalftone",
4878 "HPHalftone",
4879 "HPLJDensity",
4880 "HPPhotoHalftone",
4881 "OutputMode",
4882 "REt",
4883 "RPSBitsPerPixel",
4884 "RPSDitherType",
4885 "Resolution",
4886 "ScreenLock",
4887 "Smoothing",
4888 "TonerSaveMode",
4889 "UCRGCRForImage",
4890};
4891
4892/* keep sorted when changing */
4893static const char *image_quality_group_whitelist[] = {
4894 "FPImageQuality1",
4895 "FPImageQuality2",
4896 "FPImageQuality3",
4897 "ImageQualityPage",
4898};
4899
4900/* keep sorted when changing */
4901static const char * finishing_option_whitelist[] = {
4902 "BindColor",
4903 "BindEdge",
4904 "BindType",
4905 "BindWhen",
4906 "Booklet",
4907 "FoldType",
4908 "FoldWhen",
4909 "HPStaplerOptions",
4910 "Jog",
4911 "Slipsheet",
4912 "Sorter",
4913 "StapleLocation",
4914 "StapleOrientation",
4915 "StapleWhen",
4916 "StapleX",
4917 "StapleY",
4918};
4919
4920/* keep sorted when changing */
4921static const char *finishing_group_whitelist[] = {
4922 "FPFinishing1",
4923 "FPFinishing2",
4924 "FPFinishing3",
4925 "FPFinishing4",
4926 "FinishingPage",
4927 "HPFinishingPanel",
4928};
4929
4930/* keep sorted when changing */
4931static const char *cups_option_blacklist[] = {
4932 "Collate",
4933 "Copies",
4934 "OutputOrder",
4935 "PageRegion",
4936 "PageSize",
4937};
4938
4939static char *
4940get_option_text (ppd_file_t *ppd_file,
4941 ppd_option_t *option)
4942{
4943 int i;
4944 char *utf8;
4945
4946 for (i = 0; i < G_N_ELEMENTS (cups_option_translations)(sizeof (cups_option_translations) / sizeof ((cups_option_translations
)[0]))
; i++)
4947 {
4948 if (strcmp (cups_option_translations[i].keyword, option->keyword) == 0)
4949 return g_strdup (g_dpgettext2 (GETTEXT_PACKAGE,g_strdup_inline (g_dpgettext2 ("ctk30", "printing option", cups_option_translations
[i].translation))
4950 "printing option",g_strdup_inline (g_dpgettext2 ("ctk30", "printing option", cups_option_translations
[i].translation))
4951 cups_option_translations[i].translation))g_strdup_inline (g_dpgettext2 ("ctk30", "printing option", cups_option_translations
[i].translation))
;
4952 }
4953
4954 utf8 = ppd_text_to_utf8 (ppd_file, option->text);
4955
4956 /* Some ppd files have spaces in the text before the colon */
4957 g_strchomp (utf8);
4958
4959 return utf8;
4960}
4961
4962static char *
4963get_choice_text (ppd_file_t *ppd_file,
4964 ppd_choice_t *choice)
4965{
4966 int i;
4967 ppd_option_t *option = choice->option;
4968 const char *keyword = option->keyword;
4969
4970 for (i = 0; i < G_N_ELEMENTS (cups_choice_translations)(sizeof (cups_choice_translations) / sizeof ((cups_choice_translations
)[0]))
; i++)
4971 {
4972 if (strcmp (cups_choice_translations[i].keyword, keyword) == 0 &&
4973 strcmp (cups_choice_translations[i].choice, choice->choice) == 0)
4974 return g_strdup (g_dpgettext2 (GETTEXT_PACKAGE,g_strdup_inline (g_dpgettext2 ("ctk30", "printing option value"
, cups_choice_translations[i].translation))
4975 "printing option value",g_strdup_inline (g_dpgettext2 ("ctk30", "printing option value"
, cups_choice_translations[i].translation))
4976 cups_choice_translations[i].translation))g_strdup_inline (g_dpgettext2 ("ctk30", "printing option value"
, cups_choice_translations[i].translation))
;
4977 }
4978 return ppd_text_to_utf8 (ppd_file, choice->text);
4979}
4980
4981static gboolean
4982group_has_option (ppd_group_t *group,
4983 ppd_option_t *option)
4984{
4985 int i;
4986
4987 if (group == NULL((void*)0))
4988 return FALSE(0);
4989
4990 if (group->num_options > 0 &&
4991 option >= group->options && option < group->options + group->num_options)
4992 return TRUE(!(0));
4993
4994 for (i = 0; i < group->num_subgroups; i++)
4995 {
4996 if (group_has_option (&group->subgroups[i],option))
4997 return TRUE(!(0));
4998 }
4999 return FALSE(0);
5000}
5001
5002static void
5003set_option_off (CtkPrinterOption *option)
5004{
5005 /* Any of these will do, _set only applies the value
5006 * if its allowed of the option */
5007 ctk_printer_option_set (option, "False");
5008 ctk_printer_option_set (option, "Off");
5009 ctk_printer_option_set (option, "None");
5010}
5011
5012static gboolean
5013value_is_off (const char *value)
5014{
5015 return (strcasecmp (value, "None") == 0 ||
5016 strcasecmp (value, "Off") == 0 ||
5017 strcasecmp (value, "False") == 0);
5018}
5019
5020static const char *
5021ppd_group_name (ppd_group_t *group)
5022{
5023 return group->name;
5024}
5025
5026static int
5027available_choices (ppd_file_t *ppd,
5028 ppd_option_t *option,
5029 ppd_choice_t ***available,
5030 gboolean keep_if_only_one_option)
5031{
5032 ppd_option_t *other_option;
5033 int i, j;
5034 gchar *conflicts;
5035 ppd_const_t *constraint;
5036 const char *choice, *other_choice;
5037 ppd_option_t *option1, *option2;
5038 ppd_group_t *installed_options;
5039 int num_conflicts;
5040 gboolean all_default;
5041 int add_auto;
5042
5043 if (available)
5044 *available = NULL((void*)0);
5045
5046 conflicts = g_new0 (char, option->num_choices)((char *) g_malloc0_n ((option->num_choices), sizeof (char
)))
;
5047
5048 installed_options = NULL((void*)0);
5049 for (i = 0; i < ppd->num_groups; i++)
5050 {
5051 const char *name;
5052
5053 name = ppd_group_name (&ppd->groups[i]);
5054 if (strcmp (name, "InstallableOptions") == 0)
5055 {
5056 installed_options = &ppd->groups[i];
5057 break;
5058 }
5059 }
5060
5061 for (i = ppd->num_consts, constraint = ppd->consts; i > 0; i--, constraint++)
5062 {
5063 option1 = ppdFindOption (ppd, constraint->option1);
5064 if (option1 == NULL((void*)0))
5065 continue;
5066
5067 option2 = ppdFindOption (ppd, constraint->option2);
5068 if (option2 == NULL((void*)0))
5069 continue;
5070
5071 if (option == option1)
5072 {
5073 choice = constraint->choice1;
5074 other_option = option2;
5075 other_choice = constraint->choice2;
5076 }
5077 else if (option == option2)
5078 {
5079 choice = constraint->choice2;
5080 other_option = option1;
5081 other_choice = constraint->choice1;
5082 }
5083 else
5084 continue;
5085
5086 /* We only care of conflicts with installed_options and PageSize */
5087 if (!group_has_option (installed_options, other_option) &&
5088 (strcmp (other_option->keyword, "PageSize") != 0))
5089 continue;
5090
5091 if (*other_choice == 0)
5092 {
5093 /* Conflict only if the installed option is not off */
5094 if (value_is_off (other_option->defchoice))
5095 continue;
5096 }
5097 /* Conflict if the installed option has the specified default */
5098 else if (strcasecmp (other_choice, other_option->defchoice) != 0)
5099 continue;
5100
5101 if (*choice == 0)
5102 {
5103 /* Conflict with all non-off choices */
5104 for (j = 0; j < option->num_choices; j++)
5105 {
5106 if (!value_is_off (option->choices[j].choice))
5107 conflicts[j] = 1;
5108 }
5109 }
5110 else
5111 {
5112 for (j = 0; j < option->num_choices; j++)
5113 {
5114 if (strcasecmp (option->choices[j].choice, choice) == 0)
5115 conflicts[j] = 1;
5116 }
5117 }
5118 }
5119
5120 num_conflicts = 0;
5121 all_default = TRUE(!(0));
5122 for (j = 0; j < option->num_choices; j++)
5123 {
5124 if (conflicts[j])
5125 num_conflicts++;
5126 else if (strcmp (option->choices[j].choice, option->defchoice) != 0)
5127 all_default = FALSE(0);
5128 }
5129
5130 if ((all_default && !keep_if_only_one_option) ||
5131 (num_conflicts == option->num_choices))
5132 {
5133 g_free (conflicts);
5134
5135 return 0;
5136 }
5137
5138 /* Some ppds don't have a "use printer default" option for
5139 * InputSlot. This means you always have to select a particular slot,
5140 * and you can't auto-pick source based on the paper size. To support
5141 * this we always add an auto option if there isn't one already. If
5142 * the user chooses the generated option we don't send any InputSlot
5143 * value when printing. The way we detect existing auto-cases is based
5144 * on feedback from Michael Sweet of cups fame.
5145 */
5146 add_auto = 0;
5147 if (strcmp (option->keyword, "InputSlot") == 0)
5148 {
5149 gboolean found_auto = FALSE(0);
5150 for (j = 0; j < option->num_choices; j++)
5151 {
5152 if (!conflicts[j])
5153 {
5154 if (strcmp (option->choices[j].choice, "Auto") == 0 ||
5155 strcmp (option->choices[j].choice, "AutoSelect") == 0 ||
5156 strcmp (option->choices[j].choice, "Default") == 0 ||
5157 strcmp (option->choices[j].choice, "None") == 0 ||
5158 strcmp (option->choices[j].choice, "PrinterDefault") == 0 ||
5159 strcmp (option->choices[j].choice, "Unspecified") == 0 ||
5160 option->choices[j].code == NULL((void*)0) ||
5161 option->choices[j].code[0] == 0)
5162 {
5163 found_auto = TRUE(!(0));
5164 break;
5165 }
5166 }
5167 }
5168
5169 if (!found_auto)
5170 add_auto = 1;
5171 }
5172
5173 if (available)
5174 {
5175 *available = g_new (ppd_choice_t *, option->num_choices - num_conflicts + add_auto)((ppd_choice_t * *) g_malloc_n ((option->num_choices - num_conflicts
+ add_auto), sizeof (ppd_choice_t *)))
;
5176
5177 i = 0;
5178 for (j = 0; j < option->num_choices; j++)
5179 {
5180 if (!conflicts[j])
5181 (*available)[i++] = &option->choices[j];
5182 }
5183
5184 if (add_auto)
5185 (*available)[i++] = NULL((void*)0);
5186 }
5187
5188 g_free (conflicts);
5189
5190 return option->num_choices - num_conflicts + add_auto;
5191}
5192
5193static CtkPrinterOption *
5194create_pickone_option (ppd_file_t *ppd_file,
5195 ppd_option_t *ppd_option,
5196 const gchar *ctk_name)
5197{
5198 CtkPrinterOption *option;
5199 ppd_choice_t **available;
5200 char *label;
5201 int n_choices;
5202 int i;
5203 ppd_coption_t *coption;
5204
5205 g_assert (ppd_option->ui == PPD_UI_PICKONE)do { if (ppd_option->ui == PPD_UI_PICKONE) ; else g_assertion_message_expr
(((gchar*) 0), "ctkprintbackendcups.c", 5205, ((const char*)
(__func__)), "ppd_option->ui == PPD_UI_PICKONE"); } while
(0)
;
5206
5207 option = NULL((void*)0);
5208
5209 n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (ctk_name, "ctk-")(__builtin_constant_p ("ctk-")? __extension__ ({ const char *
const __str = (ctk_name); const char * const __prefix = ("ctk-"
); gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (ctk_name, "ctk-") )
);
5210 if (n_choices > 0)
5211 {
5212
5213 /* right now only support one parameter per custom option
5214 * if more than one print warning and only offer the default choices
5215 */
5216
5217 label = get_option_text (ppd_file, ppd_option);
5218
5219 coption = ppdFindCustomOption (ppd_file, ppd_option->keyword);
5220
5221 if (coption)
5222 {
5223 ppd_cparam_t *cparam;
5224
5225 cparam = ppdFirstCustomParam (coption);
5226
5227 if (ppdNextCustomParam (coption) == NULL((void*)0))
5228 {
5229 switch (cparam->type)
5230 {
5231 case PPD_CUSTOM_INT:
5232 option = ctk_printer_option_new (ctk_name, label,
5233 CTK_PRINTER_OPTION_TYPE_PICKONE_INT);
5234 break;
5235 case PPD_CUSTOM_PASSCODE:
5236 option = ctk_printer_option_new (ctk_name, label,
5237 CTK_PRINTER_OPTION_TYPE_PICKONE_PASSCODE);
5238 break;
5239 case PPD_CUSTOM_PASSWORD:
5240 option = ctk_printer_option_new (ctk_name, label,
5241 CTK_PRINTER_OPTION_TYPE_PICKONE_PASSWORD);
5242 break;
5243 case PPD_CUSTOM_REAL:
5244 option = ctk_printer_option_new (ctk_name, label,
5245 CTK_PRINTER_OPTION_TYPE_PICKONE_REAL);
5246 break;
5247 case PPD_CUSTOM_STRING:
5248 option = ctk_printer_option_new (ctk_name, label,
5249 CTK_PRINTER_OPTION_TYPE_PICKONE_STRING);
5250 break;
5251#ifdef PRINT_IGNORED_OPTIONS
5252 case PPD_CUSTOM_POINTS:
5253 g_warning ("CUPS Backend: PPD Custom Points Option not supported");
5254 break;
5255 case PPD_CUSTOM_CURVE:
5256 g_warning ("CUPS Backend: PPD Custom Curve Option not supported");
5257 break;
5258 case PPD_CUSTOM_INVCURVE:
5259 g_warning ("CUPS Backend: PPD Custom Inverse Curve Option not supported");
5260 break;
5261#endif
5262 default:
5263 break;
5264 }
5265 }
5266#ifdef PRINT_IGNORED_OPTIONS
5267 else
5268 g_warning ("CUPS Backend: Multi-parameter PPD Custom Option not supported");
5269#endif
5270 }
5271
5272 if (!option)
5273 option = ctk_printer_option_new (ctk_name, label,
5274 CTK_PRINTER_OPTION_TYPE_PICKONE);
5275 g_free (label);
5276
5277 ctk_printer_option_allocate_choices (option, n_choices);
5278 for (i = 0; i < n_choices; i++)
5279 {
5280 if (available[i] == NULL((void*)0))
5281 {
5282 /* This was auto-added */
5283 option->choices[i] = g_strdup ("ctk-ignore-value")g_strdup_inline ("ctk-ignore-value");
5284 option->choices_display[i] = g_strdup (_("Printer Default"))g_strdup_inline (((char *) g_dgettext ("ctk30", "Printer Default"
)))
;
5285 }
5286 else
5287 {
5288 option->choices[i] = g_strdup (available[i]->choice)g_strdup_inline (available[i]->choice);
5289 option->choices_display[i] = get_choice_text (ppd_file, available[i]);
5290 }
5291 }
5292
5293 if (option->type != CTK_PRINTER_OPTION_TYPE_PICKONE)
5294 {
5295 if (g_str_has_prefix (ppd_option->defchoice, "Custom.")(__builtin_constant_p ("Custom.")? __extension__ ({ const char
* const __str = (ppd_option->defchoice); const char * const
__prefix = ("Custom."); gboolean __result = (0); if (__str ==
((void*)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix
) (__str, __prefix); else { const size_t __str_len = strlen (
((__str) + !(__str))); const size_t __prefix_len = strlen (((
__prefix) + !(__prefix))); if (__str_len >= __prefix_len) __result
= memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len
) == 0; } __result; }) : (g_str_has_prefix) (ppd_option->defchoice
, "Custom.") )
)
5296 ctk_printer_option_set (option, ppd_option->defchoice + 7);
5297 else
5298 ctk_printer_option_set (option, ppd_option->defchoice);
5299 }
5300 else
5301 {
5302 ctk_printer_option_set (option, ppd_option->defchoice);
5303 }
5304 }
5305#ifdef PRINT_IGNORED_OPTIONS
5306 else
5307 g_warning ("CUPS Backend: Ignoring pickone %s\n", ppd_option->text);
5308#endif
5309 g_free (available);
5310
5311 return option;
5312}
5313
5314static CtkPrinterOption *
5315create_boolean_option (ppd_file_t *ppd_file,
5316 ppd_option_t *ppd_option,
5317 const gchar *ctk_name)
5318{
5319 CtkPrinterOption *option;
5320 ppd_choice_t **available;
5321 char *label;
5322 int n_choices;
5323
5324 g_assert (ppd_option->ui == PPD_UI_BOOLEAN)do { if (ppd_option->ui == PPD_UI_BOOLEAN) ; else g_assertion_message_expr
(((gchar*) 0), "ctkprintbackendcups.c", 5324, ((const char*)
(__func__)), "ppd_option->ui == PPD_UI_BOOLEAN"); } while
(0)
;
5325
5326 option = NULL((void*)0);
5327
5328 n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (ctk_name, "ctk-")(__builtin_constant_p ("ctk-")? __extension__ ({ const char *
const __str = (ctk_name); const char * const __prefix = ("ctk-"
); gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (ctk_name, "ctk-") )
);
5329 if (n_choices == 2)
5330 {
5331 label = get_option_text (ppd_file, ppd_option);
5332 option = ctk_printer_option_new (ctk_name, label,
5333 CTK_PRINTER_OPTION_TYPE_BOOLEAN);
5334 g_free (label);
5335
5336 ctk_printer_option_allocate_choices (option, 2);
5337 option->choices[0] = g_strdup ("True")g_strdup_inline ("True");
5338 option->choices_display[0] = g_strdup ("True")g_strdup_inline ("True");
5339 option->choices[1] = g_strdup ("False")g_strdup_inline ("False");
5340 option->choices_display[1] = g_strdup ("False")g_strdup_inline ("False");
5341
5342 ctk_printer_option_set (option, ppd_option->defchoice);
5343 }
5344#ifdef PRINT_IGNORED_OPTIONS
5345 else
5346 g_warning ("CUPS Backend: Ignoring boolean %s\n", ppd_option->text);
5347#endif
5348 g_free (available);
5349
5350 return option;
5351}
5352
5353static gchar *
5354get_ppd_option_name (const gchar *keyword)
5355{
5356 int i;
5357
5358 for (i = 0; i < G_N_ELEMENTS (ppd_option_names)(sizeof (ppd_option_names) / sizeof ((ppd_option_names)[0])); i++)
5359 if (strcmp (ppd_option_names[i].ppd_keyword, keyword) == 0)
5360 return g_strdup (ppd_option_names[i].name)g_strdup_inline (ppd_option_names[i].name);
5361
5362 return g_strdup_printf ("cups-%s", keyword);
5363}
5364
5365static gchar *
5366get_lpoption_name (const gchar *lpoption)
5367{
5368 int i;
5369
5370 for (i = 0; i < G_N_ELEMENTS (ppd_option_names)(sizeof (ppd_option_names) / sizeof ((ppd_option_names)[0])); i++)
5371 if (strcmp (ppd_option_names[i].ppd_keyword, lpoption) == 0)
5372 return g_strdup (ppd_option_names[i].name)g_strdup_inline (ppd_option_names[i].name);
5373
5374 for (i = 0; i < G_N_ELEMENTS (lpoption_names)(sizeof (lpoption_names) / sizeof ((lpoption_names)[0])); i++)
5375 if (strcmp (lpoption_names[i].lpoption, lpoption) == 0)
5376 return g_strdup (lpoption_names[i].name)g_strdup_inline (lpoption_names[i].name);
5377
5378 return g_strdup_printf ("cups-%s", lpoption);
5379}
5380
5381static int
5382strptr_cmp (const void *a,
5383 const void *b)
5384{
5385 char **aa = (char **)a;
5386 char **bb = (char **)b;
5387 return strcmp (*aa, *bb);
5388}
5389
5390
5391static gboolean
5392string_in_table (const gchar *str,
5393 const gchar *table[],
5394 gint table_len)
5395{
5396 return bsearch (&str, table, table_len, sizeof (char *), (void *)strptr_cmp) != NULL((void*)0);
5397}
5398
5399#define STRING_IN_TABLE(_str, _table)(string_in_table (_str, _table, (sizeof (_table) / sizeof ((_table
)[0]))))
(string_in_table (_str, _table, G_N_ELEMENTS (_table)(sizeof (_table) / sizeof ((_table)[0]))))
5400
5401static void
5402handle_option (CtkPrinterOptionSet *set,
5403 ppd_file_t *ppd_file,
5404 ppd_option_t *ppd_option,
5405 ppd_group_t *toplevel_group,
5406 CtkPrintSettings *settings)
5407{
5408 CtkPrinterOption *option;
5409 char *option_name;
5410 int i;
5411
5412 if (STRING_IN_TABLE (ppd_option->keyword, cups_option_blacklist)(string_in_table (ppd_option->keyword, cups_option_blacklist
, (sizeof (cups_option_blacklist) / sizeof ((cups_option_blacklist
)[0]))))
)
5413 return;
5414
5415 option_name = get_ppd_option_name (ppd_option->keyword);
5416
5417 option = NULL((void*)0);
5418 if (ppd_option->ui == PPD_UI_PICKONE)
5419 option = create_pickone_option (ppd_file, ppd_option, option_name);
5420 else if (ppd_option->ui == PPD_UI_BOOLEAN)
5421 option = create_boolean_option (ppd_file, ppd_option, option_name);
5422#ifdef PRINT_IGNORED_OPTIONS
5423 else
5424 g_warning ("CUPS Backend: Ignoring pickmany setting %s\n", ppd_option->text);
5425#endif
5426
5427 if (option)
5428 {
5429 const char *name;
5430
5431 name = ppd_group_name (toplevel_group);
5432 if (STRING_IN_TABLE (name, color_group_whitelist)(string_in_table (name, color_group_whitelist, (sizeof (color_group_whitelist
) / sizeof ((color_group_whitelist)[0]))))
||
5433 STRING_IN_TABLE (ppd_option->keyword, color_option_whitelist)(string_in_table (ppd_option->keyword, color_option_whitelist
, (sizeof (color_option_whitelist) / sizeof ((color_option_whitelist
)[0]))))
)
5434 {
5435 option->group = g_strdup ("ColorPage")g_strdup_inline ("ColorPage");
5436 }
5437 else if (STRING_IN_TABLE (name, image_quality_group_whitelist)(string_in_table (name, image_quality_group_whitelist, (sizeof
(image_quality_group_whitelist) / sizeof ((image_quality_group_whitelist
)[0]))))
||
5438 STRING_IN_TABLE (ppd_option->keyword, image_quality_option_whitelist)(string_in_table (ppd_option->keyword, image_quality_option_whitelist
, (sizeof (image_quality_option_whitelist) / sizeof ((image_quality_option_whitelist
)[0]))))
)
5439 {
5440 option->group = g_strdup ("ImageQualityPage")g_strdup_inline ("ImageQualityPage");
5441 }
5442 else if (STRING_IN_TABLE (name, finishing_group_whitelist)(string_in_table (name, finishing_group_whitelist, (sizeof (finishing_group_whitelist
) / sizeof ((finishing_group_whitelist)[0]))))
||
5443 STRING_IN_TABLE (ppd_option->keyword, finishing_option_whitelist)(string_in_table (ppd_option->keyword, finishing_option_whitelist
, (sizeof (finishing_option_whitelist) / sizeof ((finishing_option_whitelist
)[0]))))
)
5444 {
5445 option->group = g_strdup ("FinishingPage")g_strdup_inline ("FinishingPage");
5446 }
5447 else
5448 {
5449 for (i = 0; i < G_N_ELEMENTS (cups_group_translations)(sizeof (cups_group_translations) / sizeof ((cups_group_translations
)[0]))
; i++)
5450 {
5451 if (strcmp (cups_group_translations[i].name, toplevel_group->name) == 0)
5452 {
5453 option->group = g_strdup (g_dpgettext2 (GETTEXT_PACKAGE,g_strdup_inline (g_dpgettext2 ("ctk30", "printing option group"
, cups_group_translations[i].translation))
5454 "printing option group",g_strdup_inline (g_dpgettext2 ("ctk30", "printing option group"
, cups_group_translations[i].translation))
5455 cups_group_translations[i].translation))g_strdup_inline (g_dpgettext2 ("ctk30", "printing option group"
, cups_group_translations[i].translation))
;
5456 break;
5457 }
5458 }
5459
5460 if (i == G_N_ELEMENTS (cups_group_translations)(sizeof (cups_group_translations) / sizeof ((cups_group_translations
)[0]))
)
5461 option->group = g_strdup (toplevel_group->text)g_strdup_inline (toplevel_group->text);
5462 }
5463
5464 set_option_from_settings (option, settings);
5465
5466 ctk_printer_option_set_add (set, option);
5467 }
5468
5469 g_free (option_name);
5470}
5471
5472static void
5473handle_group (CtkPrinterOptionSet *set,
5474 ppd_file_t *ppd_file,
5475 ppd_group_t *group,
5476 ppd_group_t *toplevel_group,
5477 CtkPrintSettings *settings)
5478{
5479 gint i;
5480 const gchar *name;
5481
5482 /* Ignore installable options */
5483 name = ppd_group_name (toplevel_group);
5484 if (strcmp (name, "InstallableOptions") == 0)
5485 return;
5486
5487 for (i = 0; i < group->num_options; i++)
5488 handle_option (set, ppd_file, &group->options[i], toplevel_group, settings);
5489
5490 for (i = 0; i < group->num_subgroups; i++)
5491 handle_group (set, ppd_file, &group->subgroups[i], toplevel_group, settings);
5492
5493}
5494
5495#ifdef HAVE_COLORD1
5496
5497typedef struct {
5498 CtkPrintSettings *settings;
5499 CtkPrinter *printer;
5500} CtkPrintBackendCupsColordHelper;
5501
5502static void
5503colord_printer_option_set_changed_cb (CtkPrinterOptionSet *set,
5504 CtkPrintBackendCupsColordHelper *helper)
5505{
5506 ctk_printer_cups_update_settings (CTK_PRINTER_CUPS (helper->printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((helper->printer)), ((ctk_printer_cups_get_type ()))))
))
,
5507 helper->settings,
5508 set);
5509}
5510#endif
5511
5512/*
5513 * Lookup translation and Ctk+ name of given IPP option name.
5514 */
5515static gboolean
5516get_ipp_option_translation (const gchar *ipp_option_name,
5517 gchar **ctk_option_name,
5518 gchar **translation)
5519{
5520 gint i;
5521
5522 *ctk_option_name = NULL((void*)0);
5523 *translation = NULL((void*)0);
5524
5525 for (i = 0; i < G_N_ELEMENTS (ipp_option_translations)(sizeof (ipp_option_translations) / sizeof ((ipp_option_translations
)[0]))
; i++)
5526 {
5527 if (g_strcmp0 (ipp_option_translations[i].ipp_option_name, ipp_option_name) == 0)
5528 {
5529 *ctk_option_name = g_strdup (ipp_option_translations[i].ctk_option_name)g_strdup_inline (ipp_option_translations[i].ctk_option_name);
5530 *translation = g_strdup (g_dpgettext2 (GETTEXT_PACKAGE,g_strdup_inline (g_dpgettext2 ("ctk30", "printing option", ipp_option_translations
[i].translation))
5531 "printing option",g_strdup_inline (g_dpgettext2 ("ctk30", "printing option", ipp_option_translations
[i].translation))
5532 ipp_option_translations[i].translation))g_strdup_inline (g_dpgettext2 ("ctk30", "printing option", ipp_option_translations
[i].translation))
;
5533 return TRUE(!(0));
5534 }
5535 }
5536
5537 return FALSE(0);
5538}
5539
5540/*
5541 * Lookup translation of given IPP choice.
5542 */
5543static gchar *
5544get_ipp_choice_translation (const gchar *ipp_option_name,
5545 const gchar *ipp_choice)
5546{
5547 const gchar *nptr;
5548 guint64 index;
5549 gchar *translation = NULL((void*)0);
5550 gsize ipp_choice_length;
5551 gchar *endptr;
5552 gint i;
5553
5554 for (i = 0; ipp_choice_translations[i].ipp_option_name != NULL((void*)0); i++)
5555 {
5556 if (g_strcmp0 (ipp_choice_translations[i].ipp_option_name, ipp_option_name) == 0)
5557 {
5558 ipp_choice_length = strlen (ipp_choice_translations[i].ipp_choice);
5559
5560 if (g_strcmp0 (ipp_choice_translations[i].ipp_choice, ipp_choice) == 0)
5561 {
5562 translation = g_strdup (g_dpgettext2 (GETTEXT_PACKAGE,g_strdup_inline (g_dpgettext2 ("ctk30", ipp_option_name, ipp_choice_translations
[i].translation))
5563 ipp_option_name,g_strdup_inline (g_dpgettext2 ("ctk30", ipp_option_name, ipp_choice_translations
[i].translation))
5564 ipp_choice_translations[i].translation))g_strdup_inline (g_dpgettext2 ("ctk30", ipp_option_name, ipp_choice_translations
[i].translation))
;
5565 break;
5566 }
5567 else if (g_str_has_suffix (ipp_choice_translations[i].ipp_choice, "-N")(__builtin_constant_p ("-N")? __extension__ ({ const char * const
__str = (ipp_choice_translations[i].ipp_choice); const char *
const __suffix = ("-N"); gboolean __result = (0); if (__str ==
((void*)0) || __suffix == ((void*)0)) __result = (g_str_has_suffix
) (__str, __suffix); else { const size_t __str_len = strlen (
((__str) + !(__str))); const size_t __suffix_len = strlen (((
__suffix) + !(__suffix))); if (__str_len >= __suffix_len) __result
= memcmp (__str + __str_len - __suffix_len, ((__suffix) + !(
__suffix)), __suffix_len) == 0; } __result; }) : (g_str_has_suffix
) (ipp_choice_translations[i].ipp_choice, "-N") )
&&
5568 g_ascii_strncasecmp (ipp_choice_translations[i].ipp_choice,
5569 ipp_choice,
5570 ipp_choice_length - 2) == 0)
5571 {
5572 /* Find out index of the ipp_choice if it is supported for the choice. */
5573 endptr = NULL((void*)0);
5574 nptr = ipp_choice + ipp_choice_length - 1;
5575 index = g_ascii_strtoull (nptr,
5576 &endptr,
5577 10);
5578
5579 if (index != 0 || endptr != nptr)
5580 {
5581 translation = get_ipp_choice_translation_string (index, i);
5582 break;
5583 }
5584 }
5585 }
5586 }
5587
5588 return translation;
5589}
5590
5591/*
5592 * Format an IPP choice to a displayable string.
5593 */
5594static gchar *
5595format_ipp_choice (const gchar *ipp_choice)
5596{
5597 gboolean after_space = TRUE(!(0));
5598 gchar *result = NULL((void*)0);
5599 gsize i;
5600
5601 if (ipp_choice != NULL((void*)0))
5602 {
5603 result = g_strdup (ipp_choice)g_strdup_inline (ipp_choice);
5604 /* Replace all '-' by spaces. */
5605 result = g_strdelimit (result, "-", ' ');
5606 if (g_str_is_ascii (result))
5607 {
5608 /* Convert all leading characters to upper case. */
5609 for (i = 0; i < strlen (result); i++)
5610 {
5611 if (after_space && g_ascii_isalpha (result[i])((g_ascii_table[(guchar) (result[i])] & G_ASCII_ALPHA) !=
0)
)
5612 result[i] = g_ascii_toupper (result[i]);
5613
5614 after_space = g_ascii_isspace (result[i])((g_ascii_table[(guchar) (result[i])] & G_ASCII_SPACE) !=
0)
;
5615 }
5616 }
5617 }
5618
5619 return result;
5620}
5621
5622/*
5623 * Look the IPP option up in given set of options.
5624 * Create it if it doesn't exist and set its default value
5625 * if available.
5626 */
5627static CtkPrinterOption *
5628setup_ipp_option (gchar *ipp_option_name,
5629 gchar *ipp_choice_default,
5630 GList *ipp_choices,
5631 CtkPrinterOptionSet *set)
5632{
5633 CtkPrinterOption *option = NULL((void*)0);
5634 gchar *ctk_option_name = NULL((void*)0);
5635 gchar *translation = NULL((void*)0);
5636 gsize i;
5637
5638 get_ipp_option_translation (ipp_option_name,
5639 &ctk_option_name,
5640 &translation);
5641
5642 /* Look the option up in the given set of options. */
5643 if (ctk_option_name != NULL((void*)0))
5644 option = ctk_printer_option_set_lookup (set, ctk_option_name);
5645
5646 /* The option was not found, create it from given choices. */
5647 if (option == NULL((void*)0) &&
5648 ipp_choices != NULL((void*)0))
5649 {
5650 GList *iter;
5651 gsize length;
5652 char **choices = NULL((void*)0);
5653 char **choices_display = NULL((void*)0);
5654
5655 option = ctk_printer_option_new (ctk_option_name,
5656 translation,
5657 CTK_PRINTER_OPTION_TYPE_PICKONE);
5658
5659 length = g_list_length (ipp_choices);
5660
5661 choices = g_new0 (char *, length)((char * *) g_malloc0_n ((length), sizeof (char *)));
5662 choices_display = g_new0 (char *, length)((char * *) g_malloc0_n ((length), sizeof (char *)));
5663
5664 i = 0;
5665 for (iter = ipp_choices; iter != NULL((void*)0); iter = iter->next)
5666 {
5667 gchar *ipp_choice;
5668
5669 ipp_choice = (gchar *) iter->data;
5670
5671 choices[i] = g_strdup (ipp_choice)g_strdup_inline (ipp_choice);
5672
5673 translation = get_ipp_choice_translation (ipp_option_name,
5674 ipp_choice);
5675 if (translation != NULL((void*)0))
5676 choices_display[i] = translation;
5677 else
5678 choices_display[i] = format_ipp_choice (ipp_choice);
5679
5680 i++;
5681 }
5682
5683 if (choices != NULL((void*)0) &&
5684 choices_display != NULL((void*)0))
5685 {
5686 ctk_printer_option_choices_from_array (option,
5687 length,
5688 choices,
5689 choices_display);
5690 }
5691
5692 option_set_is_ipp_option (option, TRUE(!(0)));
5693
5694 ctk_printer_option_set_add (set, option);
5695
5696 g_free (choices);
5697 g_free (choices_display);
5698 }
5699
5700 /* The option exists. Set its default value if available. */
5701 if (option != NULL((void*)0) &&
5702 ipp_choice_default != NULL((void*)0))
5703 {
5704 ctk_printer_option_set (option, ipp_choice_default);
5705 }
5706
5707 return option;
5708}
5709
5710static CtkPrinterOptionSet *
5711cups_printer_get_options (CtkPrinter *printer,
5712 CtkPrintSettings *settings,
5713 CtkPageSetup *page_setup,
5714 CtkPrintCapabilities capabilities G_GNUC_UNUSED__attribute__ ((__unused__)))
5715{
5716 CtkPrinterOptionSet *set;
5717 CtkPrinterOption *option;
5718 ppd_file_t *ppd_file;
5719 int i;
5720 char *print_at[] = { "now", "at", "on-hold" };
5721 char *n_up[] = {"1", "2", "4", "6", "9", "16" };
5722 char *prio[] = {"100", "80", "50", "30" };
5723 /* Translators: These strings name the possible values of the
5724 * job priority option in the print dialog
5725 */
5726 char *prio_display[] = {N_("Urgent")("Urgent"), N_("High")("High"), N_("Medium")("Medium"), N_("Low")("Low") };
5727 char *n_up_layout[] = { "lrtb", "lrbt", "rltb", "rlbt", "tblr", "tbrl", "btlr", "btrl" };
5728 /* Translators: These strings name the possible arrangements of
5729 * multiple pages on a sheet when printing
5730 */
5731 char *n_up_layout_display[] = { N_("Left to right, top to bottom")("Left to right, top to bottom"), N_("Left to right, bottom to top")("Left to right, bottom to top"),
5732 N_("Right to left, top to bottom")("Right to left, top to bottom"), N_("Right to left, bottom to top")("Right to left, bottom to top"),
5733 N_("Top to bottom, left to right")("Top to bottom, left to right"), N_("Top to bottom, right to left")("Top to bottom, right to left"),
5734 N_("Bottom to top, left to right")("Bottom to top, left to right"), N_("Bottom to top, right to left")("Bottom to top, right to left") };
5735 char *name;
5736 int num_opts;
5737 cups_option_t *opts = NULL((void*)0);
5738 CtkPrintBackendCups *backend;
5739 CtkTextDirection text_direction;
5740 CtkPrinterCups *cups_printer = NULL((void*)0);
5741#ifdef HAVE_COLORD1
5742 CtkPrintBackendCupsColordHelper *helper;
5743#endif
5744 char *default_number_up;
5745
5746 set = ctk_printer_option_set_new ();
5747
5748 /* Cups specific, non-ppd related settings */
5749
5750 for (i = 0; i < G_N_ELEMENTS(prio_display)(sizeof (prio_display) / sizeof ((prio_display)[0])); i++)
5751 prio_display[i] = _(prio_display[i])((char *) g_dgettext ("ctk30", prio_display[i]));
5752
5753 /* Translators, this string is used to label the job priority option
5754 * in the print dialog
5755 */
5756 option = ctk_printer_option_new ("ctk-job-prio", _("Job Priority")((char *) g_dgettext ("ctk30", "Job Priority")), CTK_PRINTER_OPTION_TYPE_PICKONE);
5757 ctk_printer_option_choices_from_array (option, G_N_ELEMENTS (prio)(sizeof (prio) / sizeof ((prio)[0])),
5758 prio, prio_display);
5759 ctk_printer_option_set (option, "50");
5760 set_option_from_settings (option, settings);
5761 ctk_printer_option_set_add (set, option);
5762 g_object_unref (option);
5763
5764 /* Translators, this string is used to label the billing info entry
5765 * in the print dialog
5766 */
5767 option = ctk_printer_option_new ("ctk-billing-info", _("Billing Info")((char *) g_dgettext ("ctk30", "Billing Info")), CTK_PRINTER_OPTION_TYPE_STRING);
5768 ctk_printer_option_set (option, "");
5769 set_option_from_settings (option, settings);
5770 ctk_printer_option_set_add (set, option);
5771 g_object_unref (option);
5772
5773 backend = CTK_PRINT_BACKEND_CUPS (ctk_printer_get_backend (printer))((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((ctk_printer_get_backend (printer))), ((ctk_print_backend_cups_get_type
()))))))
;
5774 cups_printer = CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
;
5775
5776 if (backend != NULL((void*)0) && printer != NULL((void*)0))
5777 {
5778 char *cover_default[] = {
5779 "none",
5780 "classified",
5781 "confidential",
5782 "secret",
5783 "standard",
5784 "topsecret",
5785 "unclassified"
5786 };
5787 /* Translators, these strings are names for various 'standard' cover
5788 * pages that the printing system may support.
5789 */
5790 char *cover_display_default[] = {
5791 NC_("cover page", "None")("None"),
5792 NC_("cover page", "Classified")("Classified"),
5793 NC_("cover page", "Confidential")("Confidential"),
5794 NC_("cover page", "Secret")("Secret"),
5795 NC_("cover page", "Standard")("Standard"),
5796 NC_("cover page", "Top Secret")("Top Secret"),
5797 NC_("cover page", "Unclassified")("Unclassified")
5798 };
5799 char **cover = NULL((void*)0);
5800 char **cover_display = NULL((void*)0);
5801 char **cover_display_translated = NULL((void*)0);
5802 gint num_of_covers = 0;
5803 gpointer value;
5804 gint j;
5805
5806 /* Translators, this string is used to label the pages-per-sheet option
5807 * in the print dialog
5808 */
5809 option = ctk_printer_option_new ("ctk-n-up", C_("printer option", "Pages per Sheet")g_dpgettext ("ctk30", "printer option" "\004" "Pages per Sheet"
, strlen ("printer option") + 1)
, CTK_PRINTER_OPTION_TYPE_PICKONE);
5810 ctk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up)(sizeof (n_up) / sizeof ((n_up)[0])), n_up, n_up);
5811 default_number_up = g_strdup_printf ("%d", cups_printer->default_number_up);
5812 ctk_printer_option_set (option, default_number_up);
5813 g_free (default_number_up);
5814 set_option_from_settings (option, settings);
5815 ctk_printer_option_set_add (set, option);
5816 g_object_unref (option);
5817
5818 if (cups_printer_get_capabilities (printer) & CTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT)
5819 {
5820 for (i = 0; i < G_N_ELEMENTS (n_up_layout_display)(sizeof (n_up_layout_display) / sizeof ((n_up_layout_display)
[0]))
; i++)
5821 n_up_layout_display[i] = _(n_up_layout_display[i])((char *) g_dgettext ("ctk30", n_up_layout_display[i]));
5822
5823 /* Translators, this string is used to label the option in the print
5824 * dialog that controls in what order multiple pages are arranged
5825 */
5826 option = ctk_printer_option_new ("ctk-n-up-layout", C_("printer option", "Page Ordering")g_dpgettext ("ctk30", "printer option" "\004" "Page Ordering"
, strlen ("printer option") + 1)
, CTK_PRINTER_OPTION_TYPE_PICKONE);
5827 ctk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up_layout)(sizeof (n_up_layout) / sizeof ((n_up_layout)[0])),
5828 n_up_layout, n_up_layout_display);
5829
5830 text_direction = ctk_widget_get_default_direction ();
5831 if (text_direction == CTK_TEXT_DIR_LTR)
5832 ctk_printer_option_set (option, "lrtb");
5833 else
5834 ctk_printer_option_set (option, "rltb");
5835
5836 set_option_from_settings (option, settings);
5837 ctk_printer_option_set_add (set, option);
5838 g_object_unref (option);
5839 }
5840
5841 num_of_covers = cups_printer->number_of_covers;
5842 cover = g_new (char *, num_of_covers + 1)((char * *) g_malloc_n ((num_of_covers + 1), sizeof (char *))
)
;
5843 cover[num_of_covers] = NULL((void*)0);
5844 cover_display = g_new (char *, num_of_covers + 1)((char * *) g_malloc_n ((num_of_covers + 1), sizeof (char *))
)
;
5845 cover_display[num_of_covers] = NULL((void*)0);
5846 cover_display_translated = g_new (char *, num_of_covers + 1)((char * *) g_malloc_n ((num_of_covers + 1), sizeof (char *))
)
;
5847 cover_display_translated[num_of_covers] = NULL((void*)0);
5848
5849 for (i = 0; i < num_of_covers; i++)
5850 {
5851 cover[i] = g_strdup (cups_printer->covers[i])g_strdup_inline (cups_printer->covers[i]);
5852 value = NULL((void*)0);
5853 for (j = 0; j < G_N_ELEMENTS (cover_default)(sizeof (cover_default) / sizeof ((cover_default)[0])); j++)
5854 if (strcmp (cover_default[j], cover[i]) == 0)
5855 {
5856 value = cover_display_default[j];
5857 break;
5858 }
5859 cover_display[i] = (value != NULL((void*)0)) ? g_strdup (value)g_strdup_inline (value) : g_strdup (cups_printer->covers[i])g_strdup_inline (cups_printer->covers[i]);
5860 }
5861
5862 for (i = 0; i < num_of_covers; i++)
5863 cover_display_translated[i] = (gchar *)g_dpgettext2 (GETTEXT_PACKAGE"ctk30", "cover page", cover_display[i]);
5864
5865 /* Translators, this is the label used for the option in the print
5866 * dialog that controls the front cover page.
5867 */
5868 option = ctk_printer_option_new ("ctk-cover-before", C_("printer option", "Before")g_dpgettext ("ctk30", "printer option" "\004" "Before", strlen
("printer option") + 1)
, CTK_PRINTER_OPTION_TYPE_PICKONE);
5869 ctk_printer_option_choices_from_array (option, num_of_covers,
5870 cover, cover_display_translated);
5871
5872 if (cups_printer->default_cover_before != NULL((void*)0))
5873 ctk_printer_option_set (option, cups_printer->default_cover_before);
5874 else
5875 ctk_printer_option_set (option, "none");
5876 set_option_from_settings (option, settings);
5877 ctk_printer_option_set_add (set, option);
5878 g_object_unref (option);
5879
5880 /* Translators, this is the label used for the option in the print
5881 * dialog that controls the back cover page.
5882 */
5883 option = ctk_printer_option_new ("ctk-cover-after", C_("printer option", "After")g_dpgettext ("ctk30", "printer option" "\004" "After", strlen
("printer option") + 1)
, CTK_PRINTER_OPTION_TYPE_PICKONE);
5884 ctk_printer_option_choices_from_array (option, num_of_covers,
5885 cover, cover_display_translated);
5886 if (cups_printer->default_cover_after != NULL((void*)0))
5887 ctk_printer_option_set (option, cups_printer->default_cover_after);
5888 else
5889 ctk_printer_option_set (option, "none");
5890 set_option_from_settings (option, settings);
5891 ctk_printer_option_set_add (set, option);
5892 g_object_unref (option);
5893
5894 g_strfreev (cover);
5895 g_strfreev (cover_display);
5896 g_free (cover_display_translated);
5897 }
5898
5899 /* Translators: this is the name of the option that controls when
5900 * a print job is printed. Possible values are 'now', a specified time,
5901 * or 'on hold'
5902 */
5903 option = ctk_printer_option_new ("ctk-print-time", C_("printer option", "Print at")g_dpgettext ("ctk30", "printer option" "\004" "Print at", strlen
("printer option") + 1)
, CTK_PRINTER_OPTION_TYPE_PICKONE);
5904 ctk_printer_option_choices_from_array (option, G_N_ELEMENTS (print_at)(sizeof (print_at) / sizeof ((print_at)[0])),
5905 print_at, print_at);
5906 ctk_printer_option_set (option, "now");
5907 set_option_from_settings (option, settings);
5908 ctk_printer_option_set_add (set, option);
5909 g_object_unref (option);
5910
5911 /* Translators: this is the name of the option that allows the user
5912 * to specify a time when a print job will be printed.
5913 */
5914 option = ctk_printer_option_new ("ctk-print-time-text", C_("printer option", "Print at time")g_dpgettext ("ctk30", "printer option" "\004" "Print at time"
, strlen ("printer option") + 1)
, CTK_PRINTER_OPTION_TYPE_STRING);
5915 ctk_printer_option_set (option, "");
5916 set_option_from_settings (option, settings);
5917 ctk_printer_option_set_add (set, option);
5918 g_object_unref (option);
5919
5920 /* Printer (ppd) specific settings */
5921 ppd_file = ctk_printer_cups_get_ppd (CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
);
5922 if (ppd_file)
5923 {
5924 CtkPaperSize *paper_size;
5925 ppd_option_t *ppd_option;
5926
5927 ppdMarkDefaults (ppd_file);
5928
5929 paper_size = ctk_page_setup_get_paper_size (page_setup);
5930
5931 ppd_option = ppdFindOption (ppd_file, "PageSize");
5932 if (ppd_option)
5933 {
5934 const gchar *ppd_name;
5935
5936 ppd_name = ctk_paper_size_get_ppd_name (paper_size);
5937
5938 if (ppd_name)
5939 {
5940 strncpy (ppd_option->defchoice, ppd_name, PPD_MAX_NAME41 - 1);
5941 ppd_option->defchoice[PPD_MAX_NAME41 - 1] = '\0';
5942 }
5943 else
5944 {
5945 gchar *custom_name;
5946 char width[G_ASCII_DTOSTR_BUF_SIZE(29 + 10)];
5947 char height[G_ASCII_DTOSTR_BUF_SIZE(29 + 10)];
5948
5949 g_ascii_formatd (width, sizeof (width), "%.2f",
5950 ctk_paper_size_get_width (paper_size,
5951 CTK_UNIT_POINTS));
5952 g_ascii_formatd (height, sizeof (height), "%.2f",
5953 ctk_paper_size_get_height (paper_size,
5954 CTK_UNIT_POINTS));
5955 /* Translators: this format is used to display a custom
5956 * paper size. The two placeholders are replaced with
5957 * the width and height in points. E.g: "Custom
5958 * 230.4x142.9"
5959 */
5960 custom_name = g_strdup_printf (_("Custom %s×%s")((char *) g_dgettext ("ctk30", "Custom %s×%s")), width, height);
5961 strncpy (ppd_option->defchoice, custom_name, PPD_MAX_NAME41 - 1);
5962 ppd_option->defchoice[PPD_MAX_NAME41 - 1] = '\0';
5963 g_free (custom_name);
5964 }
5965 }
5966
5967 for (i = 0; i < ppd_file->num_groups; i++)
5968 handle_group (set, ppd_file, &ppd_file->groups[i], &ppd_file->groups[i], settings);
5969 }
5970 else
5971 {
5972 /* Try IPP options */
5973
5974 option = setup_ipp_option ("sides",
5975 cups_printer->sides_default,
5976 cups_printer->sides_supported,
5977 set);
5978
5979 if (option != NULL((void*)0))
5980 set_option_from_settings (option, settings);
5981
5982 option = setup_ipp_option ("output-bin",
5983 cups_printer->output_bin_default,
5984 cups_printer->output_bin_supported,
5985 set);
5986
5987 if (option != NULL((void*)0))
5988 set_option_from_settings (option, settings);
5989 }
5990
5991 /* Now honor the user set defaults for this printer */
5992 num_opts = cups_get_user_options (ctk_printer_get_name (printer), 0, &opts);
5993
5994 for (i = 0; i < num_opts; i++)
5995 {
5996 if (STRING_IN_TABLE (opts[i].name, cups_option_blacklist)(string_in_table (opts[i].name, cups_option_blacklist, (sizeof
(cups_option_blacklist) / sizeof ((cups_option_blacklist)[0]
))))
)
5997 continue;
5998
5999 name = get_lpoption_name (opts[i].name);
6000 if (strcmp (name, "cups-job-sheets") == 0)
6001 {
6002 gchar **values;
6003 gint num_values;
6004
6005 values = g_strsplit (opts[i].value, ",", 2);
6006 num_values = g_strv_length (values);
6007
6008 option = ctk_printer_option_set_lookup (set, "ctk-cover-before");
6009 if (option && num_values > 0)
6010 ctk_printer_option_set (option, g_strstrip (values[0])g_strchomp (g_strchug (values[0])));
6011
6012 option = ctk_printer_option_set_lookup (set, "ctk-cover-after");
6013 if (option && num_values > 1)
6014 ctk_printer_option_set (option, g_strstrip (values[1])g_strchomp (g_strchug (values[1])));
6015
6016 g_strfreev (values);
6017 }
6018 else if (strcmp (name, "cups-job-hold-until") == 0)
6019 {
6020 CtkPrinterOption *option2 = NULL((void*)0);
6021
6022 option = ctk_printer_option_set_lookup (set, "ctk-print-time-text");
6023 if (option && opts[i].value)
6024 {
6025 option2 = ctk_printer_option_set_lookup (set, "ctk-print-time");
6026 if (option2)
6027 {
6028 if (strcmp (opts[i].value, "indefinite") == 0)
6029 ctk_printer_option_set (option2, "on-hold");
6030 else
6031 {
6032 ctk_printer_option_set (option2, "at");
6033 ctk_printer_option_set (option, opts[i].value);
6034 }
6035 }
6036 }
6037 }
6038 else if (strcmp (name, "cups-sides") == 0)
6039 {
6040 option = ctk_printer_option_set_lookup (set, "ctk-duplex");
6041 if (option && opts[i].value)
6042 {
6043 if (!option_is_ipp_option (option))
6044 {
6045 if (strcmp (opts[i].value, "two-sided-short-edge") == 0)
6046 ctk_printer_option_set (option, "DuplexTumble");
6047 else if (strcmp (opts[i].value, "two-sided-long-edge") == 0)
6048 ctk_printer_option_set (option, "DuplexNoTumble");
6049 }
6050 else
6051 {
6052 ctk_printer_option_set (option, opts[i].value);
6053 }
6054 }
6055 }
6056 else
6057 {
6058 option = ctk_printer_option_set_lookup (set, name);
6059 if (option)
6060 ctk_printer_option_set (option, opts[i].value);
6061 }
6062 g_free (name);
6063 }
6064
6065 cupsFreeOptions (num_opts, opts);
6066
6067#ifdef HAVE_COLORD1
6068 /* TRANSLATORS: this this the ICC color profile to use for this job */
6069 option = ctk_printer_option_new ("colord-profile",
6070 C_("printer option", "Printer Profile")g_dpgettext ("ctk30", "printer option" "\004" "Printer Profile"
, strlen ("printer option") + 1)
,
6071 CTK_PRINTER_OPTION_TYPE_INFO);
6072
6073 /* assign it to the color page */
6074 option->group = g_strdup ("ColorPage")g_strdup_inline ("ColorPage");
6075
6076 /* TRANSLATORS: this is when color profile information is unavailable */
6077 ctk_printer_option_set (option, C_("printer option value", "Unavailable")g_dpgettext ("ctk30", "printer option value" "\004" "Unavailable"
, strlen ("printer option value") + 1)
);
6078 ctk_printer_option_set_add (set, option);
6079
6080 /* watch to see if the user changed the options */
6081 helper = g_new (CtkPrintBackendCupsColordHelper, 1)((CtkPrintBackendCupsColordHelper *) g_malloc_n ((1), sizeof (
CtkPrintBackendCupsColordHelper)))
;
6082 helper->printer = printer;
6083 helper->settings = settings;
6084 g_signal_connect_data (set, "changed",
6085 G_CALLBACK (colord_printer_option_set_changed_cb)((GCallback) (colord_printer_option_set_changed_cb)),
6086 helper,
6087 (GClosureNotify) g_free,
6088 0);
6089
6090 /* initial coldplug */
6091 ctk_printer_cups_update_settings (CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
,
6092 settings, set);
6093 g_object_bind_property (printer, "profile-title",
6094 option, "value",
6095 G_BINDING_DEFAULT);
6096
6097#endif
6098
6099 return set;
6100}
6101
6102
6103static void
6104mark_option_from_set (CtkPrinterOptionSet *set,
6105 ppd_file_t *ppd_file,
6106 ppd_option_t *ppd_option)
6107{
6108 CtkPrinterOption *option;
6109 char *name = get_ppd_option_name (ppd_option->keyword);
6110
6111 option = ctk_printer_option_set_lookup (set, name);
6112
6113 if (option)
6114 ppdMarkOption (ppd_file, ppd_option->keyword, option->value);
6115
6116 g_free (name);
6117}
6118
6119
6120static void
6121mark_group_from_set (CtkPrinterOptionSet *set,
6122 ppd_file_t *ppd_file,
6123 ppd_group_t *group)
6124{
6125 int i;
6126
6127 for (i = 0; i < group->num_options; i++)
6128 mark_option_from_set (set, ppd_file, &group->options[i]);
6129
6130 for (i = 0; i < group->num_subgroups; i++)
6131 mark_group_from_set (set, ppd_file, &group->subgroups[i]);
6132}
6133
6134static void
6135set_conflicts_from_option (CtkPrinterOptionSet *set,
6136 ppd_file_t *ppd_file G_GNUC_UNUSED__attribute__ ((__unused__)),
6137 ppd_option_t *ppd_option)
6138{
6139 CtkPrinterOption *option;
6140 char *name;
6141
6142 if (ppd_option->conflicted)
6143 {
6144 name = get_ppd_option_name (ppd_option->keyword);
6145 option = ctk_printer_option_set_lookup (set, name);
6146
6147 if (option)
6148 ctk_printer_option_set_has_conflict (option, TRUE(!(0)));
6149#ifdef PRINT_IGNORED_OPTIONS
6150 else
6151 g_warning ("CUPS Backend: Ignoring conflict for option %s", ppd_option->keyword);
6152#endif
6153
6154 g_free (name);
6155 }
6156}
6157
6158static void
6159set_conflicts_from_group (CtkPrinterOptionSet *set,
6160 ppd_file_t *ppd_file,
6161 ppd_group_t *group)
6162{
6163 int i;
6164
6165 for (i = 0; i < group->num_options; i++)
6166 set_conflicts_from_option (set, ppd_file, &group->options[i]);
6167
6168 for (i = 0; i < group->num_subgroups; i++)
6169 set_conflicts_from_group (set, ppd_file, &group->subgroups[i]);
6170}
6171
6172static gboolean
6173cups_printer_mark_conflicts (CtkPrinter *printer,
6174 CtkPrinterOptionSet *options)
6175{
6176 ppd_file_t *ppd_file;
6177 int num_conflicts;
6178 int i;
6179
6180 ppd_file = ctk_printer_cups_get_ppd (CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
);
6181
6182 if (ppd_file == NULL((void*)0))
6183 return FALSE(0);
6184
6185 ppdMarkDefaults (ppd_file);
6186
6187 for (i = 0; i < ppd_file->num_groups; i++)
6188 mark_group_from_set (options, ppd_file, &ppd_file->groups[i]);
6189
6190 num_conflicts = ppdConflicts (ppd_file);
6191
6192 if (num_conflicts > 0)
6193 {
6194 for (i = 0; i < ppd_file->num_groups; i++)
6195 set_conflicts_from_group (options, ppd_file, &ppd_file->groups[i]);
6196 }
6197
6198 return num_conflicts > 0;
6199}
6200
6201struct OptionData {
6202 CtkPrinter *printer;
6203 CtkPrinterOptionSet *options;
6204 CtkPrintSettings *settings;
6205 ppd_file_t *ppd_file;
6206};
6207
6208typedef struct {
6209 const char *cups;
6210 const char *standard;
6211} NameMapping;
6212
6213static void
6214map_settings_to_option (CtkPrinterOption *option,
6215 const NameMapping table[],
6216 gint n_elements,
6217 CtkPrintSettings *settings,
6218 const gchar *standard_name,
6219 const gchar *cups_name,
6220 const gchar *ipp_name)
6221{
6222 int i;
6223 char *name;
6224 const char *cups_value;
6225 const char *ipp_value;
6226 const char *standard_value;
6227
6228 /* If the cups-specific setting is set, always use that */
6229 name = g_strdup_printf ("cups-%s", cups_name);
6230 cups_value = ctk_print_settings_get (settings, name);
6231 g_free (name);
6232
6233 if (cups_value != NULL((void*)0))
6234 {
6235 ctk_printer_option_set (option, cups_value);
6236 return;
6237 }
6238
6239 /* If the IPP-specific setting is set, use that */
6240 name = g_strdup_printf ("cups-%s", ipp_name);
6241 ipp_value = ctk_print_settings_get (settings, name);
6242 g_free (name);
6243
6244 if (ipp_value != NULL((void*)0))
6245 {
6246 ctk_printer_option_set (option, ipp_value);
6247 return;
6248 }
6249
6250 /* Otherwise we try to convert from the general setting */
6251 standard_value = ctk_print_settings_get (settings, standard_name);
6252 if (standard_value == NULL((void*)0))
6253 return;
6254
6255 for (i = 0; i < n_elements; i++)
6256 {
6257 if (table[i].cups == NULL((void*)0) && table[i].standard == NULL((void*)0))
6258 {
6259 ctk_printer_option_set (option, standard_value);
6260 break;
6261 }
6262 else if (table[i].cups == NULL((void*)0) &&
6263 strcmp (table[i].standard, standard_value) == 0)
6264 {
6265 set_option_off (option);
6266 break;
6267 }
6268 else if (strcmp (table[i].standard, standard_value) == 0)
6269 {
6270 ctk_printer_option_set (option, table[i].cups);
6271 break;
6272 }
6273 }
6274}
6275
6276static void
6277map_option_to_settings (const gchar *value,
6278 const NameMapping table[],
6279 gint n_elements,
6280 CtkPrintSettings *settings,
6281 const gchar *standard_name,
6282 const gchar *cups_name,
6283 const gchar *ipp_name,
6284 gboolean is_ipp_option)
6285{
6286 int i;
6287 char *name;
6288
6289 for (i = 0; i < n_elements; i++)
6290 {
6291 if (table[i].cups == NULL((void*)0) && table[i].standard == NULL((void*)0))
6292 {
6293 ctk_print_settings_set (settings,
6294 standard_name,
6295 value);
6296 break;
6297 }
6298 else if (table[i].cups == NULL((void*)0) && table[i].standard != NULL((void*)0))
6299 {
6300 if (value_is_off (value))
6301 {
6302 ctk_print_settings_set (settings,
6303 standard_name,
6304 table[i].standard);
6305 break;
6306 }
6307 }
6308 else if (strcmp (table[i].cups, value) == 0)
6309 {
6310 ctk_print_settings_set (settings,
6311 standard_name,
6312 table[i].standard);
6313 break;
6314 }
6315 }
6316
6317 /* Always set the corresponding cups-specific setting */
6318 if (is_ipp_option)
6319 name = g_strdup_printf ("cups-%s", ipp_name);
6320 else
6321 name = g_strdup_printf ("cups-%s", cups_name);
6322
6323 ctk_print_settings_set (settings, name, value);
6324
6325 g_free (name);
6326}
6327
6328
6329static const NameMapping paper_source_map[] = {
6330 { "Lower", "lower"},
6331 { "Middle", "middle"},
6332 { "Upper", "upper"},
6333 { "Rear", "rear"},
6334 { "Envelope", "envelope"},
6335 { "Cassette", "cassette"},
6336 { "LargeCapacity", "large-capacity"},
6337 { "AnySmallFormat", "small-format"},
6338 { "AnyLargeFormat", "large-format"},
6339 { NULL((void*)0), NULL((void*)0)}
6340};
6341
6342static const NameMapping output_tray_map[] = {
6343 { "Upper", "upper"},
6344 { "Lower", "lower"},
6345 { "Rear", "rear"},
6346 { NULL((void*)0), NULL((void*)0)}
6347};
6348
6349static const NameMapping duplex_map[] = {
6350 { "DuplexTumble", "vertical" },
6351 { "DuplexNoTumble", "horizontal" },
6352 { NULL((void*)0), "simplex" }
6353};
6354
6355static const NameMapping output_mode_map[] = {
6356 { "Standard", "normal" },
6357 { "Normal", "normal" },
6358 { "Draft", "draft" },
6359 { "Fast", "draft" },
6360};
6361
6362static const NameMapping media_type_map[] = {
6363 { "Transparency", "transparency"},
6364 { "Standard", "stationery"},
6365 { NULL((void*)0), NULL((void*)0)}
6366};
6367
6368static const NameMapping all_map[] = {
6369 { NULL((void*)0), NULL((void*)0)}
6370};
6371
6372
6373static void
6374set_option_from_settings (CtkPrinterOption *option,
6375 CtkPrintSettings *settings)
6376{
6377 const char *cups_value;
6378 char *value;
6379
6380 if (settings == NULL((void*)0))
6381 return;
6382
6383 if (strcmp (option->name, "ctk-paper-source") == 0)
6384 map_settings_to_option (option, paper_source_map, G_N_ELEMENTS (paper_source_map)(sizeof (paper_source_map) / sizeof ((paper_source_map)[0])),
6385 settings, CTK_PRINT_SETTINGS_DEFAULT_SOURCE"default-source",
6386 "InputSlot", NULL((void*)0));
6387 else if (strcmp (option->name, "ctk-output-tray") == 0)
6388 map_settings_to_option (option, output_tray_map, G_N_ELEMENTS (output_tray_map)(sizeof (output_tray_map) / sizeof ((output_tray_map)[0])),
6389 settings, CTK_PRINT_SETTINGS_OUTPUT_BIN"output-bin",
6390 "OutputBin", "output-bin");
6391 else if (strcmp (option->name, "ctk-duplex") == 0)
6392 map_settings_to_option (option, duplex_map, G_N_ELEMENTS (duplex_map)(sizeof (duplex_map) / sizeof ((duplex_map)[0])),
6393 settings, CTK_PRINT_SETTINGS_DUPLEX"duplex",
6394 "Duplex", "sides");
6395 else if (strcmp (option->name, "cups-OutputMode") == 0)
6396 map_settings_to_option (option, output_mode_map, G_N_ELEMENTS (output_mode_map)(sizeof (output_mode_map) / sizeof ((output_mode_map)[0])),
6397 settings, CTK_PRINT_SETTINGS_QUALITY"quality",
6398 "OutputMode", NULL((void*)0));
6399 else if (strcmp (option->name, "cups-Resolution") == 0)
6400 {
6401 cups_value = ctk_print_settings_get (settings, option->name);
6402 if (cups_value)
6403 ctk_printer_option_set (option, cups_value);
6404 else
6405 {
6406 if (ctk_print_settings_get_int_with_default (settings, CTK_PRINT_SETTINGS_RESOLUTION"resolution", -1) != -1 ||
6407 ctk_print_settings_get_int_with_default (settings, CTK_PRINT_SETTINGS_RESOLUTION_X"resolution-x", -1) != -1 ||
6408 ctk_print_settings_get_int_with_default (settings, CTK_PRINT_SETTINGS_RESOLUTION_Y"resolution-y", -1) != -1 ||
6409 option->value == NULL((void*)0) || option->value[0] == '\0')
6410 {
6411 int res = ctk_print_settings_get_resolution (settings);
6412 int res_x = ctk_print_settings_get_resolution_x (settings);
6413 int res_y = ctk_print_settings_get_resolution_y (settings);
6414
6415 if (res_x != res_y)
6416 {
6417 value = g_strdup_printf ("%dx%ddpi", res_x, res_y);
6418 ctk_printer_option_set (option, value);
6419 g_free (value);
6420 }
6421 else if (res != 0)
6422 {
6423 value = g_strdup_printf ("%ddpi", res);
6424 ctk_printer_option_set (option, value);
6425 g_free (value);
6426 }
6427 }
6428 }
6429 }
6430 else if (strcmp (option->name, "ctk-paper-type") == 0)
6431 map_settings_to_option (option, media_type_map, G_N_ELEMENTS (media_type_map)(sizeof (media_type_map) / sizeof ((media_type_map)[0])),
6432 settings, CTK_PRINT_SETTINGS_MEDIA_TYPE"media-type",
6433 "MediaType", NULL((void*)0));
6434 else if (strcmp (option->name, "ctk-n-up") == 0)
6435 {
6436 map_settings_to_option (option, all_map, G_N_ELEMENTS (all_map)(sizeof (all_map) / sizeof ((all_map)[0])),
6437 settings, CTK_PRINT_SETTINGS_NUMBER_UP"number-up",
6438 "number-up", NULL((void*)0));
6439 }
6440 else if (strcmp (option->name, "ctk-n-up-layout") == 0)
6441 {
6442 map_settings_to_option (option, all_map, G_N_ELEMENTS (all_map)(sizeof (all_map) / sizeof ((all_map)[0])),
6443 settings, CTK_PRINT_SETTINGS_NUMBER_UP_LAYOUT"number-up-layout",
6444 "number-up-layout", NULL((void*)0));
6445 }
6446 else if (strcmp (option->name, "ctk-billing-info") == 0)
6447 {
6448 cups_value = ctk_print_settings_get (settings, "cups-job-billing");
6449 if (cups_value)
6450 ctk_printer_option_set (option, cups_value);
6451 }
6452 else if (strcmp (option->name, "ctk-job-prio") == 0)
6453 {
6454 cups_value = ctk_print_settings_get (settings, "cups-job-priority");
6455 if (cups_value)
6456 ctk_printer_option_set (option, cups_value);
6457 }
6458 else if (strcmp (option->name, "ctk-cover-before") == 0)
6459 {
6460 cups_value = ctk_print_settings_get (settings, "cover-before");
6461 if (cups_value)
6462 ctk_printer_option_set (option, cups_value);
6463 }
6464 else if (strcmp (option->name, "ctk-cover-after") == 0)
6465 {
6466 cups_value = ctk_print_settings_get (settings, "cover-after");
6467 if (cups_value)
6468 ctk_printer_option_set (option, cups_value);
6469 }
6470 else if (strcmp (option->name, "ctk-print-time") == 0)
6471 {
6472 cups_value = ctk_print_settings_get (settings, "print-at");
6473 if (cups_value)
6474 ctk_printer_option_set (option, cups_value);
6475 }
6476 else if (strcmp (option->name, "ctk-print-time-text") == 0)
6477 {
6478 cups_value = ctk_print_settings_get (settings, "print-at-time");
6479 if (cups_value)
6480 ctk_printer_option_set (option, cups_value);
6481 }
6482 else if (g_str_has_prefix (option->name, "cups-")(__builtin_constant_p ("cups-")? __extension__ ({ const char *
const __str = (option->name); const char * const __prefix
= ("cups-"); gboolean __result = (0); if (__str == ((void*)0
) || __prefix == ((void*)0)) __result = (g_str_has_prefix) (__str
, __prefix); else { const size_t __str_len = strlen (((__str)
+ !(__str))); const size_t __prefix_len = strlen (((__prefix
) + !(__prefix))); if (__str_len >= __prefix_len) __result
= memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len
) == 0; } __result; }) : (g_str_has_prefix) (option->name,
"cups-") )
)
6483 {
6484 cups_value = ctk_print_settings_get (settings, option->name);
6485 if (cups_value)
6486 ctk_printer_option_set (option, cups_value);
6487 }
6488}
6489
6490static void
6491foreach_option_get_settings (CtkPrinterOption *option,
6492 gpointer user_data)
6493{
6494 struct OptionData *data = user_data;
6495 CtkPrintSettings *settings = data->settings;
6496 const char *value;
6497
6498 value = option->value;
6499
6500 if (strcmp (option->name, "ctk-paper-source") == 0)
6501 map_option_to_settings (value, paper_source_map, G_N_ELEMENTS (paper_source_map)(sizeof (paper_source_map) / sizeof ((paper_source_map)[0])),
6502 settings, CTK_PRINT_SETTINGS_DEFAULT_SOURCE"default-source",
6503 "InputSlot", NULL((void*)0), FALSE(0));
6504 else if (strcmp (option->name, "ctk-output-tray") == 0)
6505 map_option_to_settings (value, output_tray_map, G_N_ELEMENTS (output_tray_map)(sizeof (output_tray_map) / sizeof ((output_tray_map)[0])),
6506 settings, CTK_PRINT_SETTINGS_OUTPUT_BIN"output-bin",
6507 "OutputBin", "output-bin", option_is_ipp_option (option));
6508 else if (strcmp (option->name, "ctk-duplex") == 0)
6509 map_option_to_settings (value, duplex_map, G_N_ELEMENTS (duplex_map)(sizeof (duplex_map) / sizeof ((duplex_map)[0])),
6510 settings, CTK_PRINT_SETTINGS_DUPLEX"duplex",
6511 "Duplex", "sides", option_is_ipp_option (option));
6512 else if (strcmp (option->name, "cups-OutputMode") == 0)
6513 map_option_to_settings (value, output_mode_map, G_N_ELEMENTS (output_mode_map)(sizeof (output_mode_map) / sizeof ((output_mode_map)[0])),
6514 settings, CTK_PRINT_SETTINGS_QUALITY"quality",
6515 "OutputMode", NULL((void*)0), FALSE(0));
6516 else if (strcmp (option->name, "cups-Resolution") == 0)
6517 {
6518 int res, res_x, res_y;
6519
6520 if (sscanf (value, "%dx%ddpi", &res_x, &res_y) == 2)
6521 {
6522 if (res_x > 0 && res_y > 0)
6523 ctk_print_settings_set_resolution_xy (settings, res_x, res_y);
6524 }
6525 else if (sscanf (value, "%ddpi", &res) == 1)
6526 {
6527 if (res > 0)
6528 ctk_print_settings_set_resolution (settings, res);
6529 }
6530
6531 ctk_print_settings_set (settings, option->name, value);
6532 }
6533 else if (strcmp (option->name, "ctk-paper-type") == 0)
6534 map_option_to_settings (value, media_type_map, G_N_ELEMENTS (media_type_map)(sizeof (media_type_map) / sizeof ((media_type_map)[0])),
6535 settings, CTK_PRINT_SETTINGS_MEDIA_TYPE"media-type",
6536 "MediaType", NULL((void*)0), FALSE(0));
6537 else if (strcmp (option->name, "ctk-n-up") == 0)
6538 map_option_to_settings (value, all_map, G_N_ELEMENTS (all_map)(sizeof (all_map) / sizeof ((all_map)[0])),
6539 settings, CTK_PRINT_SETTINGS_NUMBER_UP"number-up",
6540 "number-up", NULL((void*)0), FALSE(0));
6541 else if (strcmp (option->name, "ctk-n-up-layout") == 0)
6542 map_option_to_settings (value, all_map, G_N_ELEMENTS (all_map)(sizeof (all_map) / sizeof ((all_map)[0])),
6543 settings, CTK_PRINT_SETTINGS_NUMBER_UP_LAYOUT"number-up-layout",
6544 "number-up-layout", NULL((void*)0), FALSE(0));
6545 else if (strcmp (option->name, "ctk-billing-info") == 0 && strlen (value) > 0)
6546 ctk_print_settings_set (settings, "cups-job-billing", value);
6547 else if (strcmp (option->name, "ctk-job-prio") == 0)
6548 ctk_print_settings_set (settings, "cups-job-priority", value);
6549 else if (strcmp (option->name, "ctk-cover-before") == 0)
6550 ctk_print_settings_set (settings, "cover-before", value);
6551 else if (strcmp (option->name, "ctk-cover-after") == 0)
6552 ctk_print_settings_set (settings, "cover-after", value);
6553 else if (strcmp (option->name, "ctk-print-time") == 0)
6554 ctk_print_settings_set (settings, "print-at", value);
6555 else if (strcmp (option->name, "ctk-print-time-text") == 0)
6556 ctk_print_settings_set (settings, "print-at-time", value);
6557 else if (g_str_has_prefix (option->name, "cups-")(__builtin_constant_p ("cups-")? __extension__ ({ const char *
const __str = (option->name); const char * const __prefix
= ("cups-"); gboolean __result = (0); if (__str == ((void*)0
) || __prefix == ((void*)0)) __result = (g_str_has_prefix) (__str
, __prefix); else { const size_t __str_len = strlen (((__str)
+ !(__str))); const size_t __prefix_len = strlen (((__prefix
) + !(__prefix))); if (__str_len >= __prefix_len) __result
= memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len
) == 0; } __result; }) : (g_str_has_prefix) (option->name,
"cups-") )
)
6558 ctk_print_settings_set (settings, option->name, value);
6559}
6560
6561static gboolean
6562supports_am_pm (void)
6563{
6564 struct tm tmp_tm = { 0 };
6565 char time[8];
6566 int length;
6567
6568 length = strftime (time, sizeof (time), "%p", &tmp_tm);
6569
6570 return length != 0;
6571}
6572
6573/* Converts local time to UTC time. Local time has to be in one of these
6574 * formats: HH:MM:SS, HH:MM, HH:MM:SS {am, pm}, HH:MM {am, pm}, HH {am, pm},
6575 * {am, pm} HH:MM:SS, {am, pm} HH:MM, {am, pm} HH.
6576 * Returns a newly allocated string holding UTC time in HH:MM:SS format
6577 * or NULL.
6578 */
6579gchar *
6580localtime_to_utctime (const char *local_time)
6581{
6582 const char *formats_0[] = {" %I : %M : %S %p ", " %p %I : %M : %S ",
6583 " %H : %M : %S ",
6584 " %I : %M %p ", " %p %I : %M ",
6585 " %H : %M ",
6586 " %I %p ", " %p %I "};
6587 const char *formats_1[] = {" %H : %M : %S ", " %H : %M "};
6588 const char *end = NULL((void*)0);
6589 struct tm *actual_utc_time;
6590 struct tm local_print_time;
6591 gchar *utc_time = NULL((void*)0);
6592 int i, n;
6593
6594 if (local_time == NULL((void*)0) || local_time[0] == '\0')
6595 return NULL((void*)0);
6596
6597 n = supports_am_pm () ? G_N_ELEMENTS (formats_0)(sizeof (formats_0) / sizeof ((formats_0)[0])) : G_N_ELEMENTS (formats_1)(sizeof (formats_1) / sizeof ((formats_1)[0]));
6598
6599 for (i = 0; i < n; i++)
6600 {
6601 local_print_time.tm_hour = 0;
6602 local_print_time.tm_min = 0;
6603 local_print_time.tm_sec = 0;
6604
6605 if (supports_am_pm ())
6606 end = strptime (local_time, formats_0[i], &local_print_time);
6607 else
6608 end = strptime (local_time, formats_1[i], &local_print_time);
6609
6610 if (end != NULL((void*)0) && end[0] == '\0')
6611 break;
6612 }
6613
6614 if (end != NULL((void*)0) && end[0] == '\0')
6615 {
6616 struct tm *actual_local_time;
6617 struct tm utc_print_time;
6618 struct tm diff_time;
6619 time_t rawtime;
6620 time (&rawtime);
6621
6622 actual_utc_time = g_memdup2 (gmtime (&rawtime), sizeof (struct tm));
6623 actual_local_time = g_memdup2 (localtime (&rawtime), sizeof (struct tm));
6624
6625 diff_time.tm_hour = actual_utc_time->tm_hour - actual_local_time->tm_hour;
6626 diff_time.tm_min = actual_utc_time->tm_min - actual_local_time->tm_min;
6627 diff_time.tm_sec = actual_utc_time->tm_sec - actual_local_time->tm_sec;
6628
6629 utc_print_time.tm_hour = ((local_print_time.tm_hour + diff_time.tm_hour) + 24) % 24;
6630 utc_print_time.tm_min = ((local_print_time.tm_min + diff_time.tm_min) + 60) % 60;
6631 utc_print_time.tm_sec = ((local_print_time.tm_sec + diff_time.tm_sec) + 60) % 60;
6632
6633 utc_time = g_strdup_printf ("%02d:%02d:%02d",
6634 utc_print_time.tm_hour,
6635 utc_print_time.tm_min,
6636 utc_print_time.tm_sec);
6637 }
6638
6639 return utc_time;
6640}
6641
6642static void
6643cups_printer_get_settings_from_options (CtkPrinter *printer,
6644 CtkPrinterOptionSet *options,
6645 CtkPrintSettings *settings)
6646{
6647 struct OptionData data;
6648
6649 data.printer = printer;
6650 data.options = options;
6651 data.settings = settings;
6652 data.ppd_file = ctk_printer_cups_get_ppd (CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
);
6653
6654 ctk_printer_option_set_foreach (options, foreach_option_get_settings, &data);
6655 if (data.ppd_file != NULL((void*)0))
6656 {
6657 const char *print_at, *print_at_time;
6658 CtkPrinterOption *cover_before, *cover_after;
6659
6660 cover_before = ctk_printer_option_set_lookup (options, "ctk-cover-before");
6661 cover_after = ctk_printer_option_set_lookup (options, "ctk-cover-after");
6662 if (cover_before && cover_after)
6663 {
6664 char *value = g_strdup_printf ("%s,%s", cover_before->value, cover_after->value);
6665 ctk_print_settings_set (settings, "cups-job-sheets", value);
6666 g_free (value);
6667 }
6668
6669 print_at = ctk_print_settings_get (settings, "print-at");
6670 print_at_time = ctk_print_settings_get (settings, "print-at-time");
6671
6672 if (strcmp (print_at, "at") == 0)
6673 {
6674 gchar *utc_time = NULL((void*)0);
6675
6676 utc_time = localtime_to_utctime (print_at_time);
6677
6678 if (utc_time != NULL((void*)0))
6679 {
6680 ctk_print_settings_set (settings, "cups-job-hold-until", utc_time);
6681 g_free (utc_time);
6682 }
6683 else
6684 ctk_print_settings_set (settings, "cups-job-hold-until", print_at_time);
6685 }
6686 else if (strcmp (print_at, "on-hold") == 0)
6687 ctk_print_settings_set (settings, "cups-job-hold-until", "indefinite");
6688 }
6689}
6690
6691static void
6692cups_printer_prepare_for_print (CtkPrinter *printer,
6693 CtkPrintJob *print_job,
6694 CtkPrintSettings *settings,
6695 CtkPageSetup *page_setup)
6696{
6697 CtkPrintPages pages;
6698 CtkPageRange *ranges;
6699 gint n_ranges;
6700 CtkPageSet page_set;
6701 CtkPaperSize *paper_size;
6702 const char *ppd_paper_name;
6703 double scale;
6704 CtkPrintCapabilities capabilities;
6705
6706 capabilities = cups_printer_get_capabilities (printer);
6707 pages = ctk_print_settings_get_print_pages (settings);
6708 ctk_print_job_set_pages (print_job, pages);
6709
6710 if (pages == CTK_PRINT_PAGES_RANGES)
6711 ranges = ctk_print_settings_get_page_ranges (settings, &n_ranges);
6712 else
6713 {
6714 ranges = NULL((void*)0);
6715 n_ranges = 0;
6716 }
6717
6718 ctk_print_job_set_page_ranges (print_job, ranges, n_ranges);
6719
6720 if (capabilities & CTK_PRINT_CAPABILITY_COLLATE)
6721 {
6722 if (ctk_print_settings_get_collate (settings))
6723 ctk_print_settings_set (settings, "cups-Collate", "True");
6724 else
6725 ctk_print_settings_set (settings, "cups-Collate", "False");
6726 ctk_print_job_set_collate (print_job, FALSE(0));
6727 }
6728 else
6729 {
6730 ctk_print_job_set_collate (print_job, ctk_print_settings_get_collate (settings));
6731 }
6732
6733 if (capabilities & CTK_PRINT_CAPABILITY_REVERSE)
6734 {
6735 if (ctk_print_settings_get_reverse (settings))
6736 ctk_print_settings_set (settings, "cups-OutputOrder", "Reverse");
6737 ctk_print_job_set_reverse (print_job, FALSE(0));
6738 }
6739 else
6740 {
6741 ctk_print_job_set_reverse (print_job, ctk_print_settings_get_reverse (settings));
6742 }
6743
6744 if (capabilities & CTK_PRINT_CAPABILITY_COPIES)
6745 {
6746 if (ctk_print_settings_get_n_copies (settings) > 1)
6747 ctk_print_settings_set_int (settings, "cups-copies",
6748 ctk_print_settings_get_n_copies (settings));
6749 ctk_print_job_set_num_copies (print_job, 1);
6750 }
6751 else
6752 {
6753 ctk_print_job_set_num_copies (print_job, ctk_print_settings_get_n_copies (settings));
6754 }
6755
6756 scale = ctk_print_settings_get_scale (settings);
6757 if (scale != 100.0)
6758 ctk_print_job_set_scale (print_job, scale / 100.0);
6759
6760 page_set = ctk_print_settings_get_page_set (settings);
6761 if (page_set == CTK_PAGE_SET_EVEN)
6762 ctk_print_settings_set (settings, "cups-page-set", "even");
6763 else if (page_set == CTK_PAGE_SET_ODD)
6764 ctk_print_settings_set (settings, "cups-page-set", "odd");
6765 ctk_print_job_set_page_set (print_job, CTK_PAGE_SET_ALL);
6766
6767 paper_size = ctk_page_setup_get_paper_size (page_setup);
6768 ppd_paper_name = ctk_paper_size_get_ppd_name (paper_size);
6769 if (ppd_paper_name != NULL((void*)0))
6770 ctk_print_settings_set (settings, "cups-PageSize", ppd_paper_name);
6771 else if (ctk_paper_size_is_ipp (paper_size))
6772 ctk_print_settings_set (settings, "cups-media", ctk_paper_size_get_name (paper_size));
6773 else
6774 {
6775 char width[G_ASCII_DTOSTR_BUF_SIZE(29 + 10)];
6776 char height[G_ASCII_DTOSTR_BUF_SIZE(29 + 10)];
6777 char *custom_name;
6778
6779 g_ascii_formatd (width, sizeof (width), "%.2f", ctk_paper_size_get_width (paper_size, CTK_UNIT_POINTS));
6780 g_ascii_formatd (height, sizeof (height), "%.2f", ctk_paper_size_get_height (paper_size, CTK_UNIT_POINTS));
6781 custom_name = g_strdup_printf (("Custom.%sx%s"), width, height);
6782 ctk_print_settings_set (settings, "cups-PageSize", custom_name);
6783 g_free (custom_name);
6784 }
6785
6786 if (ctk_print_settings_get_number_up (settings) > 1)
6787 {
6788 CtkNumberUpLayout layout = ctk_print_settings_get_number_up_layout (settings);
6789 GEnumClass *enum_class;
6790 GEnumValue *enum_value;
6791
6792 switch (ctk_page_setup_get_orientation (page_setup))
6793 {
6794 case CTK_PAGE_ORIENTATION_PORTRAIT:
6795 break;
6796 case CTK_PAGE_ORIENTATION_LANDSCAPE:
6797 if (layout < 4)
6798 layout = layout + 2 + 4 * (1 - layout / 2);
6799 else
6800 layout = layout - 3 - 2 * (layout % 2);
6801 break;
6802 case CTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
6803 layout = (layout + 3 - 2 * (layout % 2)) % 4 + 4 * (layout / 4);
6804 break;
6805 case CTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
6806 if (layout < 4)
6807 layout = layout + 5 - 2 * (layout % 2);
6808 else
6809 layout = layout - 6 + 4 * (1 - (layout - 4) / 2);
6810 break;
6811 }
6812
6813 enum_class = g_type_class_ref (CTK_TYPE_NUMBER_UP_LAYOUT(ctk_number_up_layout_get_type ()));
6814 enum_value = g_enum_get_value (enum_class, layout);
6815 ctk_print_settings_set (settings, "cups-number-up-layout", enum_value->value_nick);
6816 g_type_class_unref (enum_class);
6817
6818 if (!(capabilities & CTK_PRINT_CAPABILITY_NUMBER_UP))
6819 {
6820 ctk_print_job_set_n_up (print_job, ctk_print_settings_get_number_up (settings));
6821 ctk_print_job_set_n_up_layout (print_job, ctk_print_settings_get_number_up_layout (settings));
6822 }
6823 }
6824
6825 ctk_print_job_set_rotate (print_job, TRUE(!(0)));
6826}
6827
6828static CtkPageSetup *
6829create_page_setup (ppd_file_t *ppd_file,
6830 ppd_size_t *size)
6831{
6832 char *display_name;
6833 CtkPageSetup *page_setup;
6834 CtkPaperSize *paper_size;
6835 ppd_option_t *option;
6836
6837 display_name = NULL((void*)0);
6838 option = ppdFindOption (ppd_file, "PageSize");
6839 if (option)
6840 {
6841 ppd_choice_t *choice;
6842
6843 choice = ppdFindChoice (option, size->name);
6844 if (choice)
6845 display_name = ppd_text_to_utf8 (ppd_file, choice->text);
6846 }
6847
6848 if (display_name == NULL((void*)0))
6849 display_name = g_strdup (size->name)g_strdup_inline (size->name);
6850
6851 page_setup = ctk_page_setup_new ();
6852 paper_size = ctk_paper_size_new_from_ppd (size->name,
6853 display_name,
6854 size->width,
6855 size->length);
6856 ctk_page_setup_set_paper_size (page_setup, paper_size);
6857 ctk_paper_size_free (paper_size);
6858
6859 ctk_page_setup_set_top_margin (page_setup, size->length - size->top, CTK_UNIT_POINTS);
6860 ctk_page_setup_set_bottom_margin (page_setup, size->bottom, CTK_UNIT_POINTS);
6861 ctk_page_setup_set_left_margin (page_setup, size->left, CTK_UNIT_POINTS);
6862 ctk_page_setup_set_right_margin (page_setup, size->width - size->right, CTK_UNIT_POINTS);
6863
6864 g_free (display_name);
6865
6866 return page_setup;
6867}
6868
6869static CtkPageSetup *
6870create_page_setup_from_media (gchar *media,
6871 MediaSize *media_size,
6872 gboolean media_margin_default_set,
6873 gint media_bottom_margin_default,
6874 gint media_top_margin_default,
6875 gint media_left_margin_default,
6876 gint media_right_margin_default)
6877{
6878 CtkPageSetup *page_setup;
6879 CtkPaperSize *paper_size;
6880
6881 page_setup = ctk_page_setup_new ();
6882 paper_size = ctk_paper_size_new_from_ipp (media,
6883 POINTS_PER_INCH72 * (media_size->x_dimension / MM_PER_INCH25.4),
6884 POINTS_PER_INCH72 * (media_size->y_dimension / MM_PER_INCH25.4));
6885 ctk_page_setup_set_paper_size (page_setup, paper_size);
6886 ctk_paper_size_free (paper_size);
6887
6888 if (media_margin_default_set)
6889 {
6890 ctk_page_setup_set_bottom_margin (page_setup, media_bottom_margin_default, CTK_UNIT_MM);
6891 ctk_page_setup_set_top_margin (page_setup, media_top_margin_default, CTK_UNIT_MM);
6892 ctk_page_setup_set_left_margin (page_setup, media_left_margin_default, CTK_UNIT_MM);
6893 ctk_page_setup_set_right_margin (page_setup, media_right_margin_default, CTK_UNIT_MM);
6894 }
6895
6896 return page_setup;
6897}
6898
6899static GList *
6900cups_printer_list_papers (CtkPrinter *printer)
6901{
6902 ppd_file_t *ppd_file;
6903 CtkPageSetup *page_setup;
6904 CtkPrinterCups *cups_printer = CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
;
6905 GList *result = NULL((void*)0);
6906
6907 ppd_file = ctk_printer_cups_get_ppd (cups_printer);
6908 if (ppd_file != NULL((void*)0))
6909 {
6910 int i;
6911
6912 for (i = 0; i < ppd_file->num_sizes; i++)
6913 {
6914 ppd_size_t *size;
6915
6916 size = &ppd_file->sizes[i];
6917
6918 page_setup = create_page_setup (ppd_file, size);
6919
6920 result = g_list_prepend (result, page_setup);
6921 }
6922 }
6923 else if (cups_printer->media_supported != NULL((void*)0) &&
6924 cups_printer->media_size_supported != NULL((void*)0) &&
6925 /*
6926 * 'media_supported' list can contain names of minimal and maximal sizes
6927 * for which we don't create item in 'media_size_supported' list.
6928 */
6929 g_list_length (cups_printer->media_supported) >=
6930 g_list_length (cups_printer->media_size_supported))
6931 {
6932 GList *media_iter;
6933 GList *media_size_iter;
6934
6935 for (media_iter = cups_printer->media_supported,
6936 media_size_iter = cups_printer->media_size_supported;
6937 media_size_iter != NULL((void*)0);
6938 media_iter = media_iter->next,
6939 media_size_iter = media_size_iter->next)
6940 {
6941 MediaSize *media_size;
6942 gchar *media;
6943
6944 media = (gchar *) media_iter->data;
6945 media_size = (MediaSize *) media_size_iter->data;
6946
6947 page_setup = create_page_setup_from_media (media,
6948 media_size,
6949 cups_printer->media_margin_default_set,
6950 cups_printer->media_bottom_margin_default,
6951 cups_printer->media_top_margin_default,
6952 cups_printer->media_left_margin_default,
6953 cups_printer->media_right_margin_default);
6954
6955 result = g_list_prepend (result, page_setup);
6956 }
6957 }
6958
6959 result = g_list_reverse (result);
6960
6961 return result;
6962}
6963
6964static CtkPageSetup *
6965cups_printer_get_default_page_size (CtkPrinter *printer)
6966{
6967 CtkPrinterCups *cups_printer = CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
;
6968 CtkPageSetup *result = NULL((void*)0);
6969 ppd_file_t *ppd_file;
6970
6971 ppd_file = ctk_printer_cups_get_ppd (CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
);
6972
6973 if (ppd_file != NULL((void*)0))
6974 {
6975 ppd_option_t *option;
6976 ppd_size_t *size;
6977
6978 option = ppdFindOption (ppd_file, "PageSize");
6979 if (option == NULL((void*)0))
6980 return NULL((void*)0);
6981
6982 size = ppdPageSize (ppd_file, option->defchoice);
6983 if (size == NULL((void*)0))
6984 return NULL((void*)0);
6985
6986 result = create_page_setup (ppd_file, size);
6987 }
6988 else if (cups_printer->media_default != NULL((void*)0))
6989 {
6990 GList *media_iter;
6991 GList *media_size_iter;
6992
6993 for (media_iter = cups_printer->media_supported,
6994 media_size_iter = cups_printer->media_size_supported;
6995 media_size_iter != NULL((void*)0);
6996 media_iter = media_iter->next,
6997 media_size_iter = media_size_iter->next)
6998 {
6999 MediaSize *media_size;
7000 gchar *media;
7001
7002 media = (gchar *) media_iter->data;
7003 media_size = (MediaSize *) media_size_iter->data;
7004
7005 if (g_strcmp0 (cups_printer->media_default, media) == 0)
7006 {
7007 result = create_page_setup_from_media (media,
7008 media_size,
7009 cups_printer->media_margin_default_set,
7010 cups_printer->media_bottom_margin_default,
7011 cups_printer->media_top_margin_default,
7012 cups_printer->media_left_margin_default,
7013 cups_printer->media_right_margin_default);
7014 }
7015 }
7016 }
7017
7018 return result;
7019}
7020
7021static gboolean
7022cups_printer_get_hard_margins (CtkPrinter *printer,
7023 gdouble *top,
7024 gdouble *bottom,
7025 gdouble *left,
7026 gdouble *right)
7027{
7028 CtkPrinterCups *cups_printer = CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
;
7029 ppd_file_t *ppd_file;
7030 gboolean result = FALSE(0);
7031
7032 ppd_file = ctk_printer_cups_get_ppd (CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
);
7033 if (ppd_file != NULL((void*)0))
7034 {
7035 *left = ppd_file->custom_margins[0];
7036 *bottom = ppd_file->custom_margins[1];
7037 *right = ppd_file->custom_margins[2];
7038 *top = ppd_file->custom_margins[3];
7039 result = TRUE(!(0));
7040 }
7041 else if (cups_printer->media_margin_default_set)
7042 {
7043 *left = POINTS_PER_INCH72 * cups_printer->media_left_margin_default / MM_PER_INCH25.4;
7044 *bottom = POINTS_PER_INCH72 * cups_printer->media_bottom_margin_default / MM_PER_INCH25.4;
7045 *right = POINTS_PER_INCH72 * cups_printer->media_right_margin_default / MM_PER_INCH25.4;
7046 *top = POINTS_PER_INCH72 * cups_printer->media_top_margin_default / MM_PER_INCH25.4;
7047 result = TRUE(!(0));
7048 }
7049
7050 return result;
7051}
7052
7053static gboolean
7054cups_printer_get_hard_margins_for_paper_size (CtkPrinter *printer,
7055 CtkPaperSize *paper_size,
7056 gdouble *top,
7057 gdouble *bottom,
7058 gdouble *left,
7059 gdouble *right)
7060{
7061 ppd_file_t *ppd_file;
7062 ppd_size_t *size;
7063 const gchar *paper_name;
7064 int i;
7065
7066 ppd_file = ctk_printer_cups_get_ppd (CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
);
7067 if (ppd_file == NULL((void*)0))
7068 return FALSE(0);
7069
7070 paper_name = ctk_paper_size_get_ppd_name (paper_size);
7071
7072 for (i = 0; i < ppd_file->num_sizes; i++)
7073 {
7074 size = &ppd_file->sizes[i];
7075 if (g_strcmp0(size->name, paper_name) == 0)
7076 {
7077 *top = size->length - size->top;
7078 *bottom = size->bottom;
7079 *left = size->left;
7080 *right = size->width - size->right;
7081 return TRUE(!(0));
7082 }
7083 }
7084
7085 /* Custom size */
7086 *left = ppd_file->custom_margins[0];
7087 *bottom = ppd_file->custom_margins[1];
7088 *right = ppd_file->custom_margins[2];
7089 *top = ppd_file->custom_margins[3];
7090
7091 return TRUE(!(0));
7092}
7093
7094static CtkPrintCapabilities
7095cups_printer_get_capabilities (CtkPrinter *printer)
7096{
7097 CtkPrintCapabilities capabilities = 0;
7098 CtkPrinterCups *cups_printer = CTK_PRINTER_CUPS (printer)((((CtkPrinterCups*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((printer)), ((ctk_printer_cups_get_type ()))))))
;
7099
7100 if (ctk_printer_cups_get_ppd (cups_printer))
7101 {
7102 capabilities = CTK_PRINT_CAPABILITY_REVERSE;
7103 }
7104
7105 if (cups_printer->supports_copies)
7106 {
7107 capabilities |= CTK_PRINT_CAPABILITY_COPIES;
7108 }
7109
7110 if (cups_printer->supports_collate)
7111 {
7112 capabilities |= CTK_PRINT_CAPABILITY_COLLATE;
7113 }
7114
7115 if (cups_printer->supports_number_up)
7116 {
7117 capabilities |= CTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT |
7118 CTK_PRINT_CAPABILITY_NUMBER_UP;
7119 }
7120
7121 return capabilities;
7122}
7123
7124static void
7125secrets_service_appeared_cb (GDBusConnection *connection G_GNUC_UNUSED__attribute__ ((__unused__)),
7126 const gchar *name G_GNUC_UNUSED__attribute__ ((__unused__)),
7127 const gchar *name_owner G_GNUC_UNUSED__attribute__ ((__unused__)),
7128 gpointer user_data)
7129{
7130 CtkPrintBackendCups *backend = CTK_PRINT_BACKEND_CUPS (user_data)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((user_data)), ((ctk_print_backend_cups_get_type
()))))))
;
7131
7132 backend->secrets_service_available = TRUE(!(0));
7133}
7134
7135static void
7136secrets_service_vanished_cb (GDBusConnection *connection G_GNUC_UNUSED__attribute__ ((__unused__)),
7137 const gchar *name G_GNUC_UNUSED__attribute__ ((__unused__)),
7138 gpointer user_data)
7139{
7140 CtkPrintBackendCups *backend = CTK_PRINT_BACKEND_CUPS (user_data)((((CtkPrintBackendCups*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((user_data)), ((ctk_print_backend_cups_get_type
()))))))
;
7141
7142 backend->secrets_service_available = FALSE(0);
7143}