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