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.
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.
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.
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.
24 #include "gtkcupsutils.h"
28 #include <sys/types.h>
33 #include <sys/socket.h>
35 typedef void (*GtkCupsRequestStateFunc) (GtkCupsRequest *request);
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_read_response (GtkCupsRequest *request);
44 static void _get_send (GtkCupsRequest *request);
45 static void _get_check (GtkCupsRequest *request);
46 static void _get_read_data (GtkCupsRequest *request);
52 GtkCupsErrorType error_type;
54 /* some error types like HTTP_ERROR have a status and a code */
59 guint is_ipp_response : 1;
63 #define _GTK_CUPS_MAX_ATTEMPTS 10
64 #define _GTK_CUPS_MAX_CHUNK_SIZE 8192
66 static GtkCupsRequestStateFunc post_states[] = {
75 static GtkCupsRequestStateFunc get_states[] = {
83 gtk_cups_result_set_error (GtkCupsResult *result,
84 GtkCupsErrorType error_type,
87 const char *error_msg,
92 result->is_ipp_response = FALSE;
93 result->is_error = TRUE;
94 result->error_type = error_type;
95 result->error_status = error_status;
96 result->error_code = error_code;
98 va_start (args, error_msg);
99 result->error_msg = g_strdup_vprintf (error_msg, args);
104 gtk_cups_request_new (http_t *connection,
105 GtkCupsRequestType req_type,
109 const char *resource)
111 GtkCupsRequest *request;
112 cups_lang_t *language;
114 request = g_new0 (GtkCupsRequest, 1);
115 request->result = g_new0 (GtkCupsResult, 1);
117 request->result->error_msg = NULL;
118 request->result->ipp_response = NULL;
120 request->result->is_error = FALSE;
121 request->result->is_ipp_response = FALSE;
123 request->type = req_type;
124 request->state = GTK_CUPS_REQUEST_START;
127 request->server = g_strdup (server);
129 request->server = g_strdup (cupsServer ());
133 request->resource = g_strdup (resource);
135 request->resource = g_strdup ("/");
137 if (connection != NULL)
139 request->http = connection;
140 request->own_http = FALSE;
144 request->http = NULL;
145 request->http = httpConnectEncrypt (request->server,
150 httpBlocking (request->http, 0);
152 request->own_http = TRUE;
155 request->last_status = HTTP_CONTINUE;
157 request->attempts = 0;
158 request->data_io = data_io;
160 request->ipp_request = ippNew ();
161 request->ipp_request->request.op.operation_id = operation_id;
162 request->ipp_request->request.op.request_id = 1;
164 language = cupsLangDefault ();
166 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
167 "attributes-charset",
170 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
171 "attributes-natural-language",
172 NULL, language->language);
174 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
175 "requesting-user-name",
178 cupsLangFree (language);
184 gtk_cups_result_free (GtkCupsResult *result)
186 g_free (result->error_msg);
188 if (result->ipp_response)
189 ippDelete (result->ipp_response);
195 gtk_cups_request_free (GtkCupsRequest *request)
197 if (request->own_http)
200 httpClose (request->http);
203 if (request->ipp_request)
204 ippDelete (request->ipp_request);
206 g_free (request->server);
207 g_free (request->resource);
209 gtk_cups_result_free (request->result);
215 gtk_cups_request_read_write (GtkCupsRequest *request)
217 if (request->type == GTK_CUPS_POST)
218 post_states[request->state] (request);
219 else if (request->type == GTK_CUPS_GET)
220 get_states[request->state] (request);
222 if (request->attempts > _GTK_CUPS_MAX_ATTEMPTS &&
223 request->state != GTK_CUPS_REQUEST_DONE)
225 /* TODO: should add a status or error code for too many failed attempts */
226 gtk_cups_result_set_error (request->result,
227 GTK_CUPS_ERROR_GENERAL,
230 "Too many failed attempts");
232 request->state = GTK_CUPS_REQUEST_DONE;
233 request->poll_state = GTK_CUPS_HTTP_IDLE;
236 if (request->state == GTK_CUPS_REQUEST_DONE)
238 request->poll_state = GTK_CUPS_HTTP_IDLE;
246 gtk_cups_request_get_poll_state (GtkCupsRequest *request)
248 return request->poll_state;
254 gtk_cups_request_get_result (GtkCupsRequest *request)
256 return request->result;
260 gtk_cups_request_ipp_add_string (GtkCupsRequest *request,
267 ippAddString (request->ipp_request,
276 gtk_cups_request_ipp_add_strings (GtkCupsRequest *request,
282 const char *const *values)
284 ippAddStrings (request->ipp_request,
301 static const ipp_option_t ipp_options[] = {
302 { "blackplot", IPP_TAG_BOOLEAN },
303 { "brightness", IPP_TAG_INTEGER },
304 { "columns", IPP_TAG_INTEGER },
305 { "copies", IPP_TAG_INTEGER },
306 { "finishings", IPP_TAG_ENUM },
307 { "fitplot", IPP_TAG_BOOLEAN },
308 { "gamma", IPP_TAG_INTEGER },
309 { "hue", IPP_TAG_INTEGER },
310 { "job-k-limit", IPP_TAG_INTEGER },
311 { "job-page-limit", IPP_TAG_INTEGER },
312 { "job-priority", IPP_TAG_INTEGER },
313 { "job-quota-period", IPP_TAG_INTEGER },
314 { "landscape", IPP_TAG_BOOLEAN },
315 { "media", IPP_TAG_KEYWORD },
316 { "mirror", IPP_TAG_BOOLEAN },
317 { "natural-scaling", IPP_TAG_INTEGER },
318 { "number-up", IPP_TAG_INTEGER },
319 { "orientation-requested", IPP_TAG_ENUM },
320 { "page-bottom", IPP_TAG_INTEGER },
321 { "page-left", IPP_TAG_INTEGER },
322 { "page-ranges", IPP_TAG_RANGE },
323 { "page-right", IPP_TAG_INTEGER },
324 { "page-top", IPP_TAG_INTEGER },
325 { "penwidth", IPP_TAG_INTEGER },
326 { "ppi", IPP_TAG_INTEGER },
327 { "prettyprint", IPP_TAG_BOOLEAN },
328 { "printer-resolution", IPP_TAG_RESOLUTION },
329 { "print-quality", IPP_TAG_ENUM },
330 { "saturation", IPP_TAG_INTEGER },
331 { "scaling", IPP_TAG_INTEGER },
332 { "sides", IPP_TAG_KEYWORD },
333 { "wrap", IPP_TAG_BOOLEAN }
338 _find_option_tag (const gchar *option)
340 int lower_bound, upper_bound, num_options;
344 result = IPP_TAG_ZERO;
347 upper_bound = num_options = (int) G_N_ELEMENTS (ipp_options) - 1;
352 current_option = (int) (((upper_bound - lower_bound) / 2) + lower_bound);
354 match = strcasecmp (option, ipp_options[current_option].name);
357 result = ipp_options[current_option].value_tag;
362 upper_bound = current_option - 1;
366 lower_bound = current_option + 1;
369 if (upper_bound == lower_bound && upper_bound == current_option)
375 if (lower_bound > num_options)
378 if (upper_bound < lower_bound)
384 * Note that this function uses IPP_TAG_JOB, so it is
385 * only suitable for IPP Group 2 attributes.
389 gtk_cups_request_encode_option (GtkCupsRequest *request,
393 ipp_tag_t option_tag;
395 g_return_if_fail (option != NULL);
396 g_return_if_fail (value != NULL);
398 option_tag = _find_option_tag (option);
400 if (option_tag == IPP_TAG_ZERO)
402 option_tag = IPP_TAG_NAME;
403 if (strcasecmp (value, "true") == 0 ||
404 strcasecmp (value, "false") == 0)
406 option_tag = IPP_TAG_BOOLEAN;
412 case IPP_TAG_INTEGER:
414 ippAddInteger (request->ipp_request,
418 strtol (value, NULL, 0));
421 case IPP_TAG_BOOLEAN:
425 if (strcasecmp (value, "true") == 0 ||
426 strcasecmp (value, "on") == 0 ||
427 strcasecmp (value, "yes") == 0)
432 ippAddBoolean (request->ipp_request,
452 lower = strtol (value, &s, 0);
457 upper = strtol (s + 1, NULL, 0);
464 ippAddRange (request->ipp_request,
473 case IPP_TAG_RESOLUTION:
480 xres = strtol (value, &s, 0);
483 yres = strtol (s + 1, &s, 0);
487 if (strcasecmp (s, "dpc") == 0)
488 units = IPP_RES_PER_CM;
490 units = IPP_RES_PER_INCH;
492 ippAddResolution (request->ipp_request,
510 values = g_strdup (value);
514 for (s = values, next = s; *s != '\0'; s++)
516 if (in_quotes != 2 && *s == '\'')
518 /* skip quoted value */
524 else if (in_quotes != 1 && *s == '\"')
526 /* skip quoted value */
532 else if (in_quotes == 0 && *s == ',')
534 /* found delimiter, add to value array */
537 strings = g_ptr_array_new ();
538 g_ptr_array_add (strings, next);
541 else if (in_quotes == 0 && *s == '\\' && s[1] != '\0')
543 /* skip escaped character */
551 ippAddString (request->ipp_request,
560 /* multiple values */
563 g_ptr_array_add (strings, next);
565 ippAddStrings (request->ipp_request,
571 (const char **) strings->pdata);
572 g_ptr_array_free (strings, TRUE);
584 _connect (GtkCupsRequest *request)
586 request->poll_state = GTK_CUPS_HTTP_IDLE;
588 if (request->http == NULL)
590 request->http = httpConnectEncrypt (request->server,
594 if (request->http == NULL)
598 httpBlocking (request->http, 0);
600 request->own_http = TRUE;
604 request->attempts = 0;
607 /* we always write to the socket after we get
609 request->poll_state = GTK_CUPS_HTTP_WRITE;
614 _post_send (GtkCupsRequest *request)
617 struct stat data_info;
620 g_print ("CUPS Backend: %s\n", G_STRFUNC));
622 request->poll_state = GTK_CUPS_HTTP_WRITE;
624 if (request->data_io != NULL)
626 fstat (g_io_channel_unix_get_fd (request->data_io), &data_info);
627 sprintf (length, "%lu", (unsigned long) (ippLength (request->ipp_request) + data_info.st_size));
630 sprintf (length, "%lu", (unsigned long) ippLength (request->ipp_request));
632 httpClearFields (request->http);
633 httpSetField (request->http, HTTP_FIELD_CONTENT_LENGTH, length);
634 httpSetField (request->http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
635 #ifdef HAVE_HTTPGETAUTHSTRING
636 httpSetField (request->http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString (request->http));
638 #ifdef HAVE_HTTP_AUTHSTRING
639 httpSetField (request->http, HTTP_FIELD_AUTHORIZATION, request->http->authstring);
643 if (httpPost (request->http, request->resource))
645 if (httpReconnect (request->http))
647 request->state = GTK_CUPS_POST_DONE;
648 request->poll_state = GTK_CUPS_HTTP_IDLE;
650 /* TODO: should add a status or error code for failed post */
651 gtk_cups_result_set_error (request->result,
652 GTK_CUPS_ERROR_GENERAL,
662 request->attempts = 0;
664 request->state = GTK_CUPS_POST_WRITE_REQUEST;
665 request->ipp_request->state = IPP_IDLE;
669 _post_write_request (GtkCupsRequest *request)
671 ipp_state_t ipp_status;
674 g_print ("CUPS Backend: %s\n", G_STRFUNC));
676 request->poll_state = GTK_CUPS_HTTP_WRITE;
678 ipp_status = ippWrite (request->http, request->ipp_request);
680 if (ipp_status == IPP_ERROR)
682 int cups_error = cupsLastError ();
683 request->state = GTK_CUPS_POST_DONE;
684 request->poll_state = GTK_CUPS_HTTP_IDLE;
686 gtk_cups_result_set_error (request->result,
691 ippErrorString (cups_error));
695 if (ipp_status == IPP_DATA)
697 if (request->data_io != NULL)
698 request->state = GTK_CUPS_POST_WRITE_DATA;
701 request->state = GTK_CUPS_POST_CHECK;
702 request->poll_state = GTK_CUPS_HTTP_READ;
708 _post_write_data (GtkCupsRequest *request)
711 char buffer[_GTK_CUPS_MAX_CHUNK_SIZE];
712 http_status_t http_status;
715 g_print ("CUPS Backend: %s\n", G_STRFUNC));
717 request->poll_state = GTK_CUPS_HTTP_WRITE;
719 if (httpCheck (request->http))
720 http_status = httpUpdate (request->http);
722 http_status = request->last_status;
724 request->last_status = http_status;
727 if (http_status == HTTP_CONTINUE || http_status == HTTP_OK)
736 g_io_channel_read_chars (request->data_io,
738 _GTK_CUPS_MAX_CHUNK_SIZE,
742 if (io_status == G_IO_STATUS_ERROR)
744 request->state = GTK_CUPS_POST_DONE;
745 request->poll_state = GTK_CUPS_HTTP_IDLE;
747 gtk_cups_result_set_error (request->result,
751 "Error reading from cache file: %s",
754 g_error_free (error);
757 else if (bytes == 0 && io_status == G_IO_STATUS_EOF)
759 request->state = GTK_CUPS_POST_CHECK;
760 request->poll_state = GTK_CUPS_HTTP_READ;
762 request->attempts = 0;
767 #if HAVE_CUPS_API_1_2
768 if (httpWrite2 (request->http, buffer, bytes) < bytes)
770 if (httpWrite (request->http, buffer, (int) bytes) < bytes)
771 #endif /* HAVE_CUPS_API_1_2 */
775 http_errno = httpError (request->http);
777 request->state = GTK_CUPS_POST_DONE;
778 request->poll_state = GTK_CUPS_HTTP_IDLE;
780 gtk_cups_result_set_error (request->result,
784 "Error writing to socket in Post %s",
785 g_strerror (http_errno));
796 _post_check (GtkCupsRequest *request)
798 http_status_t http_status;
800 http_status = request->last_status;
803 g_print ("CUPS Backend: %s - status %i\n", G_STRFUNC, http_status));
805 request->poll_state = GTK_CUPS_HTTP_READ;
807 if (http_status == HTTP_CONTINUE)
811 else if (http_status == HTTP_UNAUTHORIZED)
813 /* TODO: callout for auth */
814 g_warning ("NOT IMPLEMENTED: We need to prompt for authorization");
815 request->state = GTK_CUPS_POST_DONE;
816 request->poll_state = GTK_CUPS_HTTP_IDLE;
818 /* TODO: create a not implemented error code */
819 gtk_cups_result_set_error (request->result,
820 GTK_CUPS_ERROR_GENERAL,
823 "Can't prompt for authorization");
826 else if (http_status == HTTP_ERROR)
828 int error = httpError (request->http);
830 if (error != WSAENETDOWN && error != WSAENETUNREACH)
832 if (error != ENETDOWN && error != ENETUNREACH)
833 #endif /* G_OS_WIN32 */
840 request->state = GTK_CUPS_POST_DONE;
841 request->poll_state = GTK_CUPS_HTTP_IDLE;
843 gtk_cups_result_set_error (request->result,
847 "Unknown HTTP error");
852 else if (http_status == HTTP_UPGRADE_REQUIRED)
854 /* Flush any error message... */
855 httpFlush (request->http);
857 cupsSetEncryption (HTTP_ENCRYPT_REQUIRED);
858 request->state = GTK_CUPS_POST_CONNECT;
861 httpReconnect (request->http);
863 /* Upgrade with encryption... */
864 httpEncryption (request->http, HTTP_ENCRYPT_REQUIRED);
869 else if (http_status != HTTP_OK)
873 http_errno = httpError (request->http);
875 if (http_errno == EPIPE)
876 request->state = GTK_CUPS_POST_CONNECT;
879 request->state = GTK_CUPS_POST_DONE;
880 gtk_cups_result_set_error (request->result,
884 "HTTP Error in POST %s",
885 g_strerror (http_errno));
886 request->poll_state = GTK_CUPS_HTTP_IDLE;
888 httpFlush (request->http);
892 request->poll_state = GTK_CUPS_HTTP_IDLE;
894 httpFlush (request->http);
896 request->last_status = HTTP_CONTINUE;
897 httpClose (request->http);
898 request->http = NULL;
903 request->state = GTK_CUPS_POST_READ_RESPONSE;
908 http_status = HTTP_CONTINUE;
910 if (httpCheck (request->http))
911 http_status = httpUpdate (request->http);
913 request->last_status = http_status;
917 _post_read_response (GtkCupsRequest *request)
919 ipp_state_t ipp_status;
922 g_print ("CUPS Backend: %s\n", G_STRFUNC));
924 request->poll_state = GTK_CUPS_HTTP_READ;
926 if (request->result->ipp_response == NULL)
927 request->result->ipp_response = ippNew();
929 ipp_status = ippRead (request->http,
930 request->result->ipp_response);
932 if (ipp_status == IPP_ERROR)
934 int ipp_error = cupsLastError ();
935 gtk_cups_result_set_error (request->result,
940 ippErrorString (ipp_error));
942 ippDelete (request->result->ipp_response);
943 request->result->ipp_response = NULL;
945 request->state = GTK_CUPS_POST_DONE;
946 request->poll_state = GTK_CUPS_HTTP_IDLE;
948 else if (ipp_status == IPP_DATA)
950 request->state = GTK_CUPS_POST_DONE;
951 request->poll_state = GTK_CUPS_HTTP_IDLE;
956 _get_send (GtkCupsRequest *request)
959 g_print ("CUPS Backend: %s\n", G_STRFUNC));
961 request->poll_state = GTK_CUPS_HTTP_WRITE;
963 if (request->data_io == NULL)
965 gtk_cups_result_set_error (request->result,
968 G_IO_CHANNEL_ERROR_FAILED,
969 "Get requires an open io channel");
971 request->state = GTK_CUPS_GET_DONE;
972 request->poll_state = GTK_CUPS_HTTP_IDLE;
977 httpClearFields (request->http);
978 #ifdef HAVE_HTTP_AUTHSTRING
979 httpSetField (request->http, HTTP_FIELD_AUTHORIZATION, request->http->authstring);
982 if (httpGet (request->http, request->resource))
984 if (httpReconnect (request->http))
986 request->state = GTK_CUPS_GET_DONE;
987 request->poll_state = GTK_CUPS_HTTP_IDLE;
989 /* TODO: should add a status or error code for failed GET */
990 gtk_cups_result_set_error (request->result,
991 GTK_CUPS_ERROR_GENERAL,
1001 request->attempts = 0;
1003 request->state = GTK_CUPS_GET_CHECK;
1004 request->poll_state = GTK_CUPS_HTTP_READ;
1006 request->ipp_request->state = IPP_IDLE;
1010 _get_check (GtkCupsRequest *request)
1012 http_status_t http_status;
1015 g_print ("CUPS Backend: %s\n", G_STRFUNC));
1017 http_status = request->last_status;
1019 request->poll_state = GTK_CUPS_HTTP_READ;
1021 if (http_status == HTTP_CONTINUE)
1025 else if (http_status == HTTP_UNAUTHORIZED)
1027 /* TODO: callout for auth */
1028 g_warning ("NOT IMPLEMENTED: We need to prompt for authorization in a non blocking manner");
1029 request->state = GTK_CUPS_GET_DONE;
1030 request->poll_state = GTK_CUPS_HTTP_IDLE;
1032 /* TODO: should add a status or error code for not implemented */
1033 gtk_cups_result_set_error (request->result,
1034 GTK_CUPS_ERROR_GENERAL,
1037 "Can't prompt for authorization");
1040 else if (http_status == HTTP_UPGRADE_REQUIRED)
1042 /* Flush any error message... */
1043 httpFlush (request->http);
1045 cupsSetEncryption (HTTP_ENCRYPT_REQUIRED);
1046 request->state = GTK_CUPS_POST_CONNECT;
1049 httpReconnect (request->http);
1051 /* Upgrade with encryption... */
1052 httpEncryption (request->http, HTTP_ENCRYPT_REQUIRED);
1054 request->attempts++;
1057 else if (http_status != HTTP_OK)
1061 http_errno = httpError (request->http);
1063 if (http_errno == EPIPE)
1064 request->state = GTK_CUPS_GET_CONNECT;
1067 request->state = GTK_CUPS_GET_DONE;
1068 gtk_cups_result_set_error (request->result,
1069 GTK_CUPS_ERROR_HTTP,
1072 "HTTP Error in GET %s",
1073 g_strerror (http_errno));
1074 request->poll_state = GTK_CUPS_HTTP_IDLE;
1075 httpFlush (request->http);
1080 request->poll_state = GTK_CUPS_HTTP_IDLE;
1081 httpFlush (request->http);
1082 httpClose (request->http);
1083 request->last_status = HTTP_CONTINUE;
1084 request->http = NULL;
1090 request->state = GTK_CUPS_GET_READ_DATA;
1095 http_status = HTTP_CONTINUE;
1097 if (httpCheck (request->http))
1098 http_status = httpUpdate (request->http);
1100 request->last_status = http_status;
1105 _get_read_data (GtkCupsRequest *request)
1107 char buffer[_GTK_CUPS_MAX_CHUNK_SIZE];
1109 gsize bytes_written;
1110 GIOStatus io_status;
1114 g_print ("CUPS Backend: %s\n", G_STRFUNC));
1118 request->poll_state = GTK_CUPS_HTTP_READ;
1120 #if HAVE_CUPS_API_1_2
1121 bytes = httpRead2 (request->http, buffer, sizeof (buffer));
1123 bytes = httpRead (request->http, buffer, sizeof (buffer));
1124 #endif /* HAVE_CUPS_API_1_2 */
1127 g_print ("CUPS Backend: %i bytes read\n", bytes));
1131 request->state = GTK_CUPS_GET_DONE;
1132 request->poll_state = GTK_CUPS_HTTP_IDLE;
1138 g_io_channel_write_chars (request->data_io,
1144 if (io_status == G_IO_STATUS_ERROR)
1146 request->state = GTK_CUPS_POST_DONE;
1147 request->poll_state = GTK_CUPS_HTTP_IDLE;
1149 gtk_cups_result_set_error (request->result,
1154 g_error_free (error);
1159 gtk_cups_request_is_done (GtkCupsRequest *request)
1161 return (request->state == GTK_CUPS_REQUEST_DONE);
1165 gtk_cups_result_is_error (GtkCupsResult *result)
1167 return result->is_error;
1171 gtk_cups_result_get_response (GtkCupsResult *result)
1173 return result->ipp_response;
1177 gtk_cups_result_get_error_type (GtkCupsResult *result)
1179 return result->error_type;
1183 gtk_cups_result_get_error_status (GtkCupsResult *result)
1185 return result->error_status;
1189 gtk_cups_result_get_error_code (GtkCupsResult *result)
1191 return result->error_code;
1195 gtk_cups_result_get_error_string (GtkCupsResult *result)
1197 return result->error_msg;
1200 /* This function allocates new instance of GtkCupsConnectionTest() and creates
1201 * a socket for communication with a CUPS server 'server'.
1203 GtkCupsConnectionTest *
1204 gtk_cups_connection_test_new (const char *server)
1206 GtkCupsConnectionTest *result = NULL;
1207 gchar *port_str = NULL;
1209 result = g_new (GtkCupsConnectionTest, 1);
1211 port_str = g_strdup_printf ("%d", ippPort ());
1214 result->addrlist = httpAddrGetList (server, AF_UNSPEC, port_str);
1216 result->addrlist = httpAddrGetList (cupsServer (), AF_UNSPEC, port_str);
1220 result->socket = -1;
1221 result->current_addr = NULL;
1222 result->success_at_init = FALSE;
1224 result->success_at_init = gtk_cups_connection_test_is_server_available (result);
1230 /* A non-blocking test whether it is possible to connect to a CUPS server specified
1231 * inside of GtkCupsConnectionTest structure.
1232 * - you need to check it more then once.
1233 * The connection is closed after a successful connection.
1236 gtk_cups_connection_test_is_server_available (GtkCupsConnectionTest *test)
1238 http_addrlist_t *iter;
1239 gboolean result = FALSE;
1246 if (test->success_at_init)
1248 test->success_at_init = FALSE;
1253 if (test->socket == -1)
1255 iter = test->addrlist;
1258 test->socket = socket (iter->addr.addr.sa_family,
1262 if (test->socket >= 0)
1264 flags = fcntl (test->socket, F_GETFL);
1267 flags |= O_NONBLOCK;
1269 fcntl (test->socket, F_SETFL, flags);
1271 test->current_addr = iter;
1279 if (test->socket >= 0)
1281 code = connect (test->socket,
1282 &test->current_addr->addr.addr,
1283 httpAddrLength (&test->current_addr->addr));
1287 close (test->socket);
1289 test->current_addr = NULL;
1300 /* This function frees memory used by the GtkCupsConnectionTest structure.
1303 gtk_cups_connection_test_free (GtkCupsConnectionTest *test)
1308 test->current_addr = NULL;
1309 httpAddrFreeList (test->addrlist);
1310 if (test->socket != -1)
1312 close (test->socket);