--- p910nd-0.7/p910nd.c.orig	2007-09-29 17:03:03.000000000 -0700
+++ p910nd-0.7.new/p910nd.c	2007-09-29 17:06:53.000000000 -0700
@@ -144,73 +144,185 @@
 		(void)close(lockfd);
 }
 
-ssize_t safe_write(int fd, char *buf, size_t count)
+typedef struct {
+	int detectEof;
+	int infd;
+	int outfd;
+	int startidx;
+	int endidx;
+	int bytes;
+	int totalin;
+	int totalout;
+	int eof;
+	int err;
+	char buffer[8192];
+} Buffer_t;
+
+void initBuffer( Buffer_t *b, int infd, int outfd, int detectEof )
+{
+	b->detectEof = detectEof;
+	b->infd = infd;
+	b->outfd = outfd;
+	b->startidx = 0;
+	b->endidx = 0;
+	b->bytes = 0;
+	b->totalin = 0;
+	b->totalout = 0;
+	b->eof = 0;
+	b->err = 0;
+}
+
+void prepBuffer( Buffer_t *b, fd_set *readfds, fd_set *writefds )
 {
-	size_t offset = 0;
-	
-	while (offset < count) {
-		ssize_t n = write(fd, buf + offset, count - offset);
-		
-		if (n < 0 && errno != EINTR)
-			return n;
-			
-		if (n > 0)
-			offset += n;
+	if (!b->err && b->bytes != 0) {
+		FD_SET(b->outfd, writefds);
 	}
+	if (!b->eof && b->bytes < sizeof(b->buffer)) {
+		FD_SET(b->infd, readfds);
+	}
+}
 
-	return offset;
+ssize_t readBuffer( Buffer_t *b )
+{
+	int avail;
+	ssize_t result = 1;
+	if (b->bytes == 0 || b->err) {
+		b->startidx = b->endidx = 0;
+		avail = sizeof(b->buffer);
+	} else if (b->bytes == sizeof(b->buffer)) {
+		avail = 0;
+	} else if (b->endidx > b->startidx) {
+		avail = sizeof(b->buffer) - b->endidx;
+	} else {
+		avail = b->startidx - b->endidx;
+	}
+	if (avail) {
+		result = read(b->infd, b->buffer+b->endidx, avail);
+		if (result > 0) {
+			b->endidx += result;
+			b->totalin += result;
+			b->bytes += result;
+			if (b->endidx == sizeof(b->buffer))
+				b->endidx = 0;
+		} else if (result < 0 || b->detectEof) {
+			b->eof = 1;
+		}
+	}
+	return result;
+}
+
+ssize_t writeBuffer( Buffer_t *b )
+{
+	int avail;
+	ssize_t result = 1;
+	if (b->bytes == 0 || b->err) {
+		avail = 0;
+	} else if (b->endidx > b->startidx) {
+		avail = b->endidx - b->startidx;
+	} else {
+		avail = sizeof(b->buffer) - b->startidx;
+	}
+	if (avail) {
+		result = write(b->outfd, b->buffer + b->startidx, avail);
+		if (result < 0) {
+			syslog(LOG_ERR, "write: %m\n");
+			b->err = 1;
+		} else {
+			b->startidx += result;
+			b->totalout += result;
+			b->bytes -= result;
+			if (b->startidx == sizeof(b->buffer))
+				b->startidx = 0;
+		}
+	}
+	return result;
 }
 
 /* Copy network socket to FILE f until EOS */
 int copy_stream(int fd, int lp)
 {
-	int		nread, rcvd = 0, sent = 0;
-	char		buffer[8192];
+	int 		result;
+	Buffer_t	inbuffer;
+	initBuffer( &inbuffer, fd, lp, 1 );
 
 	if (bidir) {
-		for (;;) {
-			fd_set	readfds;
-			int result;
+		struct timeval  now;
+		struct timeval  then;
+		struct timeval	timeout;
+		int		timer = 0;
+		Buffer_t 	outbuffer;
+		initBuffer ( &outbuffer, lp, fd, 0 );
+		fd_set	readfds;
+		fd_set	writefds;
+		FD_ZERO(&readfds);
+		FD_ZERO(&writefds);
+		FD_SET(lp, &readfds);
+		FD_SET(fd, &readfds);
+		while (	(FD_ISSET(fd, &readfds)) ||
+			(FD_ISSET(lp, &writefds))) {
 			int maxfd = lp > fd ? lp : fd;
-			FD_ZERO(&readfds);
-			FD_SET(lp, &readfds);
-			FD_SET(fd, &readfds);
-			result = select(maxfd + 1, &readfds, 0, 0, 0);
+			if (timer) {
+				gettimeofday(&now,0);
+				// If timer expired, clear timer
+				// else don't try reading from printer
+				if ((now.tv_sec > then.tv_sec) ||
+					(now.tv_sec == then.tv_sec &&
+					 now.tv_usec > then.tv_usec)) {
+					timer = 0;
+				} else {
+					timeout.tv_sec = then.tv_sec;
+					timeout.tv_usec = then.tv_usec;
+					FD_CLR(lp, &readfds);
+				}
+			}
+			if (timer) {
+				result = select(maxfd + 1, &readfds, &writefds, 0, &timeout);
+			} else {
+				result = select(maxfd + 1, &readfds, &writefds, 0, 0);
+			}
 			if (result < 0)
 				return (result);
-			if (result == 0)
-				continue;
 			if (FD_ISSET(fd, &readfds)) {
-				nread = read(fd, buffer, sizeof(buffer));
-				if (nread <= 0)
-					break;
-				if (safe_write(lp, buffer, nread) < 0) {
-					syslog(LOG_ERR, "write: %m\n");
-					break;
-				}
-				rcvd += nread;
+				result = readBuffer(&inbuffer);
 			}
 			if (FD_ISSET(lp, &readfds)) {
-				nread = read(lp, buffer, sizeof(buffer));
-				if (nread > 0) {
-					safe_write(fd, buffer, nread);
-					sent += nread;
+				result = readBuffer(&outbuffer);
+				// Pace the printer data more slowly
+				if (result >= 0) {
+					gettimeofday(&then,0);
+					// wait 100 msec
+					then.tv_usec += 100000;
+					if (then.tv_usec > 1000000) {
+						then.tv_usec -= 1000000;
+						then.tv_sec ++;
+					}
+					timer = 1;
 				}
 			}
+			if (FD_ISSET(lp, &writefds)) {
+				result = writeBuffer(&inbuffer);
+			}
+			if (FD_ISSET(fd, &writefds)) {
+				result = writeBuffer(&outbuffer);
+				/* If socket write error, stop reading from it */
+				if (result < 0)
+					inbuffer.eof = 1;
+			}
+			FD_ZERO(&readfds);
+			FD_ZERO(&writefds);
+			prepBuffer( &inbuffer, &readfds, &writefds );
+			prepBuffer( &outbuffer, &readfds, &writefds );
 		}
 		syslog(LOG_NOTICE, "Finished job: %d bytes received, %d bytes sent\n",
-			rcvd, sent);
+			inbuffer.totalout, 
+			outbuffer.totalout);
 		return (0);
 	} else {
-		while ((nread = read(fd, buffer, sizeof(buffer))) > 0) {
-			if (safe_write(lp, buffer, nread) < 0) {
-				syslog(LOG_ERR, "write: %m\n");
-				break;
-			}
-			rcvd += nread;
+		while ((result = readBuffer( &inbuffer)) > 0) {
+			(void)writeBuffer( &inbuffer);
 		}
-		syslog(LOG_NOTICE, "Finished job: %d bytes received\n",	rcvd);
-		return (nread);
+		syslog(LOG_NOTICE, "Finished job: %d bytes received\n",	inbuffer.totalout);
+		return (result);
 	}
 }
 
