Bug 424207 – printing hangs on unreachable cups server

svn path=/trunk/; revision=20923
This commit is contained in:
Matthias Clasen
2008-07-31 23:56:17 +00:00
parent c04c884f35
commit e9d978dff9
4 changed files with 229 additions and 43 deletions

View File

@ -29,6 +29,8 @@
#include <sys/stat.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <sys/socket.h>
typedef void (*GtkCupsRequestStateFunc) (GtkCupsRequest *request);
@ -1195,3 +1197,120 @@ gtk_cups_result_get_error_string (GtkCupsResult *result)
return result->error_msg;
}
/* This function allocates new instance of GtkCupsConnectionTest() and creates
* a socket for communication with a CUPS server 'server'.
*/
GtkCupsConnectionTest *
gtk_cups_connection_test_new (const char *server)
{
GtkCupsConnectionTest *result = NULL;
gchar *port_str = NULL;
result = g_new (GtkCupsConnectionTest, 1);
port_str = g_strdup_printf ("%d", ippPort ());
if (server != NULL)
result->addrlist = httpAddrGetList (server, AF_UNSPEC, port_str);
else
result->addrlist = httpAddrGetList (cupsServer (), AF_UNSPEC, port_str);
g_free (port_str);
result->socket = -1;
result->current_addr = NULL;
result->success_at_init = FALSE;
result->success_at_init = gtk_cups_connection_test_is_server_available (result);
return result;
}
/* A non-blocking test whether it is possible to connect to a CUPS server specified
* inside of GtkCupsConnectionTest structure.
* - you need to check it more then once.
* The connection is closed after a successful connection.
*/
gboolean
gtk_cups_connection_test_is_server_available (GtkCupsConnectionTest *test)
{
http_addrlist_t *iter;
gboolean result = FALSE;
gint flags;
gint code;
if (test == NULL)
return FALSE;
if (test->success_at_init)
{
test->success_at_init = FALSE;
return TRUE;
}
else
{
if (test->socket == -1)
{
iter = test->addrlist;
while (iter)
{
test->socket = socket (iter->addr.addr.sa_family,
SOCK_STREAM,
0);
if (test->socket >= 0)
{
flags = fcntl (test->socket, F_GETFL);
if (flags != -1)
flags |= O_NONBLOCK;
fcntl (test->socket, F_SETFL, flags);
test->current_addr = iter;
break;
}
iter = iter->next;
}
}
if (test->socket >= 0)
{
code = connect (test->socket,
&test->current_addr->addr.addr,
httpAddrLength (&test->current_addr->addr));
if (code == 0)
{
close (test->socket);
test->socket = -1;
test->current_addr = NULL;
result = TRUE;
}
else
result = FALSE;
}
return result;
}
}
/* This function frees memory used by the GtkCupsConnectionTest structure.
*/
void
gtk_cups_connection_test_free (GtkCupsConnectionTest *test)
{
if (test == NULL)
return FALSE;
test->current_addr = NULL;
httpAddrFreeList (test->addrlist);
if (test->socket != -1)
{
close (test->socket);
test->socket = -1;
}
g_free (test);
}

View File

@ -28,8 +28,9 @@
G_BEGIN_DECLS
typedef struct _GtkCupsRequest GtkCupsRequest;
typedef struct _GtkCupsResult GtkCupsResult;
typedef struct _GtkCupsRequest GtkCupsRequest;
typedef struct _GtkCupsResult GtkCupsResult;
typedef struct _GtkCupsConnectionTest GtkCupsConnectionTest;
typedef enum
{
@ -80,6 +81,14 @@ struct _GtkCupsRequest
gint own_http : 1;
};
struct _GtkCupsConnectionTest
{
http_addrlist_t *addrlist;
http_addrlist_t *current_addr;
gboolean success_at_init;
gint socket;
};
#define GTK_CUPS_REQUEST_START 0
#define GTK_CUPS_REQUEST_DONE 500
@ -105,39 +114,42 @@ enum
GTK_CUPS_GET_DONE = GTK_CUPS_REQUEST_DONE
};
GtkCupsRequest * gtk_cups_request_new (http_t *connection,
GtkCupsRequestType req_type,
gint operation_id,
GIOChannel *data_io,
const char *server,
const char *resource);
void gtk_cups_request_ipp_add_string (GtkCupsRequest *request,
ipp_tag_t group,
ipp_tag_t tag,
const char *name,
const char *charset,
const char *value);
void gtk_cups_request_ipp_add_strings (GtkCupsRequest *request,
ipp_tag_t group,
ipp_tag_t tag,
const char *name,
int num_values,
const char *charset,
const char * const *values);
gboolean gtk_cups_request_read_write (GtkCupsRequest *request);
GtkCupsPollState gtk_cups_request_get_poll_state (GtkCupsRequest *request);
void gtk_cups_request_free (GtkCupsRequest *request);
GtkCupsResult * gtk_cups_request_get_result (GtkCupsRequest *request);
gboolean gtk_cups_request_is_done (GtkCupsRequest *request);
void gtk_cups_request_encode_option (GtkCupsRequest *request,
const gchar *option,
const gchar *value);
gboolean gtk_cups_result_is_error (GtkCupsResult *result);
ipp_t * gtk_cups_result_get_response (GtkCupsResult *result);
GtkCupsErrorType gtk_cups_result_get_error_type (GtkCupsResult *result);
int gtk_cups_result_get_error_status (GtkCupsResult *result);
int gtk_cups_result_get_error_code (GtkCupsResult *result);
const char * gtk_cups_result_get_error_string (GtkCupsResult *result);
GtkCupsRequest * gtk_cups_request_new (http_t *connection,
GtkCupsRequestType req_type,
gint operation_id,
GIOChannel *data_io,
const char *server,
const char *resource);
void gtk_cups_request_ipp_add_string (GtkCupsRequest *request,
ipp_tag_t group,
ipp_tag_t tag,
const char *name,
const char *charset,
const char *value);
void gtk_cups_request_ipp_add_strings (GtkCupsRequest *request,
ipp_tag_t group,
ipp_tag_t tag,
const char *name,
int num_values,
const char *charset,
const char * const *values);
gboolean gtk_cups_request_read_write (GtkCupsRequest *request);
GtkCupsPollState gtk_cups_request_get_poll_state (GtkCupsRequest *request);
void gtk_cups_request_free (GtkCupsRequest *request);
GtkCupsResult * gtk_cups_request_get_result (GtkCupsRequest *request);
gboolean gtk_cups_request_is_done (GtkCupsRequest *request);
void gtk_cups_request_encode_option (GtkCupsRequest *request,
const gchar *option,
const gchar *value);
gboolean gtk_cups_result_is_error (GtkCupsResult *result);
ipp_t * gtk_cups_result_get_response (GtkCupsResult *result);
GtkCupsErrorType gtk_cups_result_get_error_type (GtkCupsResult *result);
int gtk_cups_result_get_error_status (GtkCupsResult *result);
int gtk_cups_result_get_error_code (GtkCupsResult *result);
const char * gtk_cups_result_get_error_string (GtkCupsResult *result);
GtkCupsConnectionTest * gtk_cups_connection_test_new (const char *server);
gboolean gtk_cups_connection_test_is_server_available (GtkCupsConnectionTest *test);
void gtk_cups_connection_test_free (GtkCupsConnectionTest *test);
G_END_DECLS
#endif

View File

@ -106,6 +106,8 @@ struct _GtkPrintBackendCups
guint list_printers_poll;
guint list_printers_pending : 1;
guint got_default_printer : 1;
guint default_printer_poll;
GtkCupsConnectionTest *default_printer_connection_test;
char **covers;
char *default_cover_before;
@ -120,6 +122,7 @@ static void gtk_print_backend_cups_init (GtkPrintBack
static void gtk_print_backend_cups_finalize (GObject *object);
static void gtk_print_backend_cups_dispose (GObject *object);
static void cups_get_printer_list (GtkPrintBackend *print_backend);
static void cups_get_default_printer (GtkPrintBackendCups *print_backend);
static void cups_request_execute (GtkPrintBackendCups *print_backend,
GtkCupsRequest *request,
GtkPrintCupsResponseCallbackFunc callback,
@ -141,7 +144,7 @@ static void cups_printer_prepare_for_print (GtkPrinter
static GList * cups_printer_list_papers (GtkPrinter *printer);
static GtkPageSetup * cups_printer_get_default_page_size (GtkPrinter *printer);
static void cups_printer_request_details (GtkPrinter *printer);
static void cups_request_default_printer (GtkPrintBackendCups *print_backend);
static gboolean cups_request_default_printer (GtkPrintBackendCups *print_backend);
static void cups_request_ppd (GtkPrinter *printer);
static void cups_printer_get_hard_margins (GtkPrinter *printer,
double *top,
@ -509,7 +512,10 @@ gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
backend_cups->default_cover_after = NULL;
backend_cups->number_of_covers = 0;
cups_request_default_printer (backend_cups);
backend_cups->default_printer_poll = 0;
backend_cups->default_printer_connection_test = NULL;
cups_get_default_printer (backend_cups);
}
static void
@ -530,6 +536,8 @@ gtk_print_backend_cups_finalize (GObject *object)
g_free (backend_cups->default_cover_before);
g_free (backend_cups->default_cover_after);
gtk_cups_connection_test_free (backend_cups->default_printer_connection_test);
backend_parent_class->finalize (object);
}
@ -548,6 +556,10 @@ gtk_print_backend_cups_dispose (GObject *object)
g_source_remove (backend_cups->list_printers_poll);
backend_cups->list_printers_poll = 0;
if (backend_cups->default_printer_poll > 0)
g_source_remove (backend_cups->default_printer_poll);
backend_cups->default_printer_poll = 0;
backend_parent_class->dispose (object);
}
@ -1812,6 +1824,27 @@ cups_get_user_options (const char *printer_name,
return num_options;
}
/* This function requests default printer from a CUPS server in regular intervals.
* In the case of unreachable CUPS server the request is repeated later.
* The default printer is not requested in the case of previous success.
*/
static void
cups_get_default_printer (GtkPrintBackendCups *backend)
{
GtkPrintBackendCups *cups_backend;
cups_backend = backend;
cups_backend->default_printer_connection_test = gtk_cups_connection_test_new (NULL);
if (cups_backend->default_printer_poll == 0)
{
if (cups_request_default_printer (cups_backend))
cups_backend->default_printer_poll = gdk_threads_add_timeout_seconds (1,
(GSourceFunc) cups_request_default_printer,
backend);
}
}
static void
cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
GtkCupsResult *result,
@ -1820,6 +1853,8 @@ cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
ipp_t *response;
ipp_attribute_t *attr;
GDK_THREADS_ENTER ();
response = gtk_cups_result_get_response (result);
if ((attr = ippFindAttribute (response, "printer-name", IPP_TAG_NAME)) != NULL)
@ -1832,27 +1867,35 @@ cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
*/
if (print_backend->list_printers_poll != 0)
cups_request_printer_list (print_backend);
GDK_THREADS_LEAVE ();
}
static void
static gboolean
cups_request_default_printer (GtkPrintBackendCups *print_backend)
{
GtkCupsRequest *request;
const char *str;
char *name = NULL;
if (!gtk_cups_connection_test_is_server_available (print_backend->default_printer_connection_test))
return TRUE;
gtk_cups_connection_test_free (print_backend->default_printer_connection_test);
print_backend->default_printer_connection_test = NULL;
if ((str = g_getenv ("LPDEST")) != NULL)
{
print_backend->default_printer = g_strdup (str);
print_backend->got_default_printer = TRUE;
return;
return FALSE;
}
else if ((str = g_getenv ("PRINTER")) != NULL &&
strcmp (str, "lp") != 0)
{
print_backend->default_printer = g_strdup (str);
print_backend->got_default_printer = TRUE;
return;
return FALSE;
}
/* Figure out user setting for default printer */
@ -1861,7 +1904,7 @@ cups_request_default_printer (GtkPrintBackendCups *print_backend)
{
print_backend->default_printer = name;
print_backend->got_default_printer = TRUE;
return;
return FALSE;
}
request = gtk_cups_request_new (NULL,
@ -1876,6 +1919,8 @@ cups_request_default_printer (GtkPrintBackendCups *print_backend)
(GtkPrintCupsResponseCallbackFunc) cups_request_default_printer_cb,
g_object_ref (print_backend),
g_object_unref);
return FALSE;
}
static void