[dovecot-cvs] dovecot/src/lib Makefile.am, 1.39, 1.40 alarm-hup.c, 1.6, NONE alarm-hup.h, 1.1, NONE file-lock.c, 1.8, 1.9 iostream-internal.h, 1.4, 1.5 iostream.c, 1.5, 1.6 istream-data.c, 1.8, 1.9 istream-file.c, 1.17, 1.18 istream-limit.c, 1.6, 1.7 istream-mmap.c, 1.11, 1.12 istream.c, 1.19, 1.20 istream.h, 1.10, 1.11 lib.c, 1.10, 1.11 ostream-file.c, 1.27, 1.28 ostream-internal.h, 1.2, 1.3 ostream.c, 1.8, 1.9 ostream.h, 1.8, 1.9 strfuncs.c, 1.41, 1.42 strfuncs.h, 1.20, 1.21

cras at dovecot.org cras at dovecot.org
Sun Aug 15 06:40:34 EEST 2004


Update of /home/cvs/dovecot/src/lib
In directory talvi:/tmp/cvs-serv20173/lib

Modified Files:
	Makefile.am file-lock.c iostream-internal.h iostream.c 
	istream-data.c istream-file.c istream-limit.c istream-mmap.c 
	istream.c istream.h lib.c ostream-file.c ostream-internal.h 
	ostream.c ostream.h strfuncs.c strfuncs.h 
Removed Files:
	alarm-hup.c alarm-hup.h 
Log Message:
We never do blocking reads/writes to network anymore. Changed imap and pop3
processes to use a single I/O loop.

Not much tested yet, and currently LIST/LSUB may eat too much memory and
APPEND eats all CPU.



Index: Makefile.am
===================================================================
RCS file: /home/cvs/dovecot/src/lib/Makefile.am,v
retrieving revision 1.39
retrieving revision 1.40
diff -u -d -r1.39 -r1.40
--- Makefile.am	30 Jul 2004 01:57:04 -0000	1.39
+++ Makefile.am	15 Aug 2004 03:40:31 -0000	1.40
@@ -1,7 +1,6 @@
 noinst_LIBRARIES = liblib.a
 
 liblib_a_SOURCES = \
-	alarm-hup.c \
 	base64.c \
 	buffer.c \
 	byteorder.c \
@@ -68,7 +67,6 @@
 	write-full.c
 
 noinst_HEADERS = \
-	alarm-hup.h \
 	base64.h \
 	buffer.h \
 	byteorder.h \

--- alarm-hup.c DELETED ---

--- alarm-hup.h DELETED ---

Index: file-lock.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib/file-lock.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- file-lock.c	27 Apr 2004 20:25:52 -0000	1.8
+++ file-lock.c	15 Aug 2004 03:40:31 -0000	1.9
@@ -1,7 +1,6 @@
 /* Copyright (c) 2002-2003 Timo Sirainen */
 
 #include "lib.h"
-#include "alarm-hup.h"
 #include "file-lock.h"
 
 #include <time.h>
@@ -24,13 +23,13 @@
 {
 	struct flock fl;
 	time_t timeout_time, now;
+	unsigned int next_alarm;
 
 	if (timeout == 0)
 		timeout_time = 0;
 	else {
-		alarm_hup_init();
 		timeout_time = time(NULL) + timeout;
-		alarm(timeout);
+		alarm(I_MIN(timeout, 5));
 	}
 
 	fl.l_type = lock_type;
@@ -39,21 +38,32 @@
 	fl.l_len = 0;
 
 	while (fcntl(fd, timeout != 0 ? F_SETLKW : F_SETLK, &fl) < 0) {
-		if (timeout == 0 && (errno == EACCES || errno == EAGAIN))
+		if (timeout == 0 && (errno == EACCES || errno == EAGAIN)) {
+			alarm(0);
 			return 0;
+		}
 
-		if (errno != EINTR)
+		if (errno != EINTR) {
+			alarm(0);
 			return -1;
+		}
 
 		now = time(NULL);
 		if (timeout != 0 && now >= timeout_time) {
 			errno = EAGAIN;
+			alarm(0);
 			return 0;
 		}
 
+		next_alarm = (timeout_time - now) % 5;
+		if (next_alarm == 0)
+			next_alarm = 5;
+		alarm(next_alarm);
+
 		if (callback != NULL)
 			callback(timeout_time - now, context);
 	}
 
+	alarm(0);
 	return 1;
 }

Index: iostream-internal.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib/iostream-internal.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- iostream-internal.h	9 Nov 2003 18:26:25 -0000	1.4
+++ iostream-internal.h	15 Aug 2004 03:40:31 -0000	1.5
@@ -1,7 +1,7 @@
 #ifndef __IOSTREAM_INTERNAL_H
 #define __IOSTREAM_INTERNAL_H
 
-/* This file is private to IStream and OStream implementation */
+/* This file is private to input stream and output stream implementations */
 
 struct _iostream {
 	pool_t pool;
@@ -10,8 +10,6 @@
 	void (*close)(struct _iostream *stream);
 	void (*destroy)(struct _iostream *stream);
 	void (*set_max_buffer_size)(struct _iostream *stream, size_t max_size);
-	void (*set_blocking)(struct _iostream *stream, int timeout_msecs,
-			     void (*timeout_cb)(void *), void *context);
 };
 
 void _io_stream_init(pool_t pool, struct _iostream *stream);
@@ -19,13 +17,5 @@
 void _io_stream_unref(struct _iostream *stream);
 void _io_stream_close(struct _iostream *stream);
 void _io_stream_set_max_buffer_size(struct _iostream *stream, size_t max_size);
-void _io_stream_set_blocking(struct _iostream *stream, int timeout_msecs,
-			     void (*timeout_cb)(void *), void *context);
-
-#define GET_TIMEOUT_TIME(fstream) \
-        ((fstream)->timeout_msecs <= 0 ? 0 : \
-	 time(NULL) + ((fstream)->timeout_msecs / 1000))
-#define STREAM_IS_BLOCKING(fstream) \
-	((fstream)->timeout_msecs != 0)
 
 #endif

Index: iostream.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib/iostream.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- iostream.c	26 Aug 2003 21:18:16 -0000	1.5
+++ iostream.c	15 Aug 2004 03:40:31 -0000	1.6
@@ -40,9 +40,3 @@
 {
 	stream->set_max_buffer_size(stream, max_size);
 }
-
-void _io_stream_set_blocking(struct _iostream *stream, int timeout_msecs,
-			     void (*timeout_cb)(void *), void *context)
-{
-	stream->set_blocking(stream, timeout_msecs, timeout_cb, context);
-}

Index: istream-data.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib/istream-data.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- istream-data.c	27 Apr 2004 20:25:53 -0000	1.8
+++ istream-data.c	15 Aug 2004 03:40:31 -0000	1.9
@@ -16,13 +16,6 @@
 {
 }
 
-static void _set_blocking(struct _iostream *stream __attr_unused__,
-			  int timeout_msecs __attr_unused__,
-			  void (*timeout_cb)(void *) __attr_unused__,
-			  void *context __attr_unused__)
-{
-}
-
 static ssize_t _read(struct _istream *stream __attr_unused__)
 {
 	return -1;
@@ -51,7 +44,6 @@
 	stream->iostream.close = _close;
 	stream->iostream.destroy = _destroy;
 	stream->iostream.set_max_buffer_size = _set_max_buffer_size;
-	stream->iostream.set_blocking = _set_blocking;
 
 	stream->read = _read;
 	stream->seek = _seek;

Index: istream-file.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib/istream-file.c,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- istream-file.c	18 Jun 2004 00:32:25 -0000	1.17
+++ istream-file.c	15 Aug 2004 03:40:31 -0000	1.18
@@ -3,7 +3,6 @@
 /* @UNSAFE: whole file */
 
 #include "lib.h"
-#include "alarm-hup.h"
 #include "istream-internal.h"
 #include "network.h"
 
@@ -13,19 +12,12 @@
 
 #define I_STREAM_MIN_SIZE 4096
 
-#define STREAM_IS_BLOCKING(fstream) \
-	((fstream)->timeout_msecs != 0)
-
 struct file_istream {
 	struct _istream istream;
 
 	size_t max_buffer_size;
 	uoff_t skip_left;
 
-	int timeout_msecs;
-	void (*timeout_cb)(void *);
-	void *timeout_context;
-
 	unsigned int file:1;
 	unsigned int autoclose_fd:1;
 };
@@ -56,21 +48,6 @@
 	fstream->max_buffer_size = max_size;
 }
 
-static void _set_blocking(struct _iostream *stream, int timeout_msecs,
-			  void (*timeout_cb)(void *), void *context)
-{
-	struct file_istream *fstream = (struct file_istream *) stream;
-
-	fstream->timeout_msecs = timeout_msecs;
-	fstream->timeout_cb = timeout_cb;
-	fstream->timeout_context = context;
-
-	net_set_nonblock(fstream->istream.fd, timeout_msecs == 0);
-
-	if (timeout_msecs != 0)
-		alarm_hup_init();
-}
-
 static void i_stream_grow_buffer(struct _istream *stream, size_t bytes)
 {
 	struct file_istream *fstream = (struct file_istream *) stream;
@@ -105,7 +82,6 @@
 static ssize_t _read(struct _istream *stream)
 {
 	struct file_istream *fstream = (struct file_istream *) stream;
-	time_t timeout_time;
 	size_t size;
 	ssize_t ret;
 
@@ -129,64 +105,52 @@
 	}
 
 	size = stream->buffer_size - stream->pos;
-	timeout_time = GET_TIMEOUT_TIME(fstream);
 
 	ret = -1;
-	do {
-		if (ret == 0 && timeout_time > 0 && time(NULL) > timeout_time) {
-			/* timeouted */
-			if (fstream->timeout_cb != NULL)
-				fstream->timeout_cb(fstream->timeout_context);
-			stream->istream.stream_errno = EAGAIN;
-			return -1;
-		}
 
-		if (fstream->file) {
-			ret = pread(stream->fd,
-				    stream->w_buffer + stream->pos, size,
-				    stream->istream.v_offset +
-				    (stream->pos - stream->skip));
-		} else {
-			ret = read(stream->fd,
-				   stream->w_buffer + stream->pos, size);
-		}
-		if (ret == 0) {
-			/* EOF */
-			if (!fstream->file)
-				stream->istream.disconnected = TRUE;
+	if (fstream->file) {
+		ret = pread(stream->fd, stream->w_buffer + stream->pos, size,
+			    stream->istream.v_offset +
+			    (stream->pos - stream->skip));
+	} else {
+		ret = read(stream->fd, stream->w_buffer + stream->pos, size);
+	}
+	if (ret == 0) {
+		/* EOF */
+		if (!fstream->file)
+			stream->istream.disconnected = TRUE;
+		return -1;
+	}
+
+	if (ret < 0) {
+		if (errno == ECONNRESET || errno == ETIMEDOUT) {
+			/* treat as disconnection */
+			stream->istream.disconnected = TRUE;
 			return -1;
 		}
 
-		if (ret < 0) {
-			if (errno == ECONNRESET || errno == ETIMEDOUT) {
-				/* treat as disconnection */
-				stream->istream.disconnected = TRUE;
-				return -1;
-			}
-
-			if (errno == EINTR || errno == EAGAIN)
-				ret = 0;
-			else {
-				stream->istream.stream_errno = errno;
-				return -1;
-			}
+		if (errno == EINTR || errno == EAGAIN)
+			ret = 0;
+		else {
+			stream->istream.stream_errno = errno;
+			return -1;
 		}
+	}
 
-		if (ret > 0 && fstream->skip_left > 0) {
-			i_assert(!fstream->file);
-			i_assert(stream->skip == stream->pos);
+	if (ret > 0 && fstream->skip_left > 0) {
+		i_assert(!fstream->file);
+		i_assert(stream->skip == stream->pos);
 
-			if (fstream->skip_left >= (size_t)ret) {
-				fstream->skip_left -= ret;
-				ret = 0;
-			} else {
-				ret -= fstream->skip_left;
-				stream->pos += fstream->skip_left;
-				stream->skip += fstream->skip_left;
-				fstream->skip_left = 0;
-			}
+		if (fstream->skip_left >= (size_t)ret) {
+			fstream->skip_left -= ret;
+			ret = 0;
+		} else {
+			ret -= fstream->skip_left;
+			stream->pos += fstream->skip_left;
+			stream->skip += fstream->skip_left;
+			fstream->skip_left = 0;
 		}
-	} while (ret == 0 && STREAM_IS_BLOCKING(fstream));
+	}
 
 	stream->pos += ret;
 	return ret;
@@ -233,7 +197,6 @@
 	fstream->istream.iostream.close = _close;
 	fstream->istream.iostream.destroy = _destroy;
 	fstream->istream.iostream.set_max_buffer_size = _set_max_buffer_size;
-	fstream->istream.iostream.set_blocking = _set_blocking;
 
 	fstream->istream.read = _read;
 	fstream->istream.seek = _seek;

Index: istream-limit.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib/istream-limit.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- istream-limit.c	7 Jul 2004 13:36:29 -0000	1.6
+++ istream-limit.c	15 Aug 2004 03:40:31 -0000	1.7
@@ -31,15 +31,6 @@
 	i_stream_set_max_buffer_size(lstream->input, max_size);
 }
 
-static void _set_blocking(struct _iostream *stream, int timeout_msecs,
-			  void (*timeout_cb)(void *), void *context)
-{
-	struct limit_istream *lstream = (struct limit_istream *) stream;
-
-	i_stream_set_blocking(lstream->input, timeout_msecs,
-			      timeout_cb, context);
-}
-
 static ssize_t _read(struct _istream *stream)
 {
 	struct limit_istream *lstream = (struct limit_istream *) stream;
@@ -118,7 +109,6 @@
 	lstream->istream.iostream.close = _close;
 	lstream->istream.iostream.destroy = _destroy;
 	lstream->istream.iostream.set_max_buffer_size = _set_max_buffer_size;
-	lstream->istream.iostream.set_blocking = _set_blocking;
 
 	lstream->istream.read = _read;
 	lstream->istream.seek = _seek;

Index: istream-mmap.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib/istream-mmap.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- istream-mmap.c	19 Jun 2004 20:29:08 -0000	1.11
+++ istream-mmap.c	15 Aug 2004 03:40:31 -0000	1.12
@@ -68,14 +68,6 @@
 	}
 }
 
-static void _set_blocking(struct _iostream *stream __attr_unused__,
-			  int timeout_msecs __attr_unused__,
-			  void (*timeout_cb)(void *) __attr_unused__,
-			  void *context __attr_unused__)
-{
-	/* we never block */
-}
-
 static ssize_t _read(struct _istream *stream)
 {
 	struct mmap_istream *mstream = (struct mmap_istream *) stream;
@@ -140,6 +132,7 @@
 	}
 
 	stream->pos = stream->buffer_size;
+	i_assert(stream->pos - stream->skip != 0);
 	return stream->pos - stream->skip;
 }
 
@@ -201,7 +194,6 @@
 	mstream->istream.iostream.close = _close;
 	mstream->istream.iostream.destroy = _destroy;
 	mstream->istream.iostream.set_max_buffer_size = _set_max_buffer_size;
-	mstream->istream.iostream.set_blocking = _set_blocking;
 
 	mstream->istream.read = _read;
 	mstream->istream.seek = _seek;

Index: istream.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib/istream.c,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- istream.c	2 Jul 2004 15:36:25 -0000	1.19
+++ istream.c	15 Aug 2004 03:40:31 -0000	1.20
@@ -32,13 +32,6 @@
 				       max_size);
 }
 
-void i_stream_set_blocking(struct istream *stream, int timeout_msecs,
-			   void (*timeout_cb)(void *), void *context)
-{
-	_io_stream_set_blocking(&stream->real_stream->iostream, timeout_msecs,
-				timeout_cb, context);
-}
-
 ssize_t i_stream_read(struct istream *stream)
 {
 	struct _istream *_stream = stream->real_stream;

Index: istream.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib/istream.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- istream.h	18 Jun 2004 00:32:25 -0000	1.10
+++ istream.h	15 Aug 2004 03:40:31 -0000	1.11
@@ -37,12 +37,6 @@
 /* Change the maximum size for stream's input buffer to grow. Useful only
    for buffered streams (currently only file). */
 void i_stream_set_max_buffer_size(struct istream *stream, size_t max_size);
-/* Makes reads blocking until at least one byte is read. timeout_cb is
-   called if nothing is read in specified time. Setting timeout_msecs to 0
-   makes it non-blocking. This call changes non-blocking state of file
-   descriptor. */
-void i_stream_set_blocking(struct istream *stream, int timeout_msecs,
-			   void (*timeout_cb)(void *), void *context);
 
 /* Returns number of bytes read if read was ok, -1 if EOF or error, -2 if the
    input buffer is full. */

Index: lib.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib/lib.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- lib.c	26 Aug 2003 21:18:16 -0000	1.10
+++ lib.c	15 Aug 2004 03:40:31 -0000	1.11
@@ -1,7 +1,6 @@
 /* Copyright (c) 2001-2003 Timo Sirainen */
 
 #include "lib.h"
-#include "alarm-hup.h"
 #include "hostpid.h"
 
 #include <stdlib.h>
@@ -29,8 +28,6 @@
 
 void lib_deinit(void)
 {
-	alarm_hup_deinit(); /* doesn't harm even if init is never called */
-
         imem_deinit();
 	data_stack_deinit();
         failures_deinit();

Index: ostream-file.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib/ostream-file.c,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -d -r1.27 -r1.28
--- ostream-file.c	28 Jun 2004 16:13:59 -0000	1.27
+++ ostream-file.c	15 Aug 2004 03:40:31 -0000	1.28
@@ -3,7 +3,6 @@
 /* @UNSAFE: whole file */
 
 #include "lib.h"
-#include "alarm-hup.h"
 #include "ioloop.h"
 #include "write-full.h"
 #include "network.h"
@@ -39,10 +38,6 @@
 	size_t buffer_size, max_buffer_size, optimal_block_size;
 	size_t head, tail; /* first unsent/unused byte */
 
-	int timeout_msecs;
-	void (*timeout_cb)(void *);
-	void *timeout_context;
-
 	unsigned int full:1; /* if head == tail, is buffer empty or full? */
 	unsigned int file:1;
 	unsigned int corked:1;
@@ -51,6 +46,8 @@
 	unsigned int autoclose_fd:1;
 };
 
+static void stream_send_io(void *context);
+
 static void stream_closed(struct file_ostream *fstream)
 {
 	if (fstream->autoclose_fd && fstream->fd != -1) {
@@ -69,7 +66,7 @@
 
 static void _close(struct _iostream *stream)
 {
-	struct file_ostream *fstream = (struct file_ostream *) stream;
+	struct file_ostream *fstream = (struct file_ostream *)stream;
 
 	/* flush output before really closing it */
 	o_stream_flush(&fstream->ostream.ostream);
@@ -79,65 +76,18 @@
 
 static void _destroy(struct _iostream *stream)
 {
-	struct file_ostream *fstream = (struct file_ostream *) stream;
+	struct file_ostream *fstream = (struct file_ostream *)stream;
 
 	p_free(fstream->ostream.iostream.pool, fstream->buffer);
 }
 
 static void _set_max_buffer_size(struct _iostream *stream, size_t max_size)
 {
-	struct file_ostream *fstream = (struct file_ostream *) stream;
+	struct file_ostream *fstream = (struct file_ostream *)stream;
 
 	fstream->max_buffer_size = max_size;
 }
 
-static void _set_blocking(struct _iostream *stream, int timeout_msecs,
-			  void (*timeout_cb)(void *), void *context)
-{
-	struct file_ostream *fstream = (struct file_ostream *) stream;
-
-	fstream->timeout_msecs = timeout_msecs;
-	fstream->timeout_cb = timeout_cb;
-	fstream->timeout_context = context;
-
-	if (!fstream->file)
-		net_set_nonblock(fstream->fd, timeout_msecs == 0);
-
-	if (timeout_msecs != 0)
-		alarm_hup_init();
-}
-
-static void _cork(struct _ostream *stream)
-{
-	struct file_ostream *fstream = (struct file_ostream *) stream;
-
-	if (!fstream->corked) {
-		if (!fstream->no_socket_cork) {
-			if (net_set_cork(fstream->fd, TRUE) < 0)
-				fstream->no_socket_cork = TRUE;
-		}
-		fstream->corked = TRUE;
-	}
-}
-
-static void update_iovec(struct iovec *iov, unsigned int iov_size, size_t size)
-{
-	while (size > 0) {
-		i_assert(iov_size > 0);
-
-		if ((size_t)iov->iov_len <= size) {
-			size -= iov->iov_len;
-			iov->iov_base = NULL;
-			iov->iov_len = 0;
-		} else {
-			iov->iov_base = (void *)((char *)iov->iov_base + size);
-			iov->iov_len -= size;
-			size = 0;
-		}
-		iov++; iov_size--;
-	}
-}
-
 static void update_buffer(struct file_ostream *fstream, size_t size)
 {
 	size_t used;
@@ -175,22 +125,15 @@
 }
 
 /* NOTE: modifies iov */
-static ssize_t
-o_stream_writev(struct file_ostream *fstream, struct iovec *iov, int iov_size)
+static ssize_t o_stream_writev(struct file_ostream *fstream,
+			       const struct const_iovec *iov, int iov_size)
 {
 	ssize_t ret;
 
-	while (iov->iov_len == 0 && iov_size > 0) {
-		iov++;
-		iov_size--;
-	}
-
-	i_assert(iov_size > 0);
-
 	if (iov_size == 1)
 		ret = write(fstream->fd, iov->iov_base, iov->iov_len);
 	else
-		ret = writev(fstream->fd, iov, iov_size);
+		ret = writev(fstream->fd, (const struct iovec *)iov, iov_size);
 
 	if (ret < 0) {
 		if (errno == EAGAIN || errno == EINTR)
@@ -200,107 +143,81 @@
 		return -1;
 	}
 
-	update_iovec(iov, iov_size, ret);
-	update_buffer(fstream, ret);
-
 	return ret;
 }
 
 /* returns how much of vector was used */
 static int o_stream_fill_iovec(struct file_ostream *fstream,
-			       struct iovec iov[2])
+			       struct const_iovec iov[2])
 {
 	if (IS_STREAM_EMPTY(fstream))
 		return 0;
 
 	if (fstream->head < fstream->tail) {
-		iov[0].iov_base = (void *)(fstream->buffer + fstream->head);
+		iov[0].iov_base = fstream->buffer + fstream->head;
 		iov[0].iov_len = fstream->tail - fstream->head;
 		return 1;
 	} else {
-		iov[0].iov_base = (void *)(fstream->buffer + fstream->head);
+		iov[0].iov_base = fstream->buffer + fstream->head;
 		iov[0].iov_len = fstream->buffer_size - fstream->head;
 		if (fstream->tail == 0)
 			return 1;
 		else {
-			iov[1].iov_base = (void *)fstream->buffer;
+			iov[1].iov_base = fstream->buffer;
 			iov[1].iov_len = fstream->tail;
 			return 2;
 		}
 	}
 }
 
-static int o_stream_send_blocking(struct file_ostream *fstream,
-				  const void *data, size_t size)
+static int buffer_flush(struct file_ostream *fstream)
 {
-	time_t timeout_time;
-	struct iovec iov[3];
-	int iov_len, first;
+	struct const_iovec iov[2];
+	int iov_len;
+	ssize_t ret;
 
 	iov_len = o_stream_fill_iovec(fstream, iov);
-	if (size > 0) {
-		iov[iov_len].iov_base = (void *) data;
-		iov[iov_len].iov_len = size;
-		iov_len++;
-	}
-
-	first = TRUE;
-
-	timeout_time = GET_TIMEOUT_TIME(fstream);
-	while (iov[iov_len-1].iov_len != 0) {
-		if (first)
-			first = FALSE;
-		else if (timeout_time > 0 && time(NULL) > timeout_time) {
-			/* timeouted */
-			if (fstream->timeout_cb != NULL)
-				fstream->timeout_cb(fstream->timeout_context);
-			fstream->ostream.ostream.stream_errno = EAGAIN;
+	if (iov_len > 0) {
+		ret = o_stream_writev(fstream, iov, iov_len);
+		if (ret < 0)
 			return -1;
-		}
 
-		if (o_stream_writev(fstream, iov, iov_len) < 0)
-			return -1;
+		update_buffer(fstream, ret);
 	}
 
-        return 1;
+	return IS_STREAM_EMPTY(fstream) ? 1 : 0;
 }
 
-static int buffer_flush(struct file_ostream *fstream)
+static void _cork(struct _ostream *stream, int set)
 {
-	struct iovec iov[2];
-	int iov_len;
+	struct file_ostream *fstream = (struct file_ostream *)stream;
 
-	if (!IS_STREAM_EMPTY(fstream)) {
-		iov_len = o_stream_fill_iovec(fstream, iov);
-		if (o_stream_writev(fstream, iov, iov_len) < 0)
-			return -1;
+	if (fstream->corked != set) {
+		if (!fstream->no_socket_cork) {
+			if (net_set_cork(fstream->fd, set) < 0)
+				fstream->no_socket_cork = TRUE;
+		}
+		fstream->corked = set;
 
-		if (!IS_STREAM_EMPTY(fstream)) {
-			if (o_stream_send_blocking(fstream, NULL, 0) < 0)
-				return -1;
+		if (set && fstream->io != NULL) {
+			io_remove(fstream->io);
+			fstream->io = NULL;
+		} else if (!set && fstream->io == NULL) {
+			if (fstream->file)
+				buffer_flush(fstream);
+			else {
+				fstream->io = io_add(fstream->fd, IO_WRITE,
+						     stream_send_io, fstream);
+			}
 		}
 	}
-
-	return 1;
 }
 
 static int _flush(struct _ostream *stream)
 {
 	struct file_ostream *fstream = (struct file_ostream *) stream;
-	int ret;
-
-	ret = buffer_flush(fstream);
-
-	if (fstream->corked) {
-		/* remove cork */
-		if (!fstream->no_socket_cork) {
-			if (net_set_cork(fstream->fd, FALSE) < 0)
-				i_error("net_set_cork() failed: %m");
-		}
-		fstream->corked = FALSE;
-	}
 
-	return ret;
+	return buffer_flush(fstream);
 }
 
 static size_t get_unused_space(struct file_ostream *fstream)
@@ -317,25 +234,16 @@
 	}
 }
 
-static int _have_space(struct _ostream *stream, size_t size)
+static size_t _get_used_size(struct _ostream *stream)
 {
-	struct file_ostream *fstream = (struct file_ostream *) stream;
-	size_t unused;
-
-	unused = get_unused_space(fstream);
-	if (size <= unused)
-		return 1;
-
-	if (fstream->max_buffer_size == 0)
-		return 1;
+	struct file_ostream *fstream = (struct file_ostream *)stream;
 
-	unused += (fstream->max_buffer_size - fstream->buffer_size);
-	return size <= unused ? 1 : 0;
+	return fstream->buffer_size - get_unused_space(fstream);
 }
 
 static int _seek(struct _ostream *stream, uoff_t offset)
 {
-	struct file_ostream *fstream = (struct file_ostream *) stream;
+	struct file_ostream *fstream = (struct file_ostream *)stream;
 	off_t ret;
 
 	if (offset > OFF_T_MAX) {
@@ -367,17 +275,16 @@
 	size_t size, head_size;
 
 	size = nearest_power(fstream->buffer_size + bytes);
-	if (fstream->max_buffer_size != 0) {
-		if (size > fstream->max_buffer_size) {
-			/* limit the size */
-			size = fstream->max_buffer_size;
-		} else if (fstream->corked) {
-			/* use the largest possible buffer with corking */
-			size = fstream->max_buffer_size;
-		}
+	if (size > fstream->max_buffer_size) {
+		/* limit the size */
+		size = fstream->max_buffer_size;
+	} else if (fstream->corked) {
+		/* use optimal buffer size with corking */
+		size = I_MIN(fstream->optimal_block_size,
+			     fstream->max_buffer_size);
 	}
 
-	if (size == fstream->buffer_size)
+	if (size <= fstream->buffer_size)
 		return;
 
 	fstream->buffer = p_realloc(fstream->ostream.iostream.pool,
@@ -405,18 +312,18 @@
 static void stream_send_io(void *context)
 {
 	struct file_ostream *fstream = context;
-	struct iovec iov[2];
-	int iov_len;
 
-	iov_len = o_stream_fill_iovec(fstream, iov);
+	if (fstream->ostream.callback != NULL)
+		fstream->ostream.callback(fstream->ostream.context);
+	else {
+		if (_flush(&fstream->ostream) <= 0)
+			return;
+	}
 
-	if (iov_len == 0 || o_stream_writev(fstream, iov, iov_len) < 0 ||
-	    iov[iov_len-1].iov_len == 0) {
-		/* error / all sent */
-		if (fstream->io != NULL) {
-			io_remove(fstream->io);
-			fstream->io = NULL;
-		}
+	if (IS_STREAM_EMPTY(fstream) && fstream->io != NULL) {
+		/* all sent */
+		io_remove(fstream->io);
+		fstream->io = NULL;
 	}
 }
 
@@ -455,48 +362,64 @@
 				     fstream);
 	}
 
-	i_assert(!STREAM_IS_BLOCKING(fstream) || sent == size);
 	return sent;
 }
 
-static ssize_t _send(struct _ostream *stream, const void *data, size_t size)
+static ssize_t _sendv(struct _ostream *stream, const struct const_iovec *iov,
+		      size_t iov_count)
 {
-	struct file_ostream *fstream = (struct file_ostream *) stream;
-	struct iovec iov;
+	struct file_ostream *fstream = (struct file_ostream *)stream;
+	size_t i, size, added, optimal_size;
 	ssize_t ret = 0;
 
-	i_assert(size <= SSIZE_T_MAX);
-
 	stream->ostream.stream_errno = 0;
 
-	/* never try sending immediately if fd is blocking,
-	   so we don't need to deal with timeout issues here */
-	if (IS_STREAM_EMPTY(fstream) && !STREAM_IS_BLOCKING(fstream) &&
-	    (!fstream->corked || !_have_space(stream, size))) {
-		iov.iov_base = (void *) data;
-		iov.iov_len = size;
-
-		ret = o_stream_writev(fstream, &iov, 1);
-		if (ret > 0)
-			stream->ostream.offset += ret;
-
-		if (ret < 0 || (size_t)ret == size)
-			return ret;
+	for (i = 0, size = 0; i < iov_count; i++)
+		size += iov[i].iov_len;
 
-		data = (const char *) data + ret;
-		size -= ret;
+	if (size > get_unused_space(fstream)) {
+		if (_flush(stream) < 0)
+			return -1;
 	}
 
-	if (!_have_space(stream, size) && STREAM_IS_BLOCKING(fstream)) {
-		/* send it blocking */
-		if (o_stream_send_blocking(fstream, data, size) < 0)
+	optimal_size = I_MIN(fstream->optimal_block_size,
+			     fstream->max_buffer_size);
+	if (IS_STREAM_EMPTY(fstream) &&
+	    (!fstream->corked || size >= optimal_size)) {
+		/* send immediately */
+		ret = o_stream_writev(fstream, iov, iov_count);
+		if (ret < 0)
 			return -1;
-		ret += (ssize_t)size;
-	} else {
-		/* buffer it, at least partly */
-		ret += (ssize_t)o_stream_add(fstream, data, size);
+
+		size = ret;
+		while (size > 0 && size >= iov[0].iov_len) {
+			size -= iov[0].iov_len;
+			iov++;
+			iov_count--;
+		}
+
+		if (iov_count > 0) {
+			added = o_stream_add(fstream,
+					CONST_PTR_OFFSET(iov[0].iov_base, size),
+					iov[0].iov_len - size);
+			if (added != iov[0].iov_len - size) {
+				/* buffer full */
+				stream->ostream.offset += added;
+				return added;
+			}
+
+			iov++;
+			iov_count--;
+		}
 	}
 
+	/* buffer it, at least partly */
+	for (i = 0; i < iov_count; i++) {
+		added = o_stream_add(fstream, iov[i].iov_base, iov[i].iov_len);
+		ret += added;
+		if (added != iov[i].iov_len)
+			break;
+	}
 	stream->ostream.offset += ret;
 	return ret;
 }
@@ -505,64 +428,35 @@
 				struct istream *instream,
 				int in_fd, uoff_t in_size)
 {
-	struct file_ostream *foutstream = (struct file_ostream *) outstream;
-	time_t timeout_time;
+	struct file_ostream *foutstream = (struct file_ostream *)outstream;
 	uoff_t start_offset;
 	uoff_t offset, send_size, v_offset;
 	ssize_t ret;
-	int first;
-
-	/* set timeout time before hflushing existing buffer which may block */
-	timeout_time = GET_TIMEOUT_TIME(foutstream);
-        start_offset = instream->v_offset;
 
 	/* flush out any data in buffer */
-	if (buffer_flush(foutstream) < 0)
-		return -1;
-
-	v_offset = instream->v_offset;
+	if ((ret = buffer_flush(foutstream)) <= 0)
+		return ret;
 
-	first = TRUE;
+        start_offset = v_offset = instream->v_offset;
 	do {
-		if (first)
-			first = FALSE;
-		else if (timeout_time > 0 && time(NULL) > timeout_time) {
-			/* timeouted */
-			if (foutstream->timeout_cb != NULL) {
-				foutstream->timeout_cb(
-					foutstream->timeout_context);
-			}
-			outstream->ostream.stream_errno = EAGAIN;
-			ret = -1;
-			break;
-		}
-
 		offset = instream->real_stream->abs_start_offset + v_offset;
 		send_size = in_size - v_offset;
 
 		ret = safe_sendfile(foutstream->fd, in_fd, &offset,
 				    MAX_SSIZE_T(send_size));
 		if (ret <= 0) {
-			if (ret == 0) {
-				/* EOF */
-				break;
-			}
-
-			if (errno != EINTR && errno != EAGAIN) {
-				outstream->ostream.stream_errno = errno;
-				if (errno != EINVAL) {
-					/* close only if error wasn't because
-					   sendfile() isn't supported */
-					stream_closed(foutstream);
-				}
+			if (ret == 0 || errno == EINTR || errno == EAGAIN) {
+				ret = 0;
 				break;
 			}
 
-			ret = 0;
-			if (!STREAM_IS_BLOCKING(foutstream)) {
-				/* don't block */
-				break;
+			outstream->ostream.stream_errno = errno;
+			if (errno != EINVAL) {
+				/* close only if error wasn't because
+				   sendfile() isn't supported */
+				stream_closed(foutstream);
 			}
+			break;
 		}
 
 		v_offset += ret;
@@ -576,17 +470,15 @@
 static off_t io_stream_copy(struct _ostream *outstream,
 			    struct istream *instream, uoff_t in_size)
 {
-	struct file_ostream *foutstream = (struct file_ostream *) outstream;
-	time_t timeout_time;
+	struct file_ostream *foutstream = (struct file_ostream *)outstream;
 	uoff_t start_offset;
-	struct iovec iov[3];
+	struct const_iovec iov[3];
 	int iov_len;
 	const unsigned char *data;
 	size_t size, skip_size, block_size;
 	ssize_t ret;
 	int pos;
 
-	timeout_time = GET_TIMEOUT_TIME(foutstream);
 	iov_len = o_stream_fill_iovec(foutstream, iov);
 
         skip_size = 0;
@@ -609,17 +501,12 @@
 		iov[pos].iov_len = size;
 
 		ret = o_stream_writev(foutstream, iov, iov_len);
- 		if (ret < 0) {
-			/* error */
+		if (ret < 0)
 			return -1;
-		}
-
-		if (ret == 0 && !STREAM_IS_BLOCKING(foutstream)) {
-			/* don't block */
-			break;
-		}
 
 		if (skip_size > 0) {
+			update_buffer(foutstream, ret);
+
 			if ((size_t)ret < skip_size) {
 				skip_size -= ret;
 				ret = 0;
@@ -629,27 +516,12 @@
 			}
 		}
 		outstream->ostream.offset += ret;
+		i_stream_skip(instream, ret);
 
-		if (timeout_time > 0 && time(NULL) > timeout_time) {
-			/* timeouted */
-			if (foutstream->timeout_cb != NULL) {
-				foutstream->timeout_cb(
-					foutstream->timeout_context);
-			}
-			outstream->ostream.stream_errno = EAGAIN;
-			return -1;
-		}
-
-		i_stream_skip(instream, size - iov[pos].iov_len);
-		iov_len--;
+		if ((size_t)ret != iov[pos].iov_len)
+			break;
 
-		/* if we already sent the iov[0] and iov[1], we
-		   can just remove them from future calls */
-		while (iov_len > 0 && iov[0].iov_len == 0) {
-			iov[0] = iov[1];
-			if (iov_len > 1) iov[1] = iov[2];
-			iov_len--;
-		}
+		iov_len = 0;
 	}
 
 	return (off_t) (instream->v_offset - start_offset);
@@ -658,8 +530,7 @@
 static off_t io_stream_copy_backwards(struct _ostream *outstream,
 				      struct istream *instream, uoff_t in_size)
 {
-	struct file_ostream *foutstream = (struct file_ostream *) outstream;
-	time_t timeout_time;
+	struct file_ostream *foutstream = (struct file_ostream *)outstream;
 	uoff_t in_start_offset, in_offset, in_limit, out_offset;
 	const unsigned char *data;
 	size_t buffer_size, size, read_size;
@@ -667,8 +538,6 @@
 
 	i_assert(IS_STREAM_EMPTY(foutstream));
 
-	timeout_time = GET_TIMEOUT_TIME(foutstream);
-
 	/* figure out optimal buffer size */
 	buffer_size = instream->real_stream->buffer_size;
 	if (buffer_size == 0 || buffer_size > foutstream->buffer_size) {
@@ -705,7 +574,7 @@
 				size = read_size;
 				if (instream->mmaped) {
 					/* we'll have to write it through
-					   buffer of the file gets corrupted */
+					   buffer or the file gets corrupted */
 					i_assert(size <=
 						 foutstream->buffer_size);
 					memcpy(foutstream->buffer, data, size);
@@ -726,21 +595,11 @@
 			return -1;
 
 		ret = write_full(foutstream->fd, data, size);
- 		if (ret < 0) {
+		if (ret < 0) {
 			/* error */
 			outstream->ostream.stream_errno = errno;
 			return -1;
 		}
-
-		if (timeout_time > 0 && time(NULL) > timeout_time) {
-			/* timeouted */
-			if (foutstream->timeout_cb != NULL) {
-				foutstream->timeout_cb(
-					foutstream->timeout_context);
-			}
-			outstream->ostream.stream_errno = EAGAIN;
-			return -1;
-		}
 	}
 
 	return (off_t) (in_size - in_start_offset);
@@ -748,7 +607,7 @@
 
 static off_t _send_istream(struct _ostream *outstream, struct istream *instream)
 {
-	struct file_ostream *foutstream = (struct file_ostream *) outstream;
+	struct file_ostream *foutstream = (struct file_ostream *)outstream;
 	uoff_t in_size;
 	off_t ret;
 	int in_fd, overlapping;
@@ -814,13 +673,12 @@
 	fstream->ostream.iostream.close = _close;
 	fstream->ostream.iostream.destroy = _destroy;
 	fstream->ostream.iostream.set_max_buffer_size = _set_max_buffer_size;
-	fstream->ostream.iostream.set_blocking = _set_blocking;
 
 	fstream->ostream.cork = _cork;
 	fstream->ostream.flush = _flush;
-	fstream->ostream.have_space = _have_space;
+	fstream->ostream.get_used_size = _get_used_size;
 	fstream->ostream.seek = _seek;
-	fstream->ostream.send = _send;
+	fstream->ostream.sendv = _sendv;
 	fstream->ostream.send_istream = _send_istream;
 
 	ostream = _o_stream_create(&fstream->ostream, pool);
@@ -842,8 +700,6 @@
 			if (S_ISREG(st.st_mode)) {
 				fstream->no_socket_cork = TRUE;
 				fstream->file = TRUE;
-
-				o_stream_set_blocking(ostream, -1, 0, NULL);
 			}
 		}
 #ifndef HAVE_LINUX_SENDFILE

Index: ostream-internal.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib/ostream-internal.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- ostream-internal.h	5 Jan 2003 13:09:51 -0000	1.2
+++ ostream-internal.h	15 Aug 2004 03:40:31 -0000	1.3
@@ -9,16 +9,20 @@
 	struct _iostream iostream;
 
 /* methods: */
-	void (*cork)(struct _ostream *stream);
+	void (*cork)(struct _ostream *stream, int set);
 	int (*flush)(struct _ostream *stream);
-	int (*have_space)(struct _ostream *stream, size_t size);
+	size_t (*get_used_size)(struct _ostream *stream);
 	int (*seek)(struct _ostream *stream, uoff_t offset);
-	ssize_t (*send)(struct _ostream *stream, const void *data, size_t size);
+	ssize_t (*sendv)(struct _ostream *stream, const struct const_iovec *iov,
+			 size_t iov_count);
 	off_t (*send_istream)(struct _ostream *outstream,
 			      struct istream *instream);
 
 /* data: */
 	struct ostream ostream;
+
+	io_callback_t *callback;
+	void *context;
 };
 
 struct ostream *_o_stream_create(struct _ostream *_stream, pool_t pool);

Index: ostream.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib/ostream.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- ostream.c	26 Aug 2003 21:18:16 -0000	1.8
+++ ostream.c	15 Aug 2004 03:40:31 -0000	1.9
@@ -20,27 +20,39 @@
 	stream->closed = TRUE;
 }
 
+void o_stream_set_flush_callback(struct ostream *stream,
+				 io_callback_t *callback, void *context)
+{
+	struct _ostream *_stream = stream->real_stream;
+
+	_stream->callback = callback;
+	_stream->context = context;
+}
+
 void o_stream_set_max_buffer_size(struct ostream *stream, size_t max_size)
 {
 	_io_stream_set_max_buffer_size(&stream->real_stream->iostream,
 				       max_size);
 }
 
-void o_stream_set_blocking(struct ostream *stream, int timeout_msecs,
-			   void (*timeout_cb)(void *), void *context)
+void o_stream_cork(struct ostream *stream)
 {
-	_io_stream_set_blocking(&stream->real_stream->iostream, timeout_msecs,
-				timeout_cb, context);
+	struct _ostream *_stream = stream->real_stream;
+
+	if (stream->closed)
+		return;
+
+	_stream->cork(_stream, TRUE);
 }
 
-void o_stream_cork(struct ostream *stream)
+void o_stream_uncork(struct ostream *stream)
 {
 	struct _ostream *_stream = stream->real_stream;
 
 	if (stream->closed)
 		return;
 
-	_stream->cork(_stream);
+	_stream->cork(_stream, FALSE);
 }
 
 int o_stream_flush(struct ostream *stream)
@@ -53,11 +65,11 @@
 	return _stream->flush(_stream);
 }
 
-int o_stream_have_space(struct ostream *stream, size_t size)
+size_t o_stream_get_buffer_used_size(struct ostream *stream)
 {
 	struct _ostream *_stream = stream->real_stream;
 
-	return _stream->have_space(_stream, size);
+	return _stream->get_used_size(_stream);
 }
 
 int o_stream_seek(struct ostream *stream, uoff_t offset)
@@ -70,20 +82,28 @@
 	return _stream->seek(_stream, offset);
 }
 
-ssize_t o_stream_send(struct ostream *stream, const void *data, size_t size)
+int o_stream_send(struct ostream *stream, const void *data, size_t size)
+{
+	struct const_iovec iov;
+
+	iov.iov_base = data;
+	iov.iov_len = size;
+
+	return o_stream_sendv(stream, &iov, 1);
+}
+
+ssize_t o_stream_sendv(struct ostream *stream, const struct const_iovec *iov,
+		       size_t iov_count)
 {
 	struct _ostream *_stream = stream->real_stream;
 
 	if (stream->closed)
 		return -1;
 
-	if (size == 0)
-		return 0;
-
-	return _stream->send(_stream, data, size);
+	return _stream->sendv(_stream, iov, iov_count);
 }
 
-ssize_t o_stream_send_str(struct ostream *stream, const char *str)
+int o_stream_send_str(struct ostream *stream, const char *str)
 {
 	return o_stream_send(stream, str, strlen(str));
 }

Index: ostream.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib/ostream.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- ostream.h	28 Jun 2004 16:13:59 -0000	1.8
+++ ostream.h	15 Aug 2004 03:40:31 -0000	1.9
@@ -1,6 +1,8 @@
 #ifndef __OSTREAM_H
 #define __OSTREAM_H
 
+#include "ioloop.h"
+
 struct ostream {
 	uoff_t offset;
 
@@ -24,30 +26,29 @@
 /* Mark the stream closed. Nothing will be sent after this call. */
 void o_stream_close(struct ostream *stream);
 
+/* Set IO_WRITE callback. Default will just try to flush the output. */
+void o_stream_set_flush_callback(struct ostream *stream,
+				 io_callback_t *callback, void *context);
 /* Change the maximum size for stream's output buffer to grow. */
 void o_stream_set_max_buffer_size(struct ostream *stream, size_t max_size);
-/* Stream is made to be flushed out whenever it gets full (assumes max_size
-   is already set), ie. writes will never be partial. Also makes any blocking
-   writes to fail after specified timeout, calling timeout_cb if it's
-   set. This call changes non-blocking state of file descriptor. */
-void o_stream_set_blocking(struct ostream *stream, int timeout_msecs,
-			   void (*timeout_cb)(void *), void *context);
 
 /* Delays sending as far as possible, writing only full buffers. Also sets
-   TCP_CORK on if supported. o_stream_flush() removes the cork. */
+   TCP_CORK on if supported. */
 void o_stream_cork(struct ostream *stream);
+void o_stream_uncork(struct ostream *stream);
 /* Flush the output stream, blocks until everything is sent.
    Returns 1 if ok, -1 if error. */
 int o_stream_flush(struct ostream *stream);
-/* Returns 1 if specified amount of data currently fits into stream's output
-   buffer, 0 if not. */
-int o_stream_have_space(struct ostream *stream, size_t size);
+/* Returns number of bytes currently in buffer. */
+size_t o_stream_get_buffer_used_size(struct ostream *stream);
 
 /* Seek to specified position from beginning of file. This works only for
    files. Returns 1 if successful, -1 if error. */
 int o_stream_seek(struct ostream *stream, uoff_t offset);
-/* Returns number of bytes sent or buffered, or -1 if disconnected */
+/* Returns number of bytes sent, -1 = error */
 ssize_t o_stream_send(struct ostream *stream, const void *data, size_t size);
+ssize_t o_stream_sendv(struct ostream *stream, const struct const_iovec *iov,
+		       size_t iov_count);
 ssize_t o_stream_send_str(struct ostream *stream, const char *str);
 /* Send data from input stream. Returns number of bytes sent, or -1 if error.
    Note that this function may block if either instream or outstream is

Index: strfuncs.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib/strfuncs.c,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -d -r1.41 -r1.42
--- strfuncs.c	18 Jul 2004 01:44:59 -0000	1.41
+++ strfuncs.c	15 Aug 2004 03:40:31 -0000	1.42
@@ -478,6 +478,13 @@
 	return strcasecmp(key, *member);
 }
 
+int strcasecmp_p(const void *p1, const void *p2)
+{
+	const char *const *s1 = p1, *const *s2 = p2;
+
+	return strcasecmp(*s1, *s2);
+}
+
 static const char **_strsplit(const char *data, const char *separators,
 			      int spaces)
 {

Index: strfuncs.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib/strfuncs.h,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- strfuncs.h	20 Jun 2004 06:14:44 -0000	1.20
+++ strfuncs.h	15 Aug 2004 03:40:31 -0000	1.21
@@ -56,6 +56,7 @@
 int null_strcmp(const char *s1, const char *s2);
 int memcasecmp(const void *p1, const void *p2, size_t size);
 int bsearch_strcasecmp(const void *p1, const void *p2);
+int strcasecmp_p(const void *p1, const void *p2);
 
 /* seprators is an array of separator characters, not a separator string. */
 const char **t_strsplit(const char *data, const char *separators);



More information about the dovecot-cvs mailing list