]> Pileus Git - ~andy/gtk/blob - modules/printbackends/cups/gtkcupsutils.c
Make bits from my last commit are conditionally compiled only if cups 1.2
[~andy/gtk] / modules / printbackends / cups / gtkcupsutils.c
1 /* GTK - The GIMP Toolkit
2  * gtkcupsutils.h: Statemachine implementation of POST and GET 
3  * cup calls which can be used to create a non-blocking cups API
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 "gtkcupsutils.h"
23 #include "config.h"
24 #include "gtkdebug.h"
25
26 #include <errno.h>
27 #include <unistd.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <stdlib.h>
31 #include <time.h>
32
33 typedef void (*GtkCupsRequestStateFunc) (GtkCupsRequest *request);
34
35 static void _connect            (GtkCupsRequest *request);
36 static void _post_send          (GtkCupsRequest *request);
37 static void _post_write_request (GtkCupsRequest *request);
38 static void _post_write_data    (GtkCupsRequest *request);
39 static void _post_check         (GtkCupsRequest *request);
40 static void _post_read_response (GtkCupsRequest *request);
41
42 static void _get_send           (GtkCupsRequest *request);
43 static void _get_check          (GtkCupsRequest *request);
44 static void _get_read_data      (GtkCupsRequest *request);
45
46 struct _GtkCupsResult
47 {
48   gchar *error_msg;
49   ipp_t *ipp_response;
50
51   guint is_error : 1;
52   guint is_ipp_response : 1;
53 };
54
55
56 #define _GTK_CUPS_MAX_ATTEMPTS 10 
57 #define _GTK_CUPS_MAX_CHUNK_SIZE 8192
58
59 GtkCupsRequestStateFunc post_states[] = {_connect,
60                                          _post_send,
61                                          _post_write_request,
62                                          _post_write_data,
63                                          _post_check,
64                                          _post_read_response};
65
66 GtkCupsRequestStateFunc get_states[] = {_connect,
67                                         _get_send,
68                                         _get_check,
69                                         _get_read_data};
70
71 static void
72 gtk_cups_result_set_error (GtkCupsResult *result, 
73                            const char *error_msg,
74                            ...)
75 {
76   va_list args;
77
78   result->is_ipp_response = FALSE;
79
80   result->is_error = TRUE;
81
82   va_start (args, error_msg);
83   result->error_msg = g_strdup_vprintf (error_msg, args);
84   va_end (args);
85 }
86
87 GtkCupsRequest *
88 gtk_cups_request_new (http_t *connection,
89                       GtkCupsRequestType req_type, 
90                       gint operation_id,
91                       GIOChannel *data_io,
92                       const char *server,
93                       const char *resource)
94 {
95   GtkCupsRequest *request;
96   cups_lang_t *language;
97   
98   request = g_new0 (GtkCupsRequest, 1);
99   request->result = g_new0 (GtkCupsResult, 1);
100
101   request->result->error_msg = NULL;
102   request->result->ipp_response = NULL;
103
104   request->result->is_error = FALSE;
105   request->result->is_ipp_response = FALSE;
106
107   request->type = req_type;
108   request->state = GTK_CUPS_REQUEST_START;
109
110    if (server)
111     request->server = g_strdup (server);
112   else
113     request->server = g_strdup (cupsServer());
114
115
116   if (resource)
117     request->resource = g_strdup (resource);
118   else
119     request->resource = g_strdup ("/");
120  
121   if (connection != NULL)
122     {
123       request->http = connection;
124       request->own_http = FALSE;
125     }
126   else
127     {
128       request->http = NULL;
129       request->http = httpConnectEncrypt (request->server, ippPort(), cupsEncryption());
130
131       if (request->http)
132         httpBlocking (request->http, 0);
133         
134       request->own_http = TRUE;
135     }
136
137   request->last_status = HTTP_CONTINUE;
138
139   request->attempts = 0;
140   request->data_io = data_io;
141
142   request->ipp_request = ippNew();
143   request->ipp_request->request.op.operation_id = operation_id;
144   request->ipp_request->request.op.request_id = 1;
145
146   language = cupsLangDefault ();
147
148   gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
149                                    "attributes-charset", 
150                                    NULL, "utf-8");
151         
152   gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
153                                    "attributes-natural-language", 
154                                    NULL, language->language);
155
156   gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
157                                    "requesting-user-name",
158                                    NULL, cupsUser());
159   
160   cupsLangFree (language);
161
162   return request;
163 }
164
165 static void
166 gtk_cups_result_free (GtkCupsResult *result)
167 {
168   g_free (result->error_msg);
169
170   if (result->ipp_response)
171     ippDelete (result->ipp_response);
172
173   g_free (result);
174 }
175
176 void
177 gtk_cups_request_free (GtkCupsRequest *request)
178 {
179   if (request->own_http)
180     if (request->http)
181       httpClose (request->http);
182   
183   if (request->ipp_request)
184     ippDelete (request->ipp_request);
185
186   g_free (request->server);
187   g_free (request->resource);
188
189   gtk_cups_result_free (request->result);
190
191   g_free (request);
192 }
193
194 gboolean 
195 gtk_cups_request_read_write (GtkCupsRequest *request)
196 {
197   if (request->type == GTK_CUPS_POST)
198     post_states[request->state](request);
199   else if (request->type == GTK_CUPS_GET)
200     get_states[request->state](request);
201
202   if (request->attempts > _GTK_CUPS_MAX_ATTEMPTS && 
203       request->state != GTK_CUPS_REQUEST_DONE)
204     {
205       gtk_cups_result_set_error (request->result, "Too many failed attempts");
206       request->state = GTK_CUPS_REQUEST_DONE;
207       request->poll_state = GTK_CUPS_HTTP_IDLE;
208     }
209     
210   if (request->state == GTK_CUPS_REQUEST_DONE)
211     {
212       request->poll_state = GTK_CUPS_HTTP_IDLE;
213       return TRUE;
214     }
215   else
216     {
217       return FALSE;
218     }
219 }
220
221 GtkCupsPollState 
222 gtk_cups_request_get_poll_state (GtkCupsRequest *request)
223 {
224   return request->poll_state;
225 }
226
227
228
229 GtkCupsResult *
230 gtk_cups_request_get_result (GtkCupsRequest *request)
231 {
232   return request->result;
233 }
234
235 void            
236 gtk_cups_request_ipp_add_string (GtkCupsRequest *request,
237                                  ipp_tag_t group,
238                                  ipp_tag_t tag,
239                                  const char *name,
240                                  const char *charset,
241                                  const char *value)
242 {
243   ippAddString (request->ipp_request,
244                 group,
245                 tag,
246                 name,
247                 charset,
248                 value);
249 }
250
251 void            
252 gtk_cups_request_ipp_add_strings (GtkCupsRequest *request,
253                                   ipp_tag_t group,
254                                   ipp_tag_t tag,
255                                   const char *name,
256                                   int num_values,
257                                   const char *charset,
258                                   const char * const *values)
259 {
260   ippAddStrings (request->ipp_request,
261                  group,
262                  tag,
263                  name,
264                  num_values,
265                  charset,
266                  values);
267 }
268
269
270
271 typedef struct
272 {
273   const char    *name;
274   ipp_tag_t     value_tag;
275 } ipp_option_t;
276
277 static const ipp_option_t ipp_options[] =
278                         {
279                           { "blackplot",                IPP_TAG_BOOLEAN },
280                           { "brightness",               IPP_TAG_INTEGER },
281                           { "columns",                  IPP_TAG_INTEGER },
282                           { "copies",                   IPP_TAG_INTEGER },
283                           { "finishings",               IPP_TAG_ENUM },
284                           { "fitplot",                  IPP_TAG_BOOLEAN },
285                           { "gamma",                    IPP_TAG_INTEGER },
286                           { "hue",                      IPP_TAG_INTEGER },
287                           { "job-k-limit",              IPP_TAG_INTEGER },
288                           { "job-page-limit",           IPP_TAG_INTEGER },
289                           { "job-priority",             IPP_TAG_INTEGER },
290                           { "job-quota-period",         IPP_TAG_INTEGER },
291                           { "landscape",                IPP_TAG_BOOLEAN },
292                           { "media",                    IPP_TAG_KEYWORD },
293                           { "mirror",                   IPP_TAG_BOOLEAN },
294                           { "natural-scaling",          IPP_TAG_INTEGER },
295                           { "number-up",                IPP_TAG_INTEGER },
296                           { "orientation-requested",    IPP_TAG_ENUM },
297                           { "page-bottom",              IPP_TAG_INTEGER },
298                           { "page-left",                IPP_TAG_INTEGER },
299                           { "page-ranges",              IPP_TAG_RANGE },
300                           { "page-right",               IPP_TAG_INTEGER },
301                           { "page-top",                 IPP_TAG_INTEGER },
302                           { "penwidth",                 IPP_TAG_INTEGER },
303                           { "ppi",                      IPP_TAG_INTEGER },
304                           { "prettyprint",              IPP_TAG_BOOLEAN },
305                           { "printer-resolution",       IPP_TAG_RESOLUTION },
306                           { "print-quality",            IPP_TAG_ENUM },
307                           { "saturation",               IPP_TAG_INTEGER },
308                           { "scaling",                  IPP_TAG_INTEGER },
309                           { "sides",                    IPP_TAG_KEYWORD },
310                           { "wrap",                     IPP_TAG_BOOLEAN }
311                         };
312
313
314 static ipp_tag_t
315 _find_option_tag (const gchar *option)
316 {
317   int lower_bound, upper_bound, num_options;
318   int current_option;
319   ipp_tag_t result;
320
321   result = IPP_TAG_ZERO;
322
323   lower_bound = 0;
324   upper_bound = num_options = (int)(sizeof(ipp_options) / sizeof(ipp_options[0])) - 1;
325   
326   while (1)
327     {
328       int match;
329       current_option = (int) (((upper_bound - lower_bound) / 2) + lower_bound);
330
331       match = strcasecmp(option, ipp_options[current_option].name);
332       if (match == 0)
333         {
334           result = ipp_options[current_option].value_tag;
335           return result;
336         }
337       else if (match < 0)
338         {
339           upper_bound = current_option - 1;
340         }
341       else
342         {
343           lower_bound = current_option + 1;
344         }
345
346       if (upper_bound == lower_bound && upper_bound == current_option)
347         return result;
348
349       if (upper_bound < 0)
350         return result;
351
352       if (lower_bound > num_options)
353         return result;
354
355       if (upper_bound < lower_bound)
356         return result;
357     }
358 }
359
360 void
361 gtk_cups_request_encode_option (GtkCupsRequest *request,
362                                 const gchar *option,
363                                 const gchar *value)
364 {
365   ipp_tag_t option_tag;
366
367   g_assert (option != NULL);
368   g_assert (value != NULL);
369
370   option_tag = _find_option_tag (option);
371
372   if (option_tag == IPP_TAG_ZERO)
373     {
374       option_tag = IPP_TAG_NAME;
375       if (strcasecmp (value, "true") == 0 ||
376           strcasecmp (value, "false") == 0)
377         {
378           option_tag = IPP_TAG_BOOLEAN;
379         }
380     }
381         
382   switch (option_tag)
383     {
384       case IPP_TAG_INTEGER:
385       case IPP_TAG_ENUM:
386         ippAddInteger (request->ipp_request,
387                        IPP_TAG_OPERATION,
388                        option_tag,
389                        option,
390                        strtol (value, NULL, 0));
391         break;
392
393       case IPP_TAG_BOOLEAN:
394         {
395           char b;
396           b = 0;
397           if (!strcasecmp(value, "true") ||
398               !strcasecmp(value, "on") ||
399               !strcasecmp(value, "yes")) 
400             b = 1;
401           
402           ippAddBoolean(request->ipp_request,
403                         IPP_TAG_OPERATION,
404                         option,
405                         b);
406         
407           break;
408         }
409         
410       case IPP_TAG_RANGE:
411         {
412           char  *s;
413           int lower;
414           int upper;
415           
416           if (*value == '-')
417             {
418               lower = 1;
419               s = (char *)value;
420             }
421           else
422             lower = strtol(value, &s, 0);
423
424           if (*s == '-')
425             {
426               if (s[1])
427                 upper = strtol(s + 1, NULL, 0);
428               else
429                 upper = 2147483647;
430             }
431           else
432             upper = lower;
433          
434           ippAddRange (request->ipp_request,
435                        IPP_TAG_OPERATION,
436                        option,
437                        lower,
438                        upper);
439
440           break;
441         }
442
443       case IPP_TAG_RESOLUTION:
444         {
445           char *s;
446           int xres;
447           int yres;
448           ipp_res_t units;
449           
450           xres = strtol(value, &s, 0);
451
452           if (*s == 'x')
453             yres = strtol(s + 1, &s, 0);
454           else
455             yres = xres;
456
457           if (strcasecmp(s, "dpc") == 0)
458             units = IPP_RES_PER_CM;
459           else
460             units = IPP_RES_PER_INCH;
461           
462           ippAddResolution (request->ipp_request,
463                             IPP_TAG_OPERATION,
464                             option,
465                             units,
466                             xres,
467                             yres);
468
469           break;
470         }
471
472       default:
473         ippAddString (request->ipp_request,
474                       IPP_TAG_OPERATION,
475                       option_tag,
476                       option,
477                       NULL,
478                       value);
479
480         break;
481     }
482 }
483                                 
484
485 static void
486 _connect (GtkCupsRequest *request)
487 {
488   request->poll_state = GTK_CUPS_HTTP_IDLE;
489
490   if (request->http == NULL)
491     {
492       request->http = httpConnectEncrypt (request->server, ippPort(), cupsEncryption());
493
494       if (request->http == NULL)
495         request->attempts++;
496
497       if (request->http)
498         httpBlocking (request->http, 0);
499         
500       request->own_http = TRUE;
501     }
502   else
503     {
504       request->attempts = 0;
505       request->state++;
506
507       /* we always write to the socket after we get
508          the connection */
509       request->poll_state = GTK_CUPS_HTTP_WRITE;
510     }
511 }
512
513 static void 
514 _post_send (GtkCupsRequest *request)
515 {
516   gchar length[255];
517   struct stat data_info;
518
519   GTK_NOTE (PRINTING,
520             g_print ("CUPS Backend: %s\n", G_STRFUNC));
521
522   request->poll_state = GTK_CUPS_HTTP_WRITE;
523
524   if (request->data_io != NULL)
525     {
526       fstat (g_io_channel_unix_get_fd (request->data_io), &data_info);
527       sprintf (length, "%lu", (unsigned long)ippLength(request->ipp_request) + data_info.st_size);
528     }
529   else
530     {
531       sprintf (length, "%lu", (unsigned long)ippLength(request->ipp_request));
532     }
533         
534   httpClearFields(request->http);
535   httpSetField(request->http, HTTP_FIELD_CONTENT_LENGTH, length);
536   httpSetField(request->http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
537   httpSetField(request->http, HTTP_FIELD_AUTHORIZATION, request->http->authstring);
538
539   if (httpPost(request->http, request->resource))
540     {
541       if (httpReconnect(request->http))
542         {
543           request->state = GTK_CUPS_POST_DONE;
544           request->poll_state = GTK_CUPS_HTTP_IDLE;
545
546           gtk_cups_result_set_error (request->result, "Failed Post");
547         }
548
549       request->attempts++;
550       return;    
551     }
552         
553     request->attempts = 0;
554
555     request->state = GTK_CUPS_POST_WRITE_REQUEST;
556     request->ipp_request->state = IPP_IDLE;
557 }
558
559 static void 
560 _post_write_request (GtkCupsRequest *request)
561 {
562   ipp_state_t ipp_status;
563
564   GTK_NOTE (PRINTING,
565             g_print ("CUPS Backend: %s\n", G_STRFUNC));
566
567   request->poll_state = GTK_CUPS_HTTP_WRITE;
568   
569   ipp_status = ippWrite(request->http, request->ipp_request);
570
571   if (ipp_status == IPP_ERROR)
572     {
573       request->state = GTK_CUPS_POST_DONE;
574       request->poll_state = GTK_CUPS_HTTP_IDLE;
575  
576       gtk_cups_result_set_error (request->result, "%s",ippErrorString (cupsLastError ()));
577       return;
578     }
579
580   if (ipp_status == IPP_DATA)
581     {
582       if (request->data_io != NULL)
583         request->state = GTK_CUPS_POST_WRITE_DATA;
584       else
585         {
586           request->state = GTK_CUPS_POST_CHECK;
587           request->poll_state = GTK_CUPS_HTTP_READ;
588         }
589     }
590 }
591
592 static void 
593 _post_write_data (GtkCupsRequest *request)
594 {
595   gsize bytes;
596   char buffer[_GTK_CUPS_MAX_CHUNK_SIZE];
597   http_status_t http_status;
598
599   GTK_NOTE (PRINTING,
600             g_print ("CUPS Backend: %s\n", G_STRFUNC));
601
602   request->poll_state = GTK_CUPS_HTTP_WRITE;
603   
604   if (httpCheck (request->http))
605     http_status = httpUpdate(request->http);
606   else
607     http_status = request->last_status;
608
609   request->last_status = http_status;
610
611
612   if (http_status == HTTP_CONTINUE || http_status == HTTP_OK)
613     {
614       GIOStatus io_status;
615       GError *error;
616
617       error = NULL;
618
619       /* send data */
620       io_status =
621         g_io_channel_read_chars (request->data_io, 
622                                  buffer, 
623                                  _GTK_CUPS_MAX_CHUNK_SIZE,
624                                  &bytes,
625                                  &error);
626
627       if (io_status == G_IO_STATUS_ERROR)
628         {
629           request->state = GTK_CUPS_POST_DONE;
630           request->poll_state = GTK_CUPS_HTTP_IDLE;
631      
632           gtk_cups_result_set_error (request->result, "Error reading from cache file: %s", error->message);
633
634           g_error_free (error);
635           return;
636         }
637       else if (bytes == 0 && io_status == G_IO_STATUS_EOF)
638         {
639           request->state = GTK_CUPS_POST_CHECK;
640           request->poll_state = GTK_CUPS_HTTP_READ;
641
642           request->attempts = 0;
643           return;
644         }
645
646
647 #if HAVE_CUPS_API_1_2
648       if (httpWrite2(request->http, buffer, bytes) < bytes)
649 #else
650       if (httpWrite(request->http, buffer, (int) bytes) < bytes)
651 #endif /* HAVE_CUPS_API_1_2 */
652         {
653           request->state = GTK_CUPS_POST_DONE;
654           request->poll_state = GTK_CUPS_HTTP_IDLE;
655      
656           gtk_cups_result_set_error (request->result, "Error writting to socket in Post %s", strerror (httpError (request->http)));
657           return;
658         }
659     }
660    else
661     {
662       request->attempts++;
663     }
664 }
665
666 static void 
667 _post_check (GtkCupsRequest *request)
668 {
669   http_status_t http_status;
670
671   http_status = request->last_status;
672
673   GTK_NOTE (PRINTING,
674             g_print ("CUPS Backend: %s - status %i\n", G_STRFUNC, http_status));
675
676   request->poll_state = GTK_CUPS_HTTP_READ;
677
678   if (http_status == HTTP_CONTINUE)
679     {
680       goto again; 
681     }
682   else if (http_status == HTTP_UNAUTHORIZED)
683     {
684       /* TODO: callout for auth */
685       g_warning ("NOT IMPLEMENTED: We need to prompt for authorization");
686       request->state = GTK_CUPS_POST_DONE;
687       request->poll_state = GTK_CUPS_HTTP_IDLE;
688       
689       gtk_cups_result_set_error (request->result, "Can't prompt for authorization");
690       return;
691     }
692   else if (http_status == HTTP_ERROR)
693     {
694 #ifdef G_OS_WIN32
695       if (request->http->error != WSAENETDOWN && 
696           request->http->error != WSAENETUNREACH)
697 #else
698       if (request->http->error != ENETDOWN && 
699           request->http->error != ENETUNREACH)
700 #endif /* G_OS_WIN32 */
701         {
702           request->attempts++;
703           goto again;
704         }
705       else
706         {
707           request->state = GTK_CUPS_POST_DONE;
708           request->poll_state = GTK_CUPS_HTTP_IDLE;
709      
710           gtk_cups_result_set_error (request->result, "Unknown HTTP error");
711           return;
712         }
713     }
714 /* TODO: detect ssl in configure.ac */
715 #if HAVE_SSL
716   else if (http_status == HTTP_UPGRADE_REQUIRED)
717     {
718       /* Flush any error message... */
719       httpFlush (request->http);
720
721       /* Reconnect... */
722       httpReconnect (request->http);
723
724       /* Upgrade with encryption... */
725       httpEncryption(request->http, HTTP_ENCRYPT_REQUIRED);
726  
727       request->attempts++;
728       goto again;
729     }
730 #endif 
731   else if (http_status != HTTP_OK)
732     {
733       int http_errno;
734
735       http_errno = httpError (request->http);
736
737       if (http_errno == EPIPE)
738         request->state = GTK_CUPS_POST_CONNECT;
739       else
740         {
741           request->state = GTK_CUPS_POST_DONE;
742           gtk_cups_result_set_error (request->result, "HTTP Error in POST %s", strerror (http_errno));
743          request->poll_state = GTK_CUPS_HTTP_IDLE;
744  
745           httpFlush(request->http); 
746           return;
747         }
748
749       request->poll_state = GTK_CUPS_HTTP_IDLE;
750        
751       httpFlush(request->http); 
752       
753       request->last_status = HTTP_CONTINUE;
754       httpClose (request->http);
755       request->http = NULL;
756       return;  
757     }
758   else
759     {
760       request->state = GTK_CUPS_POST_READ_RESPONSE;
761       return;
762     }
763
764  again:
765   http_status = HTTP_CONTINUE;
766
767   if (httpCheck (request->http))
768     http_status = httpUpdate (request->http);
769
770   request->last_status = http_status;
771 }
772
773 static void 
774 _post_read_response (GtkCupsRequest *request)
775 {
776   ipp_state_t ipp_status;
777
778   GTK_NOTE (PRINTING,
779             g_print ("CUPS Backend: %s\n", G_STRFUNC));
780
781   request->poll_state = GTK_CUPS_HTTP_READ;
782
783   if (request->result->ipp_response == NULL)
784     request->result->ipp_response = ippNew();
785
786   ipp_status = ippRead (request->http, 
787                         request->result->ipp_response);
788
789   if (ipp_status == IPP_ERROR)
790     {
791       gtk_cups_result_set_error (request->result, "%s", ippErrorString (cupsLastError()));
792       
793       ippDelete (request->result->ipp_response);
794       request->result->ipp_response = NULL;
795
796       request->state = GTK_CUPS_POST_DONE;
797       request->poll_state = GTK_CUPS_HTTP_IDLE;
798     }
799   else if (ipp_status == IPP_DATA)
800     {
801       request->state = GTK_CUPS_POST_DONE;
802       request->poll_state = GTK_CUPS_HTTP_IDLE;
803     }
804 }
805
806 static void 
807 _get_send (GtkCupsRequest *request)
808 {
809   GTK_NOTE (PRINTING,
810             g_print ("CUPS Backend: %s\n", G_STRFUNC));
811
812   request->poll_state = GTK_CUPS_HTTP_WRITE;
813
814   if (request->data_io == NULL)
815     {
816       gtk_cups_result_set_error (request->result, "Get requires an open io channel");
817       request->state = GTK_CUPS_GET_DONE;
818       request->poll_state = GTK_CUPS_HTTP_IDLE;
819
820       return;
821     }
822
823   httpClearFields(request->http);
824   httpSetField(request->http, HTTP_FIELD_AUTHORIZATION, request->http->authstring);
825
826   if (httpGet(request->http, request->resource))
827     {
828       if (httpReconnect(request->http))
829         {
830           request->state = GTK_CUPS_GET_DONE;
831           request->poll_state = GTK_CUPS_HTTP_IDLE;
832           
833           gtk_cups_result_set_error (request->result, "Failed Get");
834         }
835
836       request->attempts++;
837       return;    
838     }
839         
840   request->attempts = 0;
841
842   request->state = GTK_CUPS_GET_CHECK;
843   request->poll_state = GTK_CUPS_HTTP_READ;
844   
845   request->ipp_request->state = IPP_IDLE;
846 }
847
848 static void 
849 _get_check (GtkCupsRequest *request)
850 {
851   http_status_t http_status;
852
853   GTK_NOTE (PRINTING,
854             g_print ("CUPS Backend: %s\n", G_STRFUNC));
855
856   http_status = request->last_status;
857
858   request->poll_state = GTK_CUPS_HTTP_READ;
859
860   if (http_status == HTTP_CONTINUE)
861     {
862       goto again; 
863     }
864   else if (http_status == HTTP_UNAUTHORIZED)
865     {
866       /* TODO: callout for auth */
867       g_warning ("NOT IMPLEMENTED: We need to prompt for authorization in a non blocking manner");
868       request->state = GTK_CUPS_GET_DONE;
869       request->poll_state = GTK_CUPS_HTTP_IDLE;
870  
871       gtk_cups_result_set_error (request->result, "Can't prompt for authorization");
872       return;
873     }
874 /* TODO: detect ssl in configure.ac */
875 #if HAVE_SSL
876   else if (http_status == HTTP_UPGRADE_REQUIRED)
877     {
878       /* Flush any error message... */
879       httpFlush (request->http);
880
881       /* Reconnect... */
882       httpReconnect (request->http);
883
884       /* Upgrade with encryption... */
885       httpEncryption(request->http, HTTP_ENCRYPT_REQUIRED);
886  
887       request->attempts++;
888       goto again;
889     }
890 #endif 
891   else if (http_status != HTTP_OK)
892     {
893       int http_errno;
894
895       http_errno = httpError (request->http);
896
897       if (http_errno == EPIPE)
898         request->state = GTK_CUPS_GET_CONNECT;
899       else
900         {
901           request->state = GTK_CUPS_GET_DONE;
902           gtk_cups_result_set_error (request->result, "HTTP Error in GET %s", strerror (http_errno));
903           request->poll_state = GTK_CUPS_HTTP_IDLE;
904           httpFlush(request->http);
905
906           return;
907         }
908
909       request->poll_state = GTK_CUPS_HTTP_IDLE;
910       httpFlush (request->http);
911       httpClose (request->http);
912       request->last_status = HTTP_CONTINUE;
913       request->http = NULL;
914       return;
915
916     }
917   else
918     {
919       request->state = GTK_CUPS_GET_READ_DATA;
920       return;
921     }
922
923  again:
924   http_status = HTTP_CONTINUE;
925
926   if (httpCheck (request->http))
927     http_status = httpUpdate (request->http);
928
929   request->last_status = http_status;
930
931 }
932
933 static void 
934 _get_read_data (GtkCupsRequest *request)
935 {
936   char buffer[_GTK_CUPS_MAX_CHUNK_SIZE];
937   gsize bytes;
938   gsize bytes_written;
939   GIOStatus io_status;
940   GError *error;
941
942   GTK_NOTE (PRINTING,
943             g_print ("CUPS Backend: %s\n", G_STRFUNC));
944
945   error = NULL;
946
947   request->poll_state = GTK_CUPS_HTTP_READ;
948
949 #if HAVE_CUPS_API_1_2
950   bytes = httpRead2(request->http, buffer, sizeof(buffer));
951 #else
952   bytes = httpRead(request->http, buffer, sizeof(buffer));
953 #endif /* HAVE_CUPS_API_1_2 */
954
955   GTK_NOTE (PRINTING,
956             g_print ("CUPS Backend: %i bytes read\n", bytes));
957   
958   if (bytes == 0)
959     {
960       request->state = GTK_CUPS_GET_DONE;
961       request->poll_state = GTK_CUPS_HTTP_IDLE;
962
963       return;
964     }
965   
966   io_status =
967     g_io_channel_write_chars (request->data_io, 
968                               buffer, 
969                               bytes, 
970                               &bytes_written,
971                               &error);
972
973   if (io_status == G_IO_STATUS_ERROR)
974     {
975       request->state = GTK_CUPS_POST_DONE;
976       request->poll_state = GTK_CUPS_HTTP_IDLE;
977     
978       gtk_cups_result_set_error (request->result, error->message);
979       g_error_free (error);
980     }
981 }
982
983 gboolean
984 gtk_cups_request_is_done (GtkCupsRequest *request)
985 {
986   return (request->state == GTK_CUPS_REQUEST_DONE);
987 }
988
989 gboolean
990 gtk_cups_result_is_error (GtkCupsResult *result)
991 {
992   return result->is_error;
993 }
994
995 ipp_t *
996 gtk_cups_result_get_response (GtkCupsResult *result)
997 {
998   return result->ipp_response;
999 }
1000
1001 const char *
1002 gtk_cups_result_get_error_string (GtkCupsResult *result)
1003 {
1004   return result->error_msg; 
1005 }
1006