]> Pileus Git - ~andy/gtk/blob - modules/printbackends/cups/gtkprintbackendcups.c
8dbc78bf8955a8db7760bdc9e1f0a72601f92420
[~andy/gtk] / modules / printbackends / cups / gtkprintbackendcups.c
1 /* GTK - The GIMP Toolkit
2  * gtkprintbackendcups.h: Default implementation of GtkPrintBackend
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 #ifdef __linux__
21 #define _GNU_SOURCE
22 #endif
23
24 #include "config.h"
25 #include <ctype.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <stdlib.h>
30 #include <time.h>
31 /* Cups 1.6 deprecates ppdFindAttr(), ppdFindCustomOption(),
32  * ppdFirstCustomParam(), and ppdNextCustomParam() among others. This
33  * turns off the warning so that it will compile.
34  */
35 #ifdef HAVE_CUPS_API_1_6
36 # define _PPD_DEPRECATED
37 #endif
38
39 #include <cups/cups.h>
40 #include <cups/language.h>
41 #include <cups/http.h>
42 #include <cups/ipp.h>
43 #include <errno.h>
44 #include <cairo.h>
45 #include <cairo-pdf.h>
46 #include <cairo-ps.h>
47
48 #include <glib/gstdio.h>
49 #include <glib/gi18n-lib.h>
50 #include <gmodule.h>
51
52 #include <gtk/gtk.h>
53 #include <gtk/gtkprintbackend.h>
54 #include <gtk/gtkunixprint.h>
55 #include <gtk/gtkprinter-private.h>
56
57 #include "gtkprintbackendcups.h"
58 #include "gtkprintercups.h"
59
60 #include "gtkcupsutils.h"
61
62 #ifdef HAVE_COLORD
63 #include <colord.h>
64 #endif
65
66 typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass;
67
68 #define GTK_PRINT_BACKEND_CUPS_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))
69 #define GTK_IS_PRINT_BACKEND_CUPS_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_CUPS))
70 #define GTK_PRINT_BACKEND_CUPS_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))
71
72 #define _CUPS_MAX_ATTEMPTS 10
73 #define _CUPS_MAX_CHUNK_SIZE 8192
74
75 /* define this to see warnings about ignored ppd options */
76 #undef PRINT_IGNORED_OPTIONS
77
78 #define _CUPS_MAP_ATTR_INT(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].integer;}
79 #define _CUPS_MAP_ATTR_STR(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].string.text;}
80
81 static GType print_backend_cups_type = 0;
82
83 typedef void (* GtkPrintCupsResponseCallbackFunc) (GtkPrintBackend *print_backend,
84                                                    GtkCupsResult   *result,
85                                                    gpointer         user_data);
86
87 typedef enum
88 {
89   DISPATCH_SETUP,
90   DISPATCH_REQUEST,
91   DISPATCH_SEND,
92   DISPATCH_CHECK,
93   DISPATCH_READ,
94   DISPATCH_ERROR
95 } GtkPrintCupsDispatchState;
96
97 typedef struct
98 {
99   GSource source;
100
101   http_t *http;
102   GtkCupsRequest *request;
103   GtkCupsPollState poll_state;
104   GPollFD *data_poll;
105   GtkPrintBackendCups *backend;
106   GtkPrintCupsResponseCallbackFunc callback;
107   gpointer                         callback_data;
108
109 } GtkPrintCupsDispatchWatch;
110
111 struct _GtkPrintBackendCupsClass
112 {
113   GtkPrintBackendClass parent_class;
114 };
115
116 struct _GtkPrintBackendCups
117 {
118   GtkPrintBackend parent_instance;
119
120   char *default_printer;
121
122   guint list_printers_poll;
123   guint list_printers_pending : 1;
124   gint  list_printers_attempts;
125   guint got_default_printer   : 1;
126   guint default_printer_poll;
127   GtkCupsConnectionTest *cups_connection_test;
128   gint  reading_ppds;
129
130   char **covers;
131   int    number_of_covers;
132
133   GList      *requests;
134   GHashTable *auth;
135   gchar      *username;
136   gboolean    authentication_lock;
137 #ifdef HAVE_COLORD
138   CdClient   *colord_client;
139 #endif
140 };
141
142 static GObjectClass *backend_parent_class;
143
144 static void                 gtk_print_backend_cups_class_init      (GtkPrintBackendCupsClass          *class);
145 static void                 gtk_print_backend_cups_init            (GtkPrintBackendCups               *impl);
146 static void                 gtk_print_backend_cups_finalize        (GObject                           *object);
147 static void                 gtk_print_backend_cups_dispose         (GObject                           *object);
148 static void                 cups_get_printer_list                  (GtkPrintBackend                   *print_backend);
149 static void                 cups_get_default_printer               (GtkPrintBackendCups               *print_backend);
150 static void                 cups_get_local_default_printer         (GtkPrintBackendCups               *print_backend);
151 static void                 cups_request_execute                   (GtkPrintBackendCups               *print_backend,
152                                                                     GtkCupsRequest                    *request,
153                                                                     GtkPrintCupsResponseCallbackFunc   callback,
154                                                                     gpointer                           user_data,
155                                                                     GDestroyNotify                     notify);
156 static void                 cups_printer_get_settings_from_options (GtkPrinter                        *printer,
157                                                                     GtkPrinterOptionSet               *options,
158                                                                     GtkPrintSettings                  *settings);
159 static gboolean             cups_printer_mark_conflicts            (GtkPrinter                        *printer,
160                                                                     GtkPrinterOptionSet               *options);
161 static GtkPrinterOptionSet *cups_printer_get_options               (GtkPrinter                        *printer,
162                                                                     GtkPrintSettings                  *settings,
163                                                                     GtkPageSetup                      *page_setup,
164                                                                     GtkPrintCapabilities               capabilities);
165 static void                 cups_printer_prepare_for_print         (GtkPrinter                        *printer,
166                                                                     GtkPrintJob                       *print_job,
167                                                                     GtkPrintSettings                  *settings,
168                                                                     GtkPageSetup                      *page_setup);
169 static GList *              cups_printer_list_papers               (GtkPrinter                        *printer);
170 static GtkPageSetup *       cups_printer_get_default_page_size     (GtkPrinter                        *printer);
171 static void                 cups_printer_request_details           (GtkPrinter                        *printer);
172 static gboolean             cups_request_default_printer           (GtkPrintBackendCups               *print_backend);
173 static gboolean             cups_request_ppd                       (GtkPrinter                        *printer);
174 static gboolean             cups_printer_get_hard_margins          (GtkPrinter                        *printer,
175                                                                     gdouble                           *top,
176                                                                     gdouble                           *bottom,
177                                                                     gdouble                           *left,
178                                                                     gdouble                           *right);
179 static GtkPrintCapabilities cups_printer_get_capabilities          (GtkPrinter                        *printer);
180 static void                 set_option_from_settings               (GtkPrinterOption                  *option,
181                                                                     GtkPrintSettings                  *setting);
182 static void                 cups_begin_polling_info                (GtkPrintBackendCups               *print_backend,
183                                                                     GtkPrintJob                       *job,
184                                                                     int                                job_id);
185 static gboolean             cups_job_info_poll_timeout             (gpointer                           user_data);
186 static void                 gtk_print_backend_cups_print_stream    (GtkPrintBackend                   *backend,
187                                                                     GtkPrintJob                       *job,
188                                                                     GIOChannel                        *data_io,
189                                                                     GtkPrintJobCompleteFunc            callback,
190                                                                     gpointer                           user_data,
191                                                                     GDestroyNotify                     dnotify);
192 static cairo_surface_t *    cups_printer_create_cairo_surface      (GtkPrinter                        *printer,
193                                                                     GtkPrintSettings                  *settings,
194                                                                     gdouble                            width,
195                                                                     gdouble                            height,
196                                                                     GIOChannel                        *cache_io);
197
198 static void                 gtk_print_backend_cups_set_password    (GtkPrintBackend                   *backend,
199                                                                     gchar                            **auth_info_required,
200                                                                     gchar                            **auth_info);
201
202 void                        overwrite_and_free                      (gpointer                          data);
203 static gboolean             is_address_local                        (const gchar                      *address);
204 static gboolean             request_auth_info                       (gpointer                          data);
205
206 static void
207 gtk_print_backend_cups_register_type (GTypeModule *module)
208 {
209   const GTypeInfo print_backend_cups_info =
210   {
211     sizeof (GtkPrintBackendCupsClass),
212     NULL,               /* base_init */
213     NULL,               /* base_finalize */
214     (GClassInitFunc) gtk_print_backend_cups_class_init,
215     NULL,               /* class_finalize */
216     NULL,               /* class_data */
217     sizeof (GtkPrintBackendCups),
218     0,                  /* n_preallocs */
219     (GInstanceInitFunc) gtk_print_backend_cups_init
220   };
221
222   print_backend_cups_type = g_type_module_register_type (module,
223                                                          GTK_TYPE_PRINT_BACKEND,
224                                                          "GtkPrintBackendCups",
225                                                          &print_backend_cups_info, 0);
226 }
227
228 G_MODULE_EXPORT void
229 pb_module_init (GTypeModule *module)
230 {
231   GTK_NOTE (PRINTING,
232             g_print ("CUPS Backend: Initializing the CUPS print backend module\n"));
233
234   gtk_print_backend_cups_register_type (module);
235   gtk_printer_cups_register_type (module);
236 }
237
238 G_MODULE_EXPORT void
239 pb_module_exit (void)
240 {
241
242 }
243
244 G_MODULE_EXPORT GtkPrintBackend *
245 pb_module_create (void)
246 {
247   return gtk_print_backend_cups_new ();
248 }
249 /* CUPS 1.6 Getter/Setter Functions CUPS 1.6 makes private most of the
250  * IPP structures and enforces access via new getter functions, which
251  * are unfortunately not available in earlier versions. We define
252  * below those getter functions as macros for use when building
253  * against earlier CUPS versions.
254  */
255 #ifndef HAVE_CUPS_API_1_6
256 #define ippGetOperation(ipp_request) ipp_request->request.op.operation_id
257 #define ippGetInteger(attr, index) attr->values[index].integer
258 #define ippGetBoolean(attr, index) attr->values[index].boolean
259 #define ippGetString(attr, index, foo) attr->values[index].string.text
260 #define ippGetValueTag(attr) attr->value_tag
261 #define ippGetName(attr) attr->name
262 #define ippGetCount(attr) attr->num_values
263 #define ippGetGroupTag(attr) attr->group_tag
264 #endif
265 /*
266  * GtkPrintBackendCups
267  */
268 GType
269 gtk_print_backend_cups_get_type (void)
270 {
271   return print_backend_cups_type;
272 }
273
274 /**
275  * gtk_print_backend_cups_new:
276  *
277  * Creates a new #GtkPrintBackendCups object. #GtkPrintBackendCups
278  * implements the #GtkPrintBackend interface with direct access to
279  * the filesystem using Unix/Linux API calls
280  *
281  * Return value: the new #GtkPrintBackendCups object
282  */
283 GtkPrintBackend *
284 gtk_print_backend_cups_new (void)
285 {
286   GTK_NOTE (PRINTING,
287             g_print ("CUPS Backend: Creating a new CUPS print backend object\n"));
288
289   return g_object_new (GTK_TYPE_PRINT_BACKEND_CUPS, NULL);
290 }
291
292 static void
293 gtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class)
294 {
295   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
296   GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_CLASS (class);
297
298   backend_parent_class = g_type_class_peek_parent (class);
299
300   gobject_class->finalize = gtk_print_backend_cups_finalize;
301   gobject_class->dispose = gtk_print_backend_cups_dispose;
302
303   backend_class->request_printer_list = cups_get_printer_list;
304   backend_class->print_stream = gtk_print_backend_cups_print_stream;
305   backend_class->printer_request_details = cups_printer_request_details;
306   backend_class->printer_create_cairo_surface = cups_printer_create_cairo_surface;
307   backend_class->printer_get_options = cups_printer_get_options;
308   backend_class->printer_mark_conflicts = cups_printer_mark_conflicts;
309   backend_class->printer_get_settings_from_options = cups_printer_get_settings_from_options;
310   backend_class->printer_prepare_for_print = cups_printer_prepare_for_print;
311   backend_class->printer_list_papers = cups_printer_list_papers;
312   backend_class->printer_get_default_page_size = cups_printer_get_default_page_size;
313   backend_class->printer_get_hard_margins = cups_printer_get_hard_margins;
314   backend_class->printer_get_capabilities = cups_printer_get_capabilities;
315   backend_class->set_password = gtk_print_backend_cups_set_password;
316 }
317
318 static cairo_status_t
319 _cairo_write_to_cups (void                *closure,
320                       const unsigned char *data,
321                       unsigned int         length)
322 {
323   GIOChannel *io = (GIOChannel *)closure;
324   gsize written;
325   GError *error;
326
327   error = NULL;
328
329   GTK_NOTE (PRINTING,
330             g_print ("CUPS Backend: Writing %i byte chunk to temp file\n", length));
331
332   while (length > 0)
333     {
334       g_io_channel_write_chars (io, (gchar *)data, length, &written, &error);
335
336       if (error != NULL)
337         {
338           GTK_NOTE (PRINTING,
339                     g_print ("CUPS Backend: Error writing to temp file, %s\n",
340                              error->message));
341
342           g_error_free (error);
343           return CAIRO_STATUS_WRITE_ERROR;
344         }
345
346       GTK_NOTE (PRINTING,
347                 g_print ("CUPS Backend: Wrote %"G_GSIZE_FORMAT" bytes to temp file\n", written));
348
349       data += written;
350       length -= written;
351     }
352
353   return CAIRO_STATUS_SUCCESS;
354 }
355
356 static cairo_surface_t *
357 cups_printer_create_cairo_surface (GtkPrinter       *printer,
358                                    GtkPrintSettings *settings,
359                                    gdouble           width,
360                                    gdouble           height,
361                                    GIOChannel       *cache_io)
362 {
363   cairo_surface_t *surface;
364   ppd_file_t      *ppd_file = NULL;
365   ppd_attr_t      *ppd_attr = NULL;
366   ppd_attr_t      *ppd_attr_res = NULL;
367   ppd_attr_t      *ppd_attr_screen_freq = NULL;
368   ppd_attr_t      *ppd_attr_res_screen_freq = NULL;
369   gchar           *res_string = NULL;
370   gint             level = 2;
371
372   if (gtk_printer_accepts_pdf (printer))
373     surface = cairo_pdf_surface_create_for_stream (_cairo_write_to_cups, cache_io, width, height);
374   else
375     surface = cairo_ps_surface_create_for_stream  (_cairo_write_to_cups, cache_io, width, height);
376
377   ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
378
379   if (ppd_file != NULL)
380     {
381       ppd_attr = ppdFindAttr (ppd_file, "LanguageLevel", NULL);
382
383       if (ppd_attr != NULL)
384         level = atoi (ppd_attr->value);
385
386       if (gtk_print_settings_get_resolution (settings) == 0)
387         {
388           ppd_attr_res = ppdFindAttr (ppd_file, "DefaultResolution", NULL);
389
390           if (ppd_attr_res != NULL)
391             {
392               int res, res_x, res_y;
393
394               if (sscanf (ppd_attr_res->value, "%dx%ddpi", &res_x, &res_y) == 2)
395                 {
396                   if (res_x > 0 && res_y > 0)
397                     gtk_print_settings_set_resolution_xy (settings, res_x, res_y);
398                 }
399               else if (sscanf (ppd_attr_res->value, "%ddpi", &res) == 1)
400                 {
401                   if (res > 0)
402                     gtk_print_settings_set_resolution (settings, res);
403                 }
404             }
405         }
406
407       res_string = g_strdup_printf ("%ddpi",
408                                     gtk_print_settings_get_resolution (settings));
409       ppd_attr_res_screen_freq = ppdFindAttr (ppd_file, "ResScreenFreq", res_string);
410       g_free (res_string);
411
412       if (ppd_attr_res_screen_freq == NULL)
413         {
414           res_string = g_strdup_printf ("%dx%ddpi",
415                                         gtk_print_settings_get_resolution_x (settings),
416                                         gtk_print_settings_get_resolution_y (settings));
417           ppd_attr_res_screen_freq = ppdFindAttr (ppd_file, "ResScreenFreq", res_string);
418           g_free (res_string);
419         }
420
421       ppd_attr_screen_freq = ppdFindAttr (ppd_file, "ScreenFreq", NULL);
422
423       if (ppd_attr_res_screen_freq != NULL && atof (ppd_attr_res_screen_freq->value) > 0.0)
424         gtk_print_settings_set_printer_lpi (settings, atof (ppd_attr_res_screen_freq->value));
425       else if (ppd_attr_screen_freq != NULL && atof (ppd_attr_screen_freq->value) > 0.0)
426         gtk_print_settings_set_printer_lpi (settings, atof (ppd_attr_screen_freq->value));
427     }
428
429   if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_PS)
430     {
431       if (level == 2)
432         cairo_ps_surface_restrict_to_level (surface, CAIRO_PS_LEVEL_2);
433
434       if (level == 3)
435         cairo_ps_surface_restrict_to_level (surface, CAIRO_PS_LEVEL_3);
436     }
437
438   cairo_surface_set_fallback_resolution (surface,
439                                          2.0 * gtk_print_settings_get_printer_lpi (settings),
440                                          2.0 * gtk_print_settings_get_printer_lpi (settings));
441
442   return surface;
443 }
444
445 typedef struct {
446   GtkPrintJobCompleteFunc callback;
447   GtkPrintJob *job;
448   gpointer user_data;
449   GDestroyNotify dnotify;
450 } CupsPrintStreamData;
451
452 static void
453 cups_free_print_stream_data (CupsPrintStreamData *data)
454 {
455   GTK_NOTE (PRINTING,
456             g_print ("CUPS Backend: %s\n", G_STRFUNC));
457
458   if (data->dnotify)
459     data->dnotify (data->user_data);
460   g_object_unref (data->job);
461   g_free (data);
462 }
463
464 static void
465 cups_print_cb (GtkPrintBackendCups *print_backend,
466                GtkCupsResult       *result,
467                gpointer             user_data)
468 {
469   GError *error = NULL;
470   CupsPrintStreamData *ps = user_data;
471
472   gdk_threads_enter ();
473
474   GTK_NOTE (PRINTING,
475             g_print ("CUPS Backend: %s\n", G_STRFUNC));
476
477   if (gtk_cups_result_is_error (result))
478     error = g_error_new_literal (gtk_print_error_quark (),
479                                  GTK_PRINT_ERROR_INTERNAL_ERROR,
480                                  gtk_cups_result_get_error_string (result));
481
482   if (ps->callback)
483     ps->callback (ps->job, ps->user_data, error);
484
485   if (error == NULL)
486     {
487       int job_id = 0;
488       ipp_attribute_t *attr;            /* IPP job-id attribute */
489       ipp_t *response = gtk_cups_result_get_response (result);
490
491       if ((attr = ippFindAttribute (response, "job-id", IPP_TAG_INTEGER)) != NULL)
492         job_id = ippGetInteger (attr, 0);
493
494       if (!gtk_print_job_get_track_print_status (ps->job) || job_id == 0)
495         gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED);
496       else
497         {
498           gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_PENDING);
499           cups_begin_polling_info (print_backend, ps->job, job_id);
500         }
501     }
502   else
503     gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED_ABORTED);
504
505
506   if (error)
507     g_error_free (error);
508
509   gdk_threads_leave ();
510 }
511
512 typedef struct {
513   GtkCupsRequest *request;
514   GtkPrinterCups *printer;
515 } CupsOptionsData;
516
517 static void
518 add_cups_options (const gchar *key,
519                   const gchar *value,
520                   gpointer     user_data)
521 {
522   CupsOptionsData *data = (CupsOptionsData *) user_data;
523   GtkCupsRequest *request = data->request;
524   GtkPrinterCups *printer = data->printer;
525   gboolean custom_value = FALSE;
526   gchar *new_value = NULL;
527   gint i;
528
529   if (!key || !value)
530     return;
531
532   if (!g_str_has_prefix (key, "cups-"))
533     return;
534
535   if (strcmp (value, "gtk-ignore-value") == 0)
536     return;
537
538   key = key + strlen ("cups-");
539
540   if (printer && printer->ppd_file)
541     {
542       ppd_coption_t *coption;
543       gboolean       found = FALSE;
544       gboolean       custom_values_enabled = FALSE;
545
546       coption = ppdFindCustomOption (printer->ppd_file, key);
547       if (coption && coption->option)
548         {
549           for (i = 0; i < coption->option->num_choices; i++)
550             {
551               /* Are custom values enabled ? */
552               if (g_str_equal (coption->option->choices[i].choice, "Custom"))
553                 custom_values_enabled = TRUE;
554
555               /* Is the value among available choices ? */
556               if (g_str_equal (coption->option->choices[i].choice, value))
557                 found = TRUE;
558             }
559
560           if (custom_values_enabled && !found)
561             custom_value = TRUE;
562         }
563     }
564
565   /* Add "Custom." prefix to custom values if not already added. */
566   if (custom_value && !g_str_has_prefix (value, "Custom."))
567     {
568       new_value = g_strdup_printf ("Custom.%s", value);
569       gtk_cups_request_encode_option (request, key, new_value);
570       g_free (new_value);
571     }
572   else
573     gtk_cups_request_encode_option (request, key, value);
574 }
575
576 static void
577 gtk_print_backend_cups_print_stream (GtkPrintBackend         *print_backend,
578                                      GtkPrintJob             *job,
579                                      GIOChannel              *data_io,
580                                      GtkPrintJobCompleteFunc  callback,
581                                      gpointer                 user_data,
582                                      GDestroyNotify           dnotify)
583 {
584   GtkPrinterCups *cups_printer;
585   CupsPrintStreamData *ps;
586   CupsOptionsData *options_data;
587   GtkCupsRequest *request;
588   GtkPrintSettings *settings;
589   const gchar *title;
590   char  printer_absolute_uri[HTTP_MAX_URI];
591
592   GTK_NOTE (PRINTING,
593             g_print ("CUPS Backend: %s\n", G_STRFUNC));
594
595   cups_printer = GTK_PRINTER_CUPS (gtk_print_job_get_printer (job));
596   settings = gtk_print_job_get_settings (job);
597
598   request = gtk_cups_request_new_with_username (NULL,
599                                                 GTK_CUPS_POST,
600                                                 IPP_PRINT_JOB,
601                                                 data_io,
602                                                 NULL,
603                                                 cups_printer->device_uri,
604                                                 GTK_PRINT_BACKEND_CUPS (print_backend)->username);
605
606   httpAssembleURIf (HTTP_URI_CODING_ALL,
607                     printer_absolute_uri,
608                     sizeof (printer_absolute_uri),
609                     "ipp",
610                     NULL,
611                     "localhost",
612                     ippPort (),
613                     "/printers/%s",
614                     gtk_printer_get_name (gtk_print_job_get_printer (job)));
615
616   gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION,
617                                    IPP_TAG_URI, "printer-uri",
618                                    NULL, printer_absolute_uri);
619
620   title = gtk_print_job_get_title (job);
621   if (title)
622     gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION,
623                                      IPP_TAG_NAME, "job-name",
624                                      NULL, title);
625
626   options_data = g_new0 (CupsOptionsData, 1);
627   options_data->request = request;
628   options_data->printer = cups_printer;
629   gtk_print_settings_foreach (settings, add_cups_options, options_data);
630   g_free (options_data);
631
632   ps = g_new0 (CupsPrintStreamData, 1);
633   ps->callback = callback;
634   ps->user_data = user_data;
635   ps->dnotify = dnotify;
636   ps->job = g_object_ref (job);
637
638   request->need_auth_info = cups_printer->auth_info_required != NULL;
639   request->auth_info_required = g_strdupv (cups_printer->auth_info_required);
640
641   cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
642                         request,
643                         (GtkPrintCupsResponseCallbackFunc) cups_print_cb,
644                         ps,
645                         (GDestroyNotify)cups_free_print_stream_data);
646 }
647
648 void overwrite_and_free (gpointer data)
649 {
650   gchar *password = (gchar *) data;
651
652   if (password != NULL)
653     {
654       memset (password, 0, strlen (password));
655       g_free (password);
656     }
657 }
658
659 static void
660 gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
661 {
662   backend_cups->list_printers_poll = FALSE;
663   backend_cups->got_default_printer = FALSE;
664   backend_cups->list_printers_pending = FALSE;
665   backend_cups->list_printers_attempts = 0;
666   backend_cups->reading_ppds = 0;
667
668   backend_cups->requests = NULL;
669   backend_cups->auth = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, overwrite_and_free);
670   backend_cups->authentication_lock = FALSE;
671
672   backend_cups->covers = NULL;
673   backend_cups->number_of_covers = 0;
674
675   backend_cups->default_printer_poll = 0;
676   backend_cups->cups_connection_test = NULL;
677
678   backend_cups->username = NULL;
679
680 #ifdef HAVE_COLORD
681   backend_cups->colord_client = cd_client_new ();
682 #endif
683
684   cups_get_local_default_printer (backend_cups);
685 }
686
687 static void
688 gtk_print_backend_cups_finalize (GObject *object)
689 {
690   GtkPrintBackendCups *backend_cups;
691
692   GTK_NOTE (PRINTING,
693             g_print ("CUPS Backend: finalizing CUPS backend module\n"));
694
695   backend_cups = GTK_PRINT_BACKEND_CUPS (object);
696
697   g_free (backend_cups->default_printer);
698   backend_cups->default_printer = NULL;
699
700   g_strfreev (backend_cups->covers);
701   backend_cups->number_of_covers = 0;
702
703   gtk_cups_connection_test_free (backend_cups->cups_connection_test);
704   backend_cups->cups_connection_test = NULL;
705
706   g_hash_table_destroy (backend_cups->auth);
707
708   g_free (backend_cups->username);
709
710 #ifdef HAVE_COLORD
711   g_object_unref (backend_cups->colord_client);
712 #endif
713
714   backend_parent_class->finalize (object);
715 }
716
717 static void
718 gtk_print_backend_cups_dispose (GObject *object)
719 {
720   GtkPrintBackendCups *backend_cups;
721
722   GTK_NOTE (PRINTING,
723             g_print ("CUPS Backend: %s\n", G_STRFUNC));
724
725   backend_cups = GTK_PRINT_BACKEND_CUPS (object);
726
727   if (backend_cups->list_printers_poll > 0)
728     g_source_remove (backend_cups->list_printers_poll);
729   backend_cups->list_printers_poll = 0;
730   backend_cups->list_printers_attempts = 0;
731
732   if (backend_cups->default_printer_poll > 0)
733     g_source_remove (backend_cups->default_printer_poll);
734   backend_cups->default_printer_poll = 0;
735
736   backend_parent_class->dispose (object);
737 }
738
739 static gboolean
740 is_address_local (const gchar *address)
741 {
742   if (address[0] == '/' ||
743       strcmp (address, "127.0.0.1") == 0 ||
744       strcmp (address, "[::1]") == 0)
745     return TRUE;
746   else
747     return FALSE;
748 }
749
750 static void
751 gtk_print_backend_cups_set_password (GtkPrintBackend  *backend,
752                                      gchar           **auth_info_required,
753                                      gchar           **auth_info)
754 {
755   GtkPrintBackendCups *cups_backend = GTK_PRINT_BACKEND_CUPS (backend);
756   GList *l;
757   char   dispatch_hostname[HTTP_MAX_URI];
758   gchar *username = NULL;
759   gchar *hostname = NULL;
760   gchar *password = NULL;
761   gint   length;
762   gint   i;
763
764   length = g_strv_length (auth_info_required);
765
766   if (auth_info != NULL)
767     for (i = 0; i < length; i++)
768       {
769         if (g_strcmp0 (auth_info_required[i], "username") == 0)
770           username = g_strdup (auth_info[i]);
771         else if (g_strcmp0 (auth_info_required[i], "hostname") == 0)
772           hostname = g_strdup (auth_info[i]);
773         else if (g_strcmp0 (auth_info_required[i], "password") == 0)
774           password = g_strdup (auth_info[i]);
775       }
776
777   if (hostname != NULL && username != NULL && password != NULL)
778     {
779       gchar *key = g_strconcat (username, "@", hostname, NULL);
780       g_hash_table_insert (cups_backend->auth, key, g_strdup (password));
781       GTK_NOTE (PRINTING,
782                 g_print ("CUPS backend: storing password for %s\n", key));
783     }
784
785   g_free (cups_backend->username);
786   cups_backend->username = g_strdup (username);
787
788
789   for (l = cups_backend->requests; l; l = l->next)
790     {
791       GtkPrintCupsDispatchWatch *dispatch = l->data;
792
793       httpGetHostname (dispatch->request->http, dispatch_hostname, sizeof (dispatch_hostname));
794       if (is_address_local (dispatch_hostname))
795         strcpy (dispatch_hostname, "localhost");
796
797       if (dispatch->request->need_auth_info)
798         {
799           if (auth_info != NULL)
800             {
801               dispatch->request->auth_info = g_new0 (gchar *, length + 1);
802               for (i = 0; i < length; i++)
803                 dispatch->request->auth_info[i] = g_strdup (auth_info[i]);
804             }
805           dispatch->backend->authentication_lock = FALSE;
806           dispatch->request->need_auth_info = FALSE;
807         }
808       else if (dispatch->request->password_state == GTK_CUPS_PASSWORD_REQUESTED || auth_info == NULL)
809         {
810           overwrite_and_free (dispatch->request->password);
811           dispatch->request->password = g_strdup (password);
812           g_free (dispatch->request->username);
813           dispatch->request->username = g_strdup (username);
814           dispatch->request->password_state = GTK_CUPS_PASSWORD_HAS;
815           dispatch->backend->authentication_lock = FALSE;
816         }
817     }
818 }
819
820 static gboolean
821 request_password (gpointer data)
822 {
823   GtkPrintCupsDispatchWatch *dispatch = data;
824   const gchar               *username;
825   gchar                     *password;
826   gchar                     *prompt = NULL;
827   gchar                     *key = NULL;
828   char                       hostname[HTTP_MAX_URI];
829   gchar                    **auth_info_required;
830   gchar                    **auth_info_default;
831   gchar                    **auth_info_display;
832   gboolean                  *auth_info_visible;
833   gint                       length = 3;
834   gint                       i;
835
836   if (dispatch->backend->authentication_lock)
837     return G_SOURCE_REMOVE;
838
839   httpGetHostname (dispatch->request->http, hostname, sizeof (hostname));
840   if (is_address_local (hostname))
841     strcpy (hostname, "localhost");
842
843   if (dispatch->backend->username != NULL)
844     username = dispatch->backend->username;
845   else
846     username = cupsUser ();
847
848   auth_info_required = g_new0 (gchar*, length + 1);
849   auth_info_required[0] = g_strdup ("hostname");
850   auth_info_required[1] = g_strdup ("username");
851   auth_info_required[2] = g_strdup ("password");
852
853   auth_info_default = g_new0 (gchar*, length + 1);
854   auth_info_default[0] = g_strdup (hostname);
855   auth_info_default[1] = g_strdup (username);
856
857   auth_info_display = g_new0 (gchar*, length + 1);
858   auth_info_display[1] = g_strdup (_("Username:"));
859   auth_info_display[2] = g_strdup (_("Password:"));
860
861   auth_info_visible = g_new0 (gboolean, length + 1);
862   auth_info_visible[1] = TRUE;
863
864   key = g_strconcat (username, "@", hostname, NULL);
865   password = g_hash_table_lookup (dispatch->backend->auth, key);
866
867   if (password && dispatch->request->password_state != GTK_CUPS_PASSWORD_NOT_VALID)
868     {
869       GTK_NOTE (PRINTING,
870                 g_print ("CUPS backend: using stored password for %s\n", key));
871
872       overwrite_and_free (dispatch->request->password);
873       dispatch->request->password = g_strdup (password);
874       g_free (dispatch->request->username);
875       dispatch->request->username = g_strdup (username);
876       dispatch->request->password_state = GTK_CUPS_PASSWORD_HAS;
877     }
878   else
879     {
880       const char *job_title = gtk_cups_request_ipp_get_string (dispatch->request, IPP_TAG_NAME, "job-name");
881       const char *printer_uri = gtk_cups_request_ipp_get_string (dispatch->request, IPP_TAG_URI, "printer-uri");
882       char *printer_name = NULL;
883
884       if (printer_uri != NULL && strrchr (printer_uri, '/') != NULL)
885         printer_name = g_strdup (strrchr (printer_uri, '/') + 1);
886
887       if (dispatch->request->password_state == GTK_CUPS_PASSWORD_NOT_VALID)
888         g_hash_table_remove (dispatch->backend->auth, key);
889
890       dispatch->request->password_state = GTK_CUPS_PASSWORD_REQUESTED;
891
892       dispatch->backend->authentication_lock = TRUE;
893
894       switch (ippGetOperation (dispatch->request->ipp_request))
895         {
896           case IPP_PRINT_JOB:
897             if (job_title != NULL && printer_name != NULL)
898               prompt = g_strdup_printf ( _("Authentication is required to print document '%s' on printer %s"), job_title, printer_name);
899             else
900               prompt = g_strdup_printf ( _("Authentication is required to print a document on %s"), hostname);
901             break;
902           case IPP_GET_JOB_ATTRIBUTES:
903             if (job_title != NULL)
904               prompt = g_strdup_printf ( _("Authentication is required to get attributes of job '%s'"), job_title);
905             else
906               prompt = g_strdup ( _("Authentication is required to get attributes of a job"));
907             break;
908           case IPP_GET_PRINTER_ATTRIBUTES:
909             if (printer_name != NULL)
910               prompt = g_strdup_printf ( _("Authentication is required to get attributes of printer %s"), printer_name);
911             else
912               prompt = g_strdup ( _("Authentication is required to get attributes of a printer"));
913             break;
914           case CUPS_GET_DEFAULT:
915             prompt = g_strdup_printf ( _("Authentication is required to get default printer of %s"), hostname);
916             break;
917           case CUPS_GET_PRINTERS:
918             prompt = g_strdup_printf ( _("Authentication is required to get printers from %s"), hostname);
919             break;
920           default:
921             /* work around gcc warning about 0 not being a value for this enum */
922             if (ippGetOperation (dispatch->request->ipp_request) == 0)
923               prompt = g_strdup_printf ( _("Authentication is required to get a file from %s"), hostname);
924             else
925               prompt = g_strdup_printf ( _("Authentication is required on %s"), hostname);
926             break;
927         }
928
929       g_free (printer_name);
930
931       g_signal_emit_by_name (dispatch->backend, "request-password",
932                              auth_info_required, auth_info_default, auth_info_display, auth_info_visible, prompt);
933
934       g_free (prompt);
935     }
936
937   for (i = 0; i < length; i++)
938     {
939       g_free (auth_info_required[i]);
940       g_free (auth_info_default[i]);
941       g_free (auth_info_display[i]);
942     }
943
944   g_free (auth_info_required);
945   g_free (auth_info_default);
946   g_free (auth_info_display);
947   g_free (auth_info_visible);
948   g_free (key);
949
950   return G_SOURCE_REMOVE;
951 }
952
953 static void
954 cups_dispatch_add_poll (GSource *source)
955 {
956   GtkPrintCupsDispatchWatch *dispatch;
957   GtkCupsPollState poll_state;
958
959   dispatch = (GtkPrintCupsDispatchWatch *) source;
960
961   poll_state = gtk_cups_request_get_poll_state (dispatch->request);
962
963   /* Remove the old source if the poll state changed. */
964   if (poll_state != dispatch->poll_state && dispatch->data_poll != NULL)
965     {
966       g_source_remove_poll (source, dispatch->data_poll);
967       g_free (dispatch->data_poll);
968       dispatch->data_poll = NULL;
969     }
970
971   if (dispatch->request->http != NULL)
972     {
973       if (dispatch->data_poll == NULL)
974         {
975           dispatch->data_poll = g_new0 (GPollFD, 1);
976           dispatch->poll_state = poll_state;
977
978           if (poll_state == GTK_CUPS_HTTP_READ)
979             dispatch->data_poll->events = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
980           else if (poll_state == GTK_CUPS_HTTP_WRITE)
981             dispatch->data_poll->events = G_IO_OUT | G_IO_ERR;
982           else
983             dispatch->data_poll->events = 0;
984
985           dispatch->data_poll->fd = httpGetFd (dispatch->request->http);
986           g_source_add_poll (source, dispatch->data_poll);
987         }
988     }
989 }
990
991 static gboolean
992 check_auth_info (gpointer user_data)
993 {
994   GtkPrintCupsDispatchWatch *dispatch;
995   dispatch = (GtkPrintCupsDispatchWatch *) user_data;
996
997   if (!dispatch->request->need_auth_info)
998     {
999       if (dispatch->request->auth_info == NULL)
1000         {
1001           dispatch->callback (GTK_PRINT_BACKEND (dispatch->backend),
1002                               gtk_cups_request_get_result (dispatch->request),
1003                               dispatch->callback_data);
1004           g_source_destroy ((GSource *) dispatch);
1005         }
1006       else
1007         {
1008           gint length;
1009           gint i;
1010
1011           length = g_strv_length (dispatch->request->auth_info_required);
1012
1013           gtk_cups_request_ipp_add_strings (dispatch->request,
1014                                             IPP_TAG_JOB,
1015                                             IPP_TAG_TEXT,
1016                                             "auth-info",
1017                                             length,
1018                                             NULL,
1019                                             (const char * const *) dispatch->request->auth_info);
1020
1021           g_source_attach ((GSource *) dispatch, NULL);
1022           g_source_unref ((GSource *) dispatch);
1023
1024           for (i = 0; i < length; i++)
1025             overwrite_and_free (dispatch->request->auth_info[i]);
1026           g_free (dispatch->request->auth_info);
1027           dispatch->request->auth_info = NULL;
1028         }
1029
1030       return G_SOURCE_REMOVE;
1031     }
1032
1033   return G_SOURCE_CONTINUE;
1034 }
1035
1036 static gboolean
1037 request_auth_info (gpointer user_data)
1038 {
1039   GtkPrintCupsDispatchWatch  *dispatch;
1040   const char                 *job_title;
1041   const char                 *printer_uri;
1042   gchar                      *prompt = NULL;
1043   char                       *printer_name = NULL;
1044   gint                        length;
1045   gint                        i;
1046   gboolean                   *auth_info_visible = NULL;
1047   gchar                     **auth_info_default = NULL;
1048   gchar                     **auth_info_display = NULL;
1049
1050   dispatch = (GtkPrintCupsDispatchWatch *) user_data;
1051
1052   if (dispatch->backend->authentication_lock)
1053     return FALSE;
1054
1055   job_title = gtk_cups_request_ipp_get_string (dispatch->request, IPP_TAG_NAME, "job-name");
1056   printer_uri = gtk_cups_request_ipp_get_string (dispatch->request, IPP_TAG_URI, "printer-uri");
1057   length = g_strv_length (dispatch->request->auth_info_required);
1058
1059   auth_info_visible = g_new0 (gboolean, length);
1060   auth_info_default = g_new0 (gchar *, length + 1);
1061   auth_info_display = g_new0 (gchar *, length + 1);
1062
1063   for (i = 0; i < length; i++)
1064     {
1065       if (g_strcmp0 (dispatch->request->auth_info_required[i], "domain") == 0)
1066         {
1067           auth_info_display[i] = g_strdup (_("Domain:"));
1068           auth_info_default[i] = g_strdup ("WORKGROUP");
1069           auth_info_visible[i] = TRUE;
1070         }
1071       else if (g_strcmp0 (dispatch->request->auth_info_required[i], "username") == 0)
1072         {
1073           auth_info_display[i] = g_strdup (_("Username:"));
1074           if (dispatch->backend->username != NULL)
1075             auth_info_default[i] = g_strdup (dispatch->backend->username);
1076           else
1077             auth_info_default[i] = g_strdup (cupsUser ());
1078           auth_info_visible[i] = TRUE;
1079         }
1080       else if (g_strcmp0 (dispatch->request->auth_info_required[i], "password") == 0)
1081         {
1082           auth_info_display[i] = g_strdup (_("Password:"));
1083           auth_info_visible[i] = FALSE;
1084         }
1085     }
1086
1087   if (printer_uri != NULL && strrchr (printer_uri, '/') != NULL)
1088     printer_name = g_strdup (strrchr (printer_uri, '/') + 1);
1089
1090   dispatch->backend->authentication_lock = TRUE;
1091
1092   if (job_title != NULL)
1093     {
1094       if (printer_name != NULL)
1095         prompt = g_strdup_printf ( _("Authentication is required to print document '%s' on printer %s"), job_title, printer_name);
1096       else
1097         prompt = g_strdup_printf ( _("Authentication is required to print document '%s'"), job_title);
1098     }
1099   else
1100     {
1101       if (printer_name != NULL)
1102         prompt = g_strdup_printf ( _("Authentication is required to print this document on printer %s"), printer_name);
1103       else
1104         prompt = g_strdup ( _("Authentication is required to print this document"));
1105     }
1106
1107   g_signal_emit_by_name (dispatch->backend, "request-password",
1108                          dispatch->request->auth_info_required,
1109                          auth_info_default,
1110                          auth_info_display,
1111                          auth_info_visible,
1112                          prompt);
1113
1114   for (i = 0; i < length; i++)
1115     {
1116       g_free (auth_info_default[i]);
1117       g_free (auth_info_display[i]);
1118     }
1119
1120   g_free (auth_info_default);
1121   g_free (auth_info_display);
1122   g_free (printer_name);
1123   g_free (prompt);
1124
1125   g_idle_add (check_auth_info, user_data);
1126
1127   return FALSE;
1128 }
1129
1130 static gboolean
1131 cups_dispatch_watch_check (GSource *source)
1132 {
1133   GtkPrintCupsDispatchWatch *dispatch;
1134   GtkCupsPollState poll_state;
1135   gboolean result;
1136
1137   GTK_NOTE (PRINTING,
1138             g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
1139
1140   dispatch = (GtkPrintCupsDispatchWatch *) source;
1141
1142   poll_state = gtk_cups_request_get_poll_state (dispatch->request);
1143
1144   if (poll_state != GTK_CUPS_HTTP_IDLE && !dispatch->request->need_password)
1145     if (!(dispatch->data_poll->revents & dispatch->data_poll->events))
1146        return FALSE;
1147
1148   result = gtk_cups_request_read_write (dispatch->request, FALSE);
1149   if (result && dispatch->data_poll != NULL)
1150     {
1151       g_source_remove_poll (source, dispatch->data_poll);
1152       g_free (dispatch->data_poll);
1153       dispatch->data_poll = NULL;
1154     }
1155
1156   if (dispatch->request->need_password && dispatch->request->password_state != GTK_CUPS_PASSWORD_REQUESTED)
1157     {
1158       dispatch->request->need_password = FALSE;
1159       g_idle_add (request_password, dispatch);
1160       result = FALSE;
1161     }
1162
1163   return result;
1164 }
1165
1166 static gboolean
1167 cups_dispatch_watch_prepare (GSource *source,
1168                              gint    *timeout_)
1169 {
1170   GtkPrintCupsDispatchWatch *dispatch;
1171   gboolean result;
1172
1173   dispatch = (GtkPrintCupsDispatchWatch *) source;
1174
1175   GTK_NOTE (PRINTING,
1176             g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
1177
1178   *timeout_ = -1;
1179
1180   result = gtk_cups_request_read_write (dispatch->request, TRUE);
1181
1182   cups_dispatch_add_poll (source);
1183
1184   return result;
1185 }
1186
1187 static gboolean
1188 cups_dispatch_watch_dispatch (GSource     *source,
1189                               GSourceFunc  callback,
1190                               gpointer     user_data)
1191 {
1192   GtkPrintCupsDispatchWatch *dispatch;
1193   GtkPrintCupsResponseCallbackFunc ep_callback;
1194   GtkCupsResult *result;
1195
1196   g_assert (callback != NULL);
1197
1198   ep_callback = (GtkPrintCupsResponseCallbackFunc) callback;
1199
1200   dispatch = (GtkPrintCupsDispatchWatch *) source;
1201
1202   result = gtk_cups_request_get_result (dispatch->request);
1203
1204   GTK_NOTE (PRINTING,
1205             g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
1206
1207   if (gtk_cups_result_is_error (result))
1208     {
1209       GTK_NOTE (PRINTING,
1210                 g_print("Error result: %s (type %i, status %i, code %i)\n",
1211                         gtk_cups_result_get_error_string (result),
1212                         gtk_cups_result_get_error_type (result),
1213                         gtk_cups_result_get_error_status (result),
1214                         gtk_cups_result_get_error_code (result)));
1215      }
1216
1217   ep_callback (GTK_PRINT_BACKEND (dispatch->backend), result, user_data);
1218
1219   return FALSE;
1220 }
1221
1222 static void
1223 cups_dispatch_watch_finalize (GSource *source)
1224 {
1225   GtkPrintCupsDispatchWatch *dispatch;
1226   GtkCupsResult *result;
1227
1228   GTK_NOTE (PRINTING,
1229             g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
1230
1231   dispatch = (GtkPrintCupsDispatchWatch *) source;
1232
1233   result = gtk_cups_request_get_result (dispatch->request);
1234   if (gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_AUTH)
1235     {
1236       const gchar *username;
1237       gchar        hostname[HTTP_MAX_URI];
1238       gchar       *key;
1239
1240       httpGetHostname (dispatch->request->http, hostname, sizeof (hostname));
1241       if (is_address_local (hostname))
1242         strcpy (hostname, "localhost");
1243
1244       if (dispatch->backend->username != NULL)
1245         username = dispatch->backend->username;
1246       else
1247         username = cupsUser ();
1248
1249       key = g_strconcat (username, "@", hostname, NULL);
1250       GTK_NOTE (PRINTING,
1251                 g_print ("CUPS backend: removing stored password for %s\n", key));
1252       g_hash_table_remove (dispatch->backend->auth, key);
1253       g_free (key);
1254
1255       if (dispatch->backend)
1256         dispatch->backend->authentication_lock = FALSE;
1257     }
1258
1259   gtk_cups_request_free (dispatch->request);
1260
1261   if (dispatch->backend)
1262     {
1263       /* We need to unref this at idle time, because it might be the
1264        * last reference to this module causing the code to be
1265        * unloaded (including this particular function!)
1266        * Update: Doing this at idle caused a deadlock taking the
1267        * mainloop context lock while being in a GSource callout for
1268        * multithreaded apps. So, for now we just disable unloading
1269        * of print backends. See _gtk_print_backend_create for the
1270        * disabling.
1271        */
1272
1273       dispatch->backend->requests = g_list_remove (dispatch->backend->requests, dispatch);
1274
1275
1276       g_object_unref (dispatch->backend);
1277       dispatch->backend = NULL;
1278     }
1279
1280   if (dispatch->data_poll)
1281     {
1282       g_source_remove_poll (source, dispatch->data_poll);
1283       g_free (dispatch->data_poll);
1284       dispatch->data_poll = NULL;
1285     }
1286 }
1287
1288 static GSourceFuncs _cups_dispatch_watch_funcs = {
1289   cups_dispatch_watch_prepare,
1290   cups_dispatch_watch_check,
1291   cups_dispatch_watch_dispatch,
1292   cups_dispatch_watch_finalize
1293 };
1294
1295
1296 static void
1297 cups_request_execute (GtkPrintBackendCups              *print_backend,
1298                       GtkCupsRequest                   *request,
1299                       GtkPrintCupsResponseCallbackFunc  callback,
1300                       gpointer                          user_data,
1301                       GDestroyNotify                    notify)
1302 {
1303   GtkPrintCupsDispatchWatch *dispatch;
1304
1305   dispatch = (GtkPrintCupsDispatchWatch *) g_source_new (&_cups_dispatch_watch_funcs,
1306                                                          sizeof (GtkPrintCupsDispatchWatch));
1307   g_source_set_name (&dispatch->source, "GTK+ CUPS backend");
1308
1309   GTK_NOTE (PRINTING,
1310             g_print ("CUPS Backend: %s <source %p> - Executing cups request on server '%s' and resource '%s'\n", G_STRFUNC, dispatch, request->server, request->resource));
1311
1312   dispatch->request = request;
1313   dispatch->backend = g_object_ref (print_backend);
1314   dispatch->poll_state = GTK_CUPS_HTTP_IDLE;
1315   dispatch->data_poll = NULL;
1316   dispatch->callback = NULL;
1317   dispatch->callback_data = NULL;
1318
1319   print_backend->requests = g_list_prepend (print_backend->requests, dispatch);
1320
1321   g_source_set_callback ((GSource *) dispatch, (GSourceFunc) callback, user_data, notify);
1322
1323   if (request->need_auth_info)
1324     {
1325       dispatch->callback = callback;
1326       dispatch->callback_data = user_data;
1327       request_auth_info (dispatch);
1328     }
1329   else
1330     {
1331       g_source_attach ((GSource *) dispatch, NULL);
1332       g_source_unref ((GSource *) dispatch);
1333     }
1334 }
1335
1336 #if 0
1337 static void
1338 cups_request_printer_info_cb (GtkPrintBackendCups *backend,
1339                               GtkCupsResult       *result,
1340                               gpointer             user_data)
1341 {
1342   ipp_attribute_t *attr;
1343   ipp_t *response;
1344   gchar *printer_name;
1345   GtkPrinterCups *cups_printer;
1346   GtkPrinter *printer;
1347   gchar *loc;
1348   gchar *desc;
1349   gchar *state_msg;
1350   int job_count;
1351   gboolean status_changed;
1352
1353   g_assert (GTK_IS_PRINT_BACKEND_CUPS (backend));
1354
1355   printer_name = (gchar *)user_data;
1356   printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (backend),
1357                                             printer_name);
1358
1359   GTK_NOTE (PRINTING,
1360             g_print ("CUPS Backend: %s - Got printer info for printer '%s'\n", G_STRFUNC, printer_name));
1361
1362   if (!printer)
1363     {
1364       GTK_NOTE (PRINTING,
1365             g_print ("CUPS Backend: Could not find printer called '%s'\n", printer_name));
1366       return;
1367     }
1368
1369   cups_printer = GTK_PRINTER_CUPS (printer);
1370
1371   if (gtk_cups_result_is_error (result))
1372     {
1373       if (gtk_printer_is_new (printer))
1374         {
1375           gtk_print_backend_remove_printer (GTK_PRINT_BACKEND (backend),
1376                                             printer);
1377           return;
1378         }
1379       else
1380         return; /* TODO: mark as inactive printer */
1381     }
1382
1383   response = gtk_cups_result_get_response (result);
1384
1385   /* TODO: determine printer type and use correct icon */
1386   gtk_printer_set_icon_name (printer, "printer");
1387
1388   state_msg = "";
1389   loc = "";
1390   desc = "";
1391   job_count = 0;
1392   for (attr = response->attrs; attr != NULL; attr = attr->next)
1393     {
1394       if (!attr->name)
1395         continue;
1396
1397       _CUPS_MAP_ATTR_STR (attr, loc, "printer-location");
1398       _CUPS_MAP_ATTR_STR (attr, desc, "printer-info");
1399       _CUPS_MAP_ATTR_STR (attr, state_msg, "printer-state-message");
1400       _CUPS_MAP_ATTR_INT (attr, cups_printer->state, "printer-state");
1401       _CUPS_MAP_ATTR_INT (attr, job_count, "queued-job-count");
1402     }
1403
1404   status_changed = gtk_printer_set_job_count (printer, job_count);
1405
1406   status_changed |= gtk_printer_set_location (printer, loc);
1407   status_changed |= gtk_printer_set_description (printer, desc);
1408   status_changed |= gtk_printer_set_state_message (printer, state_msg);
1409
1410   if (status_changed)
1411     g_signal_emit_by_name (GTK_PRINT_BACKEND (backend),
1412                            "printer-status-changed", printer);
1413 }
1414
1415 static void
1416 cups_request_printer_info (GtkPrintBackendCups *print_backend,
1417                            const gchar         *printer_name)
1418 {
1419   GtkCupsRequest *request;
1420   gchar *printer_uri;
1421   static const char * const pattrs[] =  /* Attributes we're interested in */
1422     {
1423       "printer-location",
1424       "printer-info",
1425       "printer-state-message",
1426       "printer-state",
1427       "queued-job-count",
1428       "job-sheets-supported",
1429       "job-sheets-default"
1430     };
1431
1432   request = gtk_cups_request_new_with_username (NULL,
1433                                                 GTK_CUPS_POST,
1434                                                 IPP_GET_PRINTER_ATTRIBUTES,
1435                                                 NULL,
1436                                                 NULL,
1437                                                 NULL,
1438                                                 print_backend->username);
1439
1440   printer_uri = g_strdup_printf ("ipp://localhost/printers/%s",
1441                                   printer_name);
1442   gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
1443                                    "printer-uri", NULL, printer_uri);
1444
1445   GTK_NOTE (PRINTING,
1446             g_print ("CUPS Backend: %s - Requesting printer info for URI '%s'\n", G_STRFUNC, printer_uri));
1447
1448   g_free (printer_uri);
1449
1450   gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1451                                     "requested-attributes", G_N_ELEMENTS (pattrs),
1452                                     NULL, pattrs);
1453
1454   cups_request_execute (print_backend,
1455                         request,
1456                         (GtkPrintCupsResponseCallbackFunc) cups_request_printer_info_cb,
1457                         g_strdup (printer_name),
1458                         (GDestroyNotify) g_free);
1459 }
1460 #endif
1461
1462 typedef struct {
1463   GtkPrintBackendCups *print_backend;
1464   GtkPrintJob *job;
1465   int job_id;
1466   int counter;
1467 } CupsJobPollData;
1468
1469 static void
1470 job_object_died (gpointer  user_data,
1471                  GObject  *where_the_object_was)
1472 {
1473   CupsJobPollData *data = user_data;
1474   data->job = NULL;
1475 }
1476
1477 static void
1478 cups_job_poll_data_free (CupsJobPollData *data)
1479 {
1480   if (data->job)
1481     g_object_weak_unref (G_OBJECT (data->job), job_object_died, data);
1482
1483   g_free (data);
1484 }
1485
1486 static void
1487 cups_request_job_info_cb (GtkPrintBackendCups *print_backend,
1488                           GtkCupsResult       *result,
1489                           gpointer             user_data)
1490 {
1491   CupsJobPollData *data = user_data;
1492   ipp_attribute_t *attr;
1493   ipp_t *response;
1494   int state;
1495   gboolean done;
1496
1497   gdk_threads_enter ();
1498
1499   if (data->job == NULL)
1500     {
1501       cups_job_poll_data_free (data);
1502       goto done;
1503     }
1504
1505   data->counter++;
1506
1507   response = gtk_cups_result_get_response (result);
1508
1509   state = 0;
1510
1511 #ifdef HAVE_CUPS_API_1_6
1512   attr = ippFindAttribute (response, "job-state", IPP_TAG_INTEGER);
1513   state = ippGetInteger (attr, 0);
1514 #else
1515   for (attr = response->attrs; attr != NULL; attr = attr->next)
1516     {
1517       if (!attr->name)
1518         continue;
1519
1520       _CUPS_MAP_ATTR_INT (attr, state, "job-state");
1521     }
1522 #endif
1523
1524   done = FALSE;
1525   switch (state)
1526     {
1527     case IPP_JOB_PENDING:
1528     case IPP_JOB_HELD:
1529     case IPP_JOB_STOPPED:
1530       gtk_print_job_set_status (data->job,
1531                                 GTK_PRINT_STATUS_PENDING);
1532       break;
1533     case IPP_JOB_PROCESSING:
1534       gtk_print_job_set_status (data->job,
1535                                 GTK_PRINT_STATUS_PRINTING);
1536       break;
1537     default:
1538     case IPP_JOB_CANCELLED:
1539     case IPP_JOB_ABORTED:
1540       gtk_print_job_set_status (data->job,
1541                                 GTK_PRINT_STATUS_FINISHED_ABORTED);
1542       done = TRUE;
1543       break;
1544     case 0:
1545     case IPP_JOB_COMPLETED:
1546       gtk_print_job_set_status (data->job,
1547                                 GTK_PRINT_STATUS_FINISHED);
1548       done = TRUE;
1549       break;
1550     }
1551
1552   if (!done && data->job != NULL)
1553     {
1554       guint32 timeout;
1555
1556       if (data->counter < 5)
1557         timeout = 100;
1558       else if (data->counter < 10)
1559         timeout = 500;
1560       else
1561         timeout = 1000;
1562
1563       g_timeout_add (timeout, cups_job_info_poll_timeout, data);
1564     }
1565   else
1566     cups_job_poll_data_free (data);
1567
1568 done:
1569   gdk_threads_leave ();
1570 }
1571
1572 static void
1573 cups_request_job_info (CupsJobPollData *data)
1574 {
1575   GtkCupsRequest *request;
1576   gchar *job_uri;
1577
1578   request = gtk_cups_request_new_with_username (NULL,
1579                                                 GTK_CUPS_POST,
1580                                                 IPP_GET_JOB_ATTRIBUTES,
1581                                                 NULL,
1582                                                 NULL,
1583                                                 NULL,
1584                                                 data->print_backend->username);
1585
1586   job_uri = g_strdup_printf ("ipp://localhost/jobs/%d", data->job_id);
1587   gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
1588                                    "job-uri", NULL, job_uri);
1589   g_free (job_uri);
1590
1591   cups_request_execute (data->print_backend,
1592                         request,
1593                         (GtkPrintCupsResponseCallbackFunc) cups_request_job_info_cb,
1594                         data,
1595                         NULL);
1596 }
1597
1598 static gboolean
1599 cups_job_info_poll_timeout (gpointer user_data)
1600 {
1601   CupsJobPollData *data = user_data;
1602
1603   if (data->job == NULL)
1604     cups_job_poll_data_free (data);
1605   else
1606     cups_request_job_info (data);
1607
1608   return G_SOURCE_REMOVE;
1609 }
1610
1611 static void
1612 cups_begin_polling_info (GtkPrintBackendCups *print_backend,
1613                          GtkPrintJob         *job,
1614                          gint                 job_id)
1615 {
1616   CupsJobPollData *data;
1617
1618   data = g_new0 (CupsJobPollData, 1);
1619
1620   data->print_backend = print_backend;
1621   data->job = job;
1622   data->job_id = job_id;
1623   data->counter = 0;
1624
1625   g_object_weak_ref (G_OBJECT (job), job_object_died, data);
1626
1627   cups_request_job_info (data);
1628 }
1629
1630 static void
1631 mark_printer_inactive (GtkPrinter      *printer,
1632                        GtkPrintBackend *backend)
1633 {
1634   gtk_printer_set_is_active (printer, FALSE);
1635   g_signal_emit_by_name (backend, "printer-removed", printer);
1636 }
1637
1638 static gint
1639 find_printer (GtkPrinter  *printer,
1640               const gchar *find_name)
1641 {
1642   const gchar *printer_name;
1643
1644   printer_name = gtk_printer_get_name (printer);
1645   return g_ascii_strcasecmp (printer_name, find_name);
1646 }
1647 /* Printer messages we're interested in */
1648 static const char * const printer_messages[] =
1649   {
1650     "toner-low",
1651     "toner-empty",
1652     "developer-low",
1653     "developer-empty",
1654     "marker-supply-low",
1655     "marker-supply-empty",
1656     "cover-open",
1657     "door-open",
1658     "media-low",
1659     "media-empty",
1660     "offline",
1661     "other"
1662   };
1663 /* Our translatable versions of the printer messages */
1664 static const char * printer_strings[] =
1665   {
1666     N_("Printer '%s' is low on toner."),
1667     N_("Printer '%s' has no toner left."),
1668     /* Translators: "Developer" like on photo development context */
1669     N_("Printer '%s' is low on developer."),
1670     /* Translators: "Developer" like on photo development context */
1671     N_("Printer '%s' is out of developer."),
1672     /* Translators: "marker" is one color bin of the printer */
1673     N_("Printer '%s' is low on at least one marker supply."),
1674     /* Translators: "marker" is one color bin of the printer */
1675     N_("Printer '%s' is out of at least one marker supply."),
1676     N_("The cover is open on printer '%s'."),
1677     N_("The door is open on printer '%s'."),
1678     N_("Printer '%s' is low on paper."),
1679     N_("Printer '%s' is out of paper."),
1680     N_("Printer '%s' is currently offline."),
1681     N_("There is a problem on printer '%s'.")
1682   };
1683
1684 typedef enum
1685   {
1686     GTK_PRINTER_STATE_LEVEL_NONE = 0,
1687     GTK_PRINTER_STATE_LEVEL_INFO = 1,
1688     GTK_PRINTER_STATE_LEVEL_WARNING = 2,
1689     GTK_PRINTER_STATE_LEVEL_ERROR = 3
1690   } PrinterStateLevel;
1691
1692 typedef struct
1693 {
1694   const gchar *printer_name;
1695   const gchar *printer_uri;
1696   const gchar *member_uris;
1697   const gchar *location;
1698   const gchar *description;
1699   gchar *state_msg;
1700   const gchar *reason_msg;
1701   PrinterStateLevel reason_level;
1702   gint state;
1703   gint job_count;
1704   gboolean is_paused;
1705   gboolean is_accepting_jobs;
1706   const gchar *default_cover_before;
1707   const gchar *default_cover_after;
1708   gboolean default_printer;
1709   gboolean got_printer_type;
1710   gboolean remote_printer;
1711   gchar  **auth_info_required;
1712   gint     default_number_up;
1713 } PrinterSetupInfo;
1714
1715 static void
1716 cups_printer_handle_attribute (GtkPrintBackendCups *cups_backend,
1717                                ipp_attribute_t *attr,
1718                                PrinterSetupInfo *info)
1719 {
1720   gint i, j;
1721   if (strcmp (ippGetName (attr), "printer-name") == 0 &&
1722       ippGetValueTag (attr) == IPP_TAG_NAME)
1723     info->printer_name = ippGetString (attr, 0, NULL);
1724   else if (strcmp (ippGetName (attr), "printer-uri-supported") == 0 &&
1725            ippGetValueTag (attr) == IPP_TAG_URI)
1726     info->printer_uri = ippGetString (attr, 0, NULL);
1727   else if (strcmp (ippGetName (attr), "member-uris") == 0 &&
1728            ippGetValueTag (attr) == IPP_TAG_URI)
1729     info->member_uris = ippGetString (attr, 0, NULL);
1730   else if (strcmp (ippGetName (attr), "printer-location") == 0)
1731     info->location = ippGetString (attr, 0, NULL);
1732   else if (strcmp (ippGetName (attr), "printer-info") == 0)
1733     info->description = ippGetString (attr, 0, NULL);
1734   else if (strcmp (ippGetName (attr), "printer-state-message") == 0)
1735     info->state_msg = g_strdup (ippGetString (attr, 0, NULL));
1736   else if (strcmp (ippGetName (attr), "printer-state-reasons") == 0)
1737     /* Store most important reason to reason_msg and set
1738        its importance at printer_state_reason_level */
1739     {
1740       for (i = 0; i < ippGetCount (attr); i++)
1741         {
1742           if (strcmp (ippGetString (attr, i, NULL), "none") != 0)
1743             {
1744               gboolean interested_in = FALSE;
1745               /* Sets is_paused flag for paused printer. */
1746               if (strcmp (ippGetString (attr, i, NULL), "paused") == 0)
1747                 {
1748                   info->is_paused = TRUE;
1749                 }
1750
1751               for (j = 0; j < G_N_ELEMENTS (printer_messages); j++)
1752                 if (strncmp (ippGetString (attr, i, NULL), printer_messages[j],
1753                              strlen (printer_messages[j])) == 0)
1754                   {
1755                     interested_in = TRUE;
1756                     break;
1757                   }
1758
1759               if (interested_in)
1760                 {
1761                   if (g_str_has_suffix (ippGetString (attr, i, NULL), "-report"))
1762                     {
1763                       if (info->reason_level <= GTK_PRINTER_STATE_LEVEL_INFO)
1764                         {
1765                           info->reason_msg = ippGetString (attr, i, NULL);
1766                           info->reason_level = GTK_PRINTER_STATE_LEVEL_INFO;
1767                         }
1768                     }
1769                   else if (g_str_has_suffix (ippGetString (attr, i, NULL), "-warning"))
1770                     {
1771                       if (info->reason_level <= GTK_PRINTER_STATE_LEVEL_WARNING)
1772                         {
1773                           info->reason_msg = ippGetString (attr, i, NULL);
1774                           info->reason_level = GTK_PRINTER_STATE_LEVEL_WARNING;
1775                         }
1776                     }
1777                   else  /* It is error in the case of no suffix. */
1778                     {
1779                       info->reason_msg = ippGetString (attr, i, NULL);
1780                       info->reason_level = GTK_PRINTER_STATE_LEVEL_ERROR;
1781                     }
1782                 }
1783             }
1784         }
1785     }
1786   else if (strcmp (ippGetName (attr), "printer-state") == 0)
1787     info->state = ippGetInteger (attr, 0);
1788   else if (strcmp (ippGetName (attr), "queued-job-count") == 0)
1789     info->job_count = ippGetInteger (attr, 0);
1790   else if (strcmp (ippGetName (attr), "printer-is-accepting-jobs") == 0)
1791     {
1792       if (ippGetBoolean (attr, 0) == 1)
1793         info->is_accepting_jobs = TRUE;
1794       else
1795         info->is_accepting_jobs = FALSE;
1796     }
1797   else if (strcmp (ippGetName (attr), "job-sheets-supported") == 0)
1798     {
1799       if (cups_backend->covers == NULL)
1800         {
1801           cups_backend->number_of_covers = ippGetCount (attr);
1802           cups_backend->covers = g_new (char *, cups_backend->number_of_covers + 1);
1803           for (i = 0; i < cups_backend->number_of_covers; i++)
1804             cups_backend->covers[i] = g_strdup (ippGetString (attr, i, NULL));
1805           cups_backend->covers[cups_backend->number_of_covers] = NULL;
1806         }
1807     }
1808   else if (strcmp (ippGetName (attr), "job-sheets-default") == 0)
1809     {
1810       if (ippGetCount (attr) == 2)
1811         {
1812           info->default_cover_before = ippGetString (attr, 0, NULL);
1813           info->default_cover_after = ippGetString (attr, 1, NULL);
1814         }
1815     }
1816   else if (strcmp (ippGetName (attr), "printer-type") == 0)
1817     {
1818       info->got_printer_type = TRUE;
1819       if (ippGetInteger (attr, 0) & 0x00020000)
1820         info->default_printer = TRUE;
1821       else
1822         info->default_printer = FALSE;
1823
1824       if (ippGetInteger (attr, 0) & 0x00000002)
1825         info->remote_printer = TRUE;
1826       else
1827         info->remote_printer = FALSE;
1828     }
1829   else if (strcmp (ippGetName (attr), "auth-info-required") == 0)
1830     {
1831       if (strcmp (ippGetString (attr, 0, NULL), "none") != 0)
1832         {
1833           info->auth_info_required = g_new0 (gchar *, ippGetCount (attr) + 1);
1834           for (i = 0; i < ippGetCount (attr); i++)
1835             info->auth_info_required[i] = g_strdup (ippGetString (attr, i, NULL));
1836         }
1837     }
1838   else if (strcmp (ippGetName (attr), "number-up-default") == 0)
1839     {
1840       info->default_number_up = ippGetInteger (attr, 0);
1841     }
1842   else
1843     {
1844       GTK_NOTE (PRINTING,
1845                 g_print ("CUPS Backend: Attribute %s ignored", ippGetName (attr)));
1846     }
1847 }
1848
1849 static GtkPrinter*
1850 cups_create_printer (GtkPrintBackendCups *cups_backend,
1851                      PrinterSetupInfo *info)
1852 {
1853   GtkPrinterCups *cups_printer;
1854   GtkPrinter *printer;
1855   GtkPrintBackend *backend = GTK_PRINT_BACKEND (cups_backend);
1856   char uri[HTTP_MAX_URI];       /* Printer URI */
1857   char method[HTTP_MAX_URI];    /* Method/scheme name */
1858   char username[HTTP_MAX_URI];  /* Username:password */
1859   char hostname[HTTP_MAX_URI];  /* Hostname */
1860   char resource[HTTP_MAX_URI];  /* Resource name */
1861   int  port;                    /* Port number */
1862   char *cups_server;            /* CUPS server */
1863
1864 #ifdef HAVE_COLORD
1865   cups_printer = gtk_printer_cups_new (info->printer_name,
1866                                        backend,
1867                                        cups_backend->colord_client);
1868 #else
1869   cups_printer = gtk_printer_cups_new (info->printer_name, backend, NULL);
1870 #endif
1871
1872   cups_printer->device_uri = g_strdup_printf ("/printers/%s",
1873                                               info->printer_name);
1874
1875   /* Check to see if we are looking at a class */
1876   if (info->member_uris)
1877     {
1878       cups_printer->printer_uri = g_strdup (info->member_uris);
1879       /* TODO if member_uris is a class we need to recursivly find a printer */
1880       GTK_NOTE (PRINTING,
1881                 g_print ("CUPS Backend: Found class with printer %s\n",
1882                          info->member_uris));
1883     }
1884   else
1885     {
1886       cups_printer->printer_uri = g_strdup (info->printer_uri);
1887       GTK_NOTE (PRINTING,
1888                 g_print ("CUPS Backend: Found printer %s\n",
1889                          info->printer_uri));
1890     }
1891
1892   httpSeparateURI (HTTP_URI_CODING_ALL, cups_printer->printer_uri,
1893                    method, sizeof (method),
1894                    username, sizeof (username),
1895                    hostname, sizeof (hostname),
1896                    &port,
1897                    resource, sizeof (resource));
1898
1899   if (strncmp (resource, "/printers/", 10) == 0)
1900     {
1901       cups_printer->ppd_name = g_strdup (resource + 10);
1902       GTK_NOTE (PRINTING,
1903                 g_print ("CUPS Backend: Setting ppd name '%s' for printer/class '%s'\n", cups_printer->ppd_name, info->printer_name));
1904     }
1905
1906   gethostname (uri, sizeof (uri));
1907   cups_server = g_strdup (cupsServer());
1908
1909   if (strcasecmp (uri, hostname) == 0)
1910     strcpy (hostname, "localhost");
1911
1912   /* if the cups server is local and listening at a unix domain socket
1913    * then use the socket connection
1914    */
1915   if ((strstr (hostname, "localhost") != NULL) &&
1916       (cups_server[0] == '/'))
1917     strcpy (hostname, cups_server);
1918
1919   g_free (cups_server);
1920
1921   cups_printer->default_cover_before = g_strdup (info->default_cover_before);
1922   cups_printer->default_cover_after = g_strdup (info->default_cover_after);
1923
1924   cups_printer->default_number_up = info->default_number_up;
1925
1926   cups_printer->hostname = g_strdup (hostname);
1927   cups_printer->port = port;
1928
1929   cups_printer->auth_info_required = g_strdupv (info->auth_info_required);
1930   g_strfreev (info->auth_info_required);
1931
1932   printer = GTK_PRINTER (cups_printer);
1933
1934   if (cups_backend->default_printer != NULL &&
1935       strcmp (cups_backend->default_printer, gtk_printer_get_name (printer)) == 0)
1936     gtk_printer_set_is_default (printer, TRUE);
1937
1938
1939   gtk_print_backend_add_printer (backend, printer);
1940   return printer;
1941 }
1942
1943
1944 static void
1945 cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
1946                               GtkCupsResult       *result,
1947                               gpointer             user_data)
1948 {
1949   GtkPrintBackend *backend = GTK_PRINT_BACKEND (cups_backend);
1950   ipp_attribute_t *attr;
1951   ipp_t *response;
1952   gboolean list_has_changed;
1953   GList *removed_printer_checklist;
1954   gchar *remote_default_printer = NULL;
1955
1956   gdk_threads_enter ();
1957
1958   list_has_changed = FALSE;
1959
1960   GTK_NOTE (PRINTING,
1961             g_print ("CUPS Backend: %s\n", G_STRFUNC));
1962
1963   cups_backend->list_printers_pending = FALSE;
1964
1965   if (gtk_cups_result_is_error (result))
1966     {
1967       GTK_NOTE (PRINTING,
1968                 g_warning ("CUPS Backend: Error getting printer list: %s %d %d",
1969                            gtk_cups_result_get_error_string (result),
1970                            gtk_cups_result_get_error_type (result),
1971                            gtk_cups_result_get_error_code (result)));
1972
1973       if (gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_AUTH &&
1974           gtk_cups_result_get_error_code (result) == 1)
1975         {
1976           /* Canceled by user, stop popping up more password dialogs */
1977           if (cups_backend->list_printers_poll > 0)
1978             g_source_remove (cups_backend->list_printers_poll);
1979           cups_backend->list_printers_poll = 0;
1980           cups_backend->list_printers_attempts = 0;
1981         }
1982
1983       goto done;
1984     }
1985
1986   /* Gather the names of the printers in the current queue
1987    * so we may check to see if they were removed
1988    */
1989   removed_printer_checklist = gtk_print_backend_get_printer_list (backend);
1990
1991   response = gtk_cups_result_get_response (result);
1992 #ifdef HAVE_CUPS_API_1_6
1993   for (attr = ippFirstAttribute (response); attr != NULL;
1994        attr = ippNextAttribute (response))
1995     {
1996       GtkPrinter *printer;
1997       gboolean status_changed = FALSE;
1998       GList *node;
1999       gint i;
2000       PrinterSetupInfo *info = g_slice_new0 (PrinterSetupInfo);
2001
2002       /* Skip leading attributes until we hit a printer...
2003        */
2004       while (attr != NULL && ippGetGroupTag (attr) != IPP_TAG_PRINTER)
2005         attr = ippNextAttribute (response);
2006
2007       if (attr == NULL)
2008         break;
2009       while (attr != NULL && ippGetGroupTag (attr) == IPP_TAG_PRINTER)
2010       {
2011         cups_printer_handle_attribute (cups_backend, attr, info);
2012         attr = ippNextAttribute (response);
2013       }
2014 #else
2015   for (attr = response->attrs; attr != NULL; attr = attr->next)
2016     {
2017       GtkPrinter *printer;
2018       gboolean status_changed = FALSE;
2019       GList *node;
2020       gint i;
2021       PrinterSetupInfo *info = g_slice_new0 (PrinterSetupInfo);
2022       info->default_number_up = 1;
2023
2024       /* Skip leading attributes until we hit a printer...
2025        */
2026       while (attr != NULL && ippGetGroupTag (attr) != IPP_TAG_PRINTER)
2027         attr = attr->next;
2028
2029       if (attr == NULL)
2030         break;
2031       while (attr != NULL && ippGetGroupTag (attr) == IPP_TAG_PRINTER)
2032       {
2033         cups_printer_handle_attribute (cups_backend, attr, info);
2034         attr = attr->next;
2035       }
2036 #endif
2037
2038       if (info->printer_name == NULL ||
2039           (info->printer_uri == NULL && info->member_uris == NULL))
2040       {
2041         if (attr == NULL)
2042           break;
2043         else
2044           continue;
2045       }
2046
2047       if (info->got_printer_type)
2048         {
2049           if (info->default_printer && !cups_backend->got_default_printer)
2050             {
2051               if (!info->remote_printer)
2052                 {
2053                   cups_backend->got_default_printer = TRUE;
2054                   cups_backend->default_printer = g_strdup (info->printer_name);
2055                 }
2056               else
2057                 {
2058                   if (remote_default_printer == NULL)
2059                     remote_default_printer = g_strdup (info->printer_name);
2060                 }
2061             }
2062         }
2063       else
2064         {
2065           if (!cups_backend->got_default_printer)
2066             cups_get_default_printer (cups_backend);
2067         }
2068
2069       /* remove name from checklist if it was found */
2070       if (removed_printer_checklist != NULL)
2071       {
2072            if (node = g_list_find_custom (removed_printer_checklist,
2073                                           info->printer_name,
2074                                           (GCompareFunc) find_printer))
2075                 removed_printer_checklist =
2076                      g_list_delete_link (removed_printer_checklist,
2077                                          node);
2078       }
2079
2080       printer = gtk_print_backend_find_printer (backend, info->printer_name);
2081       if (!printer)
2082         {
2083           printer = cups_create_printer (cups_backend, info);
2084           list_has_changed = TRUE;
2085         }
2086
2087       else
2088         g_object_ref (printer);
2089
2090       GTK_PRINTER_CUPS (printer)->remote = info->remote_printer;
2091
2092       gtk_printer_set_is_paused (printer, info->is_paused);
2093       gtk_printer_set_is_accepting_jobs (printer, info->is_accepting_jobs);
2094
2095       if (!gtk_printer_is_active (printer))
2096         {
2097           gtk_printer_set_is_active (printer, TRUE);
2098           gtk_printer_set_is_new (printer, TRUE);
2099           list_has_changed = TRUE;
2100         }
2101
2102       if (gtk_printer_is_new (printer))
2103         {
2104           g_signal_emit_by_name (backend, "printer-added", printer);
2105
2106           gtk_printer_set_is_new (printer, FALSE);
2107         }
2108
2109 #if 0
2110       /* Getting printer info with separate requests overwhelms cups
2111        * when the printer list has more than a handful of printers.
2112        */
2113       cups_request_printer_info (cups_backend, gtk_printer_get_name (printer));
2114 #endif
2115
2116       GTK_PRINTER_CUPS (printer)->state = info->state;
2117       status_changed = gtk_printer_set_job_count (printer, info->job_count);
2118       status_changed |= gtk_printer_set_location (printer, info->location);
2119       status_changed |= gtk_printer_set_description (printer,
2120                                                      info->description);
2121
2122       if (info->state_msg != NULL && strlen (info->state_msg) == 0)
2123         {
2124           gchar *tmp_msg2 = NULL;
2125           if (info->is_paused && !info->is_accepting_jobs)
2126             /* Translators: this is a printer status. */
2127             tmp_msg2 = g_strdup ( N_("Paused ; Rejecting Jobs"));
2128           if (info->is_paused && info->is_accepting_jobs)
2129             /* Translators: this is a printer status. */
2130             tmp_msg2 = g_strdup ( N_("Paused"));
2131           if (!info->is_paused && !info->is_accepting_jobs)
2132             /* Translators: this is a printer status. */
2133             tmp_msg2 = g_strdup ( N_("Rejecting Jobs"));
2134
2135           if (tmp_msg2 != NULL)
2136             {
2137               g_free (info->state_msg);
2138               info->state_msg = tmp_msg2;
2139             }
2140         }
2141
2142       /* Set description of the reason and combine it with printer-state-message. */
2143       if ( (info->reason_msg != NULL))
2144         {
2145           gchar *reason_msg_desc = NULL;
2146           gboolean found = FALSE;
2147
2148           for (i = 0; i < G_N_ELEMENTS (printer_messages); i++)
2149             {
2150               if (strncmp (info->reason_msg, printer_messages[i],
2151                            strlen (printer_messages[i])) == 0)
2152                 {
2153                   reason_msg_desc = g_strdup_printf (printer_strings[i],
2154                                                      info->printer_name);
2155                   found = TRUE;
2156                   break;
2157                 }
2158             }
2159
2160           if (!found)
2161             info->reason_level = GTK_PRINTER_STATE_LEVEL_NONE;
2162
2163           if (info->reason_level >= GTK_PRINTER_STATE_LEVEL_WARNING)
2164             {
2165               if (strlen (info->state_msg) == 0)
2166                 {
2167                   g_free (info->state_msg);
2168                   info->state_msg = reason_msg_desc;
2169                   reason_msg_desc = NULL;
2170                 }
2171               else
2172                 {
2173                   gchar *tmp_msg = NULL;
2174                   tmp_msg = g_strjoin (" ; ", info->state_msg,
2175                                        reason_msg_desc, NULL);
2176                   g_free (info->state_msg);
2177                   info->state_msg = tmp_msg;
2178                 }
2179             }
2180           if (reason_msg_desc != NULL)
2181             g_free (reason_msg_desc);
2182         }
2183
2184       status_changed |= gtk_printer_set_state_message (printer, info->state_msg);
2185       status_changed |= gtk_printer_set_is_accepting_jobs (printer, info->is_accepting_jobs);
2186
2187
2188
2189       /* Set printer icon according to importance
2190          (none, report, warning, error - report is omitted). */
2191       if (info->reason_level == GTK_PRINTER_STATE_LEVEL_ERROR)
2192         gtk_printer_set_icon_name (printer, "printer-error");
2193       else if (info->reason_level == GTK_PRINTER_STATE_LEVEL_WARNING)
2194         gtk_printer_set_icon_name (printer, "printer-warning");
2195       else if (gtk_printer_is_paused (printer))
2196         gtk_printer_set_icon_name (printer, "printer-paused");
2197       else
2198         gtk_printer_set_icon_name (printer, "printer");
2199
2200       if (status_changed)
2201         g_signal_emit_by_name (GTK_PRINT_BACKEND (backend),
2202                                "printer-status-changed", printer);
2203
2204       /* The ref is held by GtkPrintBackend, in add_printer() */
2205       g_object_unref (printer);
2206       g_free (info->state_msg);
2207       g_slice_free (PrinterSetupInfo, info);
2208
2209       if (attr == NULL)
2210         break;
2211     }
2212
2213   /* look at the removed printers checklist and mark any printer
2214      as inactive if it is in the list, emitting a printer_removed signal */
2215   if (removed_printer_checklist != NULL)
2216     {
2217       g_list_foreach (removed_printer_checklist, (GFunc) mark_printer_inactive, backend);
2218       g_list_free (removed_printer_checklist);
2219       list_has_changed = TRUE;
2220     }
2221
2222 done:
2223   if (list_has_changed)
2224     g_signal_emit_by_name (backend, "printer-list-changed");
2225
2226   gtk_print_backend_set_list_done (backend);
2227
2228   if (!cups_backend->got_default_printer && remote_default_printer != NULL)
2229     {
2230       cups_backend->default_printer = g_strdup (remote_default_printer);
2231       cups_backend->got_default_printer = TRUE;
2232       g_free (remote_default_printer);
2233
2234       if (cups_backend->default_printer != NULL)
2235         {
2236           GtkPrinter *default_printer = NULL;
2237           default_printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (cups_backend),
2238                                                             cups_backend->default_printer);
2239           if (default_printer != NULL)
2240             {
2241               gtk_printer_set_is_default (default_printer, TRUE);
2242               g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend),
2243                                      "printer-status-changed", default_printer);
2244             }
2245         }
2246     }
2247
2248   gdk_threads_leave ();
2249 }
2250
2251 static void
2252 update_backend_status (GtkPrintBackendCups    *cups_backend,
2253                        GtkCupsConnectionState  state)
2254 {
2255   switch (state)
2256     {
2257     case GTK_CUPS_CONNECTION_NOT_AVAILABLE:
2258       g_object_set (cups_backend, "status", GTK_PRINT_BACKEND_STATUS_UNAVAILABLE, NULL);
2259       break;
2260     case GTK_CUPS_CONNECTION_AVAILABLE:
2261       g_object_set (cups_backend, "status", GTK_PRINT_BACKEND_STATUS_OK, NULL);
2262       break;
2263     default: ;
2264     }
2265 }
2266
2267 static gboolean
2268 cups_request_printer_list (GtkPrintBackendCups *cups_backend)
2269 {
2270   GtkCupsConnectionState state;
2271   GtkCupsRequest *request;
2272   static const char * const pattrs[] =  /* Attributes we're interested in */
2273     {
2274       "printer-name",
2275       "printer-uri-supported",
2276       "member-uris",
2277       "printer-location",
2278       "printer-info",
2279       "printer-state-message",
2280       "printer-state-reasons",
2281       "printer-state",
2282       "queued-job-count",
2283       "printer-is-accepting-jobs",
2284       "job-sheets-supported",
2285       "job-sheets-default",
2286       "printer-type",
2287       "auth-info-required",
2288       "number-up-default"
2289     };
2290
2291   if (cups_backend->reading_ppds > 0 || cups_backend->list_printers_pending)
2292     return TRUE;
2293
2294   state = gtk_cups_connection_test_get_state (cups_backend->cups_connection_test);
2295   update_backend_status (cups_backend, state);
2296
2297   if (cups_backend->list_printers_attempts == 60)
2298     {
2299       cups_backend->list_printers_attempts = -1;
2300       if (cups_backend->list_printers_poll > 0)
2301         g_source_remove (cups_backend->list_printers_poll);
2302       cups_backend->list_printers_poll = gdk_threads_add_timeout (200,
2303                                            (GSourceFunc) cups_request_printer_list,
2304                                            cups_backend);
2305     }
2306   else if (cups_backend->list_printers_attempts != -1)
2307     cups_backend->list_printers_attempts++;
2308
2309   if (state == GTK_CUPS_CONNECTION_IN_PROGRESS || state == GTK_CUPS_CONNECTION_NOT_AVAILABLE)
2310     return TRUE;
2311   else
2312     if (cups_backend->list_printers_attempts > 0)
2313       cups_backend->list_printers_attempts = 60;
2314
2315   cups_backend->list_printers_pending = TRUE;
2316
2317   request = gtk_cups_request_new_with_username (NULL,
2318                                                 GTK_CUPS_POST,
2319                                                 CUPS_GET_PRINTERS,
2320                                                 NULL,
2321                                                 NULL,
2322                                                 NULL,
2323                                                 cups_backend->username);
2324
2325   gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2326                                     "requested-attributes", G_N_ELEMENTS (pattrs),
2327                                     NULL, pattrs);
2328
2329   cups_request_execute (cups_backend,
2330                         request,
2331                         (GtkPrintCupsResponseCallbackFunc) cups_request_printer_list_cb,
2332                         request,
2333                         NULL);
2334
2335   return TRUE;
2336 }
2337
2338 static void
2339 cups_get_printer_list (GtkPrintBackend *backend)
2340 {
2341   GtkPrintBackendCups *cups_backend;
2342
2343   cups_backend = GTK_PRINT_BACKEND_CUPS (backend);
2344
2345   if (cups_backend->cups_connection_test == NULL)
2346     cups_backend->cups_connection_test = gtk_cups_connection_test_new (NULL);
2347
2348   if (cups_backend->list_printers_poll == 0)
2349     {
2350       if (cups_request_printer_list (cups_backend))
2351         cups_backend->list_printers_poll = gdk_threads_add_timeout (50,
2352                                              (GSourceFunc) cups_request_printer_list,
2353                                              backend);
2354     }
2355 }
2356
2357 typedef struct {
2358   GtkPrinterCups *printer;
2359   GIOChannel *ppd_io;
2360   http_t *http;
2361 } GetPPDData;
2362
2363 static void
2364 get_ppd_data_free (GetPPDData *data)
2365 {
2366   GTK_NOTE (PRINTING,
2367             g_print ("CUPS Backend: %s\n", G_STRFUNC));
2368   httpClose (data->http);
2369   g_io_channel_unref (data->ppd_io);
2370   g_object_unref (data->printer);
2371   g_free (data);
2372 }
2373
2374 static void
2375 cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
2376                      GtkCupsResult       *result,
2377                      GetPPDData          *data)
2378 {
2379   GtkPrinter *printer;
2380
2381   gdk_threads_enter ();
2382
2383   GTK_NOTE (PRINTING,
2384             g_print ("CUPS Backend: %s\n", G_STRFUNC));
2385
2386   printer = GTK_PRINTER (data->printer);
2387   GTK_PRINTER_CUPS (printer)->reading_ppd = FALSE;
2388   print_backend->reading_ppds--;
2389
2390   if (gtk_cups_result_is_error (result))
2391     {
2392       gboolean success = FALSE;
2393
2394       /* if we get a 404 then it is just a raw printer without a ppd
2395          and not an error */
2396       if ((gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_HTTP) &&
2397           (gtk_cups_result_get_error_status (result) == HTTP_NOT_FOUND))
2398         {
2399           gtk_printer_set_has_details (printer, TRUE);
2400           success = TRUE;
2401         }
2402
2403       g_signal_emit_by_name (printer, "details-acquired", success);
2404       goto done;
2405     }
2406
2407   /* let ppdOpenFd take over the ownership of the open file */
2408   g_io_channel_seek_position (data->ppd_io, 0, G_SEEK_SET, NULL);
2409   data->printer->ppd_file = ppdOpenFd (dup (g_io_channel_unix_get_fd (data->ppd_io)));
2410   ppdLocalize (data->printer->ppd_file);
2411   ppdMarkDefaults (data->printer->ppd_file);
2412
2413   gtk_printer_set_has_details (printer, TRUE);
2414   g_signal_emit_by_name (printer, "details-acquired", TRUE);
2415
2416 done:
2417   gdk_threads_leave ();
2418 }
2419
2420 static gboolean
2421 cups_request_ppd (GtkPrinter *printer)
2422 {
2423   GError *error;
2424   GtkPrintBackend *print_backend;
2425   GtkPrinterCups *cups_printer;
2426   GtkCupsRequest *request;
2427   char *ppd_filename;
2428   gchar *resource;
2429   http_t *http;
2430   GetPPDData *data;
2431   int fd;
2432
2433   cups_printer = GTK_PRINTER_CUPS (printer);
2434
2435   error = NULL;
2436
2437   GTK_NOTE (PRINTING,
2438             g_print ("CUPS Backend: %s\n", G_STRFUNC));
2439
2440   if (cups_printer->remote)
2441     {
2442       GtkCupsConnectionState state;
2443
2444       state = gtk_cups_connection_test_get_state (cups_printer->remote_cups_connection_test);
2445
2446       if (state == GTK_CUPS_CONNECTION_IN_PROGRESS)
2447         {
2448           if (cups_printer->get_remote_ppd_attempts == 60)
2449             {
2450               cups_printer->get_remote_ppd_attempts = -1;
2451               if (cups_printer->get_remote_ppd_poll > 0)
2452                 g_source_remove (cups_printer->get_remote_ppd_poll);
2453               cups_printer->get_remote_ppd_poll = gdk_threads_add_timeout (200,
2454                                                     (GSourceFunc) cups_request_ppd,
2455                                                     printer);
2456             }
2457           else if (cups_printer->get_remote_ppd_attempts != -1)
2458             cups_printer->get_remote_ppd_attempts++;
2459
2460           return TRUE;
2461         }
2462
2463       gtk_cups_connection_test_free (cups_printer->remote_cups_connection_test);
2464       cups_printer->remote_cups_connection_test = NULL;
2465       cups_printer->get_remote_ppd_poll = 0;
2466       cups_printer->get_remote_ppd_attempts = 0;
2467
2468       if (state == GTK_CUPS_CONNECTION_NOT_AVAILABLE)
2469         {
2470           g_signal_emit_by_name (printer, "details-acquired", FALSE);
2471           return FALSE;
2472         }
2473     }
2474
2475   http = httpConnectEncrypt (cups_printer->hostname,
2476                              cups_printer->port,
2477                              cupsEncryption ());
2478
2479   data = g_new0 (GetPPDData, 1);
2480
2481   fd = g_file_open_tmp ("gtkprint_ppd_XXXXXX",
2482                         &ppd_filename,
2483                         &error);
2484
2485 #ifdef G_ENABLE_DEBUG
2486   /* If we are debugging printing don't delete the tmp files */
2487   if (!(gtk_get_debug_flags () & GTK_DEBUG_PRINTING))
2488     unlink (ppd_filename);
2489 #else
2490   unlink (ppd_filename);
2491 #endif /* G_ENABLE_DEBUG */
2492
2493   if (error != NULL)
2494     {
2495       GTK_NOTE (PRINTING,
2496                 g_warning ("CUPS Backend: Failed to create temp file, %s\n",
2497                            error->message));
2498       g_error_free (error);
2499       httpClose (http);
2500       g_free (ppd_filename);
2501       g_free (data);
2502
2503       g_signal_emit_by_name (printer, "details-acquired", FALSE);
2504       return FALSE;
2505     }
2506
2507   data->http = http;
2508   fchmod (fd, S_IRUSR | S_IWUSR);
2509   data->ppd_io = g_io_channel_unix_new (fd);
2510   g_io_channel_set_encoding (data->ppd_io, NULL, NULL);
2511   g_io_channel_set_close_on_unref (data->ppd_io, TRUE);
2512
2513   data->printer = g_object_ref (printer);
2514
2515   resource = g_strdup_printf ("/printers/%s.ppd",
2516                               gtk_printer_cups_get_ppd_name (GTK_PRINTER_CUPS (printer)));
2517
2518   print_backend = gtk_printer_get_backend (printer);
2519
2520   request = gtk_cups_request_new_with_username (data->http,
2521                                                 GTK_CUPS_GET,
2522                                                 0,
2523                                                 data->ppd_io,
2524                                                 cups_printer->hostname,
2525                                                 resource,
2526                                                 GTK_PRINT_BACKEND_CUPS (print_backend)->username);
2527
2528   GTK_NOTE (PRINTING,
2529             g_print ("CUPS Backend: Requesting resource %s to be written to temp file %s\n", resource, ppd_filename));
2530
2531
2532   cups_printer->reading_ppd = TRUE;
2533   GTK_PRINT_BACKEND_CUPS (print_backend)->reading_ppds++;
2534
2535   cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
2536                         request,
2537                         (GtkPrintCupsResponseCallbackFunc) cups_request_ppd_cb,
2538                         data,
2539                         (GDestroyNotify)get_ppd_data_free);
2540
2541   g_free (resource);
2542   g_free (ppd_filename);
2543
2544   return FALSE;
2545 }
2546
2547 /* Ordering matters for default preference */
2548 static const char *lpoptions_locations[] = {
2549   "/etc/cups/lpoptions",
2550   ".lpoptions",
2551   ".cups/lpoptions"
2552 };
2553
2554 static void
2555 cups_parse_user_default_printer (const char  *filename,
2556                                  char       **printer_name)
2557 {
2558   FILE *fp;
2559   char line[1024], *lineptr, *defname = NULL;
2560
2561   if ((fp = g_fopen (filename, "r")) == NULL)
2562     return;
2563
2564   while (fgets (line, sizeof (line), fp) != NULL)
2565     {
2566       if (strncasecmp (line, "default", 7) != 0 || !isspace (line[7]))
2567         continue;
2568
2569       lineptr = line + 8;
2570       while (isspace (*lineptr))
2571         lineptr++;
2572
2573       if (!*lineptr)
2574         continue;
2575
2576       defname = lineptr;
2577       while (!isspace (*lineptr) && *lineptr && *lineptr != '/')
2578         lineptr++;
2579
2580       *lineptr = '\0';
2581
2582       if (*printer_name != NULL)
2583         g_free (*printer_name);
2584
2585       *printer_name = g_strdup (defname);
2586     }
2587
2588   fclose (fp);
2589 }
2590
2591 static void
2592 cups_get_user_default_printer (char **printer_name)
2593 {
2594   int i;
2595
2596   for (i = 0; i < G_N_ELEMENTS (lpoptions_locations); i++)
2597     {
2598       if (g_path_is_absolute (lpoptions_locations[i]))
2599         {
2600           cups_parse_user_default_printer (lpoptions_locations[i],
2601                                            printer_name);
2602         }
2603       else
2604         {
2605           char *filename;
2606
2607           filename = g_build_filename (g_get_home_dir (),
2608                                        lpoptions_locations[i], NULL);
2609           cups_parse_user_default_printer (filename, printer_name);
2610           g_free (filename);
2611         }
2612     }
2613 }
2614
2615 static int
2616 cups_parse_user_options (const char     *filename,
2617                          const char     *printer_name,
2618                          int             num_options,
2619                          cups_option_t **options)
2620 {
2621   FILE *fp;
2622   gchar line[1024], *lineptr, *name;
2623
2624   if ((fp = g_fopen (filename, "r")) == NULL)
2625     return num_options;
2626
2627   while (fgets (line, sizeof (line), fp) != NULL)
2628     {
2629       if (strncasecmp (line, "dest", 4) == 0 && isspace (line[4]))
2630         lineptr = line + 4;
2631       else if (strncasecmp (line, "default", 7) == 0 && isspace (line[7]))
2632         lineptr = line + 7;
2633       else
2634         continue;
2635
2636       /* Skip leading whitespace */
2637       while (isspace (*lineptr))
2638         lineptr++;
2639
2640       if (!*lineptr)
2641         continue;
2642
2643       /* NUL-terminate the name, stripping the instance name */
2644       name = lineptr;
2645       while (!isspace (*lineptr) && *lineptr)
2646         {
2647           if (*lineptr == '/')
2648             *lineptr = '\0';
2649           lineptr++;
2650         }
2651
2652       if (!*lineptr)
2653         continue;
2654
2655       *lineptr++ = '\0';
2656
2657       if (strncasecmp (name, printer_name, strlen (printer_name)) != 0)
2658           continue;
2659
2660       /* We found our printer, parse the options */
2661       num_options = cupsParseOptions (lineptr, num_options, options);
2662     }
2663
2664   fclose (fp);
2665
2666   return num_options;
2667 }
2668
2669 static int
2670 cups_get_user_options (const char     *printer_name,
2671                        int             num_options,
2672                        cups_option_t **options)
2673 {
2674   int i;
2675
2676   for (i = 0; i < G_N_ELEMENTS (lpoptions_locations); i++)
2677     {
2678       if (g_path_is_absolute (lpoptions_locations[i]))
2679         {
2680            num_options = cups_parse_user_options (lpoptions_locations[i],
2681                                                   printer_name,
2682                                                   num_options,
2683                                                   options);
2684         }
2685       else
2686         {
2687           char *filename;
2688
2689           filename = g_build_filename (g_get_home_dir (),
2690                                        lpoptions_locations[i], NULL);
2691           num_options = cups_parse_user_options (filename, printer_name,
2692                                                  num_options, options);
2693           g_free (filename);
2694         }
2695     }
2696
2697   return num_options;
2698 }
2699
2700 /* This function requests default printer from a CUPS server in regular intervals.
2701  * In the case of unreachable CUPS server the request is repeated later.
2702  * The default printer is not requested in the case of previous success.
2703  */
2704 static void
2705 cups_get_default_printer (GtkPrintBackendCups *backend)
2706 {
2707   GtkPrintBackendCups *cups_backend;
2708
2709   cups_backend = backend;
2710
2711   if (cups_backend->cups_connection_test == NULL)
2712     cups_backend->cups_connection_test = gtk_cups_connection_test_new (NULL);
2713
2714   if (cups_backend->default_printer_poll == 0)
2715     {
2716       if (cups_request_default_printer (cups_backend))
2717         cups_backend->default_printer_poll = gdk_threads_add_timeout (200,
2718                                                (GSourceFunc) cups_request_default_printer,
2719                                                backend);
2720     }
2721 }
2722
2723 /* This function gets default printer from local settings.*/
2724 static void
2725 cups_get_local_default_printer (GtkPrintBackendCups *backend)
2726 {
2727   const char *str;
2728   char *name = NULL;
2729
2730   if ((str = g_getenv ("LPDEST")) != NULL)
2731     {
2732       backend->default_printer = g_strdup (str);
2733       backend->got_default_printer = TRUE;
2734       return;
2735     }
2736   else if ((str = g_getenv ("PRINTER")) != NULL &&
2737            strcmp (str, "lp") != 0)
2738     {
2739       backend->default_printer = g_strdup (str);
2740       backend->got_default_printer = TRUE;
2741       return;
2742     }
2743
2744   /* Figure out user setting for default printer */
2745   cups_get_user_default_printer (&name);
2746   if (name != NULL)
2747     {
2748       backend->default_printer = name;
2749       backend->got_default_printer = TRUE;
2750       return;
2751     }
2752 }
2753
2754 static void
2755 cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
2756                                  GtkCupsResult       *result,
2757                                  gpointer             user_data)
2758 {
2759   ipp_t *response;
2760   ipp_attribute_t *attr;
2761   GtkPrinter *printer;
2762
2763   gdk_threads_enter ();
2764
2765   if (gtk_cups_result_is_error (result))
2766     {
2767       if (gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_AUTH &&
2768           gtk_cups_result_get_error_code (result) == 1)
2769         {
2770           /* Canceled by user, stop popping up more password dialogs */
2771           if (print_backend->list_printers_poll > 0)
2772             g_source_remove (print_backend->list_printers_poll);
2773           print_backend->list_printers_poll = 0;
2774         }
2775
2776       return;
2777     }
2778
2779   response = gtk_cups_result_get_response (result);
2780
2781   if ((attr = ippFindAttribute (response, "printer-name", IPP_TAG_NAME)) != NULL)
2782       print_backend->default_printer = g_strdup (ippGetString (attr, 0, NULL));
2783
2784   print_backend->got_default_printer = TRUE;
2785
2786   if (print_backend->default_printer != NULL)
2787     {
2788       printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (print_backend), print_backend->default_printer);
2789       if (printer != NULL)
2790         {
2791           gtk_printer_set_is_default (printer, TRUE);
2792           g_signal_emit_by_name (GTK_PRINT_BACKEND (print_backend), "printer-status-changed", printer);
2793         }
2794     }
2795
2796   /* Make sure to kick off get_printers if we are polling it,
2797    * as we could have blocked this reading the default printer
2798    */
2799   if (print_backend->list_printers_poll != 0)
2800     cups_request_printer_list (print_backend);
2801
2802   gdk_threads_leave ();
2803 }
2804
2805 static gboolean
2806 cups_request_default_printer (GtkPrintBackendCups *print_backend)
2807 {
2808   GtkCupsConnectionState state;
2809   GtkCupsRequest *request;
2810
2811   state = gtk_cups_connection_test_get_state (print_backend->cups_connection_test);
2812   update_backend_status (print_backend, state);
2813
2814   if (state == GTK_CUPS_CONNECTION_IN_PROGRESS || state == GTK_CUPS_CONNECTION_NOT_AVAILABLE)
2815     return TRUE;
2816
2817   request = gtk_cups_request_new_with_username (NULL,
2818                                                 GTK_CUPS_POST,
2819                                                 CUPS_GET_DEFAULT,
2820                                                 NULL,
2821                                                 NULL,
2822                                                 NULL,
2823                                                 print_backend->username);
2824
2825   cups_request_execute (print_backend,
2826                         request,
2827                         (GtkPrintCupsResponseCallbackFunc) cups_request_default_printer_cb,
2828                         g_object_ref (print_backend),
2829                         g_object_unref);
2830
2831   return FALSE;
2832 }
2833
2834 static void
2835 cups_printer_request_details (GtkPrinter *printer)
2836 {
2837   GtkPrinterCups *cups_printer;
2838
2839   cups_printer = GTK_PRINTER_CUPS (printer);
2840   if (!cups_printer->reading_ppd &&
2841       gtk_printer_cups_get_ppd (cups_printer) == NULL)
2842     {
2843       if (cups_printer->remote)
2844         {
2845           if (cups_printer->get_remote_ppd_poll == 0)
2846             {
2847               cups_printer->remote_cups_connection_test = gtk_cups_connection_test_new (cups_printer->hostname);
2848
2849               if (cups_request_ppd (printer))
2850                 cups_printer->get_remote_ppd_poll = gdk_threads_add_timeout (50,
2851                                                     (GSourceFunc) cups_request_ppd,
2852                                                     printer);
2853             }
2854         }
2855       else
2856         cups_request_ppd (printer);
2857     }
2858 }
2859
2860 static char *
2861 ppd_text_to_utf8 (ppd_file_t *ppd_file,
2862                   const char *text)
2863 {
2864   const char *encoding = NULL;
2865   char *res;
2866
2867   if (g_ascii_strcasecmp (ppd_file->lang_encoding, "UTF-8") == 0)
2868     {
2869       return g_strdup (text);
2870     }
2871   else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin1") == 0)
2872     {
2873       encoding = "ISO-8859-1";
2874     }
2875   else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin2") == 0)
2876     {
2877       encoding = "ISO-8859-2";
2878     }
2879   else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin5") == 0)
2880     {
2881       encoding = "ISO-8859-5";
2882     }
2883   else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "JIS83-RKSJ") == 0)
2884     {
2885       encoding = "SHIFT-JIS";
2886     }
2887   else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "MacStandard") == 0)
2888     {
2889       encoding = "MACINTOSH";
2890     }
2891   else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "WindowsANSI") == 0)
2892     {
2893       encoding = "WINDOWS-1252";
2894     }
2895   else
2896     {
2897       /* Fallback, try iso-8859-1... */
2898       encoding = "ISO-8859-1";
2899     }
2900
2901   res = g_convert (text, -1, "UTF-8", encoding, NULL, NULL, NULL);
2902
2903   if (res == NULL)
2904     {
2905       GTK_NOTE (PRINTING,
2906                 g_warning ("CUPS Backend: Unable to convert PPD text\n"));
2907       res = g_strdup ("???");
2908     }
2909
2910   return res;
2911 }
2912
2913 /* TODO: Add more translations for common settings here */
2914
2915 static const struct {
2916   const char *keyword;
2917   const char *translation;
2918 } cups_option_translations[] = {
2919   { "Duplex", N_("Two Sided") },
2920   { "MediaType", N_("Paper Type") },
2921   { "InputSlot", N_("Paper Source") },
2922   { "OutputBin", N_("Output Tray") },
2923   { "Resolution", N_("Resolution") },
2924   { "PreFilter", N_("GhostScript pre-filtering") },
2925 };
2926
2927
2928 static const struct {
2929   const char *keyword;
2930   const char *choice;
2931   const char *translation;
2932 } cups_choice_translations[] = {
2933   { "Duplex", "None", N_("One Sided") },
2934   /* Translators: this is an option of "Two Sided" */
2935   { "Duplex", "DuplexNoTumble", N_("Long Edge (Standard)") },
2936   /* Translators: this is an option of "Two Sided" */
2937   { "Duplex", "DuplexTumble", N_("Short Edge (Flip)") },
2938   /* Translators: this is an option of "Paper Source" */
2939   { "InputSlot", "Auto", N_("Auto Select") },
2940   /* Translators: this is an option of "Paper Source" */
2941   { "InputSlot", "AutoSelect", N_("Auto Select") },
2942   /* Translators: this is an option of "Paper Source" */
2943   { "InputSlot", "Default", N_("Printer Default") },
2944   /* Translators: this is an option of "Paper Source" */
2945   { "InputSlot", "None", N_("Printer Default") },
2946   /* Translators: this is an option of "Paper Source" */
2947   { "InputSlot", "PrinterDefault", N_("Printer Default") },
2948   /* Translators: this is an option of "Paper Source" */
2949   { "InputSlot", "Unspecified", N_("Auto Select") },
2950   /* Translators: this is an option of "Resolution" */
2951   { "Resolution", "default", N_("Printer Default") },
2952   /* Translators: this is an option of "GhostScript" */
2953   { "PreFilter", "EmbedFonts", N_("Embed GhostScript fonts only") },
2954   /* Translators: this is an option of "GhostScript" */
2955   { "PreFilter", "Level1", N_("Convert to PS level 1") },
2956   /* Translators: this is an option of "GhostScript" */
2957   { "PreFilter", "Level2", N_("Convert to PS level 2") },
2958   /* Translators: this is an option of "GhostScript" */
2959   { "PreFilter", "No", N_("No pre-filtering") },
2960 };
2961
2962 static const struct {
2963   const char *name;
2964   const char *translation;
2965 } cups_group_translations[] = {
2966 /* Translators: "Miscellaneous" is the label for a button, that opens
2967    up an extra panel of settings in a print dialog. */
2968   { "Miscellaneous", N_("Miscellaneous") },
2969 };
2970
2971 static const struct {
2972   const char *ppd_keyword;
2973   const char *name;
2974 } ppd_option_names[] = {
2975   {"Duplex", "gtk-duplex" },
2976   {"MediaType", "gtk-paper-type"},
2977   {"InputSlot", "gtk-paper-source"},
2978   {"OutputBin", "gtk-output-tray"},
2979 };
2980
2981 static const struct {
2982   const char *lpoption;
2983   const char *name;
2984 } lpoption_names[] = {
2985   {"number-up", "gtk-n-up" },
2986   {"number-up-layout", "gtk-n-up-layout"},
2987   {"job-billing", "gtk-billing-info"},
2988   {"job-priority", "gtk-job-prio"},
2989 };
2990
2991 /* keep sorted when changing */
2992 static const char *color_option_whitelist[] = {
2993   "BRColorEnhancement",
2994   "BRColorMatching",
2995   "BRColorMatching",
2996   "BRColorMode",
2997   "BRGammaValue",
2998   "BRImprovedGray",
2999   "BlackSubstitution",
3000   "ColorModel",
3001   "HPCMYKInks",
3002   "HPCSGraphics",
3003   "HPCSImages",
3004   "HPCSText",
3005   "HPColorSmart",
3006   "RPSBlackMode",
3007   "RPSBlackOverPrint",
3008   "Rcmyksimulation",
3009 };
3010
3011 /* keep sorted when changing */
3012 static const char *color_group_whitelist[] = {
3013   "ColorPage",
3014   "FPColorWise1",
3015   "FPColorWise2",
3016   "FPColorWise3",
3017   "FPColorWise4",
3018   "FPColorWise5",
3019   "HPColorOptionsPanel",
3020 };
3021
3022 /* keep sorted when changing */
3023 static const char *image_quality_option_whitelist[] = {
3024   "BRDocument",
3025   "BRHalfTonePattern",
3026   "BRNormalPrt",
3027   "BRPrintQuality",
3028   "BitsPerPixel",
3029   "Darkness",
3030   "Dithering",
3031   "EconoMode",
3032   "Economode",
3033   "HPEconoMode",
3034   "HPEdgeControl",
3035   "HPGraphicsHalftone",
3036   "HPHalftone",
3037   "HPLJDensity",
3038   "HPPhotoHalftone",
3039   "OutputMode",
3040   "REt",
3041   "RPSBitsPerPixel",
3042   "RPSDitherType",
3043   "Resolution",
3044   "ScreenLock",
3045   "Smoothing",
3046   "TonerSaveMode",
3047   "UCRGCRForImage",
3048 };
3049
3050 /* keep sorted when changing */
3051 static const char *image_quality_group_whitelist[] = {
3052   "FPImageQuality1",
3053   "FPImageQuality2",
3054   "FPImageQuality3",
3055   "ImageQualityPage",
3056 };
3057
3058 /* keep sorted when changing */
3059 static const char * finishing_option_whitelist[] = {
3060   "BindColor",
3061   "BindEdge",
3062   "BindType",
3063   "BindWhen",
3064   "Booklet",
3065   "FoldType",
3066   "FoldWhen",
3067   "HPStaplerOptions",
3068   "Jog",
3069   "Slipsheet",
3070   "Sorter",
3071   "StapleLocation",
3072   "StapleOrientation",
3073   "StapleWhen",
3074   "StapleX",
3075   "StapleY",
3076 };
3077
3078 /* keep sorted when changing */
3079 static const char *finishing_group_whitelist[] = {
3080   "FPFinishing1",
3081   "FPFinishing2",
3082   "FPFinishing3",
3083   "FPFinishing4",
3084   "FinishingPage",
3085   "HPFinishingPanel",
3086 };
3087
3088 /* keep sorted when changing */
3089 static const char *cups_option_blacklist[] = {
3090   "Collate",
3091   "Copies",
3092   "OutputOrder",
3093   "PageRegion",
3094   "PageSize",
3095 };
3096
3097 static char *
3098 get_option_text (ppd_file_t   *ppd_file,
3099                  ppd_option_t *option)
3100 {
3101   int i;
3102   char *utf8;
3103
3104   for (i = 0; i < G_N_ELEMENTS (cups_option_translations); i++)
3105     {
3106       if (strcmp (cups_option_translations[i].keyword, option->keyword) == 0)
3107         return g_strdup (_(cups_option_translations[i].translation));
3108     }
3109
3110   utf8 = ppd_text_to_utf8 (ppd_file, option->text);
3111
3112   /* Some ppd files have spaces in the text before the colon */
3113   g_strchomp (utf8);
3114
3115   return utf8;
3116 }
3117
3118 static char *
3119 get_choice_text (ppd_file_t   *ppd_file,
3120                  ppd_choice_t *choice)
3121 {
3122   int i;
3123   ppd_option_t *option = choice->option;
3124   const char *keyword = option->keyword;
3125
3126   for (i = 0; i < G_N_ELEMENTS (cups_choice_translations); i++)
3127     {
3128       if (strcmp (cups_choice_translations[i].keyword, keyword) == 0 &&
3129           strcmp (cups_choice_translations[i].choice, choice->choice) == 0)
3130         return g_strdup (_(cups_choice_translations[i].translation));
3131     }
3132   return ppd_text_to_utf8 (ppd_file, choice->text);
3133 }
3134
3135 static gboolean
3136 group_has_option (ppd_group_t  *group,
3137                   ppd_option_t *option)
3138 {
3139   int i;
3140
3141   if (group == NULL)
3142     return FALSE;
3143
3144   if (group->num_options > 0 &&
3145       option >= group->options && option < group->options + group->num_options)
3146     return TRUE;
3147
3148   for (i = 0; i < group->num_subgroups; i++)
3149     {
3150       if (group_has_option (&group->subgroups[i],option))
3151         return TRUE;
3152     }
3153   return FALSE;
3154 }
3155
3156 static void
3157 set_option_off (GtkPrinterOption *option)
3158 {
3159   /* Any of these will do, _set only applies the value
3160    * if its allowed of the option */
3161   gtk_printer_option_set (option, "False");
3162   gtk_printer_option_set (option, "Off");
3163   gtk_printer_option_set (option, "None");
3164 }
3165
3166 static gboolean
3167 value_is_off (const char *value)
3168 {
3169   return  (strcasecmp (value, "None") == 0 ||
3170            strcasecmp (value, "Off") == 0 ||
3171            strcasecmp (value, "False") == 0);
3172 }
3173
3174 static char *
3175 ppd_group_name (ppd_group_t *group)
3176 {
3177   return group->name;
3178 }
3179
3180 static int
3181 available_choices (ppd_file_t     *ppd,
3182                    ppd_option_t   *option,
3183                    ppd_choice_t ***available,
3184                    gboolean        keep_if_only_one_option)
3185 {
3186   ppd_option_t *other_option;
3187   int i, j;
3188   gchar *conflicts;
3189   ppd_const_t *constraint;
3190   const char *choice, *other_choice;
3191   ppd_option_t *option1, *option2;
3192   ppd_group_t *installed_options;
3193   int num_conflicts;
3194   gboolean all_default;
3195   int add_auto;
3196
3197   if (available)
3198     *available = NULL;
3199
3200   conflicts = g_new0 (char, option->num_choices);
3201
3202   installed_options = NULL;
3203   for (i = 0; i < ppd->num_groups; i++)
3204     {
3205       char *name;
3206
3207       name = ppd_group_name (&ppd->groups[i]);
3208       if (strcmp (name, "InstallableOptions") == 0)
3209         {
3210           installed_options = &ppd->groups[i];
3211           break;
3212         }
3213     }
3214
3215   for (i = ppd->num_consts, constraint = ppd->consts; i > 0; i--, constraint++)
3216     {
3217       option1 = ppdFindOption (ppd, constraint->option1);
3218       if (option1 == NULL)
3219         continue;
3220
3221       option2 = ppdFindOption (ppd, constraint->option2);
3222       if (option2 == NULL)
3223         continue;
3224
3225       if (option == option1)
3226         {
3227           choice = constraint->choice1;
3228           other_option = option2;
3229           other_choice = constraint->choice2;
3230         }
3231       else if (option == option2)
3232         {
3233           choice = constraint->choice2;
3234           other_option = option1;
3235           other_choice = constraint->choice1;
3236         }
3237       else
3238         continue;
3239
3240       /* We only care of conflicts with installed_options and
3241          PageSize */
3242       if (!group_has_option (installed_options, other_option) &&
3243           (strcmp (other_option->keyword, "PageSize") != 0))
3244         continue;
3245
3246       if (*other_choice == 0)
3247         {
3248           /* Conflict only if the installed option is not off */
3249           if (value_is_off (other_option->defchoice))
3250             continue;
3251         }
3252       /* Conflict if the installed option has the specified default */
3253       else if (strcasecmp (other_choice, other_option->defchoice) != 0)
3254         continue;
3255
3256       if (*choice == 0)
3257         {
3258           /* Conflict with all non-off choices */
3259           for (j = 0; j < option->num_choices; j++)
3260             {
3261               if (!value_is_off (option->choices[j].choice))
3262                 conflicts[j] = 1;
3263             }
3264         }
3265       else
3266         {
3267           for (j = 0; j < option->num_choices; j++)
3268             {
3269               if (strcasecmp (option->choices[j].choice, choice) == 0)
3270                 conflicts[j] = 1;
3271             }
3272         }
3273     }
3274
3275   num_conflicts = 0;
3276   all_default = TRUE;
3277   for (j = 0; j < option->num_choices; j++)
3278     {
3279       if (conflicts[j])
3280         num_conflicts++;
3281       else if (strcmp (option->choices[j].choice, option->defchoice) != 0)
3282         all_default = FALSE;
3283     }
3284
3285   if ((all_default && !keep_if_only_one_option) ||
3286       (num_conflicts == option->num_choices))
3287     {
3288       g_free (conflicts);
3289
3290       return 0;
3291     }
3292
3293   /* Some ppds don't have a "use printer default" option for
3294    * InputSlot. This means you always have to select a particular slot,
3295    * and you can't auto-pick source based on the paper size. To support
3296    * this we always add an auto option if there isn't one already. If
3297    * the user chooses the generated option we don't send any InputSlot
3298    * value when printing. The way we detect existing auto-cases is based
3299    * on feedback from Michael Sweet of cups fame.
3300    */
3301   add_auto = 0;
3302   if (strcmp (option->keyword, "InputSlot") == 0)
3303     {
3304       gboolean found_auto = FALSE;
3305       for (j = 0; j < option->num_choices; j++)
3306         {
3307           if (!conflicts[j])
3308             {
3309               if (strcmp (option->choices[j].choice, "Auto") == 0 ||
3310                   strcmp (option->choices[j].choice, "AutoSelect") == 0 ||
3311                   strcmp (option->choices[j].choice, "Default") == 0 ||
3312                   strcmp (option->choices[j].choice, "None") == 0 ||
3313                   strcmp (option->choices[j].choice, "PrinterDefault") == 0 ||
3314                   strcmp (option->choices[j].choice, "Unspecified") == 0 ||
3315                   option->choices[j].code == NULL ||
3316                   option->choices[j].code[0] == 0)
3317                 {
3318                   found_auto = TRUE;
3319                   break;
3320                 }
3321             }
3322         }
3323
3324       if (!found_auto)
3325         add_auto = 1;
3326     }
3327
3328   if (available)
3329     {
3330       *available = g_new (ppd_choice_t *, option->num_choices - num_conflicts + add_auto);
3331
3332       i = 0;
3333       for (j = 0; j < option->num_choices; j++)
3334         {
3335           if (!conflicts[j])
3336             (*available)[i++] = &option->choices[j];
3337         }
3338
3339       if (add_auto)
3340         (*available)[i++] = NULL;
3341     }
3342
3343   g_free (conflicts);
3344
3345   return option->num_choices - num_conflicts + add_auto;
3346 }
3347
3348 static GtkPrinterOption *
3349 create_pickone_option (ppd_file_t   *ppd_file,
3350                        ppd_option_t *ppd_option,
3351                        const gchar  *gtk_name)
3352 {
3353   GtkPrinterOption *option;
3354   ppd_choice_t **available;
3355   char *label;
3356   int n_choices;
3357   int i;
3358   ppd_coption_t *coption;
3359
3360   g_assert (ppd_option->ui == PPD_UI_PICKONE);
3361
3362   option = NULL;
3363
3364   n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
3365   if (n_choices > 0)
3366     {
3367
3368       /* right now only support one parameter per custom option
3369        * if more than one print warning and only offer the default choices
3370        */
3371
3372       label = get_option_text (ppd_file, ppd_option);
3373
3374       coption = ppdFindCustomOption (ppd_file, ppd_option->keyword);
3375
3376       if (coption)
3377         {
3378           ppd_cparam_t *cparam;
3379
3380           cparam = ppdFirstCustomParam (coption);
3381
3382           if (ppdNextCustomParam (coption) == NULL)
3383             {
3384               switch (cparam->type)
3385                 {
3386                 case PPD_CUSTOM_INT:
3387                   option = gtk_printer_option_new (gtk_name, label,
3388                                          GTK_PRINTER_OPTION_TYPE_PICKONE_INT);
3389                   break;
3390                 case PPD_CUSTOM_PASSCODE:
3391                   option = gtk_printer_option_new (gtk_name, label,
3392                                          GTK_PRINTER_OPTION_TYPE_PICKONE_PASSCODE);
3393                   break;
3394                 case PPD_CUSTOM_PASSWORD:
3395                     option = gtk_printer_option_new (gtk_name, label,
3396                                          GTK_PRINTER_OPTION_TYPE_PICKONE_PASSWORD);
3397                   break;
3398                case PPD_CUSTOM_REAL:
3399                     option = gtk_printer_option_new (gtk_name, label,
3400                                          GTK_PRINTER_OPTION_TYPE_PICKONE_REAL);
3401                   break;
3402                 case PPD_CUSTOM_STRING:
3403                   option = gtk_printer_option_new (gtk_name, label,
3404                                          GTK_PRINTER_OPTION_TYPE_PICKONE_STRING);
3405                   break;
3406 #ifdef PRINT_IGNORED_OPTIONS
3407                 case PPD_CUSTOM_POINTS:
3408                   g_warning ("CUPS Backend: PPD Custom Points Option not supported");
3409                   break;
3410                 case PPD_CUSTOM_CURVE:
3411                   g_warning ("CUPS Backend: PPD Custom Curve Option not supported");
3412                   break;
3413                 case PPD_CUSTOM_INVCURVE:
3414                   g_warning ("CUPS Backend: PPD Custom Inverse Curve Option not supported");
3415                   break;
3416 #endif
3417                 default:
3418                   break;
3419                 }
3420             }
3421 #ifdef PRINT_IGNORED_OPTIONS
3422           else
3423             g_warning ("CUPS Backend: Multi-parameter PPD Custom Option not supported");
3424 #endif
3425         }
3426
3427       if (!option)
3428         option = gtk_printer_option_new (gtk_name, label,
3429                                          GTK_PRINTER_OPTION_TYPE_PICKONE);
3430       g_free (label);
3431
3432       gtk_printer_option_allocate_choices (option, n_choices);
3433       for (i = 0; i < n_choices; i++)
3434         {
3435           if (available[i] == NULL)
3436             {
3437               /* This was auto-added */
3438               option->choices[i] = g_strdup ("gtk-ignore-value");
3439               option->choices_display[i] = g_strdup (_("Printer Default"));
3440             }
3441           else
3442             {
3443               option->choices[i] = g_strdup (available[i]->choice);
3444               option->choices_display[i] = get_choice_text (ppd_file, available[i]);
3445             }
3446         }
3447
3448       if (option->type != GTK_PRINTER_OPTION_TYPE_PICKONE)
3449         {
3450           if (g_str_has_prefix (ppd_option->defchoice, "Custom."))
3451             gtk_printer_option_set (option, ppd_option->defchoice + 7);
3452           else
3453             gtk_printer_option_set (option, ppd_option->defchoice);
3454         }
3455       else
3456         {
3457           gtk_printer_option_set (option, ppd_option->defchoice);
3458         }
3459     }
3460 #ifdef PRINT_IGNORED_OPTIONS
3461   else
3462     g_warning ("CUPS Backend: Ignoring pickone %s\n", ppd_option->text);
3463 #endif
3464   g_free (available);
3465
3466   return option;
3467 }
3468
3469 static GtkPrinterOption *
3470 create_boolean_option (ppd_file_t   *ppd_file,
3471                        ppd_option_t *ppd_option,
3472                        const gchar  *gtk_name)
3473 {
3474   GtkPrinterOption *option;
3475   ppd_choice_t **available;
3476   char *label;
3477   int n_choices;
3478
3479   g_assert (ppd_option->ui == PPD_UI_BOOLEAN);
3480
3481   option = NULL;
3482
3483   n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
3484   if (n_choices == 2)
3485     {
3486       label = get_option_text (ppd_file, ppd_option);
3487       option = gtk_printer_option_new (gtk_name, label,
3488                                        GTK_PRINTER_OPTION_TYPE_BOOLEAN);
3489       g_free (label);
3490
3491       gtk_printer_option_allocate_choices (option, 2);
3492       option->choices[0] = g_strdup ("True");
3493       option->choices_display[0] = g_strdup ("True");
3494       option->choices[1] = g_strdup ("False");
3495       option->choices_display[1] = g_strdup ("False");
3496
3497       gtk_printer_option_set (option, ppd_option->defchoice);
3498     }
3499 #ifdef PRINT_IGNORED_OPTIONS
3500   else
3501     g_warning ("CUPS Backend: Ignoring boolean %s\n", ppd_option->text);
3502 #endif
3503   g_free (available);
3504
3505   return option;
3506 }
3507
3508 static gchar *
3509 get_ppd_option_name (const gchar *keyword)
3510 {
3511   int i;
3512
3513   for (i = 0; i < G_N_ELEMENTS (ppd_option_names); i++)
3514     if (strcmp (ppd_option_names[i].ppd_keyword, keyword) == 0)
3515       return g_strdup (ppd_option_names[i].name);
3516
3517   return g_strdup_printf ("cups-%s", keyword);
3518 }
3519
3520 static gchar *
3521 get_lpoption_name (const gchar *lpoption)
3522 {
3523   int i;
3524
3525   for (i = 0; i < G_N_ELEMENTS (ppd_option_names); i++)
3526     if (strcmp (ppd_option_names[i].ppd_keyword, lpoption) == 0)
3527       return g_strdup (ppd_option_names[i].name);
3528
3529   for (i = 0; i < G_N_ELEMENTS (lpoption_names); i++)
3530     if (strcmp (lpoption_names[i].lpoption, lpoption) == 0)
3531       return g_strdup (lpoption_names[i].name);
3532
3533   return g_strdup_printf ("cups-%s", lpoption);
3534 }
3535
3536 static int
3537 strptr_cmp (const void *a,
3538             const void *b)
3539 {
3540   char **aa = (char **)a;
3541   char **bb = (char **)b;
3542   return strcmp (*aa, *bb);
3543 }
3544
3545
3546 static gboolean
3547 string_in_table (gchar       *str,
3548                  const gchar *table[],
3549                  gint         table_len)
3550 {
3551   return bsearch (&str, table, table_len, sizeof (char *), (void *)strptr_cmp) != NULL;
3552 }
3553
3554 #define STRING_IN_TABLE(_str, _table) (string_in_table (_str, _table, G_N_ELEMENTS (_table)))
3555
3556 static void
3557 handle_option (GtkPrinterOptionSet *set,
3558                ppd_file_t          *ppd_file,
3559                ppd_option_t        *ppd_option,
3560                ppd_group_t         *toplevel_group,
3561                GtkPrintSettings    *settings)
3562 {
3563   GtkPrinterOption *option;
3564   char *name;
3565   int i;
3566
3567   if (STRING_IN_TABLE (ppd_option->keyword, cups_option_blacklist))
3568     return;
3569
3570   name = get_ppd_option_name (ppd_option->keyword);
3571
3572   option = NULL;
3573   if (ppd_option->ui == PPD_UI_PICKONE)
3574     {
3575       option = create_pickone_option (ppd_file, ppd_option, name);
3576     }
3577   else if (ppd_option->ui == PPD_UI_BOOLEAN)
3578     {
3579       option = create_boolean_option (ppd_file, ppd_option, name);
3580     }
3581 #ifdef PRINT_IGNORED_OPTIONS
3582   else
3583     g_warning ("CUPS Backend: Ignoring pickmany setting %s\n", ppd_option->text);
3584 #endif
3585
3586   if (option)
3587     {
3588       char *name;
3589
3590       name = ppd_group_name (toplevel_group);
3591       if (STRING_IN_TABLE (name,
3592                            color_group_whitelist) ||
3593           STRING_IN_TABLE (ppd_option->keyword,
3594                            color_option_whitelist))
3595         {
3596           option->group = g_strdup ("ColorPage");
3597         }
3598       else if (STRING_IN_TABLE (name,
3599                                 image_quality_group_whitelist) ||
3600                STRING_IN_TABLE (ppd_option->keyword,
3601                                 image_quality_option_whitelist))
3602         {
3603           option->group = g_strdup ("ImageQualityPage");
3604         }
3605       else if (STRING_IN_TABLE (name,
3606                                 finishing_group_whitelist) ||
3607                STRING_IN_TABLE (ppd_option->keyword,
3608                                 finishing_option_whitelist))
3609         {
3610           option->group = g_strdup ("FinishingPage");
3611         }
3612       else
3613         {
3614           for (i = 0; i < G_N_ELEMENTS (cups_group_translations); i++)
3615             {
3616               if (strcmp (cups_group_translations[i].name, toplevel_group->name) == 0)
3617                 {
3618                   option->group = g_strdup (_(cups_group_translations[i].translation));
3619                   break;
3620                 }
3621             }
3622
3623           if (i == G_N_ELEMENTS (cups_group_translations))
3624             option->group = g_strdup (toplevel_group->text);
3625         }
3626
3627       set_option_from_settings (option, settings);
3628
3629       gtk_printer_option_set_add (set, option);
3630     }
3631
3632   g_free (name);
3633 }
3634
3635 static void
3636 handle_group (GtkPrinterOptionSet *set,
3637               ppd_file_t          *ppd_file,
3638               ppd_group_t         *group,
3639               ppd_group_t         *toplevel_group,
3640               GtkPrintSettings    *settings)
3641 {
3642   gint i;
3643   gchar *name;
3644
3645   /* Ignore installable options */
3646   name = ppd_group_name (toplevel_group);
3647   if (strcmp (name, "InstallableOptions") == 0)
3648     return;
3649
3650   for (i = 0; i < group->num_options; i++)
3651     handle_option (set, ppd_file, &group->options[i], toplevel_group, settings);
3652
3653   for (i = 0; i < group->num_subgroups; i++)
3654     handle_group (set, ppd_file, &group->subgroups[i], toplevel_group, settings);
3655
3656 }
3657
3658 #ifdef HAVE_COLORD
3659
3660 typedef struct {
3661         GtkPrintSettings     *settings;
3662         GtkPrinter           *printer;
3663 } GtkPrintBackendCupsColordHelper;
3664
3665 static void
3666 colord_printer_option_set_changed_cb (GtkPrinterOptionSet *set,
3667                                       GtkPrintBackendCupsColordHelper *helper)
3668 {
3669   gtk_printer_cups_update_settings (GTK_PRINTER_CUPS (helper->printer),
3670                                     helper->settings,
3671                                     set);
3672 }
3673 #endif
3674
3675 static GtkPrinterOptionSet *
3676 cups_printer_get_options (GtkPrinter           *printer,
3677                           GtkPrintSettings     *settings,
3678                           GtkPageSetup         *page_setup,
3679                           GtkPrintCapabilities  capabilities)
3680 {
3681   GtkPrinterOptionSet *set;
3682   GtkPrinterOption *option;
3683   ppd_file_t *ppd_file;
3684   int i;
3685   char *print_at[] = { "now", "at", "on-hold" };
3686   char *n_up[] = {"1", "2", "4", "6", "9", "16" };
3687   char *prio[] = {"100", "80", "50", "30" };
3688   /* Translators: These strings name the possible values of the
3689    * job priority option in the print dialog
3690    */
3691   char *prio_display[] = {N_("Urgent"), N_("High"), N_("Medium"), N_("Low") };
3692   char *n_up_layout[] = { "lrtb", "lrbt", "rltb", "rlbt", "tblr", "tbrl", "btlr", "btrl" };
3693   /* Translators: These strings name the possible arrangements of
3694    * multiple pages on a sheet when printing
3695    */
3696   char *n_up_layout_display[] = { N_("Left to right, top to bottom"), N_("Left to right, bottom to top"),
3697                                   N_("Right to left, top to bottom"), N_("Right to left, bottom to top"),
3698                                   N_("Top to bottom, left to right"), N_("Top to bottom, right to left"),
3699                                   N_("Bottom to top, left to right"), N_("Bottom to top, right to left") };
3700   char *name;
3701   int num_opts;
3702   cups_option_t *opts = NULL;
3703   GtkPrintBackendCups *backend;
3704   GtkTextDirection text_direction;
3705   GtkPrinterCups *cups_printer = NULL;
3706 #ifdef HAVE_COLORD
3707   GtkPrintBackendCupsColordHelper *helper;
3708 #endif
3709   char *default_number_up;
3710
3711   set = gtk_printer_option_set_new ();
3712
3713   /* Cups specific, non-ppd related settings */
3714
3715   for (i = 0; i < G_N_ELEMENTS(prio_display); i++)
3716     prio_display[i] = _(prio_display[i]);
3717
3718   /* Translators, this string is used to label the job priority option
3719    * in the print dialog
3720    */
3721   option = gtk_printer_option_new ("gtk-job-prio", _("Job Priority"), GTK_PRINTER_OPTION_TYPE_PICKONE);
3722   gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (prio),
3723                                          prio, prio_display);
3724   gtk_printer_option_set (option, "50");
3725   set_option_from_settings (option, settings);
3726   gtk_printer_option_set_add (set, option);
3727   g_object_unref (option);
3728
3729   /* Translators, this string is used to label the billing info entry
3730    * in the print dialog
3731    */
3732   option = gtk_printer_option_new ("gtk-billing-info", _("Billing Info"), GTK_PRINTER_OPTION_TYPE_STRING);
3733   gtk_printer_option_set (option, "");
3734   set_option_from_settings (option, settings);
3735   gtk_printer_option_set_add (set, option);
3736   g_object_unref (option);
3737
3738   backend = GTK_PRINT_BACKEND_CUPS (gtk_printer_get_backend (printer));
3739   cups_printer = GTK_PRINTER_CUPS (printer);
3740
3741   if (backend != NULL && printer != NULL)
3742     {
3743       char *cover_default[] = {"none", "classified", "confidential", "secret", "standard", "topsecret", "unclassified" };
3744       /* Translators, these strings are names for various 'standard' cover
3745        * pages that the printing system may support.
3746        */
3747       char *cover_display_default[] = {N_("None"), N_("Classified"), N_("Confidential"), N_("Secret"), N_("Standard"), N_("Top Secret"), N_("Unclassified"),};
3748       char **cover = NULL;
3749       char **cover_display = NULL;
3750       char **cover_display_translated = NULL;
3751       gint num_of_covers = 0;
3752       gpointer value;
3753       gint j;
3754
3755        /* Translators, this string is used to label the pages-per-sheet option
3756         * in the print dialog
3757         */
3758       option = gtk_printer_option_new ("gtk-n-up", _("Pages per Sheet"), GTK_PRINTER_OPTION_TYPE_PICKONE);
3759       gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up),
3760                                              n_up, n_up);
3761       default_number_up = g_strdup_printf ("%d", cups_printer->default_number_up);
3762       gtk_printer_option_set (option, default_number_up);
3763       g_free (default_number_up);
3764       set_option_from_settings (option, settings);
3765       gtk_printer_option_set_add (set, option);
3766       g_object_unref (option);
3767
3768       if (cups_printer_get_capabilities (printer) & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT)
3769         {
3770           for (i = 0; i < G_N_ELEMENTS (n_up_layout_display); i++)
3771             n_up_layout_display[i] = _(n_up_layout_display[i]);
3772
3773            /* Translators, this string is used to label the option in the print
3774             * dialog that controls in what order multiple pages are arranged
3775             */
3776           option = gtk_printer_option_new ("gtk-n-up-layout", _("Page Ordering"), GTK_PRINTER_OPTION_TYPE_PICKONE);
3777           gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up_layout),
3778                                                  n_up_layout, n_up_layout_display);
3779
3780           text_direction = gtk_widget_get_default_direction ();
3781           if (text_direction == GTK_TEXT_DIR_LTR)
3782             gtk_printer_option_set (option, "lrtb");
3783           else
3784             gtk_printer_option_set (option, "rltb");
3785
3786           set_option_from_settings (option, settings);
3787           gtk_printer_option_set_add (set, option);
3788           g_object_unref (option);
3789         }
3790
3791       num_of_covers = backend->number_of_covers;
3792       cover = g_new (char *, num_of_covers + 1);
3793       cover[num_of_covers] = NULL;
3794       cover_display = g_new (char *, num_of_covers + 1);
3795       cover_display[num_of_covers] = NULL;
3796       cover_display_translated = g_new (char *, num_of_covers + 1);
3797       cover_display_translated[num_of_covers] = NULL;
3798
3799       for (i = 0; i < num_of_covers; i++)
3800         {
3801           cover[i] = g_strdup (backend->covers[i]);
3802           value = NULL;
3803           for (j = 0; j < G_N_ELEMENTS (cover_default); j++)
3804             if (strcmp (cover_default[j], cover[i]) == 0)
3805               {
3806                 value = cover_display_default[j];
3807                 break;
3808               }
3809           cover_display[i] = (value != NULL) ? g_strdup (value) : g_strdup (backend->covers[i]);
3810         }
3811
3812       for (i = 0; i < num_of_covers; i++)
3813         cover_display_translated[i] = _(cover_display[i]);
3814
3815       /* Translators, this is the label used for the option in the print
3816        * dialog that controls the front cover page.
3817        */
3818       option = gtk_printer_option_new ("gtk-cover-before", _("Before"), GTK_PRINTER_OPTION_TYPE_PICKONE);
3819       gtk_printer_option_choices_from_array (option, num_of_covers,
3820                                          cover, cover_display_translated);
3821
3822       if (cups_printer->default_cover_before != NULL)
3823         gtk_printer_option_set (option, cups_printer->default_cover_before);
3824       else
3825         gtk_printer_option_set (option, "none");
3826       set_option_from_settings (option, settings);
3827       gtk_printer_option_set_add (set, option);
3828       g_object_unref (option);
3829
3830       /* Translators, this is the label used for the option in the print
3831        * dialog that controls the back cover page.
3832        */
3833       option = gtk_printer_option_new ("gtk-cover-after", _("After"), GTK_PRINTER_OPTION_TYPE_PICKONE);
3834       gtk_printer_option_choices_from_array (option, num_of_covers,
3835                                          cover, cover_display_translated);
3836       if (cups_printer->default_cover_after != NULL)
3837         gtk_printer_option_set (option, cups_printer->default_cover_after);
3838       else
3839         gtk_printer_option_set (option, "none");
3840       set_option_from_settings (option, settings);
3841       gtk_printer_option_set_add (set, option);
3842       g_object_unref (option);
3843
3844       g_strfreev (cover);
3845       g_strfreev (cover_display);
3846       g_free (cover_display_translated);
3847     }
3848
3849   /* Translators: this is the name of the option that controls when
3850    * a print job is printed. Possible values are 'now', a specified time,
3851    * or 'on hold'
3852    */
3853   option = gtk_printer_option_new ("gtk-print-time", _("Print at"), GTK_PRINTER_OPTION_TYPE_PICKONE);
3854   gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (print_at),
3855                                          print_at, print_at);
3856   gtk_printer_option_set (option, "now");
3857   set_option_from_settings (option, settings);
3858   gtk_printer_option_set_add (set, option);
3859   g_object_unref (option);
3860
3861   /* Translators: this is the name of the option that allows the user
3862    * to specify a time when a print job will be printed.
3863    */
3864   option = gtk_printer_option_new ("gtk-print-time-text", _("Print at time"), GTK_PRINTER_OPTION_TYPE_STRING);
3865   gtk_printer_option_set (option, "");
3866   set_option_from_settings (option, settings);
3867   gtk_printer_option_set_add (set, option);
3868   g_object_unref (option);
3869
3870   /* Printer (ppd) specific settings */
3871   ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
3872   if (ppd_file)
3873     {
3874       GtkPaperSize *paper_size;
3875       ppd_option_t *option;
3876       const gchar  *ppd_name;
3877
3878       ppdMarkDefaults (ppd_file);
3879
3880       paper_size = gtk_page_setup_get_paper_size (page_setup);
3881
3882       option = ppdFindOption (ppd_file, "PageSize");
3883       ppd_name = gtk_paper_size_get_ppd_name (paper_size);
3884
3885       if (ppd_name)
3886         strncpy (option->defchoice, ppd_name, PPD_MAX_NAME);
3887       else
3888         {
3889           gchar *custom_name;
3890           char width[G_ASCII_DTOSTR_BUF_SIZE];
3891           char height[G_ASCII_DTOSTR_BUF_SIZE];
3892
3893           g_ascii_formatd (width, sizeof (width), "%.2f", gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS));
3894           g_ascii_formatd (height, sizeof (height), "%.2f", gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS));
3895           /* Translators: this format is used to display a custom paper
3896            * size. The two placeholders are replaced with the width and height
3897            * in points. E.g: "Custom 230.4x142.9"
3898            */
3899           custom_name = g_strdup_printf (_("Custom %sx%s"), width, height);
3900           strncpy (option->defchoice, custom_name, PPD_MAX_NAME);
3901           g_free (custom_name);
3902         }
3903
3904       for (i = 0; i < ppd_file->num_groups; i++)
3905         handle_group (set, ppd_file, &ppd_file->groups[i], &ppd_file->groups[i], settings);
3906     }
3907
3908   /* Now honor the user set defaults for this printer */
3909   num_opts = cups_get_user_options (gtk_printer_get_name (printer), 0, &opts);
3910
3911   for (i = 0; i < num_opts; i++)
3912     {
3913       if (STRING_IN_TABLE (opts[i].name, cups_option_blacklist))
3914         continue;
3915
3916       name = get_lpoption_name (opts[i].name);
3917       if (strcmp (name, "cups-job-sheets") == 0)
3918         {
3919           gchar **values;
3920           gint    num_values;
3921
3922           values = g_strsplit (opts[i].value, ",", 2);
3923           num_values = g_strv_length (values);
3924
3925           option = gtk_printer_option_set_lookup (set, "gtk-cover-before");
3926           if (option && num_values > 0)
3927             gtk_printer_option_set (option, g_strstrip (values[0]));
3928
3929           option = gtk_printer_option_set_lookup (set, "gtk-cover-after");
3930           if (option && num_values > 1)
3931             gtk_printer_option_set (option, g_strstrip (values[1]));
3932
3933           g_strfreev (values);
3934         }
3935       else if (strcmp (name, "cups-job-hold-until") == 0)
3936         {
3937           GtkPrinterOption *option2 = NULL;
3938
3939           option = gtk_printer_option_set_lookup (set, "gtk-print-time-text");
3940           if (option && opts[i].value)
3941             {
3942               option2 = gtk_printer_option_set_lookup (set, "gtk-print-time");
3943               if (option2)
3944                 {
3945                   if (strcmp (opts[i].value, "indefinite") == 0)
3946                     gtk_printer_option_set (option2, "on-hold");
3947                   else
3948                     {
3949                       gtk_printer_option_set (option2, "at");
3950                       gtk_printer_option_set (option, opts[i].value);
3951                     }
3952                 }
3953             }
3954         }
3955       else if (strcmp (name, "cups-sides") == 0)
3956         {
3957           option = gtk_printer_option_set_lookup (set, "gtk-duplex");
3958           if (option && opts[i].value)
3959             {
3960               if (strcmp (opts[i].value, "two-sided-short-edge") == 0)
3961                 gtk_printer_option_set (option, "DuplexTumble");
3962               else if (strcmp (opts[i].value, "two-sided-long-edge") == 0)
3963                 gtk_printer_option_set (option, "DuplexNoTumble");
3964             }
3965         }
3966       else
3967         {
3968           option = gtk_printer_option_set_lookup (set, name);
3969           if (option)
3970             gtk_printer_option_set (option, opts[i].value);
3971         }
3972       g_free (name);
3973     }
3974
3975   cupsFreeOptions (num_opts, opts);
3976
3977 #ifdef HAVE_COLORD
3978   /* TRANSLATORS: this this the ICC color profile to use for this job */
3979   option = gtk_printer_option_new ("colord-profile",
3980                                    _("Printer Profile"),
3981                                    GTK_PRINTER_OPTION_TYPE_INFO);
3982
3983   /* assign it to the color page */
3984   option->group = g_strdup ("ColorPage");
3985
3986   /* TRANSLATORS: this is when color profile information is unavailable */
3987   gtk_printer_option_set (option, _("Unavailable"));
3988   gtk_printer_option_set_add (set, option);
3989
3990   /* watch to see if the user changed the options */
3991   helper = g_new (GtkPrintBackendCupsColordHelper, 1);
3992   helper->printer = printer;
3993   helper->settings = settings;
3994   g_signal_connect_data (set, "changed",
3995                          G_CALLBACK (colord_printer_option_set_changed_cb),
3996                          helper,
3997                          (GClosureNotify) g_free,
3998                          0);
3999
4000   /* initial coldplug */
4001   gtk_printer_cups_update_settings (GTK_PRINTER_CUPS (printer),
4002                                     settings, set);
4003   g_object_bind_property (printer, "profile-title",
4004                           option, "value",
4005                           G_BINDING_DEFAULT);
4006
4007 #endif
4008
4009   return set;
4010 }
4011
4012
4013 static void
4014 mark_option_from_set (GtkPrinterOptionSet *set,
4015                       ppd_file_t          *ppd_file,
4016                       ppd_option_t        *ppd_option)
4017 {
4018   GtkPrinterOption *option;
4019   char *name = get_ppd_option_name (ppd_option->keyword);
4020
4021   option = gtk_printer_option_set_lookup (set, name);
4022
4023   if (option)
4024     ppdMarkOption (ppd_file, ppd_option->keyword, option->value);
4025
4026   g_free (name);
4027 }
4028
4029
4030 static void
4031 mark_group_from_set (GtkPrinterOptionSet *set,
4032                      ppd_file_t          *ppd_file,
4033                      ppd_group_t         *group)
4034 {
4035   int i;
4036
4037   for (i = 0; i < group->num_options; i++)
4038     mark_option_from_set (set, ppd_file, &group->options[i]);
4039
4040   for (i = 0; i < group->num_subgroups; i++)
4041     mark_group_from_set (set, ppd_file, &group->subgroups[i]);
4042 }
4043
4044 static void
4045 set_conflicts_from_option (GtkPrinterOptionSet *set,
4046                            ppd_file_t          *ppd_file,
4047                            ppd_option_t        *ppd_option)
4048 {
4049   GtkPrinterOption *option;
4050   char *name;
4051
4052   if (ppd_option->conflicted)
4053     {
4054       name = get_ppd_option_name (ppd_option->keyword);
4055       option = gtk_printer_option_set_lookup (set, name);
4056
4057       if (option)
4058         gtk_printer_option_set_has_conflict (option, TRUE);
4059 #ifdef PRINT_IGNORED_OPTIONS
4060       else
4061         g_warning ("CUPS Backend: Ignoring conflict for option %s", ppd_option->keyword);
4062 #endif
4063
4064       g_free (name);
4065     }
4066 }
4067
4068 static void
4069 set_conflicts_from_group (GtkPrinterOptionSet *set,
4070                           ppd_file_t          *ppd_file,
4071                           ppd_group_t         *group)
4072 {
4073   int i;
4074
4075   for (i = 0; i < group->num_options; i++)
4076     set_conflicts_from_option (set, ppd_file, &group->options[i]);
4077
4078   for (i = 0; i < group->num_subgroups; i++)
4079     set_conflicts_from_group (set, ppd_file, &group->subgroups[i]);
4080 }
4081
4082 static gboolean
4083 cups_printer_mark_conflicts (GtkPrinter          *printer,
4084                              GtkPrinterOptionSet *options)
4085 {
4086   ppd_file_t *ppd_file;
4087   int num_conflicts;
4088   int i;
4089
4090   ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
4091
4092   if (ppd_file == NULL)
4093     return FALSE;
4094
4095   ppdMarkDefaults (ppd_file);
4096
4097   for (i = 0; i < ppd_file->num_groups; i++)
4098     mark_group_from_set (options, ppd_file, &ppd_file->groups[i]);
4099
4100   num_conflicts = ppdConflicts (ppd_file);
4101
4102   if (num_conflicts > 0)
4103     {
4104       for (i = 0; i < ppd_file->num_groups; i++)
4105         set_conflicts_from_group (options, ppd_file, &ppd_file->groups[i]);
4106     }
4107
4108   return num_conflicts > 0;
4109 }
4110
4111 struct OptionData {
4112   GtkPrinter *printer;
4113   GtkPrinterOptionSet *options;
4114   GtkPrintSettings *settings;
4115   ppd_file_t *ppd_file;
4116 };
4117
4118 typedef struct {
4119   const char *cups;
4120   const char *standard;
4121 } NameMapping;
4122
4123 static void
4124 map_settings_to_option (GtkPrinterOption  *option,
4125                         const NameMapping  table[],
4126                         gint               n_elements,
4127                         GtkPrintSettings  *settings,
4128                         const gchar       *standard_name,
4129                         const gchar       *cups_name)
4130 {
4131   int i;
4132   char *name;
4133   const char *cups_value;
4134   const char *standard_value;
4135
4136   /* If the cups-specific setting is set, always use that */
4137   name = g_strdup_printf ("cups-%s", cups_name);
4138   cups_value = gtk_print_settings_get (settings, name);
4139   g_free (name);
4140
4141   if (cups_value != NULL)
4142     {
4143       gtk_printer_option_set (option, cups_value);
4144       return;
4145     }
4146
4147   /* Otherwise we try to convert from the general setting */
4148   standard_value = gtk_print_settings_get (settings, standard_name);
4149   if (standard_value == NULL)
4150     return;
4151
4152   for (i = 0; i < n_elements; i++)
4153     {
4154       if (table[i].cups == NULL && table[i].standard == NULL)
4155         {
4156           gtk_printer_option_set (option, standard_value);
4157           break;
4158         }
4159       else if (table[i].cups == NULL &&
4160                strcmp (table[i].standard, standard_value) == 0)
4161         {
4162           set_option_off (option);
4163           break;
4164         }
4165       else if (strcmp (table[i].standard, standard_value) == 0)
4166         {
4167           gtk_printer_option_set (option, table[i].cups);
4168           break;
4169         }
4170     }
4171 }
4172
4173 static void
4174 map_option_to_settings (const gchar       *value,
4175                         const NameMapping  table[],
4176                         gint               n_elements,
4177                         GtkPrintSettings  *settings,
4178                         const gchar       *standard_name,
4179                         const gchar       *cups_name)
4180 {
4181   int i;
4182   char *name;
4183
4184   for (i = 0; i < n_elements; i++)
4185     {
4186       if (table[i].cups == NULL && table[i].standard == NULL)
4187         {
4188           gtk_print_settings_set (settings,
4189                                   standard_name,
4190                                   value);
4191           break;
4192         }
4193       else if (table[i].cups == NULL && table[i].standard != NULL)
4194         {
4195           if (value_is_off (value))
4196             {
4197               gtk_print_settings_set (settings,
4198                                       standard_name,
4199                                       table[i].standard);
4200               break;
4201             }
4202         }
4203       else if (strcmp (table[i].cups, value) == 0)
4204         {
4205           gtk_print_settings_set (settings,
4206                                   standard_name,
4207                                   table[i].standard);
4208           break;
4209         }
4210     }
4211
4212   /* Always set the corresponding cups-specific setting */
4213   name = g_strdup_printf ("cups-%s", cups_name);
4214   gtk_print_settings_set (settings, name, value);
4215   g_free (name);
4216 }
4217
4218
4219 static const NameMapping paper_source_map[] = {
4220   { "Lower", "lower"},
4221   { "Middle", "middle"},
4222   { "Upper", "upper"},
4223   { "Rear", "rear"},
4224   { "Envelope", "envelope"},
4225   { "Cassette", "cassette"},
4226   { "LargeCapacity", "large-capacity"},
4227   { "AnySmallFormat", "small-format"},
4228   { "AnyLargeFormat", "large-format"},
4229   { NULL, NULL}
4230 };
4231
4232 static const NameMapping output_tray_map[] = {
4233   { "Upper", "upper"},
4234   { "Lower", "lower"},
4235   { "Rear", "rear"},
4236   { NULL, NULL}
4237 };
4238
4239 static const NameMapping duplex_map[] = {
4240   { "DuplexTumble", "vertical" },
4241   { "DuplexNoTumble", "horizontal" },
4242   { NULL, "simplex" }
4243 };
4244
4245 static const NameMapping output_mode_map[] = {
4246   { "Standard", "normal" },
4247   { "Normal", "normal" },
4248   { "Draft", "draft" },
4249   { "Fast", "draft" },
4250 };
4251
4252 static const NameMapping media_type_map[] = {
4253   { "Transparency", "transparency"},
4254   { "Standard", "stationery"},
4255   { NULL, NULL}
4256 };
4257
4258 static const NameMapping all_map[] = {
4259   { NULL, NULL}
4260 };
4261
4262
4263 static void
4264 set_option_from_settings (GtkPrinterOption *option,
4265                           GtkPrintSettings *settings)
4266 {
4267   const char *cups_value;
4268   char *value;
4269
4270   if (settings == NULL)
4271     return;
4272
4273   if (strcmp (option->name, "gtk-paper-source") == 0)
4274     map_settings_to_option (option, paper_source_map, G_N_ELEMENTS (paper_source_map),
4275                              settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
4276   else if (strcmp (option->name, "gtk-output-tray") == 0)
4277     map_settings_to_option (option, output_tray_map, G_N_ELEMENTS (output_tray_map),
4278                             settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
4279   else if (strcmp (option->name, "gtk-duplex") == 0)
4280     map_settings_to_option (option, duplex_map, G_N_ELEMENTS (duplex_map),
4281                             settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
4282   else if (strcmp (option->name, "cups-OutputMode") == 0)
4283     map_settings_to_option (option, output_mode_map, G_N_ELEMENTS (output_mode_map),
4284                             settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
4285   else if (strcmp (option->name, "cups-Resolution") == 0)
4286     {
4287       cups_value = gtk_print_settings_get (settings, option->name);
4288       if (cups_value)
4289         gtk_printer_option_set (option, cups_value);
4290       else
4291         {
4292           if (gtk_print_settings_get_int_with_default (settings, GTK_PRINT_SETTINGS_RESOLUTION, -1) != -1 ||
4293               gtk_print_settings_get_int_with_default (settings, GTK_PRINT_SETTINGS_RESOLUTION_X, -1) != -1 ||
4294               gtk_print_settings_get_int_with_default (settings, GTK_PRINT_SETTINGS_RESOLUTION_Y, -1) != -1 ||
4295               option->value == NULL || option->value[0] == '\0')
4296             {
4297               int res = gtk_print_settings_get_resolution (settings);
4298               int res_x = gtk_print_settings_get_resolution_x (settings);
4299               int res_y = gtk_print_settings_get_resolution_y (settings);
4300
4301               if (res_x != res_y)
4302                 {
4303                   value = g_strdup_printf ("%dx%ddpi", res_x, res_y);
4304                   gtk_printer_option_set (option, value);
4305                   g_free (value);
4306                 }
4307               else if (res != 0)
4308                 {
4309                   value = g_strdup_printf ("%ddpi", res);
4310                   gtk_printer_option_set (option, value);
4311                   g_free (value);
4312                 }
4313             }
4314         }
4315     }
4316   else if (strcmp (option->name, "gtk-paper-type") == 0)
4317     map_settings_to_option (option, media_type_map, G_N_ELEMENTS (media_type_map),
4318                             settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
4319   else if (strcmp (option->name, "gtk-n-up") == 0)
4320     {
4321       map_settings_to_option (option, all_map, G_N_ELEMENTS (all_map),
4322                               settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
4323     }
4324   else if (strcmp (option->name, "gtk-n-up-layout") == 0)
4325     {
4326       map_settings_to_option (option, all_map, G_N_ELEMENTS (all_map),
4327                               settings, GTK_PRINT_SETTINGS_NUMBER_UP_LAYOUT, "number-up-layout");
4328     }
4329   else if (strcmp (option->name, "gtk-billing-info") == 0)
4330     {
4331       cups_value = gtk_print_settings_get (settings, "cups-job-billing");
4332       if (cups_value)
4333         gtk_printer_option_set (option, cups_value);
4334     }
4335   else if (strcmp (option->name, "gtk-job-prio") == 0)
4336     {
4337       cups_value = gtk_print_settings_get (settings, "cups-job-priority");
4338       if (cups_value)
4339         gtk_printer_option_set (option, cups_value);
4340     }
4341   else if (strcmp (option->name, "gtk-cover-before") == 0)
4342     {
4343       cups_value = gtk_print_settings_get (settings, "cover-before");
4344       if (cups_value)
4345         gtk_printer_option_set (option, cups_value);
4346     }
4347   else if (strcmp (option->name, "gtk-cover-after") == 0)
4348     {
4349       cups_value = gtk_print_settings_get (settings, "cover-after");
4350       if (cups_value)
4351         gtk_printer_option_set (option, cups_value);
4352     }
4353   else if (strcmp (option->name, "gtk-print-time") == 0)
4354     {
4355       cups_value = gtk_print_settings_get (settings, "print-at");
4356       if (cups_value)
4357         gtk_printer_option_set (option, cups_value);
4358     }
4359   else if (strcmp (option->name, "gtk-print-time-text") == 0)
4360     {
4361       cups_value = gtk_print_settings_get (settings, "print-at-time");
4362       if (cups_value)
4363         gtk_printer_option_set (option, cups_value);
4364     }
4365   else if (g_str_has_prefix (option->name, "cups-"))
4366     {
4367       cups_value = gtk_print_settings_get (settings, option->name);
4368       if (cups_value)
4369         gtk_printer_option_set (option, cups_value);
4370     }
4371 }
4372
4373 static void
4374 foreach_option_get_settings (GtkPrinterOption *option,
4375                              gpointer          user_data)
4376 {
4377   struct OptionData *data = user_data;
4378   GtkPrintSettings *settings = data->settings;
4379   const char *value;
4380
4381   value = option->value;
4382
4383   if (strcmp (option->name, "gtk-paper-source") == 0)
4384     map_option_to_settings (value, paper_source_map, G_N_ELEMENTS (paper_source_map),
4385                             settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
4386   else if (strcmp (option->name, "gtk-output-tray") == 0)
4387     map_option_to_settings (value, output_tray_map, G_N_ELEMENTS (output_tray_map),
4388                             settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
4389   else if (strcmp (option->name, "gtk-duplex") == 0)
4390     map_option_to_settings (value, duplex_map, G_N_ELEMENTS (duplex_map),
4391                             settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
4392   else if (strcmp (option->name, "cups-OutputMode") == 0)
4393     map_option_to_settings (value, output_mode_map, G_N_ELEMENTS (output_mode_map),
4394                             settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
4395   else if (strcmp (option->name, "cups-Resolution") == 0)
4396     {
4397       int res, res_x, res_y;
4398
4399       if (sscanf (value, "%dx%ddpi", &res_x, &res_y) == 2)
4400         {
4401           if (res_x > 0 && res_y > 0)
4402             gtk_print_settings_set_resolution_xy (settings, res_x, res_y);
4403         }
4404       else if (sscanf (value, "%ddpi", &res) == 1)
4405         {
4406           if (res > 0)
4407             gtk_print_settings_set_resolution (settings, res);
4408         }
4409
4410       gtk_print_settings_set (settings, option->name, value);
4411     }
4412   else if (strcmp (option->name, "gtk-paper-type") == 0)
4413     map_option_to_settings (value, media_type_map, G_N_ELEMENTS (media_type_map),
4414                             settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
4415   else if (strcmp (option->name, "gtk-n-up") == 0)
4416     map_option_to_settings (value, all_map, G_N_ELEMENTS (all_map),
4417                             settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
4418   else if (strcmp (option->name, "gtk-n-up-layout") == 0)
4419     map_option_to_settings (value, all_map, G_N_ELEMENTS (all_map),
4420                             settings, GTK_PRINT_SETTINGS_NUMBER_UP_LAYOUT, "number-up-layout");
4421   else if (strcmp (option->name, "gtk-billing-info") == 0 && strlen (value) > 0)
4422     gtk_print_settings_set (settings, "cups-job-billing", value);
4423   else if (strcmp (option->name, "gtk-job-prio") == 0)
4424     gtk_print_settings_set (settings, "cups-job-priority", value);
4425   else if (strcmp (option->name, "gtk-cover-before") == 0)
4426     gtk_print_settings_set (settings, "cover-before", value);
4427   else if (strcmp (option->name, "gtk-cover-after") == 0)
4428     gtk_print_settings_set (settings, "cover-after", value);
4429   else if (strcmp (option->name, "gtk-print-time") == 0)
4430     gtk_print_settings_set (settings, "print-at", value);
4431   else if (strcmp (option->name, "gtk-print-time-text") == 0)
4432     gtk_print_settings_set (settings, "print-at-time", value);
4433   else if (g_str_has_prefix (option->name, "cups-"))
4434     gtk_print_settings_set (settings, option->name, value);
4435 }
4436
4437 static gboolean
4438 supports_am_pm (void)
4439 {
4440   struct tm tmp_tm = { 0 };
4441   char   time[8];
4442   int    length;
4443
4444   length = strftime (time, sizeof (time), "%p", &tmp_tm);
4445
4446   return length != 0;
4447 }
4448
4449 /* Converts local time to UTC time. Local time has to be in one of these
4450  * formats:  HH:MM:SS, HH:MM, HH:MM:SS {am, pm}, HH:MM {am, pm}, HH {am, pm},
4451  * {am, pm} HH:MM:SS, {am, pm} HH:MM, {am, pm} HH.
4452  * Returns a newly allocated string holding UTC time in HH:MM:SS format
4453  * or NULL.
4454  */
4455 gchar *
4456 localtime_to_utctime (const char *local_time)
4457 {
4458   const char *formats_0[] = {" %I : %M : %S %p ", " %p %I : %M : %S ",
4459                              " %H : %M : %S ",
4460                              " %I : %M %p ", " %p %I : %M ",
4461                              " %H : %M ",
4462                              " %I %p ", " %p %I "};
4463   const char *formats_1[] = {" %H : %M : %S ", " %H : %M "};
4464   const char *end = NULL;
4465   struct tm  *actual_local_time;
4466   struct tm  *actual_utc_time;
4467   struct tm   local_print_time;
4468   struct tm   utc_print_time;
4469   struct tm   diff_time;
4470   gchar      *utc_time = NULL;
4471   int         i, n;
4472
4473   if (local_time == NULL || local_time[0] == '\0')
4474     return NULL;
4475
4476   n = supports_am_pm () ? G_N_ELEMENTS (formats_0) : G_N_ELEMENTS (formats_1);
4477
4478   for (i = 0; i < n; i++)
4479     {
4480       local_print_time.tm_hour = 0;
4481       local_print_time.tm_min  = 0;
4482       local_print_time.tm_sec  = 0;
4483
4484       if (supports_am_pm ())
4485         end = strptime (local_time, formats_0[i], &local_print_time);
4486       else
4487         end = strptime (local_time, formats_1[i], &local_print_time);
4488
4489       if (end != NULL && end[0] == '\0')
4490         break;
4491     }
4492
4493   if (end != NULL && end[0] == '\0')
4494     {
4495       time_t rawtime;
4496       time (&rawtime);
4497
4498       actual_utc_time = g_memdup (gmtime (&rawtime), sizeof (struct tm));
4499       actual_local_time = g_memdup (localtime (&rawtime), sizeof (struct tm));
4500
4501       diff_time.tm_hour = actual_utc_time->tm_hour - actual_local_time->tm_hour;
4502       diff_time.tm_min  = actual_utc_time->tm_min  - actual_local_time->tm_min;
4503       diff_time.tm_sec  = actual_utc_time->tm_sec  - actual_local_time->tm_sec;
4504
4505       utc_print_time.tm_hour = ((local_print_time.tm_hour + diff_time.tm_hour) + 24) % 24;
4506       utc_print_time.tm_min  = ((local_print_time.tm_min  + diff_time.tm_min)  + 60) % 60;
4507       utc_print_time.tm_sec  = ((local_print_time.tm_sec  + diff_time.tm_sec)  + 60) % 60;
4508
4509       utc_time = g_strdup_printf ("%02d:%02d:%02d",
4510                                   utc_print_time.tm_hour,
4511                                   utc_print_time.tm_min,
4512                                   utc_print_time.tm_sec);
4513     }
4514
4515   return utc_time;
4516 }
4517
4518 static void
4519 cups_printer_get_settings_from_options (GtkPrinter          *printer,
4520                                         GtkPrinterOptionSet *options,
4521                                         GtkPrintSettings    *settings)
4522 {
4523   struct OptionData data;
4524   const char *print_at, *print_at_time;
4525
4526   data.printer = printer;
4527   data.options = options;
4528   data.settings = settings;
4529   data.ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
4530
4531   if (data.ppd_file != NULL)
4532     {
4533       GtkPrinterOption *cover_before, *cover_after;
4534
4535       gtk_printer_option_set_foreach (options, foreach_option_get_settings, &data);
4536
4537       cover_before = gtk_printer_option_set_lookup (options, "gtk-cover-before");
4538       cover_after = gtk_printer_option_set_lookup (options, "gtk-cover-after");
4539       if (cover_before && cover_after)
4540         {
4541           char *value = g_strdup_printf ("%s,%s", cover_before->value, cover_after->value);
4542           gtk_print_settings_set (settings, "cups-job-sheets", value);
4543           g_free (value);
4544         }
4545
4546       print_at = gtk_print_settings_get (settings, "print-at");
4547       print_at_time = gtk_print_settings_get (settings, "print-at-time");
4548
4549       if (strcmp (print_at, "at") == 0)
4550         {
4551           gchar *utc_time = NULL;
4552
4553           utc_time = localtime_to_utctime (print_at_time);
4554
4555           if (utc_time != NULL)
4556             {
4557               gtk_print_settings_set (settings, "cups-job-hold-until", utc_time);
4558               g_free (utc_time);
4559             }
4560           else
4561             gtk_print_settings_set (settings, "cups-job-hold-until", print_at_time);
4562         }
4563       else if (strcmp (print_at, "on-hold") == 0)
4564         gtk_print_settings_set (settings, "cups-job-hold-until", "indefinite");
4565     }
4566 }
4567
4568 static void
4569 cups_printer_prepare_for_print (GtkPrinter       *printer,
4570                                 GtkPrintJob      *print_job,
4571                                 GtkPrintSettings *settings,
4572                                 GtkPageSetup     *page_setup)
4573 {
4574   GtkPrintPages pages;
4575   GtkPageRange *ranges;
4576   gint n_ranges;
4577   GtkPageSet page_set;
4578   GtkPaperSize *paper_size;
4579   const char *ppd_paper_name;
4580   double scale;
4581
4582   pages = gtk_print_settings_get_print_pages (settings);
4583   gtk_print_job_set_pages (print_job, pages);
4584
4585   if (pages == GTK_PRINT_PAGES_RANGES)
4586     ranges = gtk_print_settings_get_page_ranges (settings, &n_ranges);
4587   else
4588     {
4589       ranges = NULL;
4590       n_ranges = 0;
4591     }
4592
4593   gtk_print_job_set_page_ranges (print_job, ranges, n_ranges);
4594   if (gtk_print_settings_get_collate (settings))
4595     gtk_print_settings_set (settings, "cups-Collate", "True");
4596   gtk_print_job_set_collate (print_job, FALSE);
4597
4598   if (gtk_print_settings_get_reverse (settings))
4599     gtk_print_settings_set (settings, "cups-OutputOrder", "Reverse");
4600   gtk_print_job_set_reverse (print_job, FALSE);
4601
4602   if (gtk_print_settings_get_n_copies (settings) > 1)
4603     gtk_print_settings_set_int (settings, "cups-copies",
4604                                 gtk_print_settings_get_n_copies (settings));
4605   gtk_print_job_set_num_copies (print_job, 1);
4606
4607   scale = gtk_print_settings_get_scale (settings);
4608   if (scale != 100.0)
4609     gtk_print_job_set_scale (print_job, scale / 100.0);
4610
4611   page_set = gtk_print_settings_get_page_set (settings);
4612   if (page_set == GTK_PAGE_SET_EVEN)
4613     gtk_print_settings_set (settings, "cups-page-set", "even");
4614   else if (page_set == GTK_PAGE_SET_ODD)
4615     gtk_print_settings_set (settings, "cups-page-set", "odd");
4616   gtk_print_job_set_page_set (print_job, GTK_PAGE_SET_ALL);
4617
4618   paper_size = gtk_page_setup_get_paper_size (page_setup);
4619   ppd_paper_name = gtk_paper_size_get_ppd_name (paper_size);
4620   if (ppd_paper_name != NULL)
4621     gtk_print_settings_set (settings, "cups-PageSize", ppd_paper_name);
4622   else
4623     {
4624       char width[G_ASCII_DTOSTR_BUF_SIZE];
4625       char height[G_ASCII_DTOSTR_BUF_SIZE];
4626       char *custom_name;
4627
4628       g_ascii_formatd (width, sizeof (width), "%.2f", gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS));
4629       g_ascii_formatd (height, sizeof (height), "%.2f", gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS));
4630       custom_name = g_strdup_printf (("Custom.%sx%s"), width, height);
4631       gtk_print_settings_set (settings, "cups-PageSize", custom_name);
4632       g_free (custom_name);
4633     }
4634
4635   if (gtk_print_settings_get_number_up (settings) > 1)
4636     {
4637       GtkNumberUpLayout  layout = gtk_print_settings_get_number_up_layout (settings);
4638       GEnumClass        *enum_class;
4639       GEnumValue        *enum_value;
4640
4641       switch (gtk_page_setup_get_orientation (page_setup))
4642         {
4643           case GTK_PAGE_ORIENTATION_PORTRAIT:
4644             break;
4645           case GTK_PAGE_ORIENTATION_LANDSCAPE:
4646             if (layout < 4)
4647               layout = layout + 2 + 4 * (1 - layout / 2);
4648             else
4649               layout = layout - 3 - 2 * (layout % 2);
4650             break;
4651           case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
4652             layout = (layout + 3 - 2 * (layout % 2)) % 4 + 4 * (layout / 4);
4653             break;
4654           case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
4655             if (layout < 4)
4656               layout = layout + 5 - 2 * (layout % 2);
4657             else
4658               layout = layout - 6 + 4 * (1 - (layout - 4) / 2);
4659             break;
4660         }
4661
4662       enum_class = g_type_class_ref (GTK_TYPE_NUMBER_UP_LAYOUT);
4663       enum_value = g_enum_get_value (enum_class, layout);
4664       gtk_print_settings_set (settings, "cups-number-up-layout", enum_value->value_nick);
4665       g_type_class_unref (enum_class);
4666     }
4667
4668   gtk_print_job_set_rotate (print_job, TRUE);
4669 }
4670
4671 static GtkPageSetup *
4672 create_page_setup (ppd_file_t *ppd_file,
4673                    ppd_size_t *size)
4674  {
4675    char *display_name;
4676    GtkPageSetup *page_setup;
4677    GtkPaperSize *paper_size;
4678    ppd_option_t *option;
4679    ppd_choice_t *choice;
4680
4681   display_name = NULL;
4682   option = ppdFindOption (ppd_file, "PageSize");
4683   if (option)
4684     {
4685       choice = ppdFindChoice (option, size->name);
4686       if (choice)
4687         display_name = ppd_text_to_utf8 (ppd_file, choice->text);
4688     }
4689
4690   if (display_name == NULL)
4691     display_name = g_strdup (size->name);
4692
4693   page_setup = gtk_page_setup_new ();
4694   paper_size = gtk_paper_size_new_from_ppd (size->name,
4695                                             display_name,
4696                                             size->width,
4697                                             size->length);
4698   gtk_page_setup_set_paper_size (page_setup, paper_size);
4699   gtk_paper_size_free (paper_size);
4700
4701   gtk_page_setup_set_top_margin (page_setup, size->length - size->top, GTK_UNIT_POINTS);
4702   gtk_page_setup_set_bottom_margin (page_setup, size->bottom, GTK_UNIT_POINTS);
4703   gtk_page_setup_set_left_margin (page_setup, size->left, GTK_UNIT_POINTS);
4704   gtk_page_setup_set_right_margin (page_setup, size->width - size->right, GTK_UNIT_POINTS);
4705
4706   g_free (display_name);
4707
4708   return page_setup;
4709 }
4710
4711 static GList *
4712 cups_printer_list_papers (GtkPrinter *printer)
4713 {
4714   ppd_file_t *ppd_file;
4715   ppd_size_t *size;
4716   GtkPageSetup *page_setup;
4717   GList *l;
4718   int i;
4719
4720   ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
4721   if (ppd_file == NULL)
4722     return NULL;
4723
4724   l = NULL;
4725
4726   for (i = 0; i < ppd_file->num_sizes; i++)
4727     {
4728       size = &ppd_file->sizes[i];
4729
4730       page_setup = create_page_setup (ppd_file, size);
4731
4732       l = g_list_prepend (l, page_setup);
4733     }
4734
4735   return g_list_reverse (l);
4736 }
4737
4738 static GtkPageSetup *
4739 cups_printer_get_default_page_size (GtkPrinter *printer)
4740 {
4741   ppd_file_t *ppd_file;
4742   ppd_size_t *size;
4743   ppd_option_t *option;
4744
4745
4746   ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
4747   if (ppd_file == NULL)
4748     return NULL;
4749
4750   option = ppdFindOption (ppd_file, "PageSize");
4751   if (option == NULL)
4752     return NULL;
4753
4754   size = ppdPageSize (ppd_file, option->defchoice);
4755   if (size == NULL)
4756     return NULL;
4757
4758   return create_page_setup (ppd_file, size);
4759 }
4760
4761 static gboolean
4762 cups_printer_get_hard_margins (GtkPrinter *printer,
4763                                gdouble    *top,
4764                                gdouble    *bottom,
4765                                gdouble    *left,
4766                                gdouble    *right)
4767 {
4768   ppd_file_t *ppd_file;
4769
4770   ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
4771   if (ppd_file == NULL)
4772     return FALSE;
4773
4774   *left = ppd_file->custom_margins[0];
4775   *bottom = ppd_file->custom_margins[1];
4776   *right = ppd_file->custom_margins[2];
4777   *top = ppd_file->custom_margins[3];
4778
4779   return TRUE;
4780 }
4781
4782 static GtkPrintCapabilities
4783 cups_printer_get_capabilities (GtkPrinter *printer)
4784 {
4785   return
4786     GTK_PRINT_CAPABILITY_COPIES |
4787     GTK_PRINT_CAPABILITY_COLLATE |
4788     GTK_PRINT_CAPABILITY_REVERSE |
4789     GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT |
4790     GTK_PRINT_CAPABILITY_NUMBER_UP;
4791 }