Advertisement
Guest User

Untitled

a guest
Dec 18th, 2014
155
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 45.57 KB | None | 0 0
  1. /* GTK - The GIMP Toolkit
  2.  * gtkcupsutils.h: Statemachine implementation of POST and GET
  3.  * cups calls which can be used to create a non-blocking cups API
  4.  * Copyright (C) 2006, 2007 Red Hat, Inc.
  5.  *
  6.  * This library is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2 of the License, or (at your option) any later version.
  10.  *
  11.  * This library is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with this library; if not, write to the
  18.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19.  * Boston, MA 02111-1307, USA.
  20.  */
  21.  
  22. #include "config.h"
  23. #include <gtk/gtk.h>
  24. #include "gtkcupsutils.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. #include <fcntl.h>
  33. #include <sys/socket.h>
  34.  
  35. typedef void (*GtkCupsRequestStateFunc) (GtkCupsRequest *request);
  36.  
  37. static void _connect            (GtkCupsRequest *request);
  38. static void _post_send          (GtkCupsRequest *request);
  39. static void _post_write_request (GtkCupsRequest *request);
  40. static void _post_write_data    (GtkCupsRequest *request);
  41. static void _post_check         (GtkCupsRequest *request);
  42. static void _post_auth          (GtkCupsRequest *request);
  43. static void _post_read_response (GtkCupsRequest *request);
  44.  
  45. static void _get_send           (GtkCupsRequest *request);
  46. static void _get_check          (GtkCupsRequest *request);
  47. static void _get_auth           (GtkCupsRequest *request);
  48. static void _get_read_data      (GtkCupsRequest *request);
  49.  
  50. struct _GtkCupsResult
  51. {
  52.   gchar *error_msg;
  53.   ipp_t *ipp_response;
  54.   GtkCupsErrorType error_type;
  55.  
  56.   /* some error types like HTTP_ERROR have a status and a code */
  57.   int error_status;            
  58.   int error_code;
  59.  
  60.   guint is_error : 1;
  61.   guint is_ipp_response : 1;
  62. };
  63.  
  64.  
  65. #define _GTK_CUPS_MAX_ATTEMPTS 10
  66. #define _GTK_CUPS_MAX_CHUNK_SIZE 8192
  67.  
  68. static GtkCupsRequestStateFunc post_states[] = {
  69.   _connect,
  70.   _post_send,
  71.   _post_write_request,
  72.   _post_write_data,
  73.   _post_check,
  74.   _post_auth,
  75.   _post_read_response
  76. };
  77.  
  78. static GtkCupsRequestStateFunc get_states[] = {
  79.   _connect,
  80.   _get_send,
  81.   _get_check,
  82.   _get_auth,
  83.   _get_read_data
  84. };
  85.  
  86. static void
  87. gtk_cups_result_set_error (GtkCupsResult    *result,
  88.                            GtkCupsErrorType  error_type,
  89.                            int               error_status,
  90.                            int               error_code,
  91.                            const char       *error_msg,
  92.                ...)
  93. {
  94.   va_list args;
  95.  
  96.   result->is_ipp_response = FALSE;
  97.   result->is_error = TRUE;
  98.   result->error_type = error_type;
  99.   result->error_status = error_status;
  100.   result->error_code = error_code;
  101.  
  102.   va_start (args, error_msg);
  103.   result->error_msg = g_strdup_vprintf (error_msg, args);
  104.   va_end (args);
  105. }
  106.  
  107. GtkCupsRequest *
  108. gtk_cups_request_new_with_username (http_t             *connection,
  109.                                     GtkCupsRequestType  req_type,
  110.                                     gint                operation_id,
  111.                                     GIOChannel         *data_io,
  112.                                     const char         *server,
  113.                                     const char         *resource,
  114.                                     const char         *username)
  115. {
  116.   GtkCupsRequest *request;
  117.   cups_lang_t *language;
  118.  
  119.   request = g_new0 (GtkCupsRequest, 1);
  120.   request->result = g_new0 (GtkCupsResult, 1);
  121.  
  122.   request->result->error_msg = NULL;
  123.   request->result->ipp_response = NULL;
  124.  
  125.   request->result->is_error = FALSE;
  126.   request->result->is_ipp_response = FALSE;
  127.  
  128.   request->type = req_type;
  129.   request->state = GTK_CUPS_REQUEST_START;
  130.  
  131.   request->password_state = GTK_CUPS_PASSWORD_NONE;
  132.  
  133.    if (server)
  134.     request->server = g_strdup (server);
  135.   else
  136.     request->server = g_strdup (cupsServer ());
  137.  
  138.  
  139.   if (resource)
  140.     request->resource = g_strdup (resource);
  141.   else
  142.     request->resource = g_strdup ("/");
  143.  
  144.   if (connection != NULL)
  145.     {
  146.       request->http = connection;
  147.       request->own_http = FALSE;
  148.     }
  149.   else
  150.     {
  151.       request->http = NULL;
  152.       request->http = httpConnectEncrypt (request->server,
  153.                                           ippPort (),
  154.                                           cupsEncryption ());
  155.  
  156.       if (request->http)
  157.         httpBlocking (request->http, 0);
  158.        
  159.       request->own_http = TRUE;
  160.     }
  161.  
  162.   request->last_status = HTTP_CONTINUE;
  163.  
  164.   request->attempts = 0;
  165.   request->data_io = data_io;
  166.  
  167.   request->ipp_request = ippNew ();
  168.   request->ipp_request->request.op.operation_id = operation_id;
  169.   request->ipp_request->request.op.request_id = 1;
  170.  
  171.   language = cupsLangDefault ();
  172.  
  173.   gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
  174.                                    "attributes-charset",
  175.                                    NULL, "utf-8");
  176.    
  177.   gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
  178.                                    "attributes-natural-language",
  179.                                    NULL, language->language);
  180.  
  181.   if (username != NULL)
  182.     gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
  183.                                      "requesting-user-name",
  184.                                      NULL, username);
  185.   else
  186.     gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
  187.                                      "requesting-user-name",
  188.                                      NULL, cupsUser ());
  189.  
  190.   request->auth_info_required = NULL;
  191.   request->auth_info = NULL;
  192.   request->need_auth_info = FALSE;
  193.  
  194.   cupsLangFree (language);
  195.  
  196.   return request;
  197. }
  198.  
  199. GtkCupsRequest *
  200. gtk_cups_request_new (http_t             *connection,
  201.                       GtkCupsRequestType  req_type,
  202.                       gint                operation_id,
  203.                       GIOChannel         *data_io,
  204.                       const char         *server,
  205.                       const char         *resource)
  206. {
  207.   return gtk_cups_request_new_with_username (connection,
  208.                                              req_type,
  209.                                              operation_id,
  210.                                              data_io,
  211.                                              server,
  212.                                              resource,
  213.                                              NULL);
  214. }
  215.  
  216. static void
  217. gtk_cups_result_free (GtkCupsResult *result)
  218. {
  219.   g_free (result->error_msg);
  220.  
  221.   if (result->ipp_response)
  222.     ippDelete (result->ipp_response);
  223.  
  224.   g_free (result);
  225. }
  226.  
  227. void
  228. gtk_cups_request_free (GtkCupsRequest *request)
  229. {
  230.   if (request->own_http)
  231.     {
  232.       if (request->http)
  233.         httpClose (request->http);
  234.     }
  235.  
  236.   if (request->ipp_request)
  237.     ippDelete (request->ipp_request);
  238.  
  239.   g_free (request->server);
  240.   g_free (request->resource);
  241.   if (request->password != NULL)
  242.     {
  243.       memset (request->password, 0, strlen (request->password));
  244.       g_free (request->password);
  245.     }
  246.  
  247.   g_free (request->username);
  248.   g_strfreev (request->auth_info_required);
  249.  
  250.   gtk_cups_result_free (request->result);
  251.  
  252.   g_free (request);
  253. }
  254.  
  255. gboolean
  256. gtk_cups_request_read_write (GtkCupsRequest *request, gboolean connect_only)
  257. {
  258.   if (connect_only && request->state != GTK_CUPS_REQUEST_START)
  259.     return FALSE;
  260.  
  261.   do
  262.     {
  263.       if (request->type == GTK_CUPS_POST)
  264.         post_states[request->state] (request);
  265.       else if (request->type == GTK_CUPS_GET)
  266.         get_states[request->state] (request);
  267.  
  268.       if (request->attempts > _GTK_CUPS_MAX_ATTEMPTS &&
  269.           request->state != GTK_CUPS_REQUEST_DONE)
  270.         {
  271.           /* TODO: should add a status or error code for too many failed attempts */
  272.           gtk_cups_result_set_error (request->result,
  273.                                      GTK_CUPS_ERROR_GENERAL,
  274.                                      0,
  275.                                      0,
  276.                                      "Too many failed attempts");
  277.  
  278.           request->state = GTK_CUPS_REQUEST_DONE;
  279.         }
  280.  
  281.       if (request->state == GTK_CUPS_REQUEST_DONE)
  282.         {
  283.           request->poll_state = GTK_CUPS_HTTP_IDLE;
  284.           return TRUE;
  285.         }
  286.     }
  287.   /* We need to recheck using httpCheck if the poll_state is read, because
  288.    * Cups has an internal read buffer. And if this buffer is filled, we may
  289.    * never get a poll event again. */
  290.   while (request->poll_state == GTK_CUPS_HTTP_READ && request->http && httpCheck(request->http));
  291.  
  292.   return FALSE;
  293. }
  294.  
  295. GtkCupsPollState
  296. gtk_cups_request_get_poll_state (GtkCupsRequest *request)
  297. {
  298.   return request->poll_state;
  299. }
  300.  
  301.  
  302.  
  303. GtkCupsResult *
  304. gtk_cups_request_get_result (GtkCupsRequest *request)
  305. {
  306.   return request->result;
  307. }
  308.  
  309. void            
  310. gtk_cups_request_ipp_add_string (GtkCupsRequest *request,
  311.                                  ipp_tag_t       group,
  312.                                  ipp_tag_t       tag,
  313.                                  const char     *name,
  314.                                  const char     *charset,
  315.                                  const char     *value)
  316. {
  317.   ippAddString (request->ipp_request,
  318.                 group,
  319.                 tag,
  320.                 name,
  321.                 charset,
  322.                 value);
  323. }
  324.  
  325. void            
  326. gtk_cups_request_ipp_add_strings (GtkCupsRequest    *request,
  327.                   ipp_tag_t          group,
  328.                   ipp_tag_t          tag,
  329.                   const char        *name,
  330.                   int                num_values,
  331.                   const char        *charset,
  332.                   const char *const *values)
  333. {
  334.   ippAddStrings (request->ipp_request,
  335.          group,
  336.          tag,
  337.          name,
  338.          num_values,
  339.          charset,
  340.          values);
  341. }
  342.  
  343. const char *
  344. gtk_cups_request_ipp_get_string (GtkCupsRequest *request,
  345.                                  ipp_tag_t       tag,
  346.                                  const char     *name)
  347. {
  348.   ipp_attribute_t *attribute = NULL;
  349.  
  350.   if (request != NULL && request->ipp_request != NULL)
  351.     attribute = ippFindAttribute (request->ipp_request,
  352.                                   name,
  353.                                   tag);
  354.  
  355.   if (attribute != NULL && attribute->values != NULL)
  356.     return attribute->values[0].string.text;
  357.   else
  358.     return NULL;
  359. }
  360.  
  361.  
  362. typedef struct
  363. {
  364.   const char    *name;
  365.   ipp_tag_t value_tag;
  366. } ipp_option_t;
  367.  
  368. static const ipp_option_t ipp_options[] = {
  369.   { "blackplot",        IPP_TAG_BOOLEAN },
  370.   { "brightness",       IPP_TAG_INTEGER },
  371.   { "columns",          IPP_TAG_INTEGER },
  372.   { "copies",           IPP_TAG_INTEGER },
  373.   { "finishings",       IPP_TAG_ENUM },
  374.   { "fitplot",          IPP_TAG_BOOLEAN },
  375.   { "gamma",            IPP_TAG_INTEGER },
  376.   { "hue",          IPP_TAG_INTEGER },
  377.   { "job-k-limit",      IPP_TAG_INTEGER },
  378.   { "job-page-limit",       IPP_TAG_INTEGER },
  379.   { "job-priority",     IPP_TAG_INTEGER },
  380.   { "job-quota-period",     IPP_TAG_INTEGER },
  381.   { "landscape",        IPP_TAG_BOOLEAN },
  382.   { "media",            IPP_TAG_KEYWORD },
  383.   { "mirror",           IPP_TAG_BOOLEAN },
  384.   { "natural-scaling",      IPP_TAG_INTEGER },
  385.   { "number-up",        IPP_TAG_INTEGER },
  386.   { "orientation-requested",    IPP_TAG_ENUM },
  387.   { "page-bottom",      IPP_TAG_INTEGER },
  388.   { "page-left",        IPP_TAG_INTEGER },
  389.   { "page-ranges",      IPP_TAG_RANGE },
  390.   { "page-right",       IPP_TAG_INTEGER },
  391.   { "page-top",         IPP_TAG_INTEGER },
  392.   { "penwidth",         IPP_TAG_INTEGER },
  393.   { "ppi",          IPP_TAG_INTEGER },
  394.   { "prettyprint",      IPP_TAG_BOOLEAN },
  395.   { "printer-resolution",   IPP_TAG_RESOLUTION },
  396.   { "print-quality",        IPP_TAG_ENUM },
  397.   { "saturation",       IPP_TAG_INTEGER },
  398.   { "scaling",          IPP_TAG_INTEGER },
  399.   { "sides",            IPP_TAG_KEYWORD },
  400.   { "wrap",         IPP_TAG_BOOLEAN },
  401.   { "number-up-layout",     IPP_TAG_INTEGER }
  402. };
  403.  
  404.  
  405. static ipp_tag_t
  406. _find_option_tag (const gchar *option)
  407. {
  408.   int lower_bound, upper_bound, num_options;
  409.   int current_option;
  410.   ipp_tag_t result;
  411.  
  412.   result = IPP_TAG_ZERO;
  413.  
  414.   lower_bound = 0;
  415.   upper_bound = num_options = (int) G_N_ELEMENTS (ipp_options) - 1;
  416.  
  417.   while (1)
  418.     {
  419.       int match;
  420.       current_option = (int) (((upper_bound - lower_bound) / 2) + lower_bound);
  421.  
  422.       match = strcasecmp (option, ipp_options[current_option].name);
  423.       if (match == 0)
  424.         {
  425.       result = ipp_options[current_option].value_tag;
  426.       return result;
  427.     }
  428.       else if (match < 0)
  429.         {
  430.           upper_bound = current_option - 1;
  431.     }
  432.       else
  433.         {
  434.           lower_bound = current_option + 1;
  435.     }
  436.  
  437.       if (upper_bound == lower_bound && upper_bound == current_option)
  438.         return result;
  439.  
  440.       if (upper_bound < 0)
  441.         return result;
  442.  
  443.       if (lower_bound > num_options)
  444.         return result;
  445.  
  446.       if (upper_bound < lower_bound)
  447.         return result;
  448.     }
  449. }
  450.  
  451. /*
  452.  * Note that this function uses IPP_TAG_JOB, so it is
  453.  * only suitable for IPP Group 2 attributes.
  454.  * See RFC 2911.
  455.  */
  456. void
  457. gtk_cups_request_encode_option (GtkCupsRequest *request,
  458.                                 const gchar    *option,
  459.                     const gchar    *value)
  460. {
  461.   ipp_tag_t option_tag;
  462.  
  463.   g_return_if_fail (option != NULL);
  464.   g_return_if_fail (value != NULL);
  465.  
  466.   option_tag = _find_option_tag (option);
  467.  
  468.   if (option_tag == IPP_TAG_ZERO)
  469.     {
  470.       option_tag = IPP_TAG_NAME;
  471.       if (strcasecmp (value, "true") == 0 ||
  472.           strcasecmp (value, "false") == 0)
  473.         {
  474.           option_tag = IPP_TAG_BOOLEAN;
  475.         }
  476.     }
  477.        
  478.   switch (option_tag)
  479.     {
  480.       case IPP_TAG_INTEGER:
  481.       case IPP_TAG_ENUM:
  482.         ippAddInteger (request->ipp_request,
  483.                        IPP_TAG_JOB,
  484.                        option_tag,
  485.                        option,
  486.                        strtol (value, NULL, 0));
  487.         break;
  488.  
  489.       case IPP_TAG_BOOLEAN:
  490.         {
  491.           char b;
  492.          
  493.           if (strcasecmp (value, "true") == 0 ||
  494.           strcasecmp (value, "on") == 0 ||
  495.           strcasecmp (value, "yes") == 0)
  496.         b = 1;
  497.       else
  498.             b = 0;
  499.  
  500.           ippAddBoolean (request->ipp_request,
  501.                          IPP_TAG_JOB,
  502.                          option,
  503.                          b);
  504.        
  505.           break;
  506.         }
  507.        
  508.       case IPP_TAG_RANGE:
  509.         {
  510.           char  *s;
  511.           int lower;
  512.           int upper;
  513.          
  514.           if (*value == '-')
  515.         {
  516.           lower = 1;
  517.           s = (char *)value;
  518.         }
  519.       else
  520.         lower = strtol (value, &s, 0);
  521.  
  522.       if (*s == '-')
  523.         {
  524.           if (s[1])
  525.         upper = strtol (s + 1, NULL, 0);
  526.           else
  527.         upper = 2147483647;
  528.             }
  529.       else
  530.         upper = lower;
  531.          
  532.           ippAddRange (request->ipp_request,
  533.                        IPP_TAG_JOB,
  534.                        option,
  535.                        lower,
  536.                        upper);
  537.  
  538.           break;
  539.         }
  540.  
  541.       case IPP_TAG_RESOLUTION:
  542.         {
  543.           char *s;
  544.           int xres;
  545.           int yres;
  546.           ipp_res_t units;
  547.          
  548.           xres = strtol (value, &s, 0);
  549.  
  550.       if (*s == 'x')
  551.         yres = strtol (s + 1, &s, 0);
  552.       else
  553.         yres = xres;
  554.  
  555.       if (strcasecmp (s, "dpc") == 0)
  556.             units = IPP_RES_PER_CM;
  557.           else
  558.             units = IPP_RES_PER_INCH;
  559.          
  560.           ippAddResolution (request->ipp_request,
  561.                             IPP_TAG_JOB,
  562.                             option,
  563.                             units,
  564.                             xres,
  565.                             yres);
  566.  
  567.           break;
  568.         }
  569.  
  570.       default:
  571.         {
  572.           char *values;
  573.           char *s;
  574.           int in_quotes;
  575.           char *next;
  576.           GPtrArray *strings;
  577.          
  578.           values = g_strdup (value);
  579.           strings = NULL;
  580.       in_quotes = 0;
  581.  
  582.           for (s = values, next = s; *s != '\0'; s++)
  583.             {
  584.               if (in_quotes != 2 && *s == '\'')
  585.                 {
  586.                   /* skip quoted value */
  587.                   if (in_quotes == 0)
  588.                     in_quotes = 1;
  589.                   else
  590.                     in_quotes = 0;
  591.                 }
  592.               else if (in_quotes != 1 && *s == '\"')
  593.                 {
  594.                   /* skip quoted value */
  595.                   if (in_quotes == 0)
  596.                     in_quotes = 2;
  597.                   else
  598.                     in_quotes = 0;
  599.                 }
  600.               else if (in_quotes == 0 && *s == ',')
  601.                 {
  602.                   /* found delimiter, add to value array */
  603.                   *s = '\0';
  604.                   if (strings == NULL)
  605.                     strings = g_ptr_array_new ();
  606.                   g_ptr_array_add (strings, next);
  607.                   next = s + 1;
  608.                 }
  609.               else if (in_quotes == 0 && *s == '\\' && s[1] != '\0')
  610.                 {
  611.                   /* skip escaped character */
  612.                   s++;
  613.                 }
  614.             }
  615.          
  616.           if (strings == NULL)
  617.             {
  618.               /* single value */
  619.               ippAddString (request->ipp_request,
  620.                             IPP_TAG_JOB,
  621.                             option_tag,
  622.                             option,
  623.                             NULL,
  624.                             value);
  625.             }
  626.           else
  627.             {
  628.               /* multiple values */
  629.              
  630.               /* add last value */
  631.               g_ptr_array_add (strings, next);
  632.              
  633.               ippAddStrings (request->ipp_request,
  634.                              IPP_TAG_JOB,
  635.                              option_tag,
  636.                              option,
  637.                              strings->len,
  638.                              NULL,
  639.                              (const char **) strings->pdata);
  640.               g_ptr_array_free (strings, TRUE);
  641.             }
  642.  
  643.           g_free (values);
  644.         }
  645.  
  646.         break;
  647.     }
  648. }
  649.                
  650.  
  651. static void
  652. _connect (GtkCupsRequest *request)
  653. {
  654.   request->poll_state = GTK_CUPS_HTTP_IDLE;
  655.   request->bytes_received = 0;
  656.  
  657.   if (request->http == NULL)
  658.     {
  659.       request->http = httpConnectEncrypt (request->server,
  660.                                           ippPort (),
  661.                                           cupsEncryption ());
  662.  
  663.       if (request->http == NULL)
  664.         request->attempts++;
  665.  
  666.       if (request->http)
  667.         httpBlocking (request->http, 0);
  668.        
  669.       request->own_http = TRUE;
  670.     }
  671.   else
  672.     {
  673.       request->attempts = 0;
  674.       request->state++;
  675.  
  676.       /* we always write to the socket after we get
  677.          the connection */
  678.       request->poll_state = GTK_CUPS_HTTP_WRITE;
  679.     }
  680. }
  681.  
  682. static void
  683. _post_send (GtkCupsRequest *request)
  684. {
  685.   gchar length[255];
  686.   struct stat data_info;
  687.  
  688.   GTK_NOTE (PRINTING,
  689.             g_print ("CUPS Backend: %s\n", G_STRFUNC));
  690.  
  691.   request->poll_state = GTK_CUPS_HTTP_WRITE;
  692.  
  693.   if (request->data_io != NULL)
  694.     {
  695.       fstat (g_io_channel_unix_get_fd (request->data_io), &data_info);
  696.       sprintf (length, "%lu", (unsigned long) (ippLength (request->ipp_request) + data_info.st_size));
  697.     }
  698.   else
  699.     sprintf (length, "%lu", (unsigned long) ippLength (request->ipp_request));
  700.    
  701.   httpClearFields (request->http);
  702.   httpSetField (request->http, HTTP_FIELD_CONTENT_LENGTH, length);
  703.   httpSetField (request->http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
  704. #ifdef HAVE_HTTPGETAUTHSTRING
  705.   httpSetField (request->http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString (request->http));
  706. #else
  707. #ifdef HAVE_HTTP_AUTHSTRING
  708.   httpSetField (request->http, HTTP_FIELD_AUTHORIZATION, request->http->authstring);
  709. #endif
  710. #endif
  711.  
  712.   if (httpPost (request->http, request->resource))
  713.     {
  714.       if (httpReconnect (request->http))
  715.         {
  716.           request->state = GTK_CUPS_POST_DONE;
  717.           request->poll_state = GTK_CUPS_HTTP_IDLE;
  718.  
  719.           /* TODO: should add a status or error code for failed post */
  720.           gtk_cups_result_set_error (request->result,
  721.                                      GTK_CUPS_ERROR_GENERAL,
  722.                                      0,
  723.                                      0,
  724.                                      "Failed Post");
  725.         }
  726.  
  727.       request->attempts++;
  728.       return;    
  729.     }
  730.        
  731.     request->attempts = 0;
  732.  
  733.     request->state = GTK_CUPS_POST_WRITE_REQUEST;
  734.     request->ipp_request->state = IPP_IDLE;
  735. }
  736.  
  737. static void
  738. _post_write_request (GtkCupsRequest *request)
  739. {
  740.   ipp_state_t ipp_status;
  741.  
  742.   GTK_NOTE (PRINTING,
  743.             g_print ("CUPS Backend: %s\n", G_STRFUNC));
  744.  
  745.   request->poll_state = GTK_CUPS_HTTP_WRITE;
  746.  
  747.   ipp_status = ippWrite (request->http, request->ipp_request);
  748.  
  749.   if (ipp_status == IPP_ERROR)
  750.     {
  751.       int cups_error = cupsLastError ();
  752.       request->state = GTK_CUPS_POST_DONE;
  753.       request->poll_state = GTK_CUPS_HTTP_IDLE;
  754.  
  755.       gtk_cups_result_set_error (request->result,
  756.                                  GTK_CUPS_ERROR_IPP,
  757.                                  ipp_status,
  758.                                  cups_error,
  759.                                  "%s",
  760.                                  ippErrorString (cups_error));
  761.       return;
  762.     }
  763.  
  764.   if (ipp_status == IPP_DATA)
  765.     {
  766.       if (request->data_io != NULL)
  767.         request->state = GTK_CUPS_POST_WRITE_DATA;
  768.       else
  769.         {
  770.           request->state = GTK_CUPS_POST_CHECK;
  771.           request->poll_state = GTK_CUPS_HTTP_READ;
  772.     }
  773.     }
  774. }
  775.  
  776. static void
  777. _post_write_data (GtkCupsRequest *request)
  778. {
  779.   gsize bytes;
  780.   char buffer[_GTK_CUPS_MAX_CHUNK_SIZE];
  781.   http_status_t http_status;
  782.  
  783.   GTK_NOTE (PRINTING,
  784.             g_print ("CUPS Backend: %s\n", G_STRFUNC));
  785.  
  786.   request->poll_state = GTK_CUPS_HTTP_WRITE;
  787.  
  788.   if (httpCheck (request->http))
  789.     http_status = httpUpdate (request->http);
  790.   else
  791.     http_status = request->last_status;
  792.  
  793.   request->last_status = http_status;
  794.  
  795.  
  796.   if (http_status == HTTP_CONTINUE || http_status == HTTP_OK)
  797.     {
  798.       GIOStatus io_status;
  799.       GError *error;
  800.  
  801.       error = NULL;
  802.  
  803.       /* send data */
  804.       io_status =
  805.         g_io_channel_read_chars (request->data_io,
  806.                              buffer,
  807.                  _GTK_CUPS_MAX_CHUNK_SIZE,
  808.                  &bytes,
  809.                  &error);
  810.  
  811.       if (io_status == G_IO_STATUS_ERROR)
  812.         {
  813.           request->state = GTK_CUPS_POST_DONE;
  814.       request->poll_state = GTK_CUPS_HTTP_IDLE;
  815.      
  816.           gtk_cups_result_set_error (request->result,
  817.                                      GTK_CUPS_ERROR_IO,
  818.                                      io_status,
  819.                                      error->code,
  820.                                      "Error reading from cache file: %s",
  821.                                      error->message);
  822.  
  823.       g_error_free (error);
  824.           return;
  825.     }
  826.       else if (bytes == 0 && io_status == G_IO_STATUS_EOF)
  827.         {
  828.           request->state = GTK_CUPS_POST_CHECK;
  829.       request->poll_state = GTK_CUPS_HTTP_READ;
  830.  
  831.           request->attempts = 0;
  832.           return;
  833.         }
  834.  
  835.  
  836. #if HAVE_CUPS_API_1_2
  837.       if (httpWrite2 (request->http, buffer, bytes) < bytes)
  838. #else
  839.       if (httpWrite (request->http, buffer, (int) bytes) < bytes)
  840. #endif /* HAVE_CUPS_API_1_2 */
  841.         {
  842.           int http_errno;
  843.  
  844.           http_errno = httpError (request->http);
  845.  
  846.           request->state = GTK_CUPS_POST_DONE;
  847.       request->poll_state = GTK_CUPS_HTTP_IDLE;
  848.      
  849.           gtk_cups_result_set_error (request->result,
  850.                                      GTK_CUPS_ERROR_HTTP,
  851.                                      http_status,
  852.                                      http_errno,
  853.                                      "Error writing to socket in Post %s",
  854.                                      g_strerror (http_errno));
  855.           return;
  856.         }
  857.     }
  858.   else if (http_status == HTTP_UNAUTHORIZED)
  859.     {
  860.       request->state = GTK_CUPS_POST_CHECK;
  861.       request->poll_state = GTK_CUPS_HTTP_READ;
  862.  
  863.       request->attempts = 0;
  864.       return;
  865.     }
  866.   else
  867.     {
  868.       request->attempts++;
  869.     }
  870. }
  871.  
  872. static void
  873. _post_auth (GtkCupsRequest *request)
  874. {
  875.   if (request->password_state == GTK_CUPS_PASSWORD_HAS)
  876.     {
  877.       if (request->password == NULL)
  878.         {
  879.           request->state = GTK_CUPS_POST_DONE;
  880.           request->poll_state = GTK_CUPS_HTTP_IDLE;
  881.  
  882.           gtk_cups_result_set_error (request->result,
  883.                                      GTK_CUPS_ERROR_AUTH,
  884.                                      0,
  885.                                      1,
  886.                                      "Canceled by user");
  887.         }
  888.       else
  889.         request->state = GTK_CUPS_POST_CHECK;
  890.     }
  891. }
  892.  
  893. static void
  894. _get_auth (GtkCupsRequest *request)
  895. {
  896.   if (request->password_state == GTK_CUPS_PASSWORD_HAS)
  897.     {
  898.       if (request->password == NULL)
  899.         {
  900.           request->state = GTK_CUPS_GET_DONE;
  901.           request->poll_state = GTK_CUPS_HTTP_IDLE;
  902.  
  903.           gtk_cups_result_set_error (request->result,
  904.                                      GTK_CUPS_ERROR_AUTH,
  905.                                      0,
  906.                                      1,
  907.                                      "Canceled by user");
  908.         }
  909.       else
  910.         request->state = GTK_CUPS_GET_CHECK;
  911.     }
  912. }
  913.  
  914. /* Very ugly hack: cups has a stupid synchronous password callback
  915.  * that doesn't even take the request or user data parameters, so
  916.  * we have to use a static variable to pass the password to it.
  917.  * Not threadsafe !
  918.  * The callback sets cups_password to NULL to signal that the
  919.  * password has been used.
  920.  */
  921. static char *cups_password;
  922. static char *cups_username;
  923.  
  924. static const char *
  925. passwordCB (const char *prompt)
  926. {
  927.   char *pwd = cups_password;
  928.   cups_password = NULL;
  929.  
  930.   cupsSetUser (cups_username);
  931.  
  932.   return pwd;
  933. }
  934.  
  935. static void
  936. _post_check (GtkCupsRequest *request)
  937. {
  938.   http_status_t http_status;
  939.  
  940.   http_status = request->last_status;
  941.  
  942.   GTK_NOTE (PRINTING,
  943.             g_print ("CUPS Backend: %s - status %i\n", G_STRFUNC, http_status));
  944.  
  945.   request->poll_state = GTK_CUPS_HTTP_READ;
  946.  
  947.   if (http_status == HTTP_CONTINUE)
  948.     {
  949.       goto again;
  950.     }
  951.   else if (http_status == HTTP_UNAUTHORIZED)
  952.     {
  953.       int auth_result = -1;
  954.       httpFlush (request->http);
  955.  
  956.       if (request->password_state == GTK_CUPS_PASSWORD_APPLIED)
  957.         {
  958.           request->password_state = GTK_CUPS_PASSWORD_NOT_VALID;
  959.           request->state = GTK_CUPS_POST_AUTH;
  960.           request->need_password = TRUE;
  961.  
  962.           return;
  963.         }
  964.  
  965.       /* Negotiate */
  966.       if (strncmp (httpGetField (request->http, HTTP_FIELD_WWW_AUTHENTICATE), "Negotiate", 9) == 0)
  967.         {
  968.           auth_result = cupsDoAuthentication (request->http, "POST", request->resource);
  969.         }
  970.       /* Basic, BasicDigest, Digest and PeerCred */
  971.       else
  972.         {
  973.           if (request->password_state == GTK_CUPS_PASSWORD_NONE)
  974.             {
  975.               cups_password = g_strdup ("");
  976.               cups_username = request->username;
  977.               cupsSetPasswordCB (passwordCB);
  978.  
  979.               /* This call success for PeerCred authentication */
  980.               auth_result = cupsDoAuthentication (request->http, "POST", request->resource);
  981.  
  982.               if (auth_result != 0)
  983.                 {
  984.                   /* move to AUTH state to let the backend
  985.                    * ask for a password
  986.                    */
  987.                   request->state = GTK_CUPS_POST_AUTH;
  988.                   request->need_password = TRUE;
  989.  
  990.                   return;
  991.                 }
  992.             }
  993.           else
  994.             {
  995.               cups_password = request->password;
  996.               cups_username = request->username;
  997.  
  998.               auth_result = cupsDoAuthentication (request->http, "POST", request->resource);
  999.  
  1000.               if (cups_password != NULL)
  1001.                 return;
  1002.  
  1003.               if (request->password != NULL)
  1004.                 {
  1005.                   memset (request->password, 0, strlen (request->password));
  1006.                   g_free (request->password);
  1007.                   request->password = NULL;
  1008.                 }
  1009.  
  1010.               request->password_state = GTK_CUPS_PASSWORD_APPLIED;
  1011.             }
  1012.         }
  1013.  
  1014.       if (auth_result ||
  1015.           httpReconnect (request->http))
  1016.         {
  1017.           /* if the password has been used, reset password_state
  1018.            * so that we ask for a new one next time around
  1019.            */
  1020.           if (cups_password == NULL)
  1021.             request->password_state = GTK_CUPS_PASSWORD_NONE;
  1022.  
  1023.           request->state = GTK_CUPS_POST_DONE;
  1024.           request->poll_state = GTK_CUPS_HTTP_IDLE;
  1025.           gtk_cups_result_set_error (request->result,
  1026.                                      GTK_CUPS_ERROR_AUTH,
  1027.                                      0,
  1028.                                      0,
  1029.                                      "Not authorized");
  1030.           return;
  1031.         }
  1032.      
  1033.       if (request->data_io != NULL)
  1034.         g_io_channel_seek_position (request->data_io, 0, G_SEEK_SET, NULL);
  1035.  
  1036.       request->state = GTK_CUPS_POST_CONNECT;
  1037.       request->poll_state = GTK_CUPS_HTTP_WRITE;
  1038.     }
  1039.   else if (http_status == HTTP_ERROR)
  1040.     {
  1041.       int error = httpError (request->http);
  1042. #ifdef G_OS_WIN32
  1043.       if (error != WSAENETDOWN && error != WSAENETUNREACH)
  1044. #else
  1045.       if (error != ENETDOWN && error != ENETUNREACH)     
  1046. #endif /* G_OS_WIN32 */
  1047.         {
  1048.           request->attempts++;
  1049.           goto again;
  1050.         }
  1051.       else
  1052.         {
  1053.           request->state = GTK_CUPS_POST_DONE;
  1054.           request->poll_state = GTK_CUPS_HTTP_IDLE;
  1055.      
  1056.           gtk_cups_result_set_error (request->result,
  1057.                                      GTK_CUPS_ERROR_HTTP,
  1058.                                      http_status,
  1059.                                      error,
  1060.                                      "Unknown HTTP error");
  1061.  
  1062.           return;
  1063.         }
  1064.     }
  1065.   else if (http_status == HTTP_UPGRADE_REQUIRED)
  1066.     {
  1067.       /* Flush any error message... */
  1068.       httpFlush (request->http);
  1069.  
  1070.       cupsSetEncryption (HTTP_ENCRYPT_REQUIRED);
  1071.       request->state = GTK_CUPS_POST_CONNECT;
  1072.  
  1073.       /* Reconnect... */
  1074.       httpReconnect (request->http);
  1075.  
  1076.       /* Upgrade with encryption... */
  1077.       httpEncryption (request->http, HTTP_ENCRYPT_REQUIRED);
  1078.  
  1079.       request->attempts++;
  1080.       goto again;
  1081.     }
  1082.   else if (http_status != HTTP_OK)
  1083.     {
  1084.       int http_errno;
  1085.  
  1086.       http_errno = httpError (request->http);
  1087.  
  1088.       if (http_errno == EPIPE)
  1089.         request->state = GTK_CUPS_POST_CONNECT;
  1090.       else
  1091.         {
  1092.           request->state = GTK_CUPS_POST_DONE;
  1093.           gtk_cups_result_set_error (request->result,
  1094.                                      GTK_CUPS_ERROR_HTTP,
  1095.                                      http_status,
  1096.                                      http_errno,
  1097.                                      "HTTP Error in POST %s",
  1098.                                      g_strerror (http_errno));
  1099.           request->poll_state = GTK_CUPS_HTTP_IDLE;
  1100.  
  1101.           httpFlush (request->http);
  1102.           return;
  1103.         }
  1104.  
  1105.       request->poll_state = GTK_CUPS_HTTP_IDLE;
  1106.        
  1107.       httpFlush (request->http);
  1108.      
  1109.       request->last_status = HTTP_CONTINUE;
  1110.       httpClose (request->http);
  1111.       request->http = NULL;
  1112.       return;  
  1113.     }
  1114.   else
  1115.     {
  1116.       request->state = GTK_CUPS_POST_READ_RESPONSE;
  1117.       return;
  1118.     }
  1119.  
  1120.  again:
  1121.   http_status = HTTP_CONTINUE;
  1122.  
  1123.   if (httpCheck (request->http))
  1124.     http_status = httpUpdate (request->http);
  1125.  
  1126.   request->last_status = http_status;
  1127. }
  1128.  
  1129. static void
  1130. _post_read_response (GtkCupsRequest *request)
  1131. {
  1132.   ipp_state_t ipp_status;
  1133.  
  1134.   GTK_NOTE (PRINTING,
  1135.             g_print ("CUPS Backend: %s\n", G_STRFUNC));
  1136.  
  1137.   request->poll_state = GTK_CUPS_HTTP_READ;
  1138.  
  1139.   if (request->result->ipp_response == NULL)
  1140.     request->result->ipp_response = ippNew();
  1141.  
  1142.   ipp_status = ippRead (request->http,
  1143.                         request->result->ipp_response);
  1144.  
  1145.   if (ipp_status == IPP_ERROR)
  1146.     {
  1147.       int ipp_error = cupsLastError ();
  1148.       gtk_cups_result_set_error (request->result,  
  1149.                                  GTK_CUPS_ERROR_IPP,
  1150.                                  ipp_status,
  1151.                                  ipp_error,
  1152.                                  "%s",
  1153.                                  ippErrorString (ipp_error));
  1154.      
  1155.       ippDelete (request->result->ipp_response);
  1156.       request->result->ipp_response = NULL;
  1157.  
  1158.       request->state = GTK_CUPS_POST_DONE;
  1159.       request->poll_state = GTK_CUPS_HTTP_IDLE;
  1160.     }
  1161.   else if (ipp_status == IPP_DATA)
  1162.     {
  1163.       request->state = GTK_CUPS_POST_DONE;
  1164.       request->poll_state = GTK_CUPS_HTTP_IDLE;
  1165.     }
  1166. }
  1167.  
  1168. static void
  1169. _get_send (GtkCupsRequest *request)
  1170. {
  1171.   GTK_NOTE (PRINTING,
  1172.             g_print ("CUPS Backend: %s\n", G_STRFUNC));
  1173.  
  1174.   request->poll_state = GTK_CUPS_HTTP_WRITE;
  1175.  
  1176.   if (request->data_io == NULL)
  1177.     {
  1178.       gtk_cups_result_set_error (request->result,
  1179.                                  GTK_CUPS_ERROR_IO,
  1180.                                  G_IO_STATUS_ERROR,
  1181.                                  G_IO_CHANNEL_ERROR_FAILED,
  1182.                                  "Get requires an open io channel");
  1183.  
  1184.       request->state = GTK_CUPS_GET_DONE;
  1185.       request->poll_state = GTK_CUPS_HTTP_IDLE;
  1186.  
  1187.       return;
  1188.     }
  1189.  
  1190.   httpClearFields (request->http);
  1191. #ifdef HAVE_HTTPGETAUTHSTRING
  1192.   httpSetField (request->http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString (request->http));
  1193. #else
  1194. #ifdef HAVE_HTTP_AUTHSTRING
  1195.   httpSetField (request->http, HTTP_FIELD_AUTHORIZATION, request->http->authstring);
  1196. #endif
  1197. #endif
  1198.  
  1199.   if (httpGet (request->http, request->resource))
  1200.     {
  1201.       if (httpReconnect (request->http))
  1202.         {
  1203.           request->state = GTK_CUPS_GET_DONE;
  1204.           request->poll_state = GTK_CUPS_HTTP_IDLE;
  1205.      
  1206.           /* TODO: should add a status or error code for failed GET */
  1207.           gtk_cups_result_set_error (request->result,
  1208.                                      GTK_CUPS_ERROR_GENERAL,
  1209.                                      0,
  1210.                                      0,
  1211.                                      "Failed Get");
  1212.         }
  1213.  
  1214.       request->attempts++;
  1215.       return;    
  1216.     }
  1217.  
  1218.   if (httpCheck (request->http))
  1219.     request->last_status = httpUpdate (request->http);
  1220.        
  1221.   request->attempts = 0;
  1222.  
  1223.   request->state = GTK_CUPS_GET_CHECK;
  1224.   request->poll_state = GTK_CUPS_HTTP_READ;
  1225.  
  1226.   request->ipp_request->state = IPP_IDLE;
  1227. }
  1228.  
  1229. static void
  1230. _get_check (GtkCupsRequest *request)
  1231. {
  1232.   http_status_t http_status;
  1233.  
  1234.   GTK_NOTE (PRINTING,
  1235.             g_print ("CUPS Backend: %s\n", G_STRFUNC));
  1236.  
  1237.   http_status = request->last_status;
  1238.  
  1239.   request->poll_state = GTK_CUPS_HTTP_READ;
  1240.  
  1241.   if (http_status == HTTP_CONTINUE)
  1242.     {
  1243.       goto again;
  1244.     }
  1245.   else if (http_status == HTTP_UNAUTHORIZED)
  1246.     {
  1247.       int auth_result = -1;
  1248.       httpFlush (request->http);
  1249.  
  1250.       if (request->password_state == GTK_CUPS_PASSWORD_APPLIED)
  1251.         {
  1252.           request->password_state = GTK_CUPS_PASSWORD_NOT_VALID;
  1253.           request->state = GTK_CUPS_GET_AUTH;
  1254.           request->need_password = TRUE;
  1255.  
  1256.           return;
  1257.         }
  1258.  
  1259.       /* Negotiate */
  1260.       if (strncmp (httpGetField (request->http, HTTP_FIELD_WWW_AUTHENTICATE), "Negotiate", 9) == 0)
  1261.         {
  1262.           auth_result = cupsDoAuthentication (request->http, "GET", request->resource);
  1263.         }
  1264.       /* Basic, BasicDigest, Digest and PeerCred */
  1265.       else
  1266.         {
  1267.           if (request->password_state == GTK_CUPS_PASSWORD_NONE)
  1268.             {
  1269.               cups_password = g_strdup ("");
  1270.               cups_username = request->username;
  1271.               cupsSetPasswordCB (passwordCB);
  1272.  
  1273.               /* This call success for PeerCred authentication */
  1274.               auth_result = cupsDoAuthentication (request->http, "GET", request->resource);
  1275.  
  1276.               if (auth_result != 0)
  1277.                 {
  1278.                   /* move to AUTH state to let the backend
  1279.                    * ask for a password
  1280.                    */
  1281.                   request->state = GTK_CUPS_GET_AUTH;
  1282.                   request->need_password = TRUE;
  1283.  
  1284.                   return;
  1285.                 }
  1286.             }
  1287.           else
  1288.             {
  1289.               cups_password = request->password;
  1290.               cups_username = request->username;
  1291.  
  1292.               auth_result = cupsDoAuthentication (request->http, "GET", request->resource);
  1293.  
  1294.               if (cups_password != NULL)
  1295.                 return;
  1296.  
  1297.               if (request->password != NULL)
  1298.                 {
  1299.                   memset (request->password, 0, strlen (request->password));
  1300.                   g_free (request->password);
  1301.                   request->password = NULL;
  1302.                 }
  1303.  
  1304.               request->password_state = GTK_CUPS_PASSWORD_APPLIED;
  1305.             }
  1306.         }
  1307.  
  1308.       if (auth_result ||
  1309.           httpReconnect (request->http))
  1310.         {
  1311.           /* if the password has been used, reset password_state
  1312.            * so that we ask for a new one next time around
  1313.            */
  1314.           if (cups_password == NULL)
  1315.             request->password_state = GTK_CUPS_PASSWORD_NONE;
  1316.  
  1317.           request->state = GTK_CUPS_GET_DONE;
  1318.           request->poll_state = GTK_CUPS_HTTP_IDLE;
  1319.           gtk_cups_result_set_error (request->result,
  1320.                                      GTK_CUPS_ERROR_AUTH,
  1321.                                      0,
  1322.                                      0,
  1323.                                      "Not authorized");
  1324.           return;
  1325.         }
  1326.  
  1327.       request->state = GTK_CUPS_GET_SEND;
  1328.       request->last_status = HTTP_CONTINUE;
  1329.  
  1330.      return;
  1331.     }
  1332.   else if (http_status == HTTP_UPGRADE_REQUIRED)
  1333.     {
  1334.       /* Flush any error message... */
  1335.       httpFlush (request->http);
  1336.  
  1337.       cupsSetEncryption (HTTP_ENCRYPT_REQUIRED);
  1338.       request->state = GTK_CUPS_GET_CONNECT;
  1339.  
  1340.       /* Reconnect... */
  1341.       httpReconnect (request->http);
  1342.  
  1343.       /* Upgrade with encryption... */
  1344.       httpEncryption (request->http, HTTP_ENCRYPT_REQUIRED);
  1345.  
  1346.       request->attempts++;
  1347.       goto again;
  1348.     }
  1349.   else if (http_status != HTTP_OK)
  1350.     {
  1351.       int http_errno;
  1352.  
  1353.       http_errno = httpError (request->http);
  1354.  
  1355.       if (http_errno == EPIPE)
  1356.         request->state = GTK_CUPS_GET_CONNECT;
  1357.       else
  1358.         {
  1359.           request->state = GTK_CUPS_GET_DONE;
  1360.           gtk_cups_result_set_error (request->result,
  1361.                                      GTK_CUPS_ERROR_HTTP,
  1362.                                      http_status,
  1363.                                      http_errno,
  1364.                                      "HTTP Error in GET %s",
  1365.                                      g_strerror (http_errno));
  1366.           request->poll_state = GTK_CUPS_HTTP_IDLE;
  1367.           httpFlush (request->http);
  1368.  
  1369.           return;
  1370.         }
  1371.  
  1372.       request->poll_state = GTK_CUPS_HTTP_IDLE;
  1373.       httpFlush (request->http);
  1374.       httpClose (request->http);
  1375.       request->last_status = HTTP_CONTINUE;
  1376.       request->http = NULL;
  1377.       return;
  1378.  
  1379.     }
  1380.   else
  1381.     {
  1382.       request->state = GTK_CUPS_GET_READ_DATA;
  1383.       return;
  1384.     }
  1385.  
  1386.  again:
  1387.   http_status = HTTP_CONTINUE;
  1388.  
  1389.   if (httpCheck (request->http))
  1390.     http_status = httpUpdate (request->http);
  1391.  
  1392.   request->last_status = http_status;
  1393.  
  1394. }
  1395.  
  1396. static void
  1397. _get_read_data (GtkCupsRequest *request)
  1398. {
  1399.   char buffer[_GTK_CUPS_MAX_CHUNK_SIZE];
  1400.   gsize bytes;
  1401.   gsize bytes_written;
  1402.   GIOStatus io_status;
  1403.   GError *error;
  1404.  
  1405.   GTK_NOTE (PRINTING,
  1406.             g_print ("CUPS Backend: %s\n", G_STRFUNC));
  1407.  
  1408.   error = NULL;
  1409.  
  1410.   request->poll_state = GTK_CUPS_HTTP_READ;
  1411.  
  1412. #if HAVE_CUPS_API_1_2
  1413.   bytes = httpRead2 (request->http, buffer, sizeof (buffer));
  1414. #else
  1415.   bytes = httpRead (request->http, buffer, sizeof (buffer));
  1416. #endif /* HAVE_CUPS_API_1_2 */
  1417.   request->bytes_received += bytes;
  1418.  
  1419.   GTK_NOTE (PRINTING,
  1420.             g_print ("CUPS Backend: %" G_GSIZE_FORMAT " bytes read\n", bytes));
  1421.  
  1422.   io_status =
  1423.     g_io_channel_write_chars (request->data_io,
  1424.                               buffer,
  1425.                   bytes,
  1426.                   &bytes_written,
  1427.                   &error);
  1428.  
  1429.   if (io_status == G_IO_STATUS_ERROR)
  1430.     {
  1431.       request->state = GTK_CUPS_GET_DONE;
  1432.       request->poll_state = GTK_CUPS_HTTP_IDLE;
  1433.    
  1434.       gtk_cups_result_set_error (request->result,
  1435.                                  GTK_CUPS_ERROR_IO,
  1436.                                  io_status,
  1437.                                  error->code,
  1438.                                  error->message);
  1439.       g_error_free (error);
  1440.     }
  1441.  
  1442.   /* Stop if we do not expect any more data or EOF was received. */
  1443. #if HAVE_CUPS_API_1_2
  1444.   if (httpGetLength2 (request->http) <= request->bytes_received || bytes == 0)
  1445. #else
  1446.   if (httpGetLength (request->http) <= request->bytes_received || bytes == 0)
  1447. #endif /* HAVE_CUPS_API_1_2 */
  1448.     {
  1449.       request->state = GTK_CUPS_GET_DONE;
  1450.       request->poll_state = GTK_CUPS_HTTP_IDLE;
  1451.  
  1452.       return;
  1453.     }
  1454. }
  1455.  
  1456. gboolean
  1457. gtk_cups_request_is_done (GtkCupsRequest *request)
  1458. {
  1459.   return (request->state == GTK_CUPS_REQUEST_DONE);
  1460. }
  1461.  
  1462. gboolean
  1463. gtk_cups_result_is_error (GtkCupsResult *result)
  1464. {
  1465.   return result->is_error;
  1466. }
  1467.  
  1468. ipp_t *
  1469. gtk_cups_result_get_response (GtkCupsResult *result)
  1470. {
  1471.   return result->ipp_response;
  1472. }
  1473.  
  1474. GtkCupsErrorType
  1475. gtk_cups_result_get_error_type (GtkCupsResult *result)
  1476. {
  1477.   return result->error_type;
  1478. }
  1479.  
  1480. int
  1481. gtk_cups_result_get_error_status (GtkCupsResult *result)
  1482. {
  1483.   return result->error_status;
  1484. }
  1485.  
  1486. int
  1487. gtk_cups_result_get_error_code (GtkCupsResult *result)
  1488. {
  1489.   return result->error_code;
  1490. }
  1491.  
  1492. const char *
  1493. gtk_cups_result_get_error_string (GtkCupsResult *result)
  1494. {
  1495.   return result->error_msg;
  1496. }
  1497.  
  1498. /* This function allocates new instance of GtkCupsConnectionTest() and creates
  1499.  * a socket for communication with a CUPS server 'server'.
  1500.  */
  1501. GtkCupsConnectionTest *
  1502. gtk_cups_connection_test_new (const char *server)
  1503. {
  1504.   GtkCupsConnectionTest *result = NULL;
  1505. #ifdef HAVE_CUPS_API_1_2
  1506.   gchar                 *port_str = NULL;
  1507.  
  1508.   result = g_new (GtkCupsConnectionTest, 1);
  1509.  
  1510.   port_str = g_strdup_printf ("%d", ippPort ());
  1511.  
  1512.   if (server != NULL)
  1513.     result->addrlist = httpAddrGetList (server, AF_UNSPEC, port_str);
  1514.   else
  1515.     result->addrlist = httpAddrGetList (cupsServer (), AF_UNSPEC, port_str);
  1516.  
  1517.   g_free (port_str);
  1518.  
  1519.   result->socket = -1;
  1520.   result->current_addr = NULL;
  1521.   result->last_wrong_addr = NULL;
  1522.   result->at_init = GTK_CUPS_CONNECTION_NOT_AVAILABLE;
  1523.  
  1524.   result->at_init = gtk_cups_connection_test_get_state (result);
  1525. #else
  1526.   result = g_new (GtkCupsConnectionTest, 1);
  1527. #endif
  1528.  
  1529.   return result;
  1530. }
  1531.  
  1532.  
  1533. /* A non-blocking test whether it is possible to connect to a CUPS server specified
  1534.  * inside of GtkCupsConnectionTest structure.
  1535.  *  - you need to check it more then once.
  1536.  * The connection is closed after a successful connection.
  1537.  */
  1538. GtkCupsConnectionState
  1539. gtk_cups_connection_test_get_state (GtkCupsConnectionTest *test)
  1540. {
  1541. #ifdef HAVE_CUPS_API_1_2
  1542.   GtkCupsConnectionState result = GTK_CUPS_CONNECTION_NOT_AVAILABLE;
  1543.   http_addrlist_t       *iter;
  1544.   gint                   error_code;
  1545.   gint                   flags;
  1546.   gint                   code;
  1547.  
  1548.   if (test == NULL)
  1549.     return GTK_CUPS_CONNECTION_NOT_AVAILABLE;
  1550.  
  1551.   if (test->at_init == GTK_CUPS_CONNECTION_AVAILABLE)
  1552.     {
  1553.       test->at_init = GTK_CUPS_CONNECTION_NOT_AVAILABLE;
  1554.       return GTK_CUPS_CONNECTION_AVAILABLE;
  1555.     }
  1556.   else
  1557.     {
  1558.       if (test->socket == -1)
  1559.         {
  1560.           if (test->last_wrong_addr != NULL && test->last_wrong_addr->next != NULL)
  1561.             iter = test->last_wrong_addr->next;
  1562.           else
  1563.             {
  1564.               test->last_wrong_addr = NULL;
  1565.               iter = test->addrlist;
  1566.             }
  1567.  
  1568.           while (iter)
  1569.             {
  1570.               test->socket = socket (iter->addr.addr.sa_family,
  1571.                                      SOCK_STREAM,
  1572.                                      0);
  1573.  
  1574.               if (test->socket >= 0)
  1575.                 {
  1576.                   flags = fcntl (test->socket, F_GETFL);
  1577.  
  1578.                   if (flags != -1)
  1579.                     flags |= O_NONBLOCK;
  1580.  
  1581.                   fcntl (test->socket, F_SETFL, flags);
  1582.              
  1583.                   test->current_addr = iter;
  1584.              
  1585.                   break;
  1586.                 }
  1587.                iter = iter->next;
  1588.             }
  1589.         }
  1590.  
  1591.       if (test->socket >= 0)
  1592.         {
  1593.           code = connect (test->socket,
  1594.                           &test->current_addr->addr.addr,
  1595.                           httpAddrLength (&test->current_addr->addr));
  1596.  
  1597.           error_code = errno;
  1598.  
  1599.           if (code == 0 || error_code == EISCONN)
  1600.             {
  1601.               close (test->socket);
  1602.               test->socket = -1;
  1603.               test->current_addr = NULL;
  1604.               result = GTK_CUPS_CONNECTION_AVAILABLE;
  1605.             }
  1606.           else
  1607.             {
  1608.               if (error_code == EALREADY || error_code == EINPROGRESS)
  1609.                 result = GTK_CUPS_CONNECTION_IN_PROGRESS;
  1610.               else
  1611.                 {
  1612.                   close (test->socket);
  1613.                   test->socket = -1;
  1614.                   test->last_wrong_addr = test->current_addr;
  1615.                   result = GTK_CUPS_CONNECTION_NOT_AVAILABLE;
  1616.                 }
  1617.             }
  1618.          }
  1619.  
  1620.       return result;
  1621.     }
  1622. #else
  1623.   return GTK_CUPS_CONNECTION_AVAILABLE;
  1624. #endif
  1625. }
  1626.  
  1627. /* This function frees memory used by the GtkCupsConnectionTest structure.
  1628.  */
  1629. void
  1630. gtk_cups_connection_test_free (GtkCupsConnectionTest *test)
  1631. {
  1632.   if (test == NULL)
  1633.     return;
  1634.  
  1635. #ifdef HAVE_CUPS_API_1_2
  1636.   test->current_addr = NULL;
  1637.   test->last_wrong_addr = NULL;
  1638.   httpAddrFreeList (test->addrlist);
  1639.   if (test->socket != -1)
  1640.     {
  1641.       close (test->socket);
  1642.       test->socket = -1;
  1643.     }
  1644. #endif
  1645.   g_free (test);
  1646. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement