]> Pileus Git - ~andy/gtk/blob - modules/printbackends/cups/gtkprintbackendcups.c
fix the build
[~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, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <stdlib.h>
26
27 #include <config.h>
28 #include <cups/cups.h>
29 #include <cups/language.h>
30 #include <cups/http.h>
31 #include <cups/ipp.h>
32 #include <errno.h>
33 #include <cairo.h>
34 #include <cairo-pdf.h>
35 #include <cairo-ps.h>
36
37 #include <glib/gi18n-lib.h>
38 #include <gmodule.h>
39
40 #include <gtk/gtkprintoperation.h>
41 #include <gtk/gtkprintsettings.h>
42 #include <gtk/gtkprintbackend.h>
43 #include <gtk/gtkprinter.h>
44 #include <gtk/gtkprinter-private.h>
45
46 #include "gtkprintbackendcups.h"
47 #include "gtkprintercups.h"
48
49 #include "gtkcupsutils.h"
50 #include "gtkdebug.h"
51
52
53 typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass;
54
55 #define GTK_PRINT_BACKEND_CUPS_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))
56 #define GTK_IS_PRINT_BACKEND_CUPS_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_CUPS))
57 #define GTK_PRINT_BACKEND_CUPS_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))
58
59 #define _CUPS_MAX_ATTEMPTS 10 
60 #define _CUPS_MAX_CHUNK_SIZE 8192
61
62 #define _CUPS_MAP_ATTR_INT(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].integer;}
63 #define _CUPS_MAP_ATTR_STR(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].string.text;}
64
65 static GType print_backend_cups_type = 0;
66
67 typedef void (* GtkPrintCupsResponseCallbackFunc) (GtkPrintBackend *print_backend,
68                                                    GtkCupsResult   *result, 
69                                                    gpointer         user_data);
70
71 typedef enum 
72 {
73   DISPATCH_SETUP,
74   DISPATCH_REQUEST,
75   DISPATCH_SEND,
76   DISPATCH_CHECK,
77   DISPATCH_READ,
78   DISPATCH_ERROR
79 } GtkPrintCupsDispatchState;
80
81 typedef struct 
82 {
83   GSource source;
84
85   http_t *http;
86   GtkCupsRequest *request;
87   GPollFD *data_poll;
88   GtkPrintBackendCups *backend;
89
90 } GtkPrintCupsDispatchWatch;
91
92 struct _GtkPrintBackendCupsClass
93 {
94   GtkPrintBackendClass parent_class;
95 };
96
97 struct _GtkPrintBackendCups
98 {
99   GtkPrintBackend parent_instance;
100
101   char *default_printer;
102   
103   guint list_printers_poll;
104   guint list_printers_pending : 1;
105   guint got_default_printer   : 1;
106 };
107
108 static GObjectClass *backend_parent_class;
109
110 static void                 gtk_print_backend_cups_class_init      (GtkPrintBackendCupsClass          *class);
111 static void                 gtk_print_backend_cups_init            (GtkPrintBackendCups               *impl);
112 static void                 gtk_print_backend_cups_finalize        (GObject                           *object);
113 static void                 gtk_print_backend_cups_dispose         (GObject                           *object);
114 static void                 cups_get_printer_list                  (GtkPrintBackend                   *print_backend);
115 static void                 cups_request_execute                   (GtkPrintBackendCups               *print_backend,
116                                                                     GtkCupsRequest                    *request,
117                                                                     GtkPrintCupsResponseCallbackFunc   callback,
118                                                                     gpointer                           user_data,
119                                                                     GDestroyNotify                     notify);
120 static void                 cups_printer_get_settings_from_options (GtkPrinter                        *printer,
121                                                                     GtkPrinterOptionSet               *options,
122                                                                     GtkPrintSettings                  *settings);
123 static gboolean             cups_printer_mark_conflicts            (GtkPrinter                        *printer,
124                                                                     GtkPrinterOptionSet               *options);
125 static GtkPrinterOptionSet *cups_printer_get_options               (GtkPrinter                        *printer,
126                                                                     GtkPrintSettings                  *settings,
127                                                                     GtkPageSetup                      *page_setup,
128                                                                     GtkPrintCapabilities               capabilities);
129 static void                 cups_printer_prepare_for_print         (GtkPrinter                        *printer,
130                                                                     GtkPrintJob                       *print_job,
131                                                                     GtkPrintSettings                  *settings,
132                                                                     GtkPageSetup                      *page_setup);
133 static GList *              cups_printer_list_papers               (GtkPrinter                        *printer);
134 static void                 cups_printer_request_details           (GtkPrinter                        *printer);
135 static void                 cups_request_default_printer           (GtkPrintBackendCups               *print_backend);
136 static void                 cups_request_ppd                       (GtkPrinter                        *printer);
137 static void                 cups_printer_get_hard_margins          (GtkPrinter                        *printer,
138                                                                     double                            *top,
139                                                                     double                            *bottom,
140                                                                     double                            *left,
141                                                                     double                            *right);
142 static GtkPrintCapabilities cups_printer_get_capabilities          (GtkPrinter                        *printer);
143 static void                 set_option_from_settings               (GtkPrinterOption                  *option,
144                                                                     GtkPrintSettings                  *setting);
145 static void                 cups_begin_polling_info                (GtkPrintBackendCups               *print_backend,
146                                                                     GtkPrintJob                       *job,
147                                                                     int                                job_id);
148 static gboolean             cups_job_info_poll_timeout             (gpointer                           user_data);
149 static void                 gtk_print_backend_cups_print_stream    (GtkPrintBackend                   *backend,
150                                                                     GtkPrintJob                       *job,
151                                                                     GIOChannel                        *data_io,
152                                                                     GtkPrintJobCompleteFunc            callback,
153                                                                     gpointer                           user_data,
154                                                                     GDestroyNotify                     dnotify);
155 static cairo_surface_t *    cups_printer_create_cairo_surface      (GtkPrinter                        *printer,
156                                                                     GtkPrintSettings                  *settings,
157                                                                     gdouble                            width,
158                                                                     gdouble                            height,
159                                                                     GIOChannel                        *cache_io);
160
161
162 static void
163 gtk_print_backend_cups_register_type (GTypeModule *module)
164 {
165   static const GTypeInfo print_backend_cups_info =
166   {
167     sizeof (GtkPrintBackendCupsClass),
168     NULL,               /* base_init */
169     NULL,               /* base_finalize */
170     (GClassInitFunc) gtk_print_backend_cups_class_init,
171     NULL,               /* class_finalize */
172     NULL,               /* class_data */
173     sizeof (GtkPrintBackendCups),
174     0,                  /* n_preallocs */
175     (GInstanceInitFunc) gtk_print_backend_cups_init
176   };
177
178   print_backend_cups_type = g_type_module_register_type (module,
179                                                          GTK_TYPE_PRINT_BACKEND,
180                                                          "GtkPrintBackendCups",
181                                                          &print_backend_cups_info, 0);
182 }
183
184 G_MODULE_EXPORT void 
185 pb_module_init (GTypeModule *module)
186 {
187   GTK_NOTE (PRINTING,
188             g_print ("CUPS Backend: Initializing the CUPS print backend module\n")); 
189
190   gtk_print_backend_cups_register_type (module);
191   gtk_printer_cups_register_type (module);
192 }
193
194 G_MODULE_EXPORT void 
195 pb_module_exit (void)
196 {
197
198 }
199   
200 G_MODULE_EXPORT GtkPrintBackend * 
201 pb_module_create (void)
202 {
203   return gtk_print_backend_cups_new ();
204 }
205
206 /*
207  * GtkPrintBackendCups
208  */
209 GType
210 gtk_print_backend_cups_get_type (void)
211 {
212   return print_backend_cups_type;
213 }
214
215 /**
216  * gtk_print_backend_cups_new:
217  *
218  * Creates a new #GtkPrintBackendCups object. #GtkPrintBackendCups
219  * implements the #GtkPrintBackend interface with direct access to
220  * the filesystem using Unix/Linux API calls
221  *
222  * Return value: the new #GtkPrintBackendCups object
223  */
224 GtkPrintBackend *
225 gtk_print_backend_cups_new (void)
226 {
227   GTK_NOTE (PRINTING,
228             g_print ("CUPS Backend: Creating a new CUPS print backend object\n"));
229
230   return g_object_new (GTK_TYPE_PRINT_BACKEND_CUPS, NULL);
231 }
232
233 static void
234 gtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class)
235 {
236   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
237   GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_CLASS (class);
238
239   backend_parent_class = g_type_class_peek_parent (class);
240
241   gobject_class->finalize = gtk_print_backend_cups_finalize;
242   gobject_class->dispose = gtk_print_backend_cups_dispose;
243
244   backend_class->request_printer_list = cups_get_printer_list; 
245   backend_class->print_stream = gtk_print_backend_cups_print_stream;
246   backend_class->printer_request_details = cups_printer_request_details;
247   backend_class->printer_create_cairo_surface = cups_printer_create_cairo_surface;
248   backend_class->printer_get_options = cups_printer_get_options;
249   backend_class->printer_mark_conflicts = cups_printer_mark_conflicts;
250   backend_class->printer_get_settings_from_options = cups_printer_get_settings_from_options;
251   backend_class->printer_prepare_for_print = cups_printer_prepare_for_print;
252   backend_class->printer_list_papers = cups_printer_list_papers;
253   backend_class->printer_get_hard_margins = cups_printer_get_hard_margins;
254   backend_class->printer_get_capabilities = cups_printer_get_capabilities;
255 }
256
257 static cairo_status_t
258 _cairo_write_to_cups (void                *closure,
259                       const unsigned char *data,
260                       unsigned int         length)
261 {
262   GIOChannel *io = (GIOChannel *)closure;
263   gsize written;
264   GError *error;
265
266   error = NULL;
267
268   GTK_NOTE (PRINTING,
269             g_print ("CUPS Backend: Writting %i byte chunk to temp file\n", length));
270
271   while (length > 0) 
272     {
273       g_io_channel_write_chars (io, (gchar *)data, length, &written, &error);
274
275       if (error != NULL)
276         {
277           GTK_NOTE (PRINTING,
278                     g_print ("CUPS Backend: Error writting to temp file, %s\n", error->message));
279
280           g_error_free (error);
281           return CAIRO_STATUS_WRITE_ERROR;
282         }    
283
284       GTK_NOTE (PRINTING,
285                 g_print ("CUPS Backend: Wrote %i bytes to temp file\n", written));
286
287       data += written;
288       length -= written;
289     }
290
291   return CAIRO_STATUS_SUCCESS;
292 }
293
294 static cairo_surface_t *
295 cups_printer_create_cairo_surface (GtkPrinter       *printer,
296                                    GtkPrintSettings *settings,
297                                    gdouble           width, 
298                                    gdouble           height,
299                                    GIOChannel       *cache_io)
300 {
301   cairo_surface_t *surface; 
302  
303   /* TODO: check if it is a ps or pdf printer */
304   
305   surface = cairo_ps_surface_create_for_stream  (_cairo_write_to_cups, cache_io, width, height);
306
307   /* TODO: DPI from settings object? */
308   cairo_surface_set_fallback_resolution (surface, 300, 300);
309
310   return surface;
311 }
312
313 typedef struct {
314   GtkPrintJobCompleteFunc callback;
315   GtkPrintJob *job;
316   gpointer user_data;
317   GDestroyNotify dnotify;
318 } CupsPrintStreamData;
319
320 static void
321 cups_free_print_stream_data (CupsPrintStreamData *data)
322 {
323   GTK_NOTE (PRINTING,
324             g_print ("CUPS Backend: %s\n", G_STRFUNC));
325
326   if (data->dnotify)
327     data->dnotify (data->user_data);
328   g_object_unref (data->job);
329   g_free (data);
330 }
331
332 static void
333 cups_print_cb (GtkPrintBackendCups *print_backend,
334                GtkCupsResult       *result,
335                gpointer             user_data)
336 {
337   GError *error = NULL;
338   CupsPrintStreamData *ps = user_data;
339
340   GTK_NOTE (PRINTING,
341             g_print ("CUPS Backend: %s\n", G_STRFUNC)); 
342
343   if (gtk_cups_result_is_error (result))
344     error = g_error_new_literal (gtk_print_error_quark (),
345                                  GTK_PRINT_ERROR_INTERNAL_ERROR,
346                                  gtk_cups_result_get_error_string (result));
347
348   if (ps->callback)
349     ps->callback (ps->job, ps->user_data, error);
350
351   if (error == NULL)
352     {
353       int job_id = 0;
354       ipp_attribute_t *attr;            /* IPP job-id attribute */
355       ipp_t *response = gtk_cups_result_get_response (result);
356
357       if ((attr = ippFindAttribute (response, "job-id", IPP_TAG_INTEGER)) != NULL)
358         job_id = attr->values[0].integer;
359
360       if (!gtk_print_job_get_track_print_status (ps->job) || job_id == 0)
361         gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED);
362       else
363         {
364           gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_PENDING);
365           cups_begin_polling_info (print_backend, ps->job, job_id);
366         }
367     } 
368   else
369     gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED_ABORTED);
370
371   
372   if (error)
373     g_error_free (error);
374   
375 }
376
377 static void
378 add_cups_options (const gchar *key,
379                   const gchar *value,
380                   gpointer     user_data)
381 {
382   GtkCupsRequest *request = user_data;
383
384   if (!g_str_has_prefix (key, "cups-"))
385     return;
386
387   if (strcmp (value, "gtk-ignore-value") == 0)
388     return;
389   
390   key = key + strlen ("cups-");
391
392   gtk_cups_request_encode_option (request, key, value);
393 }
394
395 static void
396 gtk_print_backend_cups_print_stream (GtkPrintBackend         *print_backend,
397                                      GtkPrintJob             *job,
398                                      GIOChannel              *data_io,
399                                      GtkPrintJobCompleteFunc  callback,
400                                      gpointer                 user_data,
401                                      GDestroyNotify           dnotify)
402 {
403   GtkPrinterCups *cups_printer;
404   CupsPrintStreamData *ps;
405   GtkCupsRequest *request;
406   GtkPrintSettings *settings;
407   const gchar *title;
408
409   GTK_NOTE (PRINTING,
410             g_print ("CUPS Backend: %s\n", G_STRFUNC));   
411
412   cups_printer = GTK_PRINTER_CUPS (gtk_print_job_get_printer (job));
413   settings = gtk_print_job_get_settings (job);
414
415   request = gtk_cups_request_new (NULL,
416                                   GTK_CUPS_POST,
417                                   IPP_PRINT_JOB,
418                                   data_io,
419                                   NULL,
420                                   cups_printer->device_uri);
421
422   gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, 
423                                    IPP_TAG_URI, "printer-uri",
424                                    NULL, cups_printer->printer_uri);
425
426   title = gtk_print_job_get_title (job);
427   if (title)
428     gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, 
429                                      IPP_TAG_NAME, "job-name", 
430                                      NULL, title);
431
432   gtk_print_settings_foreach (settings, add_cups_options, request);
433   
434   ps = g_new0 (CupsPrintStreamData, 1);
435   ps->callback = callback;
436   ps->user_data = user_data;
437   ps->dnotify = dnotify;
438   ps->job = g_object_ref (job);
439
440   cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
441                         request,
442                         (GtkPrintCupsResponseCallbackFunc) cups_print_cb,
443                         ps,
444                         (GDestroyNotify)cups_free_print_stream_data);
445 }
446
447
448 static void
449 gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
450 {
451   backend_cups->list_printers_poll = FALSE;  
452   backend_cups->got_default_printer = FALSE;  
453   backend_cups->list_printers_pending = FALSE;
454
455   cups_request_default_printer (backend_cups);
456 }
457
458 static void
459 gtk_print_backend_cups_finalize (GObject *object)
460 {
461   GtkPrintBackendCups *backend_cups;
462   
463   GTK_NOTE (PRINTING,
464             g_print ("CUPS Backend: finalizing CUPS backend module\n"));
465
466   backend_cups = GTK_PRINT_BACKEND_CUPS (object);
467
468   g_free (backend_cups->default_printer);
469   backend_cups->default_printer = NULL;
470   
471   backend_parent_class->finalize (object);
472 }
473
474 static void
475 gtk_print_backend_cups_dispose (GObject *object)
476 {
477   GtkPrintBackendCups *backend_cups;
478
479   GTK_NOTE (PRINTING,
480             g_print ("CUPS Backend: %s\n", G_STRFUNC));
481
482   backend_cups = GTK_PRINT_BACKEND_CUPS (object);
483
484   if (backend_cups->list_printers_poll > 0)
485     g_source_remove (backend_cups->list_printers_poll);
486   backend_cups->list_printers_poll = 0;
487   
488   backend_parent_class->dispose (object);
489 }
490
491
492 static gboolean
493 cups_dispatch_watch_check (GSource *source)
494 {
495   GtkPrintCupsDispatchWatch *dispatch;
496   GtkCupsPollState poll_state;
497   gboolean result;
498
499   GTK_NOTE (PRINTING,
500             g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source)); 
501
502   dispatch = (GtkPrintCupsDispatchWatch *) source;
503
504   poll_state = gtk_cups_request_get_poll_state (dispatch->request);
505
506   if (dispatch->request->http != NULL)
507     {
508       if (dispatch->data_poll == NULL)
509         {
510           dispatch->data_poll = g_new0 (GPollFD, 1);
511           g_source_add_poll (source, dispatch->data_poll);
512         }
513       else
514         {
515           if (poll_state == GTK_CUPS_HTTP_READ)
516             dispatch->data_poll->events = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
517           else if (poll_state == GTK_CUPS_HTTP_WRITE)
518             dispatch->data_poll->events = G_IO_OUT | G_IO_ERR;
519           else
520             dispatch->data_poll->events = 0;
521         }
522
523 #ifdef HAVE_CUPS_API_1_2
524       dispatch->data_poll->fd = httpGetFd (dispatch->request->http);
525 #else
526       dispatch->data_poll->fd = dispatch->request->http->fd;
527 #endif
528     }
529     
530   if (poll_state != GTK_CUPS_HTTP_IDLE)  
531     if (!(dispatch->data_poll->revents & dispatch->data_poll->events)) 
532        return FALSE;
533   
534   result = gtk_cups_request_read_write (dispatch->request);
535   if (result && dispatch->data_poll != NULL)
536     {
537       g_source_remove_poll (source, dispatch->data_poll);
538       g_free (dispatch->data_poll);
539       dispatch->data_poll = NULL;
540     }
541   
542   return result;
543 }
544
545 static gboolean
546 cups_dispatch_watch_prepare (GSource *source,
547                              gint    *timeout_)
548 {
549   GtkPrintCupsDispatchWatch *dispatch;
550
551   dispatch = (GtkPrintCupsDispatchWatch *) source;
552
553   GTK_NOTE (PRINTING,
554             g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
555
556   *timeout_ = -1;
557   
558   return gtk_cups_request_read_write (dispatch->request);
559 }
560
561 static gboolean
562 cups_dispatch_watch_dispatch (GSource     *source,
563                               GSourceFunc  callback,
564                               gpointer     user_data)
565 {
566   GtkPrintCupsDispatchWatch *dispatch;
567   GtkPrintCupsResponseCallbackFunc ep_callback;  
568   GtkCupsResult *result;
569   
570   g_assert (callback != NULL);
571
572   ep_callback = (GtkPrintCupsResponseCallbackFunc) callback;
573   
574   dispatch = (GtkPrintCupsDispatchWatch *) source;
575
576   result = gtk_cups_request_get_result (dispatch->request);
577
578   GTK_NOTE (PRINTING,
579             g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
580
581   if (gtk_cups_result_is_error (result))
582     g_warning ("Error result: %s", gtk_cups_result_get_error_string (result));
583
584   ep_callback (GTK_PRINT_BACKEND (dispatch->backend), result, user_data);
585
586   return FALSE;
587 }
588
589 static void
590 cups_dispatch_watch_finalize (GSource *source)
591 {
592   GtkPrintCupsDispatchWatch *dispatch;
593
594   GTK_NOTE (PRINTING,
595             g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
596
597   dispatch = (GtkPrintCupsDispatchWatch *) source;
598
599   gtk_cups_request_free (dispatch->request);
600
601   if (dispatch->backend)
602     {
603       /* We need to unref this at idle time, because it might be the
604        * last reference to this module causing the code to be
605        * unloaded (including this particular function!)
606        * Update: Doing this at idle caused a deadlock taking the
607        * mainloop context lock while being in a GSource callout for
608        * multithreaded apps. So, for now we just disable unloading
609        * of print backends. See _gtk_print_backend_create for the
610        * disabling.
611        */
612       g_object_unref (dispatch->backend);
613       dispatch->backend = NULL;
614     }
615
616   if (dispatch->data_poll != NULL)
617     g_free (dispatch->data_poll);
618 }
619
620 static GSourceFuncs _cups_dispatch_watch_funcs = {
621   cups_dispatch_watch_prepare,
622   cups_dispatch_watch_check,
623   cups_dispatch_watch_dispatch,
624   cups_dispatch_watch_finalize
625 };
626
627
628 static void
629 cups_request_execute (GtkPrintBackendCups              *print_backend,
630                       GtkCupsRequest                   *request,
631                       GtkPrintCupsResponseCallbackFunc  callback,
632                       gpointer                          user_data,
633                       GDestroyNotify                    notify)
634 {
635   GtkPrintCupsDispatchWatch *dispatch;
636
637   dispatch = (GtkPrintCupsDispatchWatch *) g_source_new (&_cups_dispatch_watch_funcs, 
638                                                          sizeof (GtkPrintCupsDispatchWatch));
639
640   GTK_NOTE (PRINTING,
641             g_print ("CUPS Backend: %s <source %p> - Executing cups request on server '%s' and resource '%s'\n", G_STRFUNC, dispatch, request->server, request->resource));
642
643   dispatch->request = request;
644   dispatch->backend = g_object_ref (print_backend);
645   dispatch->data_poll = NULL;
646
647   g_source_set_callback ((GSource *) dispatch, (GSourceFunc) callback, user_data, notify);
648
649   g_source_attach ((GSource *) dispatch, NULL);
650   g_source_unref ((GSource *) dispatch);
651 }
652
653 static void
654 cups_request_printer_info_cb (GtkPrintBackendCups *backend,
655                               GtkCupsResult       *result,
656                               gpointer             user_data)
657 {
658   ipp_attribute_t *attr;
659   ipp_t *response;
660   gchar *printer_name;
661   GtkPrinterCups *cups_printer;
662   GtkPrinter *printer;
663   gchar *loc;
664   gchar *desc;
665   gchar *state_msg;
666   int job_count;
667   gboolean status_changed;  
668
669   g_assert (GTK_IS_PRINT_BACKEND_CUPS (backend));
670
671   printer_name = (gchar *)user_data;
672   printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (backend),
673                                             printer_name);
674
675   GTK_NOTE (PRINTING,
676             g_print ("CUPS Backend: %s - Got printer info for printer '%s'\n", G_STRFUNC, printer_name));
677
678   if (!printer)
679     {
680       GTK_NOTE (PRINTING,
681             g_print ("CUPS Backend: Could not find printer called '%s'\n", printer_name));
682       return;
683     }
684
685   cups_printer = GTK_PRINTER_CUPS (printer);
686   
687   if (gtk_cups_result_is_error (result))
688     {
689       if (gtk_printer_is_new (printer))
690         {
691           gtk_print_backend_remove_printer (GTK_PRINT_BACKEND (backend),
692                                             printer);
693           return;
694         }
695       else
696         return; /* TODO: mark as inactive printer */
697     }
698
699   response = gtk_cups_result_get_response (result);
700
701   /* TODO: determine printer type and use correct icon */
702   gtk_printer_set_icon_name (printer, "gtk-print");
703  
704   state_msg = "";
705   loc = "";
706   desc = "";
707   job_count = 0;
708   for (attr = response->attrs; attr != NULL; attr = attr->next) 
709     {
710       if (!attr->name)
711         continue;
712
713       _CUPS_MAP_ATTR_STR (attr, loc, "printer-location");
714       _CUPS_MAP_ATTR_STR (attr, desc, "printer-info");
715       _CUPS_MAP_ATTR_STR (attr, state_msg, "printer-state-message");
716       _CUPS_MAP_ATTR_INT (attr, cups_printer->state, "printer-state");
717       _CUPS_MAP_ATTR_INT (attr, job_count, "queued-job-count");
718     }
719
720   status_changed = gtk_printer_set_job_count (printer, job_count);
721   
722   status_changed |= gtk_printer_set_location (printer, loc);
723   status_changed |= gtk_printer_set_description (printer, desc);
724   status_changed |= gtk_printer_set_state_message (printer, state_msg);
725
726   if (status_changed)
727     g_signal_emit_by_name (GTK_PRINT_BACKEND (backend),
728                            "printer-status-changed", printer); 
729 }
730
731 static void
732 cups_request_printer_info (GtkPrintBackendCups *print_backend,
733                            const gchar         *printer_name)
734 {
735   GtkCupsRequest *request;
736   gchar *printer_uri;
737   static const char * const pattrs[] =  /* Attributes we're interested in */
738     {
739       "printer-location",
740       "printer-info",
741       "printer-state-message",
742       "printer-state",
743       "queued-job-count"
744     };
745
746   request = gtk_cups_request_new (NULL,
747                                   GTK_CUPS_POST,
748                                   IPP_GET_PRINTER_ATTRIBUTES,
749                                   NULL,
750                                   NULL,
751                                   NULL);
752
753   printer_uri = g_strdup_printf ("ipp://localhost/printers/%s",
754                                   printer_name);
755   gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
756                                    "printer-uri", NULL, printer_uri);
757
758   GTK_NOTE (PRINTING,
759             g_print ("CUPS Backend: %s - Requesting printer info for URI '%s'\n", G_STRFUNC, printer_uri));
760
761   g_free (printer_uri);
762
763   gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
764                                     "requested-attributes", G_N_ELEMENTS (pattrs),
765                                     NULL, pattrs);
766  
767   cups_request_execute (print_backend,
768                         request,
769                         (GtkPrintCupsResponseCallbackFunc) cups_request_printer_info_cb,
770                         g_strdup (printer_name),
771                         (GDestroyNotify) g_free);
772 }
773
774
775 typedef struct {
776   GtkPrintBackendCups *print_backend;
777   GtkPrintJob *job;
778   int job_id;
779   int counter;
780 } CupsJobPollData;
781
782 static void
783 job_object_died (gpointer  user_data,
784                  GObject  *where_the_object_was)
785 {
786   CupsJobPollData *data = user_data;
787   data->job = NULL;
788 }
789
790 static void
791 cups_job_poll_data_free (CupsJobPollData *data)
792 {
793   if (data->job)
794     g_object_weak_unref (G_OBJECT (data->job), job_object_died, data);
795     
796   g_free (data);
797 }
798
799 static void
800 cups_request_job_info_cb (GtkPrintBackendCups *print_backend,
801                           GtkCupsResult       *result,
802                           gpointer             user_data)
803 {
804   CupsJobPollData *data = user_data;
805   ipp_attribute_t *attr;
806   ipp_t *response;
807   int state;
808   gboolean done;
809
810   if (data->job == NULL)
811     {
812       cups_job_poll_data_free (data);
813       return;
814     }
815
816   data->counter++;
817   
818   response = gtk_cups_result_get_response (result);
819
820   state = 0;
821   for (attr = response->attrs; attr != NULL; attr = attr->next) 
822     {
823       if (!attr->name)
824         continue;
825       
826       _CUPS_MAP_ATTR_INT (attr, state, "job-state");
827     }
828   
829   done = FALSE;
830   switch (state)
831     {
832     case IPP_JOB_PENDING:
833     case IPP_JOB_HELD:
834     case IPP_JOB_STOPPED:
835       gtk_print_job_set_status (data->job,
836                                 GTK_PRINT_STATUS_PENDING);
837       break;
838     case IPP_JOB_PROCESSING:
839       gtk_print_job_set_status (data->job,
840                                 GTK_PRINT_STATUS_PRINTING);
841       break;
842     default:
843     case IPP_JOB_CANCELLED:
844     case IPP_JOB_ABORTED:
845       gtk_print_job_set_status (data->job,
846                                 GTK_PRINT_STATUS_FINISHED_ABORTED);
847       done = TRUE;
848       break;
849     case 0:
850     case IPP_JOB_COMPLETED:
851       gtk_print_job_set_status (data->job,
852                                 GTK_PRINT_STATUS_FINISHED);
853       done = TRUE;
854       break;
855     }
856
857   if (!done && data->job != NULL)
858     {
859       guint32 timeout;
860
861       if (data->counter < 5)
862         timeout = 100;
863       else if (data->counter < 10)
864         timeout = 500;
865       else
866         timeout = 1000;
867       
868       g_timeout_add (timeout, cups_job_info_poll_timeout, data);
869     }
870   else
871     cups_job_poll_data_free (data);    
872 }
873
874 static void
875 cups_request_job_info (CupsJobPollData *data)
876 {
877   GtkCupsRequest *request;
878   gchar *job_uri;
879
880   request = gtk_cups_request_new (NULL,
881                                   GTK_CUPS_POST,
882                                   IPP_GET_JOB_ATTRIBUTES,
883                                   NULL,
884                                   NULL,
885                                   NULL);
886
887   job_uri = g_strdup_printf ("ipp://localhost/jobs/%d", data->job_id);
888   gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
889                                    "job-uri", NULL, job_uri);
890   g_free (job_uri);
891
892   cups_request_execute (data->print_backend,
893                         request,
894                         (GtkPrintCupsResponseCallbackFunc) cups_request_job_info_cb,
895                         data,
896                         NULL);
897 }
898
899 static gboolean
900 cups_job_info_poll_timeout (gpointer user_data)
901 {
902   CupsJobPollData *data = user_data;
903   
904   if (data->job == NULL)
905     cups_job_poll_data_free (data);
906   else
907     cups_request_job_info (data);
908   
909   return FALSE;
910 }
911
912 static void
913 cups_begin_polling_info (GtkPrintBackendCups *print_backend,
914                          GtkPrintJob         *job,
915                          gint                 job_id)
916 {
917   CupsJobPollData *data;
918
919   data = g_new0 (CupsJobPollData, 1);
920
921   data->print_backend = print_backend;
922   data->job = job;
923   data->job_id = job_id;
924   data->counter = 0;
925
926   g_object_weak_ref (G_OBJECT (job), job_object_died, data);
927
928   cups_request_job_info (data);
929 }
930
931 static void
932 mark_printer_inactive (GtkPrinter      *printer, 
933                        GtkPrintBackend *backend)
934 {
935   gtk_printer_set_is_active (printer, FALSE);
936   g_signal_emit_by_name (backend, "printer-removed", printer);
937 }
938
939 static gint
940 find_printer (GtkPrinter  *printer, 
941               const gchar *find_name)
942 {
943   const gchar *printer_name;
944
945   printer_name = gtk_printer_get_name (printer);
946   return g_ascii_strcasecmp (printer_name, find_name);
947 }
948
949 static void
950 cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
951                               GtkCupsResult       *result,
952                               gpointer             user_data)
953 {
954   GtkPrintBackend *backend = GTK_PRINT_BACKEND (cups_backend);
955   ipp_attribute_t *attr;
956   ipp_t *response;
957   gboolean list_has_changed;
958   GList *removed_printer_checklist;
959
960   list_has_changed = FALSE;
961
962   GTK_NOTE (PRINTING,
963             g_print ("CUPS Backend: %s\n", G_STRFUNC));
964
965   cups_backend->list_printers_pending = FALSE;
966
967   if (gtk_cups_result_is_error (result))
968     {
969       g_warning ("Error getting printer list: %s", 
970                  gtk_cups_result_get_error_string (result));
971
972       goto done;
973     }
974   
975   /* Gather the names of the printers in the current queue
976    * so we may check to see if they were removed 
977    */
978   removed_printer_checklist = gtk_print_backend_get_printer_list (backend);
979                                                                   
980   response = gtk_cups_result_get_response (result);
981
982   for (attr = response->attrs; attr != NULL; attr = attr->next)
983     {
984       GtkPrinter *printer;
985       const gchar *printer_name;
986       const gchar *printer_uri;
987       const gchar *member_uris;
988       GList *node;
989       
990       /* Skip leading attributes until we hit a printer...
991        */
992       while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
993         attr = attr->next;
994
995       if (attr == NULL)
996         break;
997
998       printer_name = NULL;
999       printer_uri = NULL;
1000       member_uris = NULL;
1001       while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
1002       {
1003         if (strcmp (attr->name, "printer-name") == 0 &&
1004             attr->value_tag == IPP_TAG_NAME)
1005           printer_name = attr->values[0].string.text;
1006         else if (strcmp (attr->name, "printer-uri-supported") == 0 &&
1007                  attr->value_tag == IPP_TAG_URI)
1008           printer_uri = attr->values[0].string.text;
1009         else if (strcmp (attr->name, "member-uris") == 0 &&
1010                  attr->value_tag == IPP_TAG_URI)
1011           member_uris = attr->values[0].string.text;
1012         else
1013           {
1014             GTK_NOTE (PRINTING,
1015                       g_print ("CUPS Backend: Attribute %s ignored", attr->name));
1016           }
1017
1018         attr = attr->next;
1019       }
1020
1021       if (printer_name == NULL ||
1022           (printer_uri == NULL && member_uris == NULL))
1023       {
1024         if (attr == NULL)
1025           break;
1026         else
1027           continue;
1028       }
1029    
1030       /* remove name from checklist if it was found */
1031       node = g_list_find_custom (removed_printer_checklist, printer_name, (GCompareFunc) find_printer);
1032       removed_printer_checklist = g_list_delete_link (removed_printer_checklist, node);
1033  
1034       printer = gtk_print_backend_find_printer (backend, printer_name);
1035       if (!printer)
1036         {
1037           GtkPrinterCups *cups_printer;
1038           char uri[HTTP_MAX_URI];       /* Printer URI */
1039           char method[HTTP_MAX_URI];    /* Method/scheme name */
1040           char username[HTTP_MAX_URI];  /* Username:password */
1041           char hostname[HTTP_MAX_URI];  /* Hostname */
1042           char resource[HTTP_MAX_URI];  /* Resource name */
1043           int  port;                    /* Port number */
1044           
1045           list_has_changed = TRUE;
1046           cups_printer = gtk_printer_cups_new (printer_name, backend);
1047
1048           cups_printer->device_uri = g_strdup_printf ("/printers/%s", printer_name);
1049
1050           /* Check to see if we are looking at a class */
1051           if (member_uris)
1052             {
1053               cups_printer->printer_uri = g_strdup (member_uris);
1054               /* TODO if member_uris is a class we need to recursivly find a printer */
1055               GTK_NOTE (PRINTING,
1056                         g_print ("CUPS Backend: Found class with printer %s\n", member_uris));
1057             }
1058           else
1059             {
1060               cups_printer->printer_uri = g_strdup (printer_uri);
1061               GTK_NOTE (PRINTING,
1062                         g_print ("CUPS Backend: Found printer %s\n", printer_uri));
1063             }
1064
1065 #if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
1066           httpSeparateURI (HTTP_URI_CODING_ALL, cups_printer->printer_uri, 
1067                            method, sizeof (method), 
1068                            username, sizeof (username),
1069                            hostname, sizeof (hostname),
1070                            &port, 
1071                            resource, sizeof (resource));
1072
1073 #else
1074           httpSeparate (cups_printer->printer_uri, 
1075                         method, 
1076                         username, 
1077                         hostname,
1078                         &port, 
1079                         resource);
1080 #endif
1081
1082           if (strncmp (resource, "/printers/", 10) == 0)
1083             {
1084               cups_printer->ppd_name = g_strdup (resource + 10);
1085               GTK_NOTE (PRINTING,
1086                         g_print ("CUPS Backend: Setting ppd name '%s' for printer/class '%s'\n", cups_printer->ppd_name, printer_name));
1087             }
1088
1089           gethostname (uri, sizeof (uri));
1090           if (strcasecmp (uri, hostname) == 0)
1091             strcpy (hostname, "localhost");
1092
1093           cups_printer->hostname = g_strdup (hostname);
1094           cups_printer->port = port;
1095           
1096           printer = GTK_PRINTER (cups_printer);
1097           
1098           if (cups_backend->default_printer != NULL &&
1099               strcmp (cups_backend->default_printer, gtk_printer_get_name (printer)) == 0)
1100             gtk_printer_set_is_default (printer, TRUE);
1101
1102           
1103           gtk_print_backend_add_printer (backend, printer);
1104         }
1105       else
1106         g_object_ref (printer);
1107
1108       if (!gtk_printer_is_active (printer))
1109         {
1110           gtk_printer_set_is_active (printer, TRUE);
1111           gtk_printer_set_is_new (printer, TRUE);
1112           list_has_changed = TRUE;
1113         }
1114
1115       if (gtk_printer_is_new (printer))
1116         {
1117           g_signal_emit_by_name (backend, "printer-added", printer);
1118
1119           gtk_printer_set_is_new (printer, FALSE);
1120         }
1121
1122       cups_request_printer_info (cups_backend, gtk_printer_get_name (printer));
1123
1124       /* The ref is held by GtkPrintBackend, in add_printer() */
1125       g_object_unref (printer);
1126       
1127       if (attr == NULL)
1128         break;
1129     }
1130
1131   /* look at the removed printers checklist and mark any printer
1132      as inactive if it is in the list, emitting a printer_removed signal */
1133   if (removed_printer_checklist != NULL)
1134     {
1135       g_list_foreach (removed_printer_checklist, (GFunc) mark_printer_inactive, backend);
1136       g_list_free (removed_printer_checklist);
1137       list_has_changed = TRUE;
1138     }
1139   
1140 done:
1141   if (list_has_changed)
1142     g_signal_emit_by_name (backend, "printer-list-changed");
1143   
1144   gtk_print_backend_set_list_done (backend);
1145 }
1146
1147 static gboolean
1148 cups_request_printer_list (GtkPrintBackendCups *cups_backend)
1149 {
1150   GtkCupsRequest *request;
1151   static const char * const pattrs[] =  /* Attributes we're interested in */
1152     {
1153       "printer-name",
1154       "printer-uri-supported",
1155       "member-uris"
1156     };
1157  
1158   if (cups_backend->list_printers_pending ||
1159       !cups_backend->got_default_printer)
1160     return TRUE;
1161
1162   g_object_ref (cups_backend);
1163
1164   GDK_THREADS_LEAVE ();
1165
1166   cups_backend->list_printers_pending = TRUE;
1167
1168   request = gtk_cups_request_new (NULL,
1169                                   GTK_CUPS_POST,
1170                                   CUPS_GET_PRINTERS,
1171                                   NULL,
1172                                   NULL,
1173                                   NULL);
1174
1175   gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1176                                     "requested-attributes", G_N_ELEMENTS (pattrs),
1177                                     NULL, pattrs);
1178
1179   cups_request_execute (cups_backend,
1180                         request,
1181                         (GtkPrintCupsResponseCallbackFunc) cups_request_printer_list_cb,
1182                         request,
1183                         NULL);
1184
1185   GDK_THREADS_ENTER ();
1186
1187   g_object_unref (cups_backend);
1188
1189   return TRUE;
1190 }
1191
1192 static void
1193 cups_get_printer_list (GtkPrintBackend *backend)
1194 {
1195   GtkPrintBackendCups *cups_backend;
1196
1197   cups_backend = GTK_PRINT_BACKEND_CUPS (backend);
1198   if (cups_backend->list_printers_poll == 0)
1199     {
1200       cups_request_printer_list (cups_backend);
1201       cups_backend->list_printers_poll = gdk_threads_add_timeout (3000,
1202                                                         (GSourceFunc) cups_request_printer_list,
1203                                                         backend);
1204     }
1205 }
1206
1207 typedef struct {
1208   GtkPrinterCups *printer;
1209   GIOChannel *ppd_io;
1210   http_t *http;
1211 } GetPPDData;
1212
1213 static void
1214 get_ppd_data_free (GetPPDData *data)
1215 {
1216   GTK_NOTE (PRINTING,
1217             g_print ("CUPS Backend: %s\n", G_STRFUNC));
1218   httpClose (data->http);
1219   g_io_channel_unref (data->ppd_io);
1220   g_object_unref (data->printer);
1221   g_free (data);
1222 }
1223
1224 static void
1225 cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
1226                      GtkCupsResult       *result,
1227                      GetPPDData          *data)
1228 {
1229   ipp_t *response;
1230   GtkPrinter *printer;
1231
1232   GTK_NOTE (PRINTING,
1233             g_print ("CUPS Backend: %s\n", G_STRFUNC));
1234
1235   printer = GTK_PRINTER (data->printer);
1236   GTK_PRINTER_CUPS (printer)->reading_ppd = FALSE;
1237
1238   if (gtk_cups_result_is_error (result))
1239     {
1240       g_signal_emit_by_name (printer, "details-acquired", FALSE);
1241       return;
1242     }
1243
1244   response = gtk_cups_result_get_response (result);
1245
1246   /* let ppdOpenFd take over the ownership of the open file */
1247   g_io_channel_seek_position (data->ppd_io, 0, G_SEEK_SET, NULL);
1248   data->printer->ppd_file = ppdOpenFd (dup (g_io_channel_unix_get_fd (data->ppd_io)));
1249   
1250   gtk_printer_set_has_details (printer, TRUE);
1251   g_signal_emit_by_name (printer, "details-acquired", TRUE);
1252 }
1253
1254 static void
1255 cups_request_ppd (GtkPrinter *printer)
1256 {
1257   GError *error;
1258   GtkPrintBackend *print_backend;
1259   GtkPrinterCups *cups_printer;
1260   GtkCupsRequest *request;
1261   char *ppd_filename;
1262   gchar *resource;
1263   http_t *http;
1264   GetPPDData *data;
1265   int fd;
1266
1267   cups_printer = GTK_PRINTER_CUPS (printer);
1268
1269   error = NULL;
1270
1271   GTK_NOTE (PRINTING,
1272             g_print ("CUPS Backend: %s\n", G_STRFUNC));
1273
1274   http = httpConnectEncrypt (cups_printer->hostname, 
1275                              cups_printer->port,
1276                              cupsEncryption ());
1277   
1278   data = g_new0 (GetPPDData, 1);
1279
1280   fd = g_file_open_tmp ("gtkprint_ppd_XXXXXX", 
1281                         &ppd_filename, 
1282                         &error);
1283
1284 #ifdef G_ENABLE_DEBUG 
1285   /* If we are debugging printing don't delete the tmp files */
1286   if (!(gtk_debug_flags & GTK_DEBUG_PRINTING))
1287     unlink (ppd_filename);
1288 #else
1289   unlink (ppd_filename);
1290 #endif /* G_ENABLE_DEBUG */
1291
1292   if (error != NULL)
1293     {
1294       g_warning ("%s", error->message);
1295       g_error_free (error);
1296       httpClose (http);
1297       g_free (ppd_filename);
1298       g_free (data);
1299
1300       g_signal_emit_by_name (printer, "details-acquired", FALSE);
1301       return;
1302     }
1303     
1304   data->http = http;
1305   fchmod (fd, S_IRUSR | S_IWUSR);
1306   data->ppd_io = g_io_channel_unix_new (fd);
1307   g_io_channel_set_encoding (data->ppd_io, NULL, NULL);
1308   g_io_channel_set_close_on_unref (data->ppd_io, TRUE);
1309
1310   data->printer = g_object_ref (printer);
1311
1312   resource = g_strdup_printf ("/printers/%s.ppd", 
1313                               gtk_printer_cups_get_ppd_name (GTK_PRINTER_CUPS (printer)));
1314
1315   request = gtk_cups_request_new (data->http,
1316                                   GTK_CUPS_GET,
1317                                   0,
1318                                   data->ppd_io,
1319                                   cups_printer->hostname,
1320                                   resource);
1321
1322   GTK_NOTE (PRINTING,
1323             g_print ("CUPS Backend: Requesting resource %s to be written to temp file %s\n", resource, ppd_filename));
1324
1325   g_free (resource);
1326   g_free (ppd_filename);
1327
1328   cups_printer->reading_ppd = TRUE;
1329
1330   print_backend = gtk_printer_get_backend (printer);
1331
1332   cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
1333                         request,
1334                         (GtkPrintCupsResponseCallbackFunc) cups_request_ppd_cb,
1335                         data,
1336                         (GDestroyNotify)get_ppd_data_free);
1337 }
1338
1339
1340 static void
1341 cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
1342                                  GtkCupsResult       *result,
1343                                  gpointer             user_data)
1344 {
1345   ipp_t *response;
1346   ipp_attribute_t *attr;
1347
1348   response = gtk_cups_result_get_response (result);
1349   
1350   if ((attr = ippFindAttribute (response, "printer-name", IPP_TAG_NAME)) != NULL)
1351     print_backend->default_printer = g_strdup (attr->values[0].string.text);
1352
1353   print_backend->got_default_printer = TRUE;
1354
1355   /* Make sure to kick off get_printers if we are polling it, 
1356    * as we could have blocked this reading the default printer 
1357    */
1358   if (print_backend->list_printers_poll != 0)
1359     cups_request_printer_list (print_backend);
1360 }
1361
1362 static void
1363 cups_request_default_printer (GtkPrintBackendCups *print_backend)
1364 {
1365   GtkCupsRequest *request;
1366   const char *str;
1367
1368   if ((str = g_getenv ("LPDEST")) != NULL)
1369     {
1370       print_backend->default_printer = g_strdup (str);
1371       print_backend->got_default_printer = TRUE;
1372       return;
1373     }
1374   else if ((str = g_getenv ("PRINTER")) != NULL &&
1375            strcmp (str, "lp") != 0)
1376     {
1377       print_backend->default_printer = g_strdup (str);
1378       print_backend->got_default_printer = TRUE;
1379       return;
1380     }
1381   
1382   request = gtk_cups_request_new (NULL,
1383                                   GTK_CUPS_POST,
1384                                   CUPS_GET_DEFAULT,
1385                                   NULL,
1386                                   NULL,
1387                                   NULL);
1388   
1389   cups_request_execute (print_backend,
1390                         request,
1391                         (GtkPrintCupsResponseCallbackFunc) cups_request_default_printer_cb,
1392                         g_object_ref (print_backend),
1393                         g_object_unref);
1394 }
1395
1396 static void
1397 cups_printer_request_details (GtkPrinter *printer)
1398 {
1399   GtkPrinterCups *cups_printer;
1400
1401   cups_printer = GTK_PRINTER_CUPS (printer);
1402   if (!cups_printer->reading_ppd && 
1403       gtk_printer_cups_get_ppd (cups_printer) == NULL)
1404     cups_request_ppd (printer); 
1405 }
1406
1407 static char *
1408 ppd_text_to_utf8 (ppd_file_t *ppd_file, 
1409                   const char *text)
1410 {
1411   const char *encoding = NULL;
1412   char *res;
1413   
1414   if (g_ascii_strcasecmp (ppd_file->lang_encoding, "UTF-8") == 0)
1415     {
1416       return g_strdup (text);
1417     }
1418   else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin1") == 0)
1419     {
1420       encoding = "ISO-8859-1";
1421     }
1422   else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin2") == 0)
1423     {
1424       encoding = "ISO-8859-2";
1425     }
1426   else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin5") == 0)
1427     {
1428       encoding = "ISO-8859-5";
1429     }
1430   else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "JIS83-RKSJ") == 0)
1431     {
1432       encoding = "SHIFT-JIS";
1433     }
1434   else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "MacStandard") == 0)
1435     {
1436       encoding = "MACINTOSH";
1437     }
1438   else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "WindowsANSI") == 0)
1439     {
1440       encoding = "WINDOWS-1252";
1441     }
1442   else 
1443     {
1444       /* Fallback, try iso-8859-1... */
1445       encoding = "ISO-8859-1";
1446     }
1447
1448   res = g_convert (text, -1, "UTF-8", encoding, NULL, NULL, NULL);
1449
1450   if (res == NULL)
1451     {
1452       g_warning ("unable to convert PPD text");
1453       res = g_strdup ("???");
1454     }
1455   
1456   return res;
1457 }
1458
1459 /* TODO: Add more translations for common settings here */
1460
1461 static const struct {
1462   const char *keyword;
1463   const char *translation;
1464 } cups_option_translations[] = {
1465   { "Duplex", N_("Two Sided") },
1466   { "MediaType", N_("Paper Type") },
1467   { "InputSlot", N_("Paper Source") },
1468   { "OutputBin", N_("Output Tray") },
1469 };
1470
1471
1472 static const struct {
1473   const char *keyword;
1474   const char *choice;
1475   const char *translation;
1476 } cups_choice_translations[] = {
1477   { "Duplex", "None", N_("One Sided") },
1478   { "InputSlot", "Auto", N_("Auto Select") },
1479   { "InputSlot", "AutoSelect", N_("Auto Select") },
1480   { "InputSlot", "Default", N_("Printer Default") },
1481   { "InputSlot", "None", N_("Printer Default") },
1482   { "InputSlot", "PrinterDefault", N_("Printer Default") },
1483   { "InputSlot", "Unspecified", N_("Auto Select") },
1484 };
1485
1486 static const struct {
1487   const char *ppd_keyword;
1488   const char *name;
1489 } option_names[] = {
1490   {"Duplex", "gtk-duplex" },
1491   {"MediaType", "gtk-paper-type"},
1492   {"InputSlot", "gtk-paper-source"},
1493   {"OutputBin", "gtk-output-tray"},
1494 };
1495
1496 /* keep sorted when changing */
1497 static const char *color_option_whitelist[] = {
1498   "BRColorEnhancement",
1499   "BRColorMatching",
1500   "BRColorMatching",
1501   "BRColorMode",
1502   "BRGammaValue",
1503   "BRImprovedGray",
1504   "BlackSubstitution",
1505   "ColorModel",
1506   "HPCMYKInks",
1507   "HPCSGraphics",
1508   "HPCSImages",
1509   "HPCSText",
1510   "HPColorSmart",
1511   "RPSBlackMode",
1512   "RPSBlackOverPrint",
1513   "Rcmyksimulation",
1514 };
1515
1516 /* keep sorted when changing */
1517 static const char *color_group_whitelist[] = {
1518   "ColorPage",
1519   "FPColorWise1",
1520   "FPColorWise2",
1521   "FPColorWise3",
1522   "FPColorWise4",
1523   "FPColorWise5",
1524   "HPColorOptionsPanel",
1525 };
1526   
1527 /* keep sorted when changing */
1528 static const char *image_quality_option_whitelist[] = {
1529   "BRDocument",
1530   "BRHalfTonePattern",
1531   "BRNormalPrt",
1532   "BRPrintQuality",
1533   "BitsPerPixel",
1534   "Darkness",
1535   "Dithering",
1536   "EconoMode",
1537   "Economode",
1538   "HPEconoMode",
1539   "HPEdgeControl",
1540   "HPGraphicsHalftone",
1541   "HPHalftone",
1542   "HPLJDensity",
1543   "HPPhotoHalftone",
1544   "OutputMode",
1545   "REt",
1546   "RPSBitsPerPixel",
1547   "RPSDitherType",
1548   "Resolution",
1549   "ScreenLock",
1550   "Smoothing",
1551   "TonerSaveMode",
1552   "UCRGCRForImage",
1553 };
1554
1555 /* keep sorted when changing */
1556 static const char *image_quality_group_whitelist[] = {
1557   "FPImageQuality1",
1558   "FPImageQuality2",
1559   "FPImageQuality3",
1560   "ImageQualityPage",
1561 };
1562
1563 /* keep sorted when changing */
1564 static const char * finishing_option_whitelist[] = {
1565   "BindColor",
1566   "BindEdge",
1567   "BindType",
1568   "BindWhen",
1569   "Booklet",
1570   "FoldType",
1571   "FoldWhen",
1572   "HPStaplerOptions",
1573   "Jog",
1574   "Slipsheet",
1575   "Sorter",
1576   "StapleLocation",
1577   "StapleOrientation",
1578   "StapleWhen",
1579   "StapleX",
1580   "StapleY",
1581 };
1582
1583 /* keep sorted when changing */
1584 static const char *finishing_group_whitelist[] = {
1585   "FPFinishing1",
1586   "FPFinishing2",
1587   "FPFinishing3",
1588   "FPFinishing4",
1589   "FinishingPage",
1590   "HPFinishingPanel",
1591 };
1592
1593 /* keep sorted when changing */
1594 static const char *cups_option_blacklist[] = {
1595   "Collate",
1596   "Copies", 
1597   "OutputOrder",
1598   "PageRegion",
1599   "PageSize",
1600 };
1601
1602 static char *
1603 get_option_text (ppd_file_t   *ppd_file, 
1604                  ppd_option_t *option)
1605 {
1606   int i;
1607   char *utf8;
1608   
1609   for (i = 0; i < G_N_ELEMENTS (cups_option_translations); i++)
1610     {
1611       if (strcmp (cups_option_translations[i].keyword, option->keyword) == 0)
1612         return g_strdup (_(cups_option_translations[i].translation));
1613     }
1614
1615   utf8 = ppd_text_to_utf8 (ppd_file, option->text);
1616
1617   /* Some ppd files have spaces in the text before the colon */
1618   g_strchomp (utf8);
1619   
1620   return utf8;
1621 }
1622
1623 static char *
1624 get_choice_text (ppd_file_t   *ppd_file, 
1625                  ppd_choice_t *choice)
1626 {
1627   int i;
1628   ppd_option_t *option = choice->option;
1629   const char *keyword = option->keyword;
1630   
1631   for (i = 0; i < G_N_ELEMENTS (cups_choice_translations); i++)
1632     {
1633       if (strcmp (cups_choice_translations[i].keyword, keyword) == 0 &&
1634           strcmp (cups_choice_translations[i].choice, choice->choice) == 0)
1635         return g_strdup (_(cups_choice_translations[i].translation));
1636     }
1637   return ppd_text_to_utf8 (ppd_file, choice->text);
1638 }
1639
1640 static gboolean
1641 group_has_option (ppd_group_t  *group, 
1642                   ppd_option_t *option)
1643 {
1644   int i;
1645
1646   if (group == NULL)
1647     return FALSE;
1648   
1649   if (group->num_options > 0 &&
1650       option >= group->options && option < group->options + group->num_options)
1651     return TRUE;
1652   
1653   for (i = 0; i < group->num_subgroups; i++)
1654     {
1655       if (group_has_option (&group->subgroups[i],option))
1656         return TRUE;
1657     }
1658   return FALSE;
1659 }
1660
1661 static void
1662 set_option_off (GtkPrinterOption *option)
1663 {
1664   /* Any of these will do, _set only applies the value
1665    * if its allowed of the option */
1666   gtk_printer_option_set (option, "False");
1667   gtk_printer_option_set (option, "Off");
1668   gtk_printer_option_set (option, "None");
1669 }
1670
1671 static gboolean
1672 value_is_off (const char *value)
1673 {
1674   return  (strcasecmp (value, "None") == 0 ||
1675            strcasecmp (value, "Off") == 0 ||
1676            strcasecmp (value, "False") == 0);
1677 }
1678
1679 static char *
1680 ppd_group_name (ppd_group_t *group)
1681 {
1682 #if CUPS_VERSION_MAJOR > 1 || (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR > 1) || (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR == 1 && CUPS_VERSION_PATCH >= 18) 
1683   return group->name;
1684 #else
1685   return group->text;
1686 #endif
1687 }
1688
1689 static int
1690 available_choices (ppd_file_t     *ppd,
1691                    ppd_option_t   *option,
1692                    ppd_choice_t ***available,
1693                    gboolean        keep_if_only_one_option)
1694 {
1695   ppd_option_t *other_option;
1696   int i, j;
1697   gchar *conflicts;
1698   ppd_const_t *constraint;
1699   const char *choice, *other_choice;
1700   ppd_option_t *option1, *option2;
1701   ppd_group_t *installed_options;
1702   int num_conflicts;
1703   gboolean all_default;
1704   int add_auto;
1705
1706   if (available)
1707     *available = NULL;
1708
1709   conflicts = g_new0 (char, option->num_choices);
1710
1711   installed_options = NULL;
1712   for (i = 0; i < ppd->num_groups; i++)
1713     {
1714       char *name; 
1715
1716       name = ppd_group_name (&ppd->groups[i]);
1717       if (strcmp (name, "InstallableOptions") == 0)
1718         {
1719           installed_options = &ppd->groups[i];
1720           break;
1721         }
1722     }
1723
1724   for (i = ppd->num_consts, constraint = ppd->consts; i > 0; i--, constraint++)
1725     {
1726       option1 = ppdFindOption (ppd, constraint->option1);
1727       if (option1 == NULL)
1728         continue;
1729
1730       option2 = ppdFindOption (ppd, constraint->option2);
1731       if (option2 == NULL)
1732         continue;
1733
1734       if (option == option1)
1735         {
1736           choice = constraint->choice1;
1737           other_option = option2;
1738           other_choice = constraint->choice2;
1739         }
1740       else if (option == option2)
1741         {
1742           choice = constraint->choice2;
1743           other_option = option1;
1744           other_choice = constraint->choice1;
1745         }
1746       else
1747         continue;
1748
1749       /* We only care of conflicts with installed_options and
1750          PageSize */
1751       if (!group_has_option (installed_options, other_option) &&
1752           (strcmp (other_option->keyword, "PageSize") != 0))
1753         continue;
1754
1755       if (*other_choice == 0)
1756         {
1757           /* Conflict only if the installed option is not off */
1758           if (value_is_off (other_option->defchoice))
1759             continue;
1760         }
1761       /* Conflict if the installed option has the specified default */
1762       else if (strcasecmp (other_choice, other_option->defchoice) != 0)
1763         continue;
1764
1765       if (*choice == 0)
1766         {
1767           /* Conflict with all non-off choices */
1768           for (j = 0; j < option->num_choices; j++)
1769             {
1770               if (!value_is_off (option->choices[j].choice))
1771                 conflicts[j] = 1;
1772             }
1773         }
1774       else
1775         {
1776           for (j = 0; j < option->num_choices; j++)
1777             {
1778               if (strcasecmp (option->choices[j].choice, choice) == 0)
1779                 conflicts[j] = 1;
1780             }
1781         }
1782     }
1783
1784   num_conflicts = 0;
1785   all_default = TRUE;
1786   for (j = 0; j < option->num_choices; j++)
1787     {
1788       if (conflicts[j])
1789         num_conflicts++;
1790       else if (strcmp (option->choices[j].choice, option->defchoice) != 0)
1791         all_default = FALSE;
1792     }
1793
1794   if ((all_default && !keep_if_only_one_option) ||
1795       (num_conflicts == option->num_choices))
1796     {
1797       g_free (conflicts);
1798
1799       return 0;
1800     }
1801
1802   /* Some ppds don't have a "use printer default" option for
1803    * InputSlot. This means you always have to select a particular slot,
1804    * and you can't auto-pick source based on the paper size. To support
1805    * this we always add an auto option if there isn't one already. If
1806    * the user chooses the generated option we don't send any InputSlot
1807    * value when printing. The way we detect existing auto-cases is based
1808    * on feedback from Michael Sweet of cups fame.
1809    */
1810   add_auto = 0;
1811   if (strcmp (option->keyword, "InputSlot") == 0)
1812     {
1813       gboolean found_auto = FALSE;
1814       for (j = 0; j < option->num_choices; j++)
1815         {
1816           if (!conflicts[j])
1817             {
1818               if (strcmp (option->choices[j].choice, "Auto") == 0 ||
1819                   strcmp (option->choices[j].choice, "AutoSelect") == 0 ||
1820                   strcmp (option->choices[j].choice, "Default") == 0 ||
1821                   strcmp (option->choices[j].choice, "None") == 0 ||
1822                   strcmp (option->choices[j].choice, "PrinterDefault") == 0 ||
1823                   strcmp (option->choices[j].choice, "Unspecified") == 0 ||
1824                   option->choices[j].code == NULL ||
1825                   option->choices[j].code[0] == 0)
1826                 {
1827                   found_auto = TRUE;
1828                   break;
1829                 }
1830             }
1831         }
1832
1833       if (!found_auto)
1834         add_auto = 1;
1835     }
1836   
1837   if (available)
1838     {
1839       *available = g_new (ppd_choice_t *, option->num_choices - num_conflicts + add_auto);
1840
1841       i = 0;
1842       for (j = 0; j < option->num_choices; j++)
1843         {
1844           if (!conflicts[j])
1845             (*available)[i++] = &option->choices[j];
1846         }
1847
1848       if (add_auto) 
1849         (*available)[i++] = NULL;
1850     }
1851
1852   g_free (conflicts);
1853   
1854   return option->num_choices - num_conflicts + add_auto;
1855 }
1856
1857 static GtkPrinterOption *
1858 create_pickone_option (ppd_file_t   *ppd_file,
1859                        ppd_option_t *ppd_option,
1860                        const gchar  *gtk_name)
1861 {
1862   GtkPrinterOption *option;
1863   ppd_choice_t **available;
1864   char *label;
1865   int n_choices;
1866   int i;
1867 #ifdef HAVE_CUPS_API_1_2
1868   ppd_coption_t *coption;
1869 #endif
1870
1871   g_assert (ppd_option->ui == PPD_UI_PICKONE);
1872   
1873   option = NULL;
1874
1875   n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
1876   if (n_choices > 0)
1877     {
1878       
1879       /* right now only support one parameter per custom option 
1880        * if more than one print warning and only offer the default choices
1881        */
1882
1883       label = get_option_text (ppd_file, ppd_option);
1884
1885 #ifdef HAVE_CUPS_API_1_2
1886       coption = ppdFindCustomOption (ppd_file, ppd_option->keyword);
1887
1888       if (coption)
1889         {
1890           ppd_cparam_t *cparam;
1891
1892           cparam = ppdFirstCustomParam (coption);
1893
1894           if (ppdNextCustomParam (coption) == NULL)
1895             {
1896               switch (cparam->type)
1897                 {
1898                 case PPD_CUSTOM_INT:
1899                   option = gtk_printer_option_new (gtk_name, label,
1900                                          GTK_PRINTER_OPTION_TYPE_PICKONE_INT);
1901                   break;
1902                 case PPD_CUSTOM_PASSCODE:
1903                   option = gtk_printer_option_new (gtk_name, label,
1904                                          GTK_PRINTER_OPTION_TYPE_PICKONE_PASSCODE);
1905                   break;
1906                 case PPD_CUSTOM_PASSWORD:
1907                     option = gtk_printer_option_new (gtk_name, label,
1908                                          GTK_PRINTER_OPTION_TYPE_PICKONE_PASSWORD);
1909                   break;
1910                case PPD_CUSTOM_REAL:
1911                     option = gtk_printer_option_new (gtk_name, label,
1912                                          GTK_PRINTER_OPTION_TYPE_PICKONE_REAL);
1913                   break;
1914                 case PPD_CUSTOM_STRING:
1915                   option = gtk_printer_option_new (gtk_name, label,
1916                                          GTK_PRINTER_OPTION_TYPE_PICKONE_STRING);
1917                   break;
1918                 case PPD_CUSTOM_POINTS: 
1919                   g_warning ("Not Supported: PPD Custom Points Option");
1920                   break;
1921                 case PPD_CUSTOM_CURVE:
1922                   g_warning ("Not Supported: PPD Custom Curve Option");
1923                   break;
1924                 case PPD_CUSTOM_INVCURVE:       
1925                   g_warning ("Not Supported: PPD Custom Inverse Curve Option");
1926                   break;
1927                 }
1928             }
1929           else
1930             g_warning ("Not Supported: PPD Custom Option has more than one parameter");
1931         }
1932 #endif /* HAVE_CUPS_API_1_2 */
1933
1934       if (!option)
1935         option = gtk_printer_option_new (gtk_name, label,
1936                                          GTK_PRINTER_OPTION_TYPE_PICKONE);
1937       g_free (label);
1938       
1939       gtk_printer_option_allocate_choices (option, n_choices);
1940       for (i = 0; i < n_choices; i++)
1941         {
1942           if (available[i] == NULL)
1943             {
1944               /* This was auto-added */
1945               option->choices[i] = g_strdup ("gtk-ignore-value");
1946               option->choices_display[i] = g_strdup (_("Printer Default"));
1947             }
1948           else
1949             {
1950               option->choices[i] = g_strdup (available[i]->choice);
1951               option->choices_display[i] = get_choice_text (ppd_file, available[i]);
1952             }
1953         }
1954       gtk_printer_option_set (option, ppd_option->defchoice);
1955     }
1956 #ifdef PRINT_IGNORED_OPTIONS
1957   else
1958     g_warning ("Ignoring pickone %s\n", ppd_option->text);
1959 #endif
1960   g_free (available);
1961
1962   return option;
1963 }
1964
1965 static GtkPrinterOption *
1966 create_boolean_option (ppd_file_t   *ppd_file,
1967                        ppd_option_t *ppd_option,
1968                        const gchar  *gtk_name)
1969 {
1970   GtkPrinterOption *option;
1971   ppd_choice_t **available;
1972   char *label;
1973   int n_choices;
1974
1975   g_assert (ppd_option->ui == PPD_UI_BOOLEAN);
1976   
1977   option = NULL;
1978
1979   n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
1980   if (n_choices == 2)
1981     {
1982       label = get_option_text (ppd_file, ppd_option);
1983       option = gtk_printer_option_new (gtk_name, label,
1984                                        GTK_PRINTER_OPTION_TYPE_BOOLEAN);
1985       g_free (label);
1986       
1987       gtk_printer_option_allocate_choices (option, 2);
1988       option->choices[0] = g_strdup ("True");
1989       option->choices_display[0] = g_strdup ("True");
1990       option->choices[1] = g_strdup ("False");
1991       option->choices_display[1] = g_strdup ("False");
1992       
1993       gtk_printer_option_set (option, ppd_option->defchoice);
1994     }
1995 #ifdef PRINT_IGNORED_OPTIONS
1996   else
1997     g_warning ("Ignoring boolean %s\n", ppd_option->text);
1998 #endif
1999   g_free (available);
2000
2001   return option;
2002 }
2003
2004 static gchar *
2005 get_option_name (const gchar *keyword)
2006 {
2007   int i;
2008
2009   for (i = 0; i < G_N_ELEMENTS (option_names); i++)
2010     if (strcmp (option_names[i].ppd_keyword, keyword) == 0)
2011       return g_strdup (option_names[i].name);
2012
2013   return g_strdup_printf ("cups-%s", keyword);
2014 }
2015
2016 static int
2017 strptr_cmp (const void *a, 
2018             const void *b)
2019 {
2020   char **aa = (char **)a;
2021   char **bb = (char **)b;
2022   return strcmp (*aa, *bb);
2023 }
2024
2025
2026 static gboolean
2027 string_in_table (gchar       *str, 
2028                  const gchar *table[], 
2029                  gint         table_len)
2030 {
2031   return bsearch (&str, table, table_len, sizeof (char *), (void *)strptr_cmp) != NULL;
2032 }
2033
2034 #define STRING_IN_TABLE(_str, _table) (string_in_table (_str, _table, G_N_ELEMENTS (_table)))
2035
2036 static void
2037 handle_option (GtkPrinterOptionSet *set,
2038                ppd_file_t          *ppd_file,
2039                ppd_option_t        *ppd_option,
2040                ppd_group_t         *toplevel_group,
2041                GtkPrintSettings    *settings)
2042 {
2043   GtkPrinterOption *option;
2044   char *name;
2045
2046   if (STRING_IN_TABLE (ppd_option->keyword, cups_option_blacklist))
2047     return;
2048
2049   name = get_option_name (ppd_option->keyword);
2050
2051   option = NULL;
2052   if (ppd_option->ui == PPD_UI_PICKONE)
2053     {
2054       option = create_pickone_option (ppd_file, ppd_option, name);
2055     }
2056   else if (ppd_option->ui == PPD_UI_BOOLEAN)
2057     {
2058       option = create_boolean_option (ppd_file, ppd_option, name);
2059     }
2060   else
2061     g_warning ("Ignored pickmany setting %s\n", ppd_option->text);
2062   
2063   
2064   if (option)
2065     {
2066       char *name;
2067
2068       name = ppd_group_name (toplevel_group);
2069       if (STRING_IN_TABLE (name,
2070                            color_group_whitelist) ||
2071           STRING_IN_TABLE (ppd_option->keyword,
2072                            color_option_whitelist))
2073         {
2074           option->group = g_strdup ("ColorPage");
2075         }
2076       else if (STRING_IN_TABLE (name,
2077                                 image_quality_group_whitelist) ||
2078                STRING_IN_TABLE (ppd_option->keyword,
2079                                 image_quality_option_whitelist))
2080         {
2081           option->group = g_strdup ("ImageQualityPage");
2082         }
2083       else if (STRING_IN_TABLE (name,
2084                                 finishing_group_whitelist) ||
2085                STRING_IN_TABLE (ppd_option->keyword,
2086                                 finishing_option_whitelist))
2087         {
2088           option->group = g_strdup ("FinishingPage");
2089         }
2090       else
2091         {
2092           option->group = g_strdup (toplevel_group->text);
2093         }
2094
2095       set_option_from_settings (option, settings);
2096       
2097       gtk_printer_option_set_add (set, option);
2098     }
2099   
2100   g_free (name);
2101 }
2102
2103 static void
2104 handle_group (GtkPrinterOptionSet *set,
2105               ppd_file_t          *ppd_file,
2106               ppd_group_t         *group,
2107               ppd_group_t         *toplevel_group,
2108               GtkPrintSettings    *settings)
2109 {
2110   gint i;
2111   gchar *name;
2112   
2113   /* Ignore installable options */
2114   name = ppd_group_name (toplevel_group);
2115   if (strcmp (name, "InstallableOptions") == 0)
2116     return;
2117   
2118   for (i = 0; i < group->num_options; i++)
2119     handle_option (set, ppd_file, &group->options[i], toplevel_group, settings);
2120
2121   for (i = 0; i < group->num_subgroups; i++)
2122     handle_group (set, ppd_file, &group->subgroups[i], toplevel_group, settings);
2123
2124 }
2125
2126 static GtkPrinterOptionSet *
2127 cups_printer_get_options (GtkPrinter           *printer,
2128                           GtkPrintSettings     *settings,
2129                           GtkPageSetup         *page_setup,
2130                           GtkPrintCapabilities  capabilities)
2131 {
2132   GtkPrinterOptionSet *set;
2133   GtkPrinterOption *option;
2134   ppd_file_t *ppd_file;
2135   int i;
2136   char *print_at[] = { "now", "at", "on-hold" };
2137   char *n_up[] = {"1", "2", "4", "6", "9", "16" };
2138   char *prio[] = {"100", "80", "50", "30" };
2139   char *prio_display[] = {N_("Urgent"), N_("High"), N_("Medium"), N_("Low") };
2140   char *cover[] = {"none", "classified", "confidential", "secret", "standard", "topsecret", "unclassified" };
2141   char *cover_display[] = {N_("None"), N_("Classified"), N_("Confidential"), N_("Secret"), N_("Standard"), N_("Top Secret"), N_("Unclassified"),};
2142
2143
2144   set = gtk_printer_option_set_new ();
2145
2146   /* Cups specific, non-ppd related settings */
2147
2148   option = gtk_printer_option_new ("gtk-n-up", "Pages Per Sheet", GTK_PRINTER_OPTION_TYPE_PICKONE);
2149   gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up),
2150                                          n_up, n_up);
2151   gtk_printer_option_set (option, "1");
2152   set_option_from_settings (option, settings);
2153   gtk_printer_option_set_add (set, option);
2154   g_object_unref (option);
2155
2156   for (i = 0; i < G_N_ELEMENTS(prio_display); i++)
2157     prio_display[i] = _(prio_display[i]);
2158   
2159   option = gtk_printer_option_new ("gtk-job-prio", "Job Priority", GTK_PRINTER_OPTION_TYPE_PICKONE);
2160   gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (prio),
2161                                          prio, prio_display);
2162   gtk_printer_option_set (option, "50");
2163   set_option_from_settings (option, settings);
2164   gtk_printer_option_set_add (set, option);
2165   g_object_unref (option);
2166
2167   option = gtk_printer_option_new ("gtk-billing-info", "Billing Info", GTK_PRINTER_OPTION_TYPE_STRING);
2168   gtk_printer_option_set (option, "");
2169   set_option_from_settings (option, settings);
2170   gtk_printer_option_set_add (set, option);
2171   g_object_unref (option);
2172
2173   for (i = 0; i < G_N_ELEMENTS(cover_display); i++)
2174     cover_display[i] = _(cover_display[i]);
2175   
2176   option = gtk_printer_option_new ("gtk-cover-before", "Before", GTK_PRINTER_OPTION_TYPE_PICKONE);
2177   gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (cover),
2178                                          cover, cover_display);
2179   gtk_printer_option_set (option, "none");
2180   set_option_from_settings (option, settings);
2181   gtk_printer_option_set_add (set, option);
2182   g_object_unref (option);
2183
2184   option = gtk_printer_option_new ("gtk-cover-after", "After", GTK_PRINTER_OPTION_TYPE_PICKONE);
2185   gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (cover),
2186                                          cover, cover_display);
2187   gtk_printer_option_set (option, "none");
2188   set_option_from_settings (option, settings);
2189   gtk_printer_option_set_add (set, option);
2190   g_object_unref (option);
2191
2192   option = gtk_printer_option_new ("gtk-print-time", "Print at", GTK_PRINTER_OPTION_TYPE_PICKONE);
2193   gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (print_at),
2194                                          print_at, print_at);
2195   gtk_printer_option_set (option, "now");
2196   set_option_from_settings (option, settings);
2197   gtk_printer_option_set_add (set, option);
2198   g_object_unref (option);
2199   
2200   option = gtk_printer_option_new ("gtk-print-time-text", "Print at time", GTK_PRINTER_OPTION_TYPE_STRING);
2201   gtk_printer_option_set (option, "");
2202   set_option_from_settings (option, settings);
2203   gtk_printer_option_set_add (set, option);
2204   g_object_unref (option);
2205   
2206   /* Printer (ppd) specific settings */
2207   ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2208   if (ppd_file)
2209     {
2210       GtkPaperSize *paper_size;
2211       ppd_option_t *option;
2212       const gchar  *ppd_name;
2213
2214       ppdMarkDefaults (ppd_file);
2215
2216       paper_size = gtk_page_setup_get_paper_size (page_setup);
2217
2218       option = ppdFindOption (ppd_file, "PageSize");
2219       ppd_name = gtk_paper_size_get_ppd_name (paper_size);
2220       
2221       if (ppd_name)
2222         strncpy (option->defchoice, ppd_name, PPD_MAX_NAME);
2223       else
2224         {
2225           gchar *custom_name;
2226
2227           custom_name = g_strdup_printf (_("Custom.%2fx%.2f"),
2228                                          gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS),
2229                                          gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS));
2230           strncpy (option->defchoice, custom_name, PPD_MAX_NAME);
2231           g_free (custom_name);
2232         }
2233
2234       for (i = 0; i < ppd_file->num_groups; i++)
2235         handle_group (set, ppd_file, &ppd_file->groups[i], &ppd_file->groups[i], settings);
2236     }
2237
2238   return set;
2239 }
2240
2241
2242 static void
2243 mark_option_from_set (GtkPrinterOptionSet *set,
2244                       ppd_file_t          *ppd_file,
2245                       ppd_option_t        *ppd_option)
2246 {
2247   GtkPrinterOption *option;
2248   char *name = get_option_name (ppd_option->keyword);
2249
2250   option = gtk_printer_option_set_lookup (set, name);
2251
2252   if (option)
2253     ppdMarkOption (ppd_file, ppd_option->keyword, option->value);
2254   
2255   g_free (name);
2256 }
2257
2258
2259 static void
2260 mark_group_from_set (GtkPrinterOptionSet *set,
2261                      ppd_file_t          *ppd_file,
2262                      ppd_group_t         *group)
2263 {
2264   int i;
2265
2266   for (i = 0; i < group->num_options; i++)
2267     mark_option_from_set (set, ppd_file, &group->options[i]);
2268
2269   for (i = 0; i < group->num_subgroups; i++)
2270     mark_group_from_set (set, ppd_file, &group->subgroups[i]);
2271 }
2272
2273 static void
2274 set_conflicts_from_option (GtkPrinterOptionSet *set,
2275                            ppd_file_t          *ppd_file,
2276                            ppd_option_t        *ppd_option)
2277 {
2278   GtkPrinterOption *option;
2279   char *name;
2280
2281   if (ppd_option->conflicted)
2282     {
2283       name = get_option_name (ppd_option->keyword);
2284       option = gtk_printer_option_set_lookup (set, name);
2285
2286       if (option)
2287         gtk_printer_option_set_has_conflict (option, TRUE);
2288       else
2289         g_warning ("conflict for option %s ignored", ppd_option->keyword);
2290       
2291       g_free (name);
2292     }
2293 }
2294
2295 static void
2296 set_conflicts_from_group (GtkPrinterOptionSet *set,
2297                           ppd_file_t          *ppd_file,
2298                           ppd_group_t         *group)
2299 {
2300   int i;
2301
2302   for (i = 0; i < group->num_options; i++)
2303     set_conflicts_from_option (set, ppd_file, &group->options[i]);
2304
2305   for (i = 0; i < group->num_subgroups; i++)
2306     set_conflicts_from_group (set, ppd_file, &group->subgroups[i]);
2307 }
2308
2309 static gboolean
2310 cups_printer_mark_conflicts (GtkPrinter          *printer,
2311                              GtkPrinterOptionSet *options)
2312 {
2313   ppd_file_t *ppd_file;
2314   int num_conflicts;
2315   int i;
2316  
2317   ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2318
2319   if (ppd_file == NULL)
2320     return FALSE;
2321
2322   ppdMarkDefaults (ppd_file);
2323
2324   for (i = 0; i < ppd_file->num_groups; i++)
2325     mark_group_from_set (options, ppd_file, &ppd_file->groups[i]);
2326
2327   num_conflicts = ppdConflicts (ppd_file);
2328
2329   if (num_conflicts > 0)
2330     {
2331       for (i = 0; i < ppd_file->num_groups; i++)
2332         set_conflicts_from_group (options, ppd_file, &ppd_file->groups[i]);
2333     }
2334  
2335   return num_conflicts > 0;
2336 }
2337
2338 struct OptionData {
2339   GtkPrinter *printer;
2340   GtkPrinterOptionSet *options;
2341   GtkPrintSettings *settings;
2342   ppd_file_t *ppd_file;
2343 };
2344
2345 typedef struct {
2346   const char *cups;
2347   const char *standard;
2348 } NameMapping;
2349
2350 static void
2351 map_settings_to_option (GtkPrinterOption  *option,
2352                         const NameMapping  table[],
2353                         gint               n_elements,
2354                         GtkPrintSettings  *settings,
2355                         const gchar       *standard_name,
2356                         const gchar       *cups_name)
2357 {
2358   int i;
2359   char *name;
2360   const char *cups_value;
2361   const char *standard_value;
2362
2363   /* If the cups-specific setting is set, always use that */
2364   name = g_strdup_printf ("cups-%s", cups_name);
2365   cups_value = gtk_print_settings_get (settings, name);
2366   g_free (name);
2367   
2368   if (cups_value != NULL) 
2369     {
2370       gtk_printer_option_set (option, cups_value);
2371       return;
2372     }
2373
2374   /* Otherwise we try to convert from the general setting */
2375   standard_value = gtk_print_settings_get (settings, standard_name);
2376   if (standard_value == NULL)
2377     return;
2378
2379   for (i = 0; i < n_elements; i++)
2380     {
2381       if (table[i].cups == NULL && table[i].standard == NULL)
2382         {
2383           gtk_printer_option_set (option, standard_value);
2384           break;
2385         }
2386       else if (table[i].cups == NULL &&
2387                strcmp (table[i].standard, standard_value) == 0)
2388         {
2389           set_option_off (option);
2390           break;
2391         }
2392       else if (strcmp (table[i].standard, standard_value) == 0)
2393         {
2394           gtk_printer_option_set (option, table[i].cups);
2395           break;
2396         }
2397     }
2398 }
2399
2400 static void
2401 map_option_to_settings (const gchar       *value,
2402                         const NameMapping  table[],
2403                         gint               n_elements,
2404                         GtkPrintSettings  *settings,
2405                         const gchar       *standard_name,
2406                         const gchar       *cups_name)
2407 {
2408   int i;
2409   char *name;
2410
2411   for (i = 0; i < n_elements; i++)
2412     {
2413       if (table[i].cups == NULL && table[i].standard == NULL)
2414         {
2415           gtk_print_settings_set (settings,
2416                                   standard_name,
2417                                   value);
2418           break;
2419         }
2420       else if (table[i].cups == NULL && table[i].standard != NULL)
2421         {
2422           if (value_is_off (value))
2423             {
2424               gtk_print_settings_set (settings,
2425                                       standard_name,
2426                                       table[i].standard);
2427               break;
2428             }
2429         }
2430       else if (strcmp (table[i].cups, value) == 0)
2431         {
2432           gtk_print_settings_set (settings,
2433                                   standard_name,
2434                                   table[i].standard);
2435           break;
2436         }
2437     }
2438
2439   /* Always set the corresponding cups-specific setting */
2440   name = g_strdup_printf ("cups-%s", cups_name);
2441   gtk_print_settings_set (settings, name, value);
2442   g_free (name);
2443 }
2444
2445
2446 static const NameMapping paper_source_map[] = {
2447   { "Lower", "lower"},
2448   { "Middle", "middle"},
2449   { "Upper", "upper"},
2450   { "Rear", "rear"},
2451   { "Envelope", "envelope"},
2452   { "Cassette", "cassette"},
2453   { "LargeCapacity", "large-capacity"},
2454   { "AnySmallFormat", "small-format"},
2455   { "AnyLargeFormat", "large-format"},
2456   { NULL, NULL}
2457 };
2458
2459 static const NameMapping output_tray_map[] = {
2460   { "Upper", "upper"},
2461   { "Lower", "lower"},
2462   { "Rear", "rear"},
2463   { NULL, NULL}
2464 };
2465
2466 static const NameMapping duplex_map[] = {
2467   { "DuplexTumble", "vertical" },
2468   { "DuplexNoTumble", "horizontal" },
2469   { NULL, "simplex" }
2470 };
2471
2472 static const NameMapping output_mode_map[] = {
2473   { "Standard", "normal" },
2474   { "Normal", "normal" },
2475   { "Draft", "draft" },
2476   { "Fast", "draft" },
2477 };
2478
2479 static const NameMapping media_type_map[] = {
2480   { "Transparency", "transparency"},
2481   { "Standard", "stationery"},
2482   { NULL, NULL}
2483 };
2484
2485 static const NameMapping all_map[] = {
2486   { NULL, NULL}
2487 };
2488
2489
2490 static void
2491 set_option_from_settings (GtkPrinterOption *option,
2492                           GtkPrintSettings *settings)
2493 {
2494   const char *cups_value;
2495   char *value;
2496   
2497   if (settings == NULL)
2498     return;
2499
2500   if (strcmp (option->name, "gtk-paper-source") == 0)
2501     map_settings_to_option (option, paper_source_map, G_N_ELEMENTS (paper_source_map),
2502                              settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
2503   else if (strcmp (option->name, "gtk-output-tray") == 0)
2504     map_settings_to_option (option, output_tray_map, G_N_ELEMENTS (output_tray_map),
2505                             settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
2506   else if (strcmp (option->name, "gtk-duplex") == 0)
2507     map_settings_to_option (option, duplex_map, G_N_ELEMENTS (duplex_map),
2508                             settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
2509   else if (strcmp (option->name, "cups-OutputMode") == 0)
2510     map_settings_to_option (option, output_mode_map, G_N_ELEMENTS (output_mode_map),
2511                             settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
2512   else if (strcmp (option->name, "cups-Resolution") == 0)
2513     {
2514       cups_value = gtk_print_settings_get (settings, option->name);
2515       if (cups_value)
2516         gtk_printer_option_set (option, cups_value);
2517       else
2518         {
2519           int res = gtk_print_settings_get_resolution (settings);
2520           if (res != 0)
2521             {
2522               value = g_strdup_printf ("%ddpi", res);
2523               gtk_printer_option_set (option, value);
2524               g_free (value);
2525             }
2526         }
2527     }
2528   else if (strcmp (option->name, "gtk-paper-type") == 0)
2529     map_settings_to_option (option, media_type_map, G_N_ELEMENTS (media_type_map),
2530                             settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
2531   else if (strcmp (option->name, "gtk-n-up") == 0)
2532     {
2533       map_settings_to_option (option, all_map, G_N_ELEMENTS (all_map),
2534                               settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
2535     }
2536   else if (strcmp (option->name, "gtk-billing-info") == 0)
2537     {
2538       cups_value = gtk_print_settings_get (settings, "cups-job-billing");
2539       if (cups_value)
2540         gtk_printer_option_set (option, cups_value);
2541     } 
2542   else if (strcmp (option->name, "gtk-job-prio") == 0)
2543     {
2544       cups_value = gtk_print_settings_get (settings, "cups-job-priority");
2545       if (cups_value)
2546         gtk_printer_option_set (option, cups_value);
2547     } 
2548   else if (strcmp (option->name, "gtk-cover-before") == 0)
2549     {
2550       cups_value = gtk_print_settings_get (settings, "cover-before");
2551       if (cups_value)
2552         gtk_printer_option_set (option, cups_value);
2553     } 
2554   else if (strcmp (option->name, "gtk-cover-after") == 0)
2555     {
2556       cups_value = gtk_print_settings_get (settings, "cover-after");
2557       if (cups_value)
2558         gtk_printer_option_set (option, cups_value);
2559     } 
2560   else if (strcmp (option->name, "gtk-print-time") == 0)
2561     {
2562       cups_value = gtk_print_settings_get (settings, "print-at");
2563       if (cups_value)
2564         gtk_printer_option_set (option, cups_value);
2565     } 
2566   else if (strcmp (option->name, "gtk-print-time-text") == 0)
2567     {
2568       cups_value = gtk_print_settings_get (settings, "print-at-time");
2569       if (cups_value)
2570         gtk_printer_option_set (option, cups_value);
2571     } 
2572   else if (g_str_has_prefix (option->name, "cups-"))
2573     {
2574       cups_value = gtk_print_settings_get (settings, option->name);
2575       if (cups_value)
2576         gtk_printer_option_set (option, cups_value);
2577     } 
2578 }
2579
2580 static void
2581 foreach_option_get_settings (GtkPrinterOption *option,
2582                              gpointer          user_data)
2583 {
2584   struct OptionData *data = user_data;
2585   GtkPrintSettings *settings = data->settings;
2586   const char *value;
2587
2588   value = option->value;
2589
2590   if (strcmp (option->name, "gtk-paper-source") == 0)
2591     map_option_to_settings (value, paper_source_map, G_N_ELEMENTS (paper_source_map),
2592                             settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
2593   else if (strcmp (option->name, "gtk-output-tray") == 0)
2594     map_option_to_settings (value, output_tray_map, G_N_ELEMENTS (output_tray_map),
2595                             settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
2596   else if (strcmp (option->name, "gtk-duplex") == 0)
2597     map_option_to_settings (value, duplex_map, G_N_ELEMENTS (duplex_map),
2598                             settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
2599   else if (strcmp (option->name, "cups-OutputMode") == 0)
2600     map_option_to_settings (value, output_mode_map, G_N_ELEMENTS (output_mode_map),
2601                             settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
2602   else if (strcmp (option->name, "cups-Resolution") == 0)
2603     {
2604       int res = atoi (value);
2605       /* TODO: What if resolution is on XXXxYYYdpi form? */
2606       if (res != 0)
2607         gtk_print_settings_set_resolution (settings, res);
2608       gtk_print_settings_set (settings, option->name, value);
2609     }
2610   else if (strcmp (option->name, "gtk-paper-type") == 0)
2611     map_option_to_settings (value, media_type_map, G_N_ELEMENTS (media_type_map),
2612                             settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
2613   else if (strcmp (option->name, "gtk-n-up") == 0)
2614     map_option_to_settings (value, all_map, G_N_ELEMENTS (all_map),
2615                             settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
2616   else if (strcmp (option->name, "gtk-billing-info") == 0 && strlen (value) > 0)
2617     gtk_print_settings_set (settings, "cups-job-billing", value);
2618   else if (strcmp (option->name, "gtk-job-prio") == 0)
2619     gtk_print_settings_set (settings, "cups-job-priority", value);
2620   else if (strcmp (option->name, "gtk-cover-before") == 0)
2621     gtk_print_settings_set (settings, "cover-before", value);
2622   else if (strcmp (option->name, "gtk-cover-after") == 0)
2623     gtk_print_settings_set (settings, "cover-after", value);
2624   else if (strcmp (option->name, "gtk-print-time") == 0)
2625     gtk_print_settings_set (settings, "print-at", value);
2626   else if (strcmp (option->name, "gtk-print-time-text") == 0)
2627     gtk_print_settings_set (settings, "print-at-time", value);
2628   else if (g_str_has_prefix (option->name, "cups-"))
2629     gtk_print_settings_set (settings, option->name, value);
2630 }
2631
2632 static void
2633 cups_printer_get_settings_from_options (GtkPrinter          *printer,
2634                                         GtkPrinterOptionSet *options,
2635                                         GtkPrintSettings    *settings)
2636 {
2637   struct OptionData data;
2638   const char *print_at, *print_at_time;
2639
2640   data.printer = printer;
2641   data.options = options;
2642   data.settings = settings;
2643   data.ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2644  
2645   if (data.ppd_file != NULL)
2646     {
2647       GtkPrinterOption *cover_before, *cover_after;
2648       
2649       gtk_printer_option_set_foreach (options, foreach_option_get_settings, &data);
2650
2651       cover_before = gtk_printer_option_set_lookup (options, "gtk-cover-before");
2652       cover_after = gtk_printer_option_set_lookup (options, "gtk-cover-after");
2653       if (cover_before && cover_after)
2654         {
2655           char *value = g_strdup_printf ("%s,%s", cover_before->value, cover_after->value);
2656           gtk_print_settings_set (settings, "cups-job-sheets", value);
2657           g_free (value);
2658         }
2659
2660       print_at = gtk_print_settings_get (settings, "print-at");
2661       print_at_time = gtk_print_settings_get (settings, "print-at-time");
2662       if (strcmp (print_at, "at") == 0)
2663         gtk_print_settings_set (settings, "cups-job-hold-until", print_at_time);
2664       else if (strcmp (print_at, "on-hold") == 0)
2665         gtk_print_settings_set (settings, "cups-job-hold-until", "indefinite");
2666     }
2667 }
2668
2669 static void
2670 cups_printer_prepare_for_print (GtkPrinter       *printer,
2671                                 GtkPrintJob      *print_job,
2672                                 GtkPrintSettings *settings,
2673                                 GtkPageSetup     *page_setup)
2674 {
2675   GtkPageSet page_set;
2676   GtkPaperSize *paper_size;
2677   const char *ppd_paper_name;
2678   double scale;
2679
2680   print_job->print_pages = gtk_print_settings_get_print_pages (settings);
2681   print_job->page_ranges = NULL;
2682   print_job->num_page_ranges = 0;
2683   
2684   if (print_job->print_pages == GTK_PRINT_PAGES_RANGES)
2685     print_job->page_ranges =
2686       gtk_print_settings_get_page_ranges (settings,
2687                                           &print_job->num_page_ranges);
2688   
2689   if (gtk_print_settings_get_collate (settings))
2690     gtk_print_settings_set (settings, "cups-Collate", "True");
2691   print_job->collate = FALSE;
2692
2693   if (gtk_print_settings_get_reverse (settings))
2694     gtk_print_settings_set (settings, "cups-OutputOrder", "Reverse");
2695   print_job->reverse = FALSE;
2696
2697   if (gtk_print_settings_get_n_copies (settings) > 1)
2698     gtk_print_settings_set_int (settings, "cups-copies",
2699                                 gtk_print_settings_get_n_copies (settings));
2700   print_job->num_copies = 1;
2701
2702   scale = gtk_print_settings_get_scale (settings);
2703   print_job->scale = 1.0;
2704   if (scale != 100.0)
2705     print_job->scale = scale/100.0;
2706
2707   page_set = gtk_print_settings_get_page_set (settings);
2708   if (page_set == GTK_PAGE_SET_EVEN)
2709     gtk_print_settings_set (settings, "cups-page-set", "even");
2710   else if (page_set == GTK_PAGE_SET_ODD)
2711     gtk_print_settings_set (settings, "cups-page-set", "odd");
2712   print_job->page_set = GTK_PAGE_SET_ALL;
2713
2714   paper_size = gtk_page_setup_get_paper_size (page_setup);
2715   ppd_paper_name = gtk_paper_size_get_ppd_name (paper_size);
2716   if (ppd_paper_name != NULL)
2717     gtk_print_settings_set (settings, "cups-PageSize", ppd_paper_name);
2718   else
2719     {
2720       char *custom_name = g_strdup_printf ("Custom.%2fx%.2f",
2721                                            gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS),
2722                                            gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS));
2723       gtk_print_settings_set (settings, "cups-PageSize", custom_name);
2724       g_free (custom_name);
2725     }
2726
2727   print_job->rotate_to_orientation = TRUE;
2728 }
2729
2730 static GList *
2731 cups_printer_list_papers (GtkPrinter *printer)
2732 {
2733   ppd_file_t *ppd_file;
2734   ppd_size_t *size;
2735   char *display_name;
2736   GtkPageSetup *page_setup;
2737   GtkPaperSize *paper_size;
2738   ppd_option_t *option;
2739   ppd_choice_t *choice;
2740   GList *l;
2741   int i;
2742
2743   ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2744   if (ppd_file == NULL)
2745     return NULL;
2746
2747   l = NULL;
2748   
2749   for (i = 0; i < ppd_file->num_sizes; i++)
2750     {
2751       size = &ppd_file->sizes[i];
2752
2753       display_name = NULL;
2754       option = ppdFindOption (ppd_file, "PageSize");
2755       if (option)
2756         {
2757           choice = ppdFindChoice (option, size->name);
2758           if (choice)
2759             display_name = ppd_text_to_utf8 (ppd_file, choice->text);
2760         }
2761       if (display_name == NULL)
2762         display_name = g_strdup (size->name);
2763
2764       page_setup = gtk_page_setup_new ();
2765       paper_size = gtk_paper_size_new_from_ppd (size->name,
2766                                                 display_name,
2767                                                 size->width,
2768                                                 size->length);
2769       gtk_page_setup_set_paper_size (page_setup, paper_size);
2770       gtk_paper_size_free (paper_size);
2771
2772       gtk_page_setup_set_top_margin (page_setup, size->length - size->top, GTK_UNIT_POINTS);
2773       gtk_page_setup_set_bottom_margin (page_setup, size->bottom, GTK_UNIT_POINTS);
2774       gtk_page_setup_set_left_margin (page_setup, size->left, GTK_UNIT_POINTS);
2775       gtk_page_setup_set_right_margin (page_setup, size->width - size->right, GTK_UNIT_POINTS);
2776         
2777       g_free (display_name);
2778
2779       l = g_list_prepend (l, page_setup);
2780     }
2781
2782   return g_list_reverse (l);
2783 }
2784
2785 static void
2786 cups_printer_get_hard_margins (GtkPrinter *printer,
2787                                gdouble    *top,
2788                                gdouble    *bottom,
2789                                gdouble    *left,
2790                                gdouble    *right)
2791 {
2792   ppd_file_t *ppd_file;
2793
2794   ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2795   if (ppd_file == NULL)
2796     return;
2797
2798   *left = ppd_file->custom_margins[0];
2799   *bottom = ppd_file->custom_margins[1];
2800   *right = ppd_file->custom_margins[2];
2801   *top = ppd_file->custom_margins[3];
2802 }
2803
2804 static GtkPrintCapabilities
2805 cups_printer_get_capabilities (GtkPrinter *printer)
2806 {
2807   return
2808     GTK_PRINT_CAPABILITY_COPIES |
2809     GTK_PRINT_CAPABILITY_COLLATE |
2810     GTK_PRINT_CAPABILITY_REVERSE;
2811 }