diff --git a/modules/printbackends/cups/gtkcupsutils.c b/modules/printbackends/cups/gtkcupsutils.c index a7b47f194d..a1eb1a1c17 100644 --- a/modules/printbackends/cups/gtkcupsutils.c +++ b/modules/printbackends/cups/gtkcupsutils.c @@ -253,34 +253,43 @@ gtk_cups_request_free (GtkCupsRequest *request) } gboolean -gtk_cups_request_read_write (GtkCupsRequest *request) +gtk_cups_request_read_write (GtkCupsRequest *request, gboolean connect_only) { - if (request->type == GTK_CUPS_POST) - post_states[request->state] (request); - else if (request->type == GTK_CUPS_GET) - get_states[request->state] (request); - - if (request->attempts > _GTK_CUPS_MAX_ATTEMPTS && - request->state != GTK_CUPS_REQUEST_DONE) - { - /* TODO: should add a status or error code for too many failed attempts */ - gtk_cups_result_set_error (request->result, - GTK_CUPS_ERROR_GENERAL, - 0, - 0, - "Too many failed attempts"); - - request->state = GTK_CUPS_REQUEST_DONE; - request->poll_state = GTK_CUPS_HTTP_IDLE; - } - - if (request->state == GTK_CUPS_REQUEST_DONE) - { - request->poll_state = GTK_CUPS_HTTP_IDLE; - return TRUE; - } - else + if (connect_only && request->state != GTK_CUPS_REQUEST_START) return FALSE; + + do + { + if (request->type == GTK_CUPS_POST) + post_states[request->state] (request); + else if (request->type == GTK_CUPS_GET) + get_states[request->state] (request); + + if (request->attempts > _GTK_CUPS_MAX_ATTEMPTS && + request->state != GTK_CUPS_REQUEST_DONE) + { + /* TODO: should add a status or error code for too many failed attempts */ + gtk_cups_result_set_error (request->result, + GTK_CUPS_ERROR_GENERAL, + 0, + 0, + "Too many failed attempts"); + + request->state = GTK_CUPS_REQUEST_DONE; + } + + if (request->state == GTK_CUPS_REQUEST_DONE) + { + request->poll_state = GTK_CUPS_HTTP_IDLE; + return TRUE; + } + } + /* We need to recheck using httpCheck if the poll_state is read, because + * Cups has an internal read buffer. And if this buffer is filled, we may + * never get a poll event again. */ + while (request->poll_state == GTK_CUPS_HTTP_READ && request->http && httpCheck(request->http)); + + return FALSE; } GtkCupsPollState @@ -643,6 +652,7 @@ static void _connect (GtkCupsRequest *request) { request->poll_state = GTK_CUPS_HTTP_IDLE; + request->bytes_received = 0; if (request->http == NULL) { @@ -1404,18 +1414,11 @@ _get_read_data (GtkCupsRequest *request) #else bytes = httpRead (request->http, buffer, sizeof (buffer)); #endif /* HAVE_CUPS_API_1_2 */ + request->bytes_received += bytes; GTK_NOTE (PRINTING, g_print ("CUPS Backend: %" G_GSIZE_FORMAT " bytes read\n", bytes)); - if (bytes == 0) - { - request->state = GTK_CUPS_GET_DONE; - request->poll_state = GTK_CUPS_HTTP_IDLE; - - return; - } - io_status = g_io_channel_write_chars (request->data_io, buffer, @@ -1435,6 +1438,19 @@ _get_read_data (GtkCupsRequest *request) error->message); g_error_free (error); } + + /* Stop if we do not expect any more data or EOF was received. */ +#if HAVE_CUPS_API_1_2 + if (httpGetLength2 (request->http) <= request->bytes_received || bytes == 0) +#else + if (httpGetLength (request->http) <= request->bytes_received || bytes == 0) +#endif /* HAVE_CUPS_API_1_2 */ + { + request->state = GTK_CUPS_GET_DONE; + request->poll_state = GTK_CUPS_HTTP_IDLE; + + return; + } } gboolean diff --git a/modules/printbackends/cups/gtkcupsutils.h b/modules/printbackends/cups/gtkcupsutils.h index 2438b86696..2adfc16507 100644 --- a/modules/printbackends/cups/gtkcupsutils.h +++ b/modules/printbackends/cups/gtkcupsutils.h @@ -93,6 +93,7 @@ struct _GtkCupsRequest gint state; GtkCupsPollState poll_state; + guint64 bytes_received; gchar *password; gchar *username; @@ -172,7 +173,8 @@ void gtk_cups_request_ipp_add_strings (GtkCupsRequest * const char * gtk_cups_request_ipp_get_string (GtkCupsRequest *request, ipp_tag_t tag, const char *name); -gboolean gtk_cups_request_read_write (GtkCupsRequest *request); +gboolean gtk_cups_request_read_write (GtkCupsRequest *request, + gboolean connect_only); GtkCupsPollState gtk_cups_request_get_poll_state (GtkCupsRequest *request); void gtk_cups_request_free (GtkCupsRequest *request); GtkCupsResult * gtk_cups_request_get_result (GtkCupsRequest *request); diff --git a/modules/printbackends/cups/gtkprintbackendcups.c b/modules/printbackends/cups/gtkprintbackendcups.c index 71324b50f8..14a1b5d055 100644 --- a/modules/printbackends/cups/gtkprintbackendcups.c +++ b/modules/printbackends/cups/gtkprintbackendcups.c @@ -92,6 +92,7 @@ typedef struct http_t *http; GtkCupsRequest *request; + GtkCupsPollState poll_state; GPollFD *data_poll; GtkPrintBackendCups *backend; GtkPrintCupsResponseCallbackFunc callback; @@ -917,11 +918,20 @@ cups_dispatch_add_poll (GSource *source) poll_state = gtk_cups_request_get_poll_state (dispatch->request); + /* Remove the old source if the poll state changed. */ + if (poll_state != dispatch->poll_state && dispatch->data_poll != NULL) + { + g_source_remove_poll (source, dispatch->data_poll); + g_free (dispatch->data_poll); + dispatch->data_poll = NULL; + } + if (dispatch->request->http != NULL) { if (dispatch->data_poll == NULL) { dispatch->data_poll = g_new0 (GPollFD, 1); + dispatch->poll_state = poll_state; if (poll_state == GTK_CUPS_HTTP_READ) dispatch->data_poll->events = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI; @@ -1093,13 +1103,11 @@ cups_dispatch_watch_check (GSource *source) poll_state = gtk_cups_request_get_poll_state (dispatch->request); - cups_dispatch_add_poll (source); - if (poll_state != GTK_CUPS_HTTP_IDLE && !dispatch->request->need_password) if (!(dispatch->data_poll->revents & dispatch->data_poll->events)) return FALSE; - result = gtk_cups_request_read_write (dispatch->request); + result = gtk_cups_request_read_write (dispatch->request, FALSE); if (result && dispatch->data_poll != NULL) { g_source_remove_poll (source, dispatch->data_poll); @@ -1130,8 +1138,8 @@ cups_dispatch_watch_prepare (GSource *source, g_print ("CUPS Backend: %s \n", G_STRFUNC, source)); *timeout_ = -1; - - result = gtk_cups_request_read_write (dispatch->request); + + result = gtk_cups_request_read_write (dispatch->request, TRUE); cups_dispatch_add_poll (source); @@ -1231,7 +1239,12 @@ cups_dispatch_watch_finalize (GSource *source) dispatch->backend = NULL; } - g_free (dispatch->data_poll); + if (dispatch->data_poll) + { + g_source_remove_poll (source, dispatch->data_poll); + g_free (dispatch->data_poll); + dispatch->data_poll = NULL; + } } static GSourceFuncs _cups_dispatch_watch_funcs = { @@ -1260,6 +1273,7 @@ cups_request_execute (GtkPrintBackendCups *print_backend, dispatch->request = request; dispatch->backend = g_object_ref (print_backend); + dispatch->poll_state = GTK_CUPS_HTTP_IDLE; dispatch->data_poll = NULL; dispatch->callback = NULL; dispatch->callback_data = NULL;