File pidgin-nonblock-aim.patch of Package pidgin

diff -upr gaim-1.5.0/libgaim/protocols/oscar/aim.h gaim-1.5.0-new/libgaim/protocols/oscar/aim.h
--- gaim-1.5.0/libpurple/protocols/oscar/aim.h	2005-08-07 23:36:16.000000000 -0500
+++ gaim-1.5.0-new/libpurple/protocols/oscar/aim.h	2005-09-28 11:29:23.000000000 -0500
@@ -35,6 +35,8 @@
 #include "libc_interface.h"
 #endif
 
+#include "gaim-io.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -310,8 +312,13 @@ struct client_info_s {
 #define AIM_FRAMETYPE_FLAP		0x0000
 #define AIM_FRAMETYPE_OFT		0x0001
 
+typedef struct aim_frame_s aim_frame_t;
+
 typedef struct aim_conn_s {
 	int fd;
+	GaimIO *io;
+	aim_frame_t *current_frame;
+	int current_payload_len;
 	fu16_t type;
 	fu16_t subtype;
 	flap_seqnum_t seqnum;
@@ -346,7 +353,7 @@ typedef struct aim_bstream_s {
 	fu32_t offset;
 } aim_bstream_t;
 
-typedef struct aim_frame_s {
+struct aim_frame_s {
 	fu8_t hdrtype; /* defines which piece of the union to use */
 	union {
 		struct { 
@@ -363,7 +370,7 @@ typedef struct aim_frame_s {
 	aim_conn_t *conn;		/* the connection it came in on/is going out on */
 	fu8_t handled;			/* 0 = new, !0 = been handled */
 	struct aim_frame_s *next;
-} aim_frame_t;
+};
 
 typedef struct aim_msgcookie_s {
 	fu8_t cookie[8];
diff -upr gaim-1.5.0/libgaim/protocols/oscar/aim_internal.h gaim-1.5.0-new/libgaim/protocols/oscar/aim_internal.h
--- gaim-1.5.0/libgaim/protocols/oscar/aim_internal.h	2005-03-06 22:51:56.000000000 -0600
+++ gaim-1.5.0-new/libgaim/protocols/oscar/aim_internal.h	2005-09-28 11:29:23.000000000 -0500
@@ -102,8 +102,8 @@ faim_internal int aim_parse_unknown(aim_
 faim_internal void aim_clonehandlers(aim_session_t *sess, aim_conn_t *dest, aim_conn_t *libgaim);
 
 /* rxqueue.c */
-faim_internal int aim_recv(int fd, void *buf, size_t count);
-faim_internal int aim_bstream_recv(aim_bstream_t *bs, int fd, size_t count);
+faim_internal int aim_recv(aim_conn_t *conn, void *buf, size_t count);
+faim_internal int aim_bstream_recv(aim_bstream_t *bs, aim_conn_t *conn, size_t count);
 faim_internal void aim_rxqueue_cleanbyconn(aim_session_t *sess, aim_conn_t *conn);
 faim_internal void aim_frame_destroy(aim_frame_t *);
 
diff -upr gaim-1.5.0/libgaim/protocols/oscar/conn.c gaim-1.5.0-new/libgaim/protocols/oscar/conn.c
--- gaim-1.5.0/libgaim/protocols/oscar/conn.c	2005-07-09 14:26:51.000000000 -0500
+++ gaim-1.5.0-new/libgaim/protocols/oscar/conn.c	2005-09-28 11:29:23.000000000 -0500
@@ -161,6 +161,9 @@ static void connkill_real(aim_session_t 
 	if ((*deadconn)->fd != -1) 
 		aim_conn_close(*deadconn);
 
+	if ((*deadconn)->io)
+		gaim_io_destroy ((*deadconn)->io);
+
 	/*
 	 * This will free ->internal if it necessary...
 	 */
@@ -218,6 +221,7 @@ static void aim_conn_init(aim_conn_t *de
 		return;
 
 	deadconn->fd = -1;
+	deadconn->io = NULL;
 	deadconn->subtype = -1;
 	deadconn->type = -1;
 	deadconn->seqnum = 0;
@@ -304,8 +308,12 @@ faim_export void aim_conn_close(aim_conn
 {
 	aim_rxcallback_t userfunc;
 
-	if (deadconn->fd >= 3)
+	if (deadconn->io) {
+		gaim_io_destroy (deadconn->io);
+		deadconn->io = NULL;
+	} else if (deadconn->fd >= 3) {
 		close(deadconn->fd);
+	}
 
 	deadconn->fd = -1;
 
@@ -559,6 +567,7 @@ faim_internal aim_conn_t *aim_cloneconn(
 		return NULL;
 
 	conn->fd = libgaim->fd;
+	conn->io = gaim_io_new (conn->fd);
 	conn->type = libgaim->type;
 	conn->subtype = libgaim->subtype;
 	conn->seqnum = libgaim->seqnum;
@@ -606,6 +615,7 @@ faim_export aim_conn_t *aim_newconn(aim_
 
 	connstruct->sessv = (void *)sess;
 	connstruct->type = type;
+	connstruct->io = NULL;
 
 	if (!dest) { /* just allocate a struct */
 		connstruct->fd = -1;
diff -upr gaim-1.5.0/libgaim/protocols/oscar/ft.c gaim-1.5.0-new/libgaim/protocols/oscar/ft.c
--- gaim-1.5.0/libgaim/protocols/oscar/ft.c	2005-08-07 23:36:17.000000000 -0500
+++ gaim-1.5.0-new/libgaim/protocols/oscar/ft.c	2005-09-28 11:29:23.000000000 -0500
@@ -630,9 +630,9 @@ static int handlehdr_odc(aim_session_t *
 
 		while (payloadlength - recvd) {
 			if (payloadlength - recvd >= 1024)
-				i = aim_recv(conn->fd, &msg[recvd], 1024);
+				i = aim_recv(conn, &msg[recvd], 1024);
 			else 
-				i = aim_recv(conn->fd, &msg[recvd], payloadlength - recvd);
+				i = aim_recv(conn, &msg[recvd], payloadlength - recvd);
 			if (i <= 0) {
 				free(msg);
 				free(snptr);
diff -upr gaim-1.5.0/libgaim/protocols/oscar/oscar.c gaim-1.5.0-new/libgaim/protocols/oscar/oscar.c
--- gaim-1.5.0/libgaim/protocols/oscar/oscar.c	2005-08-11 19:57:27.000000000 -0500
+++ gaim-1.5.0-new/libgaim/protocols/oscar/oscar.c	2005-09-28 11:29:24.000000000 -0500
@@ -1580,7 +1580,7 @@ static void oscar_callback(gpointer data
 					gaim_debug_error("oscar", "Waiting to be destroyed\n");
 					return;
 				}
-			} else {
+			} else if (!conn->io || !gaim_io_is_connected (conn->io)) {
 				if ((conn->type == AIM_CONN_TYPE_BOS) ||
 					   !(aim_getconn_type(od->sess, AIM_CONN_TYPE_BOS))) {
 					gaim_debug_error("oscar",
@@ -3243,6 +3243,11 @@ static void oscar_sendfile_connected(gpo
 	return;
 }
 
+static void oscar_sendfile_ready_to_xfer (GaimIO *io, GaimXfer *xfer)
+{
+	gaim_xfer_start(xfer, xfer->fd, NULL, 0);
+}
+
 /*
  * This is called when a buddy sends us some file info.  This happens when they 
  * are sending a file to you, and you have just established a connection to them.
@@ -3285,7 +3290,12 @@ static int oscar_sendfile_prompt(aim_ses
 
 	/* XXX - convert the name from UTF-8 to UCS-2 if necessary, and pass the encoding to the call below */
 	aim_oft_sendheader(oft_info->sess, AIM_CB_OFT_ACK, oft_info);
-	gaim_xfer_start(xfer, xfer->fd, NULL, 0);
+
+	if (xfer->fd == conn->fd && conn->io && gaim_io_get_pending_write (conn->io)) {
+		gaim_io_set_flushed_func (conn->io, (GaimIOFunc) oscar_sendfile_ready_to_xfer, xfer);
+	} else {
+		oscar_sendfile_ready_to_xfer (conn->io, xfer);
+	}
 
 	return 0;
 }
@@ -3317,7 +3327,11 @@ static int oscar_sendfile_ack(aim_sessio
 	gaim_input_remove(xfer->watcher);
 	xfer->watcher = 0;
 
-	gaim_xfer_start(xfer, xfer->fd, NULL, 0);
+	if (xfer->fd == conn->fd && conn->io && gaim_io_get_pending_write (conn->io)) {
+		gaim_io_set_flushed_func (conn->io, (GaimIOFunc) oscar_sendfile_ready_to_xfer, xfer);
+	} else {
+		oscar_sendfile_ready_to_xfer (conn->io, xfer);
+	}
 
 	return 0;
 }
diff -upr gaim-1.5.0/libgaim/protocols/oscar/rxqueue.c gaim-1.5.0-new/libgaim/protocols/oscar/rxqueue.c
--- gaim-1.5.0/libgaim/protocols/oscar/rxqueue.c	2004-05-05 23:41:24.000000000 -0500
+++ gaim-1.5.0-new/libgaim/protocols/oscar/rxqueue.c	2005-09-28 11:29:24.000000000 -0500
@@ -5,7 +5,7 @@
  */
 
 #define FAIM_INTERNAL
-#include <aim.h> 
+#include <aim.h>
 
 #ifndef _WIN32
 #include <sys/socket.h>
@@ -14,43 +14,44 @@
 /*
  *
  */
-faim_internal int aim_recv(int fd, void *buf, size_t count)
+faim_internal int aim_recv(aim_conn_t *conn, void *buf, size_t count)
 {
-	int left, cur; 
+	int left, cur;
 
-	for (cur = 0, left = count; left; ) {
-		int ret;
-		
-		ret = recv(fd, ((unsigned char *)buf)+cur, left, 0);
+	if (!conn->io)
+		conn->io = gaim_io_new (conn->fd);
 
-		/* Of course EOF is an error, only morons disagree with that. */
-		if (ret <= 0)
-			return -1;
-
-		cur += ret;
-		left -= ret;
+	if (gaim_io_get_fd (conn->io) != conn->fd) {
+		gaim_io_destroy (conn->io);
+		conn->io = gaim_io_new (conn->fd);
 	}
 
-	return cur;
+	if (!gaim_io_is_connected (conn->io))
+		return -1;
+
+	if (!gaim_io_read_bytes (conn->io, buf, count))
+		return gaim_io_is_connected (conn->io) ? 0 : -1;
+
+	return count;
 }
 
 /*
  * Read into a byte stream.  Will not read more than count, but may read
  * less if there is not enough room in the stream buffer.
  */
-faim_internal int aim_bstream_recv(aim_bstream_t *bs, int fd, size_t count)
+faim_internal int aim_bstream_recv(aim_bstream_t *bs, aim_conn_t *conn, size_t count)
 {
 	int red = 0;
 
-	if (!bs || (fd < 0) || (count < 0))
+	if (!bs || (conn->fd < 0) || (count < 0))
 		return -1;
-	
+
 	if (count > (bs->len - bs->offset))
 		count = bs->len - bs->offset; /* truncate to remaining space */
 
 	if (count) {
 
-		red = aim_recv(fd, bs->data + bs->offset, count);
+		red = aim_recv(conn, bs->data + bs->offset, count);
 
 		if (red <= 0)
 			return -1;
@@ -86,7 +87,7 @@ static int aim_get_command_flap(aim_sess
 {
 	fu8_t hdr_raw[6];
 	aim_bstream_t hdr;
-	
+
 	fr->hdrtype = AIM_FRAMETYPE_FLAP;
 
 	/*
@@ -101,8 +102,7 @@ static int aim_get_command_flap(aim_sess
 	 *    0x04  | Number of data bytes that follow, 2 bytes.
 	 */
 	aim_bstream_init(&hdr, hdr_raw, sizeof(hdr_raw));
-	if (aim_bstream_recv(&hdr, conn->fd, 6) < 6) {
-		aim_conn_close(conn);
+	if (aim_bstream_recv(&hdr, conn, 6) < 6) {
 		return -1;
 	}
 
@@ -113,10 +113,10 @@ static int aim_get_command_flap(aim_sess
 	 * or we break.  We must handle it just in case.
 	 */
 	if (aimbs_get8(&hdr) != 0x2a) {
-		faimdprintf(sess, 0, "Invalid FLAP frame received on FLAP connection!");
+		gaim_debug_misc("oscar", "Invalid FLAP frame received on FLAP connection!");
 		aim_conn_close(conn);
 		return -1;
-	}	
+	}
 
 	fr->hdr.flap.channel = aimbs_get8(&hdr);
 	fr->hdr.flap.seqnum = aimbs_get16(&hdr);
@@ -141,8 +141,7 @@ static int aim_get_command_rendezvous(ai
 	 * Read rendezvous header
 	 */
 	aim_bstream_init(&hdr, hdr_raw, sizeof(hdr_raw));
-	if (aim_bstream_recv(&hdr, conn->fd, 8) < 8) {
-		aim_conn_close(conn);
+	if (aim_bstream_recv(&hdr, conn, 8) < 8) {
 		return -1;
 	}
 
@@ -163,7 +162,6 @@ static int aim_get_command_rendezvous(ai
  */
 faim_export int aim_get_command(aim_session_t *sess, aim_conn_t *conn)
 {
-	aim_frame_t *fr;
 	int payloadlen;
 
 	if (!sess || !conn)
@@ -172,69 +170,81 @@ faim_export int aim_get_command(aim_sess
 	if (conn->fd == -1)
 		return -1; /* it's an aim_conn_close()'d connection */
 
-	if (conn->fd < 3) /* can happen when people abuse the interface */
+	/* If stdin is closed, then zero becomes a valid fd
+	if (conn->fd < 3)
 		return -1;
+	*/
 
 	if (conn->status & AIM_CONN_STATUS_INPROGRESS)
 		return aim_conn_completeconnect(sess, conn);
 
-	if (!(fr = (aim_frame_t *)calloc(sizeof(aim_frame_t), 1)))
-		return -ENOMEM;
+	if (!conn->current_frame) {
+		if (!(conn->current_frame = (aim_frame_t *)calloc(sizeof(aim_frame_t), 1)))
+			return -ENOMEM;
+
+		/*
+		 * Rendezvous (client to client) connections do not speak FLAP, so this 
+		 * function will break on them.
+		 */
+		if (conn->type == AIM_CONN_TYPE_RENDEZVOUS)
+			payloadlen = aim_get_command_rendezvous(sess, conn, conn->current_frame);
+		else if (conn->type == AIM_CONN_TYPE_LISTENER) {
+			gaim_debug_misc("oscar", "AIM_CONN_TYPE_LISTENER on fd %d\n", conn->fd);
+			free(conn->current_frame);
+			conn->current_frame = NULL;
+			return -1;
+		} else
+			payloadlen = aim_get_command_flap(sess, conn, conn->current_frame);
 
-	/*
-	 * Rendezvous (client to client) connections do not speak FLAP, so this 
-	 * function will break on them.
-	 */
-	if (conn->type == AIM_CONN_TYPE_RENDEZVOUS)
-		payloadlen = aim_get_command_rendezvous(sess, conn, fr);
-	else if (conn->type == AIM_CONN_TYPE_LISTENER) {
-		faimdprintf(sess, 0, "AIM_CONN_TYPE_LISTENER on fd %d\n", conn->fd);
-		free(fr);
-		return -1;
-	} else
-		payloadlen = aim_get_command_flap(sess, conn, fr);
+		if (payloadlen < 0) {
+			free(conn->current_frame);
+			conn->current_frame = NULL;
+			return -1;
+		}
 
-	if (payloadlen < 0) {
-		free(fr);
-		return -1;
-	}
+		conn->current_payload_len = payloadlen;
+	} else
+		payloadlen = conn->current_payload_len;
 
-	if (payloadlen > 0) {
+	if (conn->current_payload_len > 0) {
 		fu8_t *payload = NULL;
 
 		if (!(payload = (fu8_t *) malloc(payloadlen))) {
-			aim_frame_destroy(fr);
 			return -1;
 		}
 
-		aim_bstream_init(&fr->data, payload, payloadlen);
+		aim_bstream_init(&conn->current_frame->data, payload, payloadlen);
 
 		/* read the payload */
-		if (aim_bstream_recv(&fr->data, conn->fd, payloadlen) < payloadlen) {
-			aim_frame_destroy(fr); /* free's payload */
-			aim_conn_close(conn);
+		if (aim_bstream_recv(&conn->current_frame->data, conn, payloadlen) < payloadlen) {
+			free (payload);
 			return -1;
 		}
-	} else
-		aim_bstream_init(&fr->data, NULL, 0);
+	} else if (conn->current_payload_len == 0)
+		aim_bstream_init(&conn->current_frame->data, NULL, 0);
 
-	aim_bstream_rewind(&fr->data);
+	if (conn->current_payload_len >= 0) {
+		aim_bstream_rewind(&conn->current_frame->data);
 
-	fr->conn = conn;
+		conn->current_frame->conn = conn;
 
-	/* Enqueue this puppy */
-	fr->next = NULL;  /* this will always be at the bottom */
-	if (sess->queue_incoming == NULL)
-		sess->queue_incoming = fr;
-	else {
-		aim_frame_t *cur;
-		for (cur = sess->queue_incoming; cur->next; cur = cur->next);
-		cur->next = fr;
-	}
+		/* Enqueue this puppy */
+		conn->current_frame->next = NULL;  /* this will always be at the bottom */
+		if (sess->queue_incoming == NULL)
+			sess->queue_incoming = conn->current_frame;
+		else {
+			aim_frame_t *cur;
+			for (cur = sess->queue_incoming; cur->next; cur = cur->next);
+			cur->next = conn->current_frame;
+		}
 
-	fr->conn->lastactivity = time(NULL);
+		conn->current_frame->conn->lastactivity = time(NULL);
 
-	return 0;  
+		conn->current_frame = NULL;
+		return 0;
+	}
+
+	return -1;
 }
 
 /*
@@ -270,7 +280,7 @@ faim_internal void aim_rxqueue_cleanbyco
 	for (currx = sess->queue_incoming; currx; currx = currx->next) {
 		if ((!currx->handled) && (currx->conn == conn))
 			currx->handled = 1;
-	}	
+	}
 
 	return;
 }
diff -upr gaim-1.5.0/libgaim/protocols/oscar/txqueue.c gaim-1.5.0-new/libgaim/protocols/oscar/txqueue.c
--- gaim-1.5.0/libgaim/protocols/oscar/txqueue.c	2004-07-06 02:00:32.000000000 -0500
+++ gaim-1.5.0-new/libgaim/protocols/oscar/txqueue.c	2005-09-28 11:29:24.000000000 -0500
@@ -192,25 +192,22 @@ faim_internal int aim_tx_enqueue(aim_ses
 	return (*sess->tx_enqueue)(sess, fr);
 }
 
-static int aim_send(int fd, const void *buf, size_t count)
+static int aim_send(aim_conn_t *conn, const void *buf, size_t count)
 {
 	int left, cur;
 
-	for (cur = 0, left = count; left; ) {
-		int ret;
+	if (!conn->io)
+		conn->io = gaim_io_new (conn->fd);
 
-		ret = send(fd, ((unsigned char *)buf)+cur, left, 0);
-
-		if (ret == -1)
-			return -1;
-		else if (ret == 0)
-			return cur;
-
-		cur += ret;
-		left -= ret;
+	if (gaim_io_get_fd (conn->io) != conn->fd) {
+		gaim_io_destroy (conn->io);
+		conn->io = gaim_io_new (conn->fd);
 	}
 
-	return cur;
+	if (!gaim_io_write_bytes (conn->io, buf, count))
+		return -1;
+
+	return count;
 }
 
 static int aim_bstream_send(aim_bstream_t *bs, aim_conn_t *conn, size_t count)
@@ -239,7 +236,7 @@ static int aim_bstream_send(aim_bstream_
 			while (count - wrote > 1024) {
 				int ret;
 
-				ret = aim_send(conn->fd, bs->data + bs->offset + wrote, 1024);
+				ret = aim_send(conn, bs->data + bs->offset + wrote, 1024);
 				if (ret > 0)
 					wrote += ret;
 				if (ret < 0)
@@ -250,7 +247,7 @@ static int aim_bstream_send(aim_bstream_
 		}
 
 		if (count - wrote) {
-			wrote = wrote + aim_send(conn->fd, bs->data + bs->offset + wrote, count - wrote);
+			wrote = wrote + aim_send(conn, bs->data + bs->offset + wrote, count - wrote);
 		}
 	}
 
openSUSE Build Service is sponsored by