* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
_get_read_data
};
+#ifndef HAVE_CUPS_API_1_6
+#define ippSetOperation(ipp_request, ipp_op_id) ipp_request->request.op.operation_id = ipp_op_id
+#define ippSetRequestId(ipp_request, ipp_rq_id) ipp_request->request.op.request_id = ipp_rq_id
+#define ippSetState(ipp_request, ipp_state) ipp_request->state = ipp_state
+#define ippGetString(attr, index, foo) attr->values[index].string.text
+#define ippGetCount(attr) attr->num_values
+
+int
+ippSetVersion (ipp_t *ipp,
+ int major,
+ int minor)
+{
+ if (!ipp || major < 0 || minor < 0)
+ return 0;
+
+ ipp->request.any.version[0] = major;
+ ipp->request.any.version[1] = minor;
+
+ return 1;
+}
+#endif
+
static void
gtk_cups_result_set_error (GtkCupsResult *result,
GtkCupsErrorType error_type,
request->data_io = data_io;
request->ipp_request = ippNew ();
- request->ipp_request->request.op.operation_id = operation_id;
- request->ipp_request->request.op.request_id = 1;
+ ippSetOperation (request->ipp_request, operation_id);
+ ippSetRequestId (request->ipp_request, 1);
language = cupsLangDefault ();
"requesting-user-name",
NULL, cupsUser ());
+ request->auth_info_required = NULL;
+ request->auth_info = NULL;
+ request->need_auth_info = FALSE;
+
cupsLangFree (language);
return request;
}
g_free (request->username);
+ g_strfreev (request->auth_info_required);
gtk_cups_result_free (request->result);
}
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 (connect_only && request->state != GTK_CUPS_REQUEST_START)
+ return FALSE;
- if (request->attempts > _GTK_CUPS_MAX_ATTEMPTS &&
- request->state != GTK_CUPS_REQUEST_DONE)
+ do
{
- /* 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");
+ if (request->type == GTK_CUPS_POST)
+ post_states[request->state] (request);
+ else if (request->type == GTK_CUPS_GET)
+ get_states[request->state] (request);
- 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;
+ if (gtk_cups_result_is_error (request->result))
+ request->state = GTK_CUPS_REQUEST_DONE;
+
+ 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;
+ }
}
- else
- return FALSE;
+ /* 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
name,
tag);
- if (attribute != NULL && attribute->values != NULL)
- return attribute->values[0].string.text;
+ if (attribute != NULL && ippGetCount (attribute) > 0)
+ return ippGetString (attribute, 0, NULL);
else
return NULL;
}
{ "saturation", IPP_TAG_INTEGER },
{ "scaling", IPP_TAG_INTEGER },
{ "sides", IPP_TAG_KEYWORD },
- { "wrap", IPP_TAG_BOOLEAN }
+ { "wrap", IPP_TAG_BOOLEAN },
+ { "number-up-layout", IPP_TAG_INTEGER }
};
}
}
+void
+gtk_cups_request_set_ipp_version (GtkCupsRequest *request,
+ gint major,
+ gint minor)
+{
+ ippSetVersion (request->ipp_request, major, minor);
+}
static void
_connect (GtkCupsRequest *request)
{
request->poll_state = GTK_CUPS_HTTP_IDLE;
+ request->bytes_received = 0;
if (request->http == NULL)
{
request->attempts = 0;
request->state = GTK_CUPS_POST_WRITE_REQUEST;
- request->ipp_request->state = IPP_IDLE;
+ ippSetState (request->ipp_request, IPP_IDLE);
}
static void
}
-#if HAVE_CUPS_API_1_2
if (httpWrite2 (request->http, buffer, bytes) < bytes)
-#else
- if (httpWrite (request->http, buffer, (int) bytes) < bytes)
-#endif /* HAVE_CUPS_API_1_2 */
{
int http_errno;
* The callback sets cups_password to NULL to signal that the
* password has been used.
*/
-static char *cups_password;
-static char *cups_username;
+static char *cups_password = NULL;
+static char *cups_username = NULL;
static const char *
passwordCB (const char *prompt)
if (request->password_state == GTK_CUPS_PASSWORD_APPLIED)
{
+ request->poll_state = GTK_CUPS_HTTP_IDLE;
request->password_state = GTK_CUPS_PASSWORD_NOT_VALID;
request->state = GTK_CUPS_POST_AUTH;
request->need_password = TRUE;
{
if (request->password_state == GTK_CUPS_PASSWORD_NONE)
{
- cups_password = g_strdup ("");
cups_username = request->username;
cupsSetPasswordCB (passwordCB);
/* move to AUTH state to let the backend
* ask for a password
*/
+ request->poll_state = GTK_CUPS_HTTP_IDLE;
request->state = GTK_CUPS_POST_AUTH;
request->need_password = TRUE;
request->state = GTK_CUPS_GET_CHECK;
request->poll_state = GTK_CUPS_HTTP_READ;
- request->ipp_request->state = IPP_IDLE;
+ ippSetState (request->ipp_request, IPP_IDLE);
}
static void
if (request->password_state == GTK_CUPS_PASSWORD_APPLIED)
{
+ request->poll_state = GTK_CUPS_HTTP_IDLE;
request->password_state = GTK_CUPS_PASSWORD_NOT_VALID;
request->state = GTK_CUPS_GET_AUTH;
request->need_password = TRUE;
{
if (request->password_state == GTK_CUPS_PASSWORD_NONE)
{
- cups_password = g_strdup ("");
cups_username = request->username;
cupsSetPasswordCB (passwordCB);
/* move to AUTH state to let the backend
* ask for a password
*/
+ request->poll_state = GTK_CUPS_HTTP_IDLE;
request->state = GTK_CUPS_GET_AUTH;
request->need_password = TRUE;
return;
}
- request->state = GTK_CUPS_GET_SEND;
+ request->state = GTK_CUPS_GET_CONNECT;
request->last_status = HTTP_CONTINUE;
return;
request->poll_state = GTK_CUPS_HTTP_READ;
-#if HAVE_CUPS_API_1_2
bytes = httpRead2 (request->http, buffer, sizeof (buffer));
-#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: %i bytes read\n", bytes));
-
- if (bytes == 0)
- {
- request->state = GTK_CUPS_GET_DONE;
- request->poll_state = GTK_CUPS_HTTP_IDLE;
+ g_print ("CUPS Backend: %"G_GSIZE_FORMAT" bytes read\n", bytes));
- return;
- }
-
io_status =
g_io_channel_write_chars (request->data_io,
buffer,
error->message);
g_error_free (error);
}
+
+ /* Stop if we do not expect any more data or EOF was received. */
+ if (httpGetLength2 (request->http) <= request->bytes_received || bytes == 0)
+ {
+ request->state = GTK_CUPS_GET_DONE;
+ request->poll_state = GTK_CUPS_HTTP_IDLE;
+
+ return;
+ }
}
gboolean
gtk_cups_connection_test_new (const char *server)
{
GtkCupsConnectionTest *result = NULL;
-#ifdef HAVE_CUPS_API_1_2
gchar *port_str = NULL;
result = g_new (GtkCupsConnectionTest, 1);
result->socket = -1;
result->current_addr = NULL;
+ result->last_wrong_addr = NULL;
result->at_init = GTK_CUPS_CONNECTION_NOT_AVAILABLE;
result->at_init = gtk_cups_connection_test_get_state (result);
-#else
- result = g_new (GtkCupsConnectionTest, 1);
-#endif
return result;
}
GtkCupsConnectionState
gtk_cups_connection_test_get_state (GtkCupsConnectionTest *test)
{
-#ifdef HAVE_CUPS_API_1_2
GtkCupsConnectionState result = GTK_CUPS_CONNECTION_NOT_AVAILABLE;
http_addrlist_t *iter;
gint error_code;
{
if (test->socket == -1)
{
- iter = test->addrlist;
+ if (test->last_wrong_addr != NULL && test->last_wrong_addr->next != NULL)
+ iter = test->last_wrong_addr->next;
+ else
+ {
+ test->last_wrong_addr = NULL;
+ iter = test->addrlist;
+ }
+
while (iter)
{
test->socket = socket (iter->addr.addr.sa_family,
error_code = errno;
- if (code == 0)
+ if (code == 0 || error_code == EISCONN)
{
close (test->socket);
test->socket = -1;
if (error_code == EALREADY || error_code == EINPROGRESS)
result = GTK_CUPS_CONNECTION_IN_PROGRESS;
else
- result = GTK_CUPS_CONNECTION_NOT_AVAILABLE;
+ {
+ close (test->socket);
+ test->socket = -1;
+ test->last_wrong_addr = test->current_addr;
+ result = GTK_CUPS_CONNECTION_NOT_AVAILABLE;
+ }
}
}
return result;
}
-#else
- return GTK_CUPS_CONNECTION_AVAILABLE;
-#endif
}
/* This function frees memory used by the GtkCupsConnectionTest structure.
if (test == NULL)
return;
-#ifdef HAVE_CUPS_API_1_2
test->current_addr = NULL;
+ test->last_wrong_addr = NULL;
httpAddrFreeList (test->addrlist);
if (test->socket != -1)
{
close (test->socket);
test->socket = -1;
}
-#endif
g_free (test);
}