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