changeset 14681:ca37d1577291

Added o_stream_nsend*() and related functions to make delayed error handling safer. Once o_stream_nsend*() is called, o_stream_nfinish() must be called before stream is destroyed to finish checking if there were any errors. If something failed and the stream is just wanted to be closed, o_stream_ignore_last_errors() can be called. For streams where errors don't really make any difference (network sockets) you can call o_stream_set_no_error_handling() immediately after creating the stream.
author Timo Sirainen <tss@iki.fi>
date Mon, 25 Jun 2012 00:01:59 +0300
parents 3ffdb4bf36d3
children d0d7b810646b
files src/anvil/anvil-connection.c src/anvil/connect-limit.c src/anvil/penalty.c src/auth/auth-client-connection.c src/auth/auth-client-connection.h src/auth/auth-master-connection.c src/auth/auth-postfix-connection.c src/auth/auth-worker-client.c src/auth/auth-worker-server.c src/auth/main.c src/auth/mech-winbind.c src/config/config-connection.c src/config/doveconf.c src/dict/dict-commands.c src/dict/dict-connection.c src/director/auth-connection.c src/director/director-connection.c src/director/director-test.c src/director/doveadm-connection.c src/director/login-connection.c src/dns/dns-client.c src/doveadm/client-connection.c src/doveadm/doveadm-mail-fetch.c src/doveadm/doveadm-print-server.c src/doveadm/dsync/dsync-slave-io.c src/doveadm/server-connection.c src/imap-login/imap-proxy.c src/imap/cmd-append.c src/imap/cmd-copy.c src/imap/cmd-thread.c src/imap/imap-client.c src/imap/imap-fetch-body.c src/imap/imap-fetch.c src/imap/imap-search.c src/imap/imap-sync.c src/imap/mail-storage-callbacks.c src/indexer/indexer-client.c src/indexer/worker-connection.c src/ipc/client.c src/ipc/ipc-connection.c src/lib-auth/auth-master.c src/lib-dict/dict-file.c src/lib-fs/fs-posix.c src/lib-fs/ostream-cmp.c src/lib-imap-client/imapc-connection.c src/lib-imap/imap-parser.c src/lib-index/mail-cache-compress.c src/lib-index/mail-index-strmap.c src/lib-index/mail-index-write.c src/lib-lda/duplicate.c src/lib-lda/lmtp-client.c src/lib-lda/mail-send.c src/lib-lda/smtp-client.c src/lib-master/anvil-client.c src/lib-master/ipc-client.c src/lib-master/ipc-server.c src/lib-master/master-instance.c src/lib-master/master-login-auth.c src/lib-master/master-login.c src/lib-storage/index/cydir/cydir-save.c src/lib-storage/index/dbox-common/dbox-file-fix.c src/lib-storage/index/dbox-common/dbox-file.c src/lib-storage/index/dbox-common/dbox-save.c src/lib-storage/index/dbox-multi/mdbox-purge.c src/lib-storage/index/dbox-single/sdbox-file.c src/lib-storage/index/imapc/imapc-save.c src/lib-storage/index/index-attachment.c src/lib-storage/index/maildir/maildir-save.c src/lib-storage/index/maildir/maildir-uidlist.c src/lib-storage/index/mbox/mbox-save.c src/lib-storage/index/pop3c/pop3c-client.c src/lib-storage/list/subscription-file.c src/lib/ostream-file.c src/lib/ostream-private.h src/lib/ostream-rawlog.c src/lib/ostream.c src/lib/ostream.h src/lib/test-ostream-file.c src/lmtp/client.c src/lmtp/lmtp-proxy.c src/login-common/client-common-auth.c src/login-common/client-common.c src/login-common/login-proxy.c src/plugins/acl/acl-backend-vfile-acllist.c src/plugins/acl/acl-backend-vfile.c src/plugins/fts-squat/squat-trie.c src/plugins/fts-squat/squat-uidlist.c src/plugins/imap-quota/imap-quota-plugin.c src/plugins/zlib/doveadm-zlib.c src/plugins/zlib/ostream-bzlib.c src/plugins/zlib/ostream-zlib.c src/pop3-login/pop3-proxy.c src/pop3/pop3-client.c src/pop3/pop3-commands.c src/replication/aggregator/notify-connection.c src/replication/aggregator/replicator-connection.c src/replication/replicator/doveadm-connection.c src/replication/replicator/notify-connection.c src/replication/replicator/replicator-queue.c src/ssl-params/main.c src/stats/client-export.c src/stats/client.c src/stats/mail-server-connection.c src/util/rawlog.c
diffstat 104 files changed, 593 insertions(+), 490 deletions(-) [+]
line wrap: on
line diff
--- a/src/anvil/anvil-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/anvil/anvil-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -90,15 +90,15 @@
 			return -1;
 		}
 		value = connect_limit_lookup(connect_limit, args[0]);
-		(void)o_stream_send_str(conn->output,
-					t_strdup_printf("%u\n", value));
+		o_stream_nsend_str(conn->output,
+				   t_strdup_printf("%u\n", value));
 	} else if (strcmp(cmd, "PENALTY-GET") == 0) {
 		if (args[0] == NULL) {
 			*error_r = "PENALTY-GET: Not enough parameters";
 			return -1;
 		}
 		value = penalty_get(penalty, args[0], &stamp);
-		(void)o_stream_send_str(conn->output,
+		o_stream_nsend_str(conn->output,
 			t_strdup_printf("%u %s\n", value, dec2str(stamp)));
 	} else if (strcmp(cmd, "PENALTY-INC") == 0) {
 		if (args[0] == NULL || args[1] == NULL || args[2] == NULL) {
@@ -183,8 +183,10 @@
 	conn = i_new(struct anvil_connection, 1);
 	conn->fd = fd;
 	conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
-	if (!fifo)
+	if (!fifo) {
 		conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+		o_stream_set_no_error_handling(conn->output, TRUE);
+	}
 	conn->io = io_add(fd, IO_READ, anvil_connection_input, conn);
 	conn->master = master;
 	conn->fifo = fifo;
--- a/src/anvil/connect-limit.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/anvil/connect-limit.c	Mon Jun 25 00:01:59 2012 +0300
@@ -185,5 +185,5 @@
 			break;
 	}
 	hash_table_iterate_deinit(&iter);
-	(void)o_stream_send(output, "\n", 1);
+	o_stream_nsend(output, "\n", 1);
 }
--- a/src/anvil/penalty.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/anvil/penalty.c	Mon Jun 25 00:01:59 2012 +0300
@@ -268,5 +268,5 @@
 		if (o_stream_send(output, str_data(str), str_len(str)) < 0)
 			break;
 	}
-	(void)o_stream_send(output, "\n", 1);
+	o_stream_nsend(output, "\n", 1);
 }
--- a/src/auth/auth-client-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/auth/auth-client-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -54,7 +54,7 @@
 	iov[0].iov_len = strlen(cmd);
 	iov[1].iov_base = "\n";
 	iov[1].iov_len = 1;
-	(void)o_stream_sendv(conn->output, iov, 2);
+	o_stream_nsendv(conn->output, iov, 2);
 
 	if (o_stream_get_buffer_used_size(conn->output) >=
 	    OUTBUF_THROTTLE_SIZE) {
@@ -292,8 +292,8 @@
 	auth_client_connection_unref(&conn);
 }
 
-struct auth_client_connection *
-auth_client_connection_create(struct auth *auth, int fd, bool login_requests)
+void auth_client_connection_create(struct auth *auth, int fd,
+				   bool login_requests)
 {
 	static unsigned int connect_uid_counter = 0;
 	struct auth_client_connection *conn;
@@ -310,6 +310,7 @@
 	conn->input = i_stream_create_fd(fd, AUTH_CLIENT_MAX_LINE_LENGTH,
 					 FALSE);
 	conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
 	o_stream_set_flush_callback(conn->output, auth_client_output, conn);
 	conn->io = io_add(fd, IO_READ, auth_client_input, conn);
 
@@ -325,8 +326,6 @@
 
 	if (o_stream_send(conn->output, str_data(str), str_len(str)) < 0)
 		auth_client_disconnected(&conn);
-
-	return conn;
 }
 
 void auth_client_connection_destroy(struct auth_client_connection **_conn)
--- a/src/auth/auth-client-connection.h	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/auth/auth-client-connection.h	Mon Jun 25 00:01:59 2012 +0300
@@ -22,8 +22,8 @@
 	unsigned int version_received:1;
 };
 
-struct auth_client_connection *
-auth_client_connection_create(struct auth *auth, int fd, bool login_requests);
+void auth_client_connection_create(struct auth *auth, int fd,
+				   bool login_requests);
 void auth_client_connection_destroy(struct auth_client_connection **conn);
 
 struct auth_client_connection *
--- a/src/auth/auth-master-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/auth/auth-master-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -87,7 +87,7 @@
 	iov[1].iov_base = "\n";
 	iov[1].iov_len = 1;
 
-	(void)o_stream_sendv(conn->output, iov, 2);
+	o_stream_nsendv(conn->output, iov, 2);
 }
 
 static bool
@@ -119,19 +119,19 @@
 	if (client_conn == NULL) {
 		i_error("Master requested auth for nonexistent client %u",
 			client_pid);
-		(void)o_stream_send_str(conn->output,
-					t_strdup_printf("FAIL\t%u\n", id));
+		o_stream_nsend_str(conn->output,
+				   t_strdup_printf("FAIL\t%u\n", id));
 	} else if (memcmp(client_conn->cookie, cookie, sizeof(cookie)) != 0) {
 		i_error("Master requested auth for client %u with invalid cookie",
 			client_pid);
-		(void)o_stream_send_str(conn->output,
-					t_strdup_printf("FAIL\t%u\n", id));
+		o_stream_nsend_str(conn->output,
+				   t_strdup_printf("FAIL\t%u\n", id));
 	} else if (!auth_request_handler_master_request(
 			client_conn->request_handler, conn, id, client_id)) {
 		i_error("Master requested auth for non-login client %u",
 			client_pid);
-		(void)o_stream_send_str(conn->output,
-					t_strdup_printf("FAIL\t%u\n", id));
+		o_stream_nsend_str(conn->output,
+				   t_strdup_printf("FAIL\t%u\n", id));
 	}
 	return TRUE;
 }
@@ -260,7 +260,7 @@
 	}
 
 	str_append_c(str, '\n');
-	(void)o_stream_send(conn->output, str_data(str), str_len(str));
+	o_stream_nsend(conn->output, str_data(str), str_len(str));
 
 	auth_request_unref(&auth_request);
 	auth_master_connection_unref(&conn);
@@ -320,7 +320,7 @@
 		i_debug("master out: %s", str_c(str));
 
 	str_append_c(str, '\n');
-	(void)o_stream_send(conn->output, str_data(str), str_len(str));
+	o_stream_nsend(conn->output, str_data(str), str_len(str));
 
 	auth_request_unref(&auth_request);
 	auth_master_connection_unref(&conn);
@@ -446,7 +446,7 @@
 			str = t_strdup_printf("DONE\t%u\t%s\n",
 					      ctx->auth_request->id,
 					      ctx->failed ? "fail" : "");
-			(void)o_stream_send_str(ctx->conn->output, str);
+			o_stream_nsend_str(ctx->conn->output, str);
 			master_input_list_finish(ctx);
 			return;
 		}
@@ -496,7 +496,7 @@
 		i_error("Auth client doesn't have permissions to list users: %s",
 			auth_restricted_reason(conn));
 		str = t_strdup_printf("DONE\t%u\tfail\n", id);
-		(void)o_stream_send_str(conn->output, str);
+		o_stream_nsend_str(conn->output, str);
 		return TRUE;
 	}
 
@@ -505,7 +505,7 @@
 	if (userdb == NULL) {
 		i_error("Trying to iterate users, but userdbs don't support it");
 		str = t_strdup_printf("DONE\t%u\tfail\n", id);
-		(void)o_stream_send_str(conn->output, str);
+		o_stream_nsend_str(conn->output, str);
 		return TRUE;
 	}
 
@@ -693,6 +693,7 @@
 	conn->auth = auth;
 	conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
 	conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
 	o_stream_set_flush_callback(conn->output, master_output, conn);
 	conn->io = io_add(fd, IO_READ, master_input, conn);
 	conn->userdb_only = userdb_only;
@@ -701,7 +702,7 @@
 			       AUTH_MASTER_PROTOCOL_MAJOR_VERSION,
 			       AUTH_MASTER_PROTOCOL_MINOR_VERSION,
 			       my_pid);
-	(void)o_stream_send_str(conn->output, line);
+	o_stream_nsend_str(conn->output, line);
 	DLLIST_PREPEND(&auth_master_connections, conn);
 
 	if (auth_master_connection_set_permissions(conn, socket_st) < 0) {
--- a/src/auth/auth-postfix-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/auth/auth-postfix-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -95,7 +95,7 @@
 		i_debug("postfix out: %s", str_c(str));
 
 	str_append_c(str, '\n');
-	(void)o_stream_send(conn->output, str_data(str), str_len(str));
+	o_stream_nsend(conn->output, str_data(str), str_len(str));
 
 	i_assert(conn->io == NULL);
 	if (!conn->destroyed)
@@ -179,6 +179,7 @@
 	conn->auth = auth;
 	conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
 	conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
 	conn->io = io_add(fd, IO_READ, postfix_input, conn);
 	DLLIST_PREPEND(&auth_postfix_connections, conn);
 	return conn;
--- a/src/auth/auth-worker-client.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/auth/auth-worker-client.c	Mon Jun 25 00:01:59 2012 +0300
@@ -102,8 +102,8 @@
 				   string_t *str)
 {
 	if (worker_restart_request)
-		o_stream_send_str(client->output, "RESTART\n");
-	o_stream_send(client->output, str_data(str), str_len(str));
+		o_stream_nsend_str(client->output, "RESTART\n");
+	o_stream_nsend(client->output, str_data(str), str_len(str));
 }
 
 static void verify_plain_callback(enum passdb_result result,
@@ -464,7 +464,7 @@
 	T_BEGIN {
 		str = t_str_new(128);
 		str_printfa(str, "%u\t*\t%s\n", ctx->auth_request->id, user);
-		o_stream_send(ctx->client->output, str_data(str), str_len(str));
+		o_stream_nsend(ctx->client->output, str_data(str), str_len(str));
 	} T_END;
 
 	if (ctx->sending) {
@@ -694,6 +694,7 @@
 	client->input = i_stream_create_fd(fd, AUTH_WORKER_MAX_LINE_LENGTH,
 					   FALSE);
 	client->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(client->output, TRUE);
 	o_stream_set_flush_callback(client->output, auth_worker_output, client);
 	client->io = io_add(fd, IO_READ, auth_worker_input, client);
 	auth_worker_refresh_proctitle(CLIENT_STATE_HANDSHAKE);
@@ -755,7 +756,7 @@
 	auth_worker_client_error = TRUE;
 	if (auth_worker_client != NULL &&
 	    !auth_worker_client->error_sent) {
-		o_stream_send_str(auth_worker_client->output, "ERROR\n");
+		o_stream_nsend_str(auth_worker_client->output, "ERROR\n");
 		auth_worker_client->error_sent = TRUE;
 	}
 	auth_worker_refresh_proctitle("");
@@ -766,7 +767,7 @@
 	auth_worker_client_error = FALSE;
 	if (auth_worker_client != NULL &&
 	    auth_worker_client->error_sent) {
-		o_stream_send_str(auth_worker_client->output, "SUCCESS\n");
+		o_stream_nsend_str(auth_worker_client->output, "SUCCESS\n");
 		auth_worker_client->error_sent = FALSE;
 	}
 	auth_worker_refresh_proctitle(CLIENT_STATE_IDLE);
@@ -775,6 +776,6 @@
 void auth_worker_client_send_shutdown(void)
 {
 	if (auth_worker_client != NULL)
-		o_stream_send_str(auth_worker_client->output, "SHUTDOWN\n");
+		o_stream_nsend_str(auth_worker_client->output, "SHUTDOWN\n");
 	auth_worker_refresh_proctitle(CLIENT_STATE_STOP);
 }
--- a/src/auth/auth-worker-server.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/auth/auth-worker-server.c	Mon Jun 25 00:01:59 2012 +0300
@@ -101,7 +101,7 @@
 	iov[2].iov_base = "\n";
 	iov[2].iov_len = 1;
 
-	o_stream_sendv(conn->output, iov, 3);
+	o_stream_nsendv(conn->output, iov, 3);
 
 	i_assert(conn->request == NULL);
 	conn->request = request;
@@ -145,7 +145,7 @@
 	binary_to_hex_append(str, userdb_md5, sizeof(userdb_md5));
 	str_append_c(str, '\n');
 
-	o_stream_send(conn->output, str_data(str), str_len(str));
+	o_stream_nsend(conn->output, str_data(str), str_len(str));
 }
 
 static struct auth_worker_connection *auth_worker_create(void)
@@ -173,6 +173,7 @@
 	conn->input = i_stream_create_fd(fd, AUTH_WORKER_MAX_LINE_LENGTH,
 					 FALSE);
 	conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
 	conn->io = io_add(fd, IO_READ, worker_input, conn);
 	conn->to = timeout_add(AUTH_WORKER_MAX_IDLE_SECS * 1000,
 			       auth_worker_idle_timeout, conn);
--- a/src/auth/main.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/auth/main.c	Mon Jun 25 00:01:59 2012 +0300
@@ -326,10 +326,10 @@
 		(void)auth_postfix_connection_create(auth, conn->fd);
 		break;
 	case AUTH_SOCKET_LOGIN_CLIENT:
-		(void)auth_client_connection_create(auth, conn->fd, TRUE);
+		auth_client_connection_create(auth, conn->fd, TRUE);
 		break;
 	case AUTH_SOCKET_CLIENT:
-		(void)auth_client_connection_create(auth, conn->fd, FALSE);
+		auth_client_connection_create(auth, conn->fd, FALSE);
 		break;
 	default:
 		i_unreached();
--- a/src/auth/mech-winbind.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/auth/mech-winbind.c	Mon Jun 25 00:01:59 2012 +0300
@@ -177,7 +177,8 @@
 	base64_encode(data, data_size, str);
 	str_append_c(str, '\n');
 
-	if (o_stream_send_str(request->winbind->out_pipe, str_c(str)) < 0 ||
+	if (o_stream_send(request->winbind->out_pipe,
+			  str_data(str), str_len(str)) < 0 ||
 	    o_stream_flush(request->winbind->out_pipe) < 0) {
 		auth_request_log_error(auth_request, "winbind",
 				       "write(out_pipe) failed: %m");
--- a/src/config/config-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/config/config-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -52,15 +52,15 @@
 	struct ostream *output = context;
 	const char *p;
 
-	o_stream_send_str(output, key);
-	o_stream_send_str(output, "=");
+	o_stream_nsend_str(output, key);
+	o_stream_nsend_str(output, "=");
 	while ((p = strchr(value, '\n')) != NULL) {
-		o_stream_send(output, value, p-value);
-		o_stream_send(output, SETTING_STREAM_LF_CHAR, 1);
+		o_stream_nsend(output, value, p-value);
+		o_stream_nsend(output, SETTING_STREAM_LF_CHAR, 1);
 		value = p+1;
 	}
-	o_stream_send_str(output, value);
-	o_stream_send_str(output, "\n");
+	o_stream_nsend_str(output, value);
+	o_stream_nsend_str(output, "\n");
 }
 
 static int config_connection_request(struct config_connection *conn,
@@ -99,7 +99,7 @@
 		/* master reads configuration only when reloading settings */
 		path = master_service_get_config_path(master_service);
 		if (config_parse_file(path, TRUE, "", &error) <= 0) {
-			o_stream_send_str(conn->output,
+			o_stream_nsend_str(conn->output,
 				t_strconcat("ERROR ", error, "\n", NULL));
 			config_connection_destroy(conn);
 			return -1;
@@ -117,25 +117,25 @@
 		const char *const *s;
 
 		for (s = output.specific_services; *s != NULL; s++) {
-			o_stream_send_str(conn->output,
+			o_stream_nsend_str(conn->output,
 				t_strdup_printf("service=%s\t", *s));
 		}
 	}
 	if (output.service_uses_local)
-		o_stream_send_str(conn->output, "service-uses-local\t");
+		o_stream_nsend_str(conn->output, "service-uses-local\t");
 	if (output.service_uses_remote)
-		o_stream_send_str(conn->output, "service-uses-remote\t");
+		o_stream_nsend_str(conn->output, "service-uses-remote\t");
 	if (output.used_local)
-		o_stream_send_str(conn->output, "used-local\t");
+		o_stream_nsend_str(conn->output, "used-local\t");
 	if (output.used_remote)
-		o_stream_send_str(conn->output, "used-remote\t");
-	o_stream_send_str(conn->output, "\n");
+		o_stream_nsend_str(conn->output, "used-remote\t");
+	o_stream_nsend_str(conn->output, "\n");
 
 	if (config_export_finish(&ctx) < 0) {
 		config_connection_destroy(conn);
 		return -1;
 	}
-	o_stream_send_str(conn->output, "\n");
+	o_stream_nsend_str(conn->output, "\n");
 	o_stream_uncork(conn->output);
 	return 0;
 }
@@ -188,6 +188,7 @@
 	conn->fd = fd;
 	conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
 	conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
 	conn->io = io_add(fd, IO_READ, config_connection_input, conn);
 	DLLIST_PREPEND(&config_connections, conn);
 	return conn;
--- a/src/config/doveconf.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/config/doveconf.c	Mon Jun 25 00:01:59 2012 +0300
@@ -242,8 +242,8 @@
 				if (prefix.str_pos != -1U)
 					str_truncate(ctx->list_prefix, prefix.str_pos);
 				else {
-					o_stream_send(output, indent_str, indent*2);
-					o_stream_send_str(output, "}\n");
+					o_stream_nsend(output, indent_str, indent*2);
+					o_stream_nsend_str(output, "}\n");
 				}
 				prefix_idx = prefix.prefix_idx;
 			} else {
@@ -285,7 +285,7 @@
 					goto again;
 			}
 		}
-		o_stream_send(output, str_data(ctx->list_prefix), str_len(ctx->list_prefix));
+		o_stream_nsend(output, str_data(ctx->list_prefix), str_len(ctx->list_prefix));
 		str_truncate(ctx->list_prefix, 0);
 		prefix_stack_reset_str(&prefix_stack);
 		ctx->list_prefix_sent = TRUE;
@@ -293,20 +293,20 @@
 		skip_len = prefix_idx == -1U ? 0 : strlen(prefixes[prefix_idx]);
 		i_assert(skip_len == 0 ||
 			 strncmp(prefixes[prefix_idx], strings[i], skip_len) == 0);
-		o_stream_send(output, indent_str, indent*2);
+		o_stream_nsend(output, indent_str, indent*2);
 		key = strings[i] + skip_len;
 		if (unique_key) key++;
 		value = strchr(key, '=');
-		o_stream_send(output, key, value-key);
-		o_stream_send_str(output, " = ");
+		o_stream_nsend(output, key, value-key);
+		o_stream_nsend_str(output, " = ");
 		if (!value_need_quote(value+1))
-			o_stream_send_str(output, value+1);
+			o_stream_nsend_str(output, value+1);
 		else {
-			o_stream_send(output, "\"", 1);
-			o_stream_send_str(output, str_escape(value+1));
-			o_stream_send(output, "\"", 1);
+			o_stream_nsend(output, "\"", 1);
+			o_stream_nsend_str(output, str_escape(value+1));
+			o_stream_nsend(output, "\"", 1);
 		}
-		o_stream_send(output, "\n", 1);
+		o_stream_nsend(output, "\n", 1);
 	end: ;
 	} T_END;
 
@@ -316,8 +316,8 @@
 			break;
 		prefix_idx = prefix.prefix_idx;
 		indent--;
-		o_stream_send(output, indent_str, indent*2);
-		o_stream_send_str(output, "}\n");
+		o_stream_nsend(output, indent_str, indent*2);
+		o_stream_nsend_str(output, "}\n");
 	}
 
 	/* flush output before writing errors */
@@ -382,8 +382,8 @@
 {
 	while (indent > 0) {
 		indent--;
-		o_stream_send(output, indent_str, indent*2);
-		o_stream_send(output, "}\n", 2);
+		o_stream_nsend(output, indent_str, indent*2);
+		o_stream_nsend(output, "}\n", 2);
 	}
 }
 
@@ -427,6 +427,7 @@
 	int ret;
 
 	output = o_stream_create_fd(STDOUT_FILENO, 0, FALSE);
+	o_stream_set_no_error_handling(output, TRUE);
 	o_stream_cork(output);
 
 	ctx = config_dump_human_init(module, scope, TRUE);
@@ -438,7 +439,7 @@
 		ret = config_dump_human_sections(output, filter, module);
 
 	o_stream_uncork(output);
-	o_stream_unref(&output);
+	o_stream_destroy(&output);
 	return ret;
 }
 
--- a/src/dict/dict-commands.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/dict/dict-commands.c	Mon Jun 25 00:01:59 2012 +0300
@@ -34,12 +34,12 @@
 	if (ret > 0) {
 		reply = t_strdup_printf("%c%s\n",
 					DICT_PROTOCOL_REPLY_OK, value);
-		o_stream_send_str(conn->output, reply);
+		o_stream_nsend_str(conn->output, reply);
 	} else {
 		reply = t_strdup_printf("%c\n", ret == 0 ?
 					DICT_PROTOCOL_REPLY_NOTFOUND :
 					DICT_PROTOCOL_REPLY_FAIL);
-		o_stream_send_str(conn->output, reply);
+		o_stream_nsend_str(conn->output, reply);
 	}
 	return 0;
 }
@@ -55,7 +55,7 @@
 		str_truncate(str, 0);
 		str_printfa(str, "%c%s\t%s\n", DICT_PROTOCOL_REPLY_OK,
 			    key, value);
-		o_stream_send(conn->output, str_data(str), str_len(str));
+		o_stream_nsend(conn->output, str_data(str), str_len(str));
 
 		if (o_stream_get_buffer_used_size(conn->output) >
 		    DICT_OUTPUT_OPTIMAL_SIZE) {
@@ -75,7 +75,7 @@
 	if (dict_iterate_deinit(&conn->iter_ctx) < 0)
 		str_append_c(str, DICT_PROTOCOL_REPLY_FAIL);
 	str_append_c(str, '\n');
-	o_stream_send(conn->output, str_data(str), str_len(str));
+	o_stream_nsend(conn->output, str_data(str), str_len(str));
 	o_stream_uncork(conn->output);
 	return 1;
 }
@@ -207,7 +207,7 @@
 		chr = DICT_PROTOCOL_REPLY_FAIL;
 		break;
 	}
-	o_stream_send_str(conn->output, t_strdup_printf("%c\n", chr));
+	o_stream_nsend_str(conn->output, t_strdup_printf("%c\n", chr));
 	dict_connection_transaction_array_remove(conn, trans);
 	return 0;
 }
@@ -231,7 +231,7 @@
 	}
 	reply = t_strdup_printf("%c%c%u\n", DICT_PROTOCOL_REPLY_ASYNC_COMMIT,
 				chr, trans->id);
-	o_stream_send_str(trans->conn->output, reply);
+	o_stream_nsend_str(trans->conn->output, reply);
 
 	dict_connection_transaction_array_remove(trans->conn, trans);
 }
--- a/src/dict/dict-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/dict/dict-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -149,6 +149,7 @@
 	conn->input = i_stream_create_fd(fd, DICT_CLIENT_MAX_LINE_LENGTH,
 					 FALSE);
 	conn->output = o_stream_create_fd(fd, 128*1024, FALSE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
 	conn->io = io_add(fd, IO_READ, dict_connection_input, conn);
 	DLLIST_PREPEND(&dict_connections, conn);
 	return conn;
--- a/src/director/auth-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/director/auth-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -88,6 +88,7 @@
 	conn->input = i_stream_create_fd(conn->fd, AUTH_CLIENT_MAX_LINE_LENGTH,
 					 FALSE);
 	conn->output = o_stream_create_fd(conn->fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
 	conn->io = io_add(conn->fd, IO_READ, auth_connection_input, conn);
 	return 0;
 }
@@ -125,7 +126,7 @@
 {
 	i_assert(conn->fd != -1);
 
-	(void)o_stream_send(conn->output, data, size);
+	o_stream_nsend(conn->output, data, size);
 }
 
 void auth_connections_deinit(void)
--- a/src/director/director-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/director/director-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -183,7 +183,6 @@
 	connect_str = t_strdup_printf("CONNECT\t%s\t%u\n",
 				      net_ip2addr(&host->ip), host->port);
 	director_connection_send(conn, connect_str);
-	(void)o_stream_flush(conn->output);
 	o_stream_uncork(conn->output);
 
 	conn->to_disconnect =
@@ -1388,6 +1387,7 @@
 	conn->dir = dir;
 	conn->input = i_stream_create_fd(conn->fd, MAX_INBUF_SIZE, FALSE);
 	conn->output = o_stream_create_fd(conn->fd, MAX_OUTBUF_SIZE, FALSE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
 	conn->to_ping = timeout_add(DIRECTOR_CONNECTION_ME_TIMEOUT_MSECS,
 				    director_connection_init_timeout, conn);
 	array_append(&dir->connections, &conn, 1);
--- a/src/director/director-test.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/director/director-test.c	Mon Jun 25 00:01:59 2012 +0300
@@ -194,22 +194,22 @@
 		if (!imap_arg_get_astring(args, &str))
 			return -1;
 
-		o_stream_send_str(client->output,
+		o_stream_nsend_str(client->output,
 			t_strconcat(tag, " OK Logged in.\r\n", NULL));
 		client->username = i_strdup(str);
 		client_username_check(client);
 	} else if (strcasecmp(cmd, "logout") == 0) {
-		o_stream_send_str(client->output, t_strconcat(
+		o_stream_nsend_str(client->output, t_strconcat(
 			"* BYE Out.\r\n",
 			tag, " OK Logged out.\r\n", NULL));
 		imap_client_destroy(&client);
 		return 0;
 	} else if (strcasecmp(cmd, "capability") == 0) {
-		o_stream_send_str(client->output,
+		o_stream_nsend_str(client->output,
 			t_strconcat("* CAPABILITY IMAP4rev1\r\n",
 				    tag, " OK Done.\r\n", NULL));
 	} else {
-		o_stream_send_str(client->output,
+		o_stream_nsend_str(client->output,
 			t_strconcat(tag, " BAD Not supported.\r\n", NULL));
 	}
 
@@ -249,10 +249,11 @@
 	client->fd = fd;
 	client->input = i_stream_create_fd(fd, 4096, FALSE);
 	client->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(client->output, TRUE);
 	client->io = io_add(fd, IO_READ, imap_client_input, client);
 	client->parser =
 		imap_parser_create(client->input, client->output, 4096);
-	o_stream_send_str(client->output,
+	o_stream_nsend_str(client->output,
 		"* OK [CAPABILITY IMAP4rev1] director-test ready.\r\n");
 	DLLIST_PREPEND(&imap_clients, client);
 }
@@ -277,8 +278,8 @@
 	DLLIST_REMOVE(&imap_clients, client);
 	imap_parser_unref(&client->parser);
 	io_remove(&client->io);
-	i_stream_unref(&client->input);
-	o_stream_unref(&client->output);
+	i_stream_destroy(&client->input);
+	o_stream_destroy(&client->output);
 	net_disconnect(client->fd);
 	i_free(client->username);
 	i_free(client);
@@ -298,7 +299,7 @@
 		return;
 	}
 
-	o_stream_send(output, data, size);
+	o_stream_nsend(output, data, size);
 	i_stream_skip(input, size);
 
 	if (rand() % 3 == 0 && conn->to_delay == NULL) {
@@ -345,12 +346,14 @@
 	conn->in_fd = in_fd;
 	conn->in_input = i_stream_create_fd(conn->in_fd, (size_t)-1, FALSE);
 	conn->in_output = o_stream_create_fd(conn->in_fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(conn->in_output, TRUE);
 	conn->in_io = io_add(conn->in_fd, IO_READ,
 			     director_connection_in_input, conn);
 
 	conn->out_fd = out_fd;
 	conn->out_input = i_stream_create_fd(conn->out_fd, (size_t)-1, FALSE);
 	conn->out_output = o_stream_create_fd(conn->out_fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(conn->out_output, TRUE);
 	conn->out_io = io_add(conn->out_fd, IO_READ,
 			      director_connection_out_input, conn);
 
--- a/src/director/doveadm-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/director/doveadm-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -51,7 +51,7 @@
 			    (*hostp)->user_count);
 	}
 	str_append_c(str, '\n');
-	o_stream_send(conn->output, str_data(str), str_len(str));
+	o_stream_nsend(conn->output, str_data(str), str_len(str));
 }
 
 static void doveadm_cmd_host_list_removed(struct doveadm_connection *conn)
@@ -87,7 +87,7 @@
 	for (; i < orig_hosts_count; i++)
 		str_printfa(str, "%s\n", net_ip2addr(&orig_hosts[i]->ip));
 	str_append_c(str, '\n');
-	o_stream_send(conn->output, str_data(str), str_len(str));
+	o_stream_nsend(conn->output, str_data(str), str_len(str));
 
 	mail_hosts_deinit(&orig_hosts_list);
 }
@@ -127,7 +127,7 @@
 			    (unsigned long)last_failed);
 	}
 	str_append_c(str, '\n');
-	o_stream_send(conn->output, str_data(str), str_len(str));
+	o_stream_nsend(conn->output, str_data(str), str_len(str));
 }
 
 static bool
@@ -150,7 +150,7 @@
 		host = director_host_add(conn->dir, &ip, port);
 		director_notify_ring_added(host, conn->dir->self_host);
 	}
-	o_stream_send(conn->output, "OK\n", 3);
+	o_stream_nsend(conn->output, "OK\n", 3);
 	return TRUE;
 }
 
@@ -174,10 +174,10 @@
 		director_host_lookup(conn->dir, &ip, port) :
 		director_host_lookup_ip(conn->dir, &ip);
 	if (host == NULL)
-		o_stream_send_str(conn->output, "NOTFOUND\n");
+		o_stream_nsend_str(conn->output, "NOTFOUND\n");
 	else {
 		director_ring_remove(host, conn->dir->self_host);
-		o_stream_send(conn->output, "OK\n", 3);
+		o_stream_nsend(conn->output, "OK\n", 3);
 	}
 	return TRUE;
 }
@@ -199,7 +199,7 @@
 		return FALSE;
 	}
 	if (vhost_count > MAX_VALID_VHOST_COUNT && vhost_count != -1U) {
-		o_stream_send_str(conn->output, "vhost count too large\n");
+		o_stream_nsend_str(conn->output, "vhost count too large\n");
 		return TRUE;
 	}
 	host = mail_host_lookup(dir->mail_hosts, &ip);
@@ -209,7 +209,7 @@
 		mail_host_set_vhost_count(dir->mail_hosts, host, vhost_count);
 	director_update_host(dir, dir->self_host, NULL, host);
 
-	o_stream_send(conn->output, "OK\n", 3);
+	o_stream_nsend(conn->output, "OK\n", 3);
 	return TRUE;
 }
 
@@ -225,11 +225,11 @@
 	}
 	host = mail_host_lookup(conn->dir->mail_hosts, &ip);
 	if (host == NULL)
-		o_stream_send_str(conn->output, "NOTFOUND\n");
+		o_stream_nsend_str(conn->output, "NOTFOUND\n");
 	else {
 		director_remove_host(conn->dir, conn->dir->self_host,
 				     NULL, host);
-		o_stream_send(conn->output, "OK\n", 3);
+		o_stream_nsend(conn->output, "OK\n", 3);
 	}
 	return TRUE;
 }
@@ -243,7 +243,7 @@
 		director_flush_host(conn->dir, conn->dir->self_host,
 				    NULL, *hostp);
 	}
-	o_stream_send(conn->output, "OK\n", 3);
+	o_stream_nsend(conn->output, "OK\n", 3);
 }
 
 static bool
@@ -263,11 +263,11 @@
 	}
 	host = mail_host_lookup(conn->dir->mail_hosts, &ip);
 	if (host == NULL)
-		o_stream_send_str(conn->output, "NOTFOUND\n");
+		o_stream_nsend_str(conn->output, "NOTFOUND\n");
 	else {
 		director_flush_host(conn->dir, conn->dir->self_host,
 				    NULL, host);
-		o_stream_send(conn->output, "OK\n", 3);
+		o_stream_nsend(conn->output, "OK\n", 3);
 	}
 	return TRUE;
 }
@@ -307,7 +307,7 @@
 		str_append(str, "\t");
 	else
 		str_printfa(str, "\t%s\n", net_ip2addr(&host->ip));
-	o_stream_send(conn->output, str_data(str), str_len(str));
+	o_stream_nsend(conn->output, str_data(str), str_len(str));
 	return TRUE;
 }
 
@@ -334,14 +334,14 @@
 			unsigned int expire_time = user->timestamp +
 				conn->dir->set->director_user_expire;
 
-			o_stream_send_str(conn->output, t_strdup_printf(
+			o_stream_nsend_str(conn->output, t_strdup_printf(
 				"%u\t%u\t%s\n",
 				user->username_hash, expire_time,
 				net_ip2addr(&user->host->ip)));
 		} T_END;
 	}
 	user_directory_iter_deinit(&iter);
-	o_stream_send(conn->output, "\n", 1);
+	o_stream_nsend(conn->output, "\n", 1);
 	return TRUE;
 }
 
@@ -362,7 +362,7 @@
 	}
 	host = mail_host_lookup(conn->dir->mail_hosts, &ip);
 	if (host == NULL) {
-		o_stream_send_str(conn->output, "NOTFOUND\n");
+		o_stream_nsend_str(conn->output, "NOTFOUND\n");
 		return TRUE;
 	}
 
@@ -370,13 +370,13 @@
 		username_hash = user_directory_get_username_hash(conn->dir->users, line);
 	user = user_directory_lookup(conn->dir->users, username_hash);
 	if (user != NULL && user->kill_state != USER_KILL_STATE_NONE) {
-		o_stream_send_str(conn->output, "TRYAGAIN\n");
+		o_stream_nsend_str(conn->output, "TRYAGAIN\n");
 		return TRUE;
 	}
 
 	director_move_user(conn->dir, conn->dir->self_host, NULL,
 			   username_hash, host);
-	o_stream_send(conn->output, "OK\n", 3);
+	o_stream_nsend(conn->output, "OK\n", 3);
 	return TRUE;
 }
 
@@ -453,8 +453,9 @@
 	conn->dir = dir;
 	conn->input = i_stream_create_fd(conn->fd, 1024, FALSE);
 	conn->output = o_stream_create_fd(conn->fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
 	conn->io = io_add(conn->fd, IO_READ, doveadm_connection_input, conn);
-	o_stream_send_str(conn->output, DOVEADM_HANDSHAKE);
+	o_stream_nsend_str(conn->output, DOVEADM_HANDSHAKE);
 
 	DLLIST_PREPEND(&doveadm_connections, conn);
 	return conn;
--- a/src/director/login-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/director/login-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -67,7 +67,7 @@
 	iov[0].iov_len = strlen(line);
 	iov[1].iov_base = "\n";
 	iov[1].iov_len = 1;
-	(void)o_stream_sendv(conn->output, iov, N_ELEMENTS(iov));
+	o_stream_nsendv(conn->output, iov, N_ELEMENTS(iov));
 }
 
 static void
@@ -175,6 +175,7 @@
 	conn->auth = auth;
 	conn->dir = dir;
 	conn->output = o_stream_create_fd(conn->fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
 	conn->io = io_add(conn->fd, IO_READ, login_connection_input, conn);
 	conn->userdb = userdb;
 
@@ -195,7 +196,7 @@
 
 	DLLIST_REMOVE(&login_connections, conn);
 	io_remove(&conn->io);
-	o_stream_unref(&conn->output);
+	o_stream_destroy(&conn->output);
 	if (close(conn->fd) < 0)
 		i_error("close(login connection) failed: %m");
 	conn->fd = -1;
--- a/src/dns/dns-client.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/dns/dns-client.c	Mon Jun 25 00:01:59 2012 +0300
@@ -38,20 +38,20 @@
 			ret = NO_ADDRESS;
 		}
 		if (ret != 0) {
-			o_stream_send_str(client->output,
+			o_stream_nsend_str(client->output,
 				t_strdup_printf("%d\n", ret));
 		} else {
-			o_stream_send_str(client->output,
+			o_stream_nsend_str(client->output,
 				t_strdup_printf("0 %u\n", ips_count));
 			for (i = 0; i < ips_count; i++) {
-				o_stream_send_str(client->output, t_strconcat(
+				o_stream_nsend_str(client->output, t_strconcat(
 					net_ip2addr(&ips[i]), "\n", NULL));
 			}
 		}
 	} else if (strcmp(line, "QUIT") == 0) {
 		return -1;
 	} else {
-		o_stream_send_str(client->output, "Unknown command\n");
+		o_stream_nsend_str(client->output, "Unknown command\n");
 	}
 
 	if (client->output->overflow)
@@ -91,6 +91,7 @@
 	client->fd = fd;
 	client->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
 	client->output = o_stream_create_fd(fd, MAX_OUTBUF_SIZE, FALSE);
+	o_stream_set_no_error_handling(client->output, TRUE);
 	client->io = io_add(fd, IO_READ, dns_client_input, client);
 	client->to = timeout_add(INPUT_TIMEOUT_MSECS, dns_client_timeout,
 				 client);
--- a/src/doveadm/client-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/doveadm/client-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -127,14 +127,14 @@
 
 	if (ret < 0) {
 		i_error("%s: %s", ctx->cmd->name, error);
-		o_stream_send(conn->output, "\n-\n", 3);
+		o_stream_nsend(conn->output, "\n-\n", 3);
 	} else if (ret == 0) {
-		o_stream_send_str(conn->output, "\n-NOUSER\n");
+		o_stream_nsend_str(conn->output, "\n-NOUSER\n");
 	} else if (ctx->exit_code != 0) {
 		/* maybe not an error, but not a full success either */
-		o_stream_send(conn->output, "\n-\n", 3);
+		o_stream_nsend(conn->output, "\n-\n", 3);
 	} else {
-		o_stream_send(conn->output, "\n+\n", 3);
+		o_stream_nsend(conn->output, "\n+\n", 3);
 	}
 	pool_unref(&ctx->pool);
 }
@@ -211,7 +211,7 @@
 	o_stream_cork(conn->output);
 	ctx = doveadm_mail_cmd_server_parse(cmd_name, conn->set, &input, argc, args);
 	if (ctx == NULL)
-		o_stream_send(conn->output, "\n-\n", 3);
+		o_stream_nsend(conn->output, "\n-\n", 3);
 	else
 		doveadm_mail_cmd_server_run(conn, ctx, &input);
 	o_stream_uncork(conn->output);
@@ -293,12 +293,12 @@
 	if (!conn->authenticated) {
 		if ((ret = client_connection_authenticate(conn)) <= 0) {
 			if (ret < 0) {
-				o_stream_send(conn->output, "-\n", 2);
+				o_stream_nsend(conn->output, "-\n", 2);
 				client_connection_destroy(&conn);
 			}
 			return;
 		}
-		o_stream_send(conn->output, "+\n", 2);
+		o_stream_nsend(conn->output, "+\n", 2);
 		conn->authenticated = TRUE;
 	}
 
@@ -356,6 +356,7 @@
 	conn->io = io_add(fd, IO_READ, client_connection_input, conn);
 	conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
 	conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
 
 	(void)net_getsockname(fd, &conn->local_ip, &port);
 	(void)net_getpeername(fd, &conn->remote_ip, &port);
@@ -367,9 +368,9 @@
 	    (st.st_mode & 0777) == 0600) {
 		/* no need for client to authenticate */
 		conn->authenticated = TRUE;
-		o_stream_send(conn->output, "+\n", 2);
+		o_stream_nsend(conn->output, "+\n", 2);
 	} else {
-		o_stream_send(conn->output, "-\n", 2);
+		o_stream_nsend(conn->output, "-\n", 2);
 	}
 	if (client_connection_read_settings(conn) < 0)
 		client_connection_destroy(&conn);
--- a/src/doveadm/doveadm-mail-fetch.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/doveadm/doveadm-mail-fetch.c	Mon Jun 25 00:01:59 2012 +0300
@@ -562,6 +562,7 @@
 	_ctx->search_args = doveadm_mail_build_search_args(args + 1);
 
 	ctx->output = o_stream_create_fd(STDOUT_FILENO, 0, FALSE);
+	o_stream_set_no_error_handling(ctx->output, TRUE);
 }
 
 static struct doveadm_mail_cmd_context *cmd_fetch_alloc(void)
--- a/src/doveadm/doveadm-print-server.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/doveadm/doveadm-print-server.c	Mon Jun 25 00:01:59 2012 +0300
@@ -68,8 +68,8 @@
 	if (doveadm_client == NULL)
 		return;
 
-	o_stream_send(client_connection_get_output(doveadm_client),
-		      str_data(ctx.str), str_len(ctx.str));
+	o_stream_nsend(client_connection_get_output(doveadm_client),
+		       str_data(ctx.str), str_len(ctx.str));
 	str_truncate(ctx.str, 0);
 }
 
--- a/src/doveadm/dsync/dsync-slave-io.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/doveadm/dsync/dsync-slave-io.c	Mon Jun 25 00:01:59 2012 +0300
@@ -201,7 +201,7 @@
 		}
 
 		if (i > 0) {
-			(void)o_stream_send(slave->output, data, i);
+			o_stream_nsend(slave->output, data, i);
 			slave->mail_output_last = data[i-1];
 			i_stream_skip(slave->mail_output, i);
 		}
@@ -219,7 +219,7 @@
 		}
 
 		if (add != '\0') {
-			(void)o_stream_send(slave->output, &add, 1);
+			o_stream_nsend(slave->output, &add, 1);
 			slave->mail_output_last = add;
 		}
 	}
@@ -233,7 +233,7 @@
 	}
 
 	/* finished sending the stream */
-	(void)o_stream_send_str(slave->output, "\r\n.\r\n");
+	o_stream_nsend_str(slave->output, "\r\n.\r\n");
 	i_stream_unref(&slave->mail_output);
 	return 1;
 }
@@ -273,11 +273,12 @@
 	slave->input = i_stream_create_fd(slave->fd_in, (size_t)-1, FALSE);
 	slave->output = o_stream_create_fd(slave->fd_out, (size_t)-1, FALSE);
 	slave->io = io_add(slave->fd_in, IO_READ, dsync_slave_io_input, slave);
+	o_stream_set_no_error_handling(slave->output, TRUE);
 	o_stream_set_flush_callback(slave->output, dsync_slave_io_output, slave);
 	slave->to = timeout_add(DSYNC_SLAVE_IO_TIMEOUT_MSECS,
 				dsync_slave_io_timeout, slave);
 	o_stream_cork(slave->output);
-	o_stream_send_str(slave->output, DSYNC_HANDSHAKE_VERSION);
+	o_stream_nsend_str(slave->output, DSYNC_HANDSHAKE_VERSION);
 
 	/* initialize serializers and send their headers to remote */
 	for (i = 1; i < ITEM_END_OF_LIST; i++) T_BEGIN {
@@ -291,12 +292,12 @@
 
 			slave->serializers[i] =
 				dsync_serializer_init(t_strsplit_spaces(keys, " "));
-			o_stream_send(slave->output, &items[i].chr, 1);
-			o_stream_send_str(slave->output,
+			o_stream_nsend(slave->output, &items[i].chr, 1);
+			o_stream_nsend_str(slave->output,
 				dsync_serializer_encode_header_line(slave->serializers[i]));
 		}
 	} T_END;
-	o_stream_send_str(slave->output, ".\n");
+	o_stream_nsend_str(slave->output, ".\n");
 
 	dsync_slave_flush(&slave->slave);
 }
@@ -387,7 +388,7 @@
 dsync_slave_io_send_string(struct dsync_slave_io *slave, const string_t *str)
 {
 	i_assert(slave->mail_output == NULL);
-	o_stream_send(slave->output, str_data(str), str_len(str));
+	o_stream_nsend(slave->output, str_data(str), str_len(str));
 }
 
 static int dsync_slave_check_missing_deserializers(struct dsync_slave_io *slave)
@@ -607,7 +608,7 @@
 
 	i_assert(slave->mail_output == NULL);
 
-	o_stream_send_str(slave->output, END_OF_LIST_LINE"\n");
+	o_stream_nsend_str(slave->output, END_OF_LIST_LINE"\n");
 }
 
 static void
--- a/src/doveadm/server-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/doveadm/server-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -162,7 +162,7 @@
 {
 	conn->authenticated = TRUE;
 	if (conn->delayed_cmd != NULL) {
-		o_stream_send_str(conn->output, conn->delayed_cmd);
+		o_stream_nsend_str(conn->output, conn->delayed_cmd);
 		conn->delayed_cmd = NULL;
 	}
 }
@@ -188,7 +188,7 @@
 	base64_encode(plain->data, plain->used, cmd);
 	str_append_c(cmd, '\n');
 
-	o_stream_send(conn->output, cmd->data, cmd->used);
+	o_stream_nsend(conn->output, cmd->data, cmd->used);
 	return 0;
 }
 
@@ -319,8 +319,9 @@
 	conn->io = io_add(conn->fd, IO_READ, server_connection_input, conn);
 	conn->input = i_stream_create_fd(conn->fd, MAX_INBUF_SIZE, FALSE);
 	conn->output = o_stream_create_fd(conn->fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
 	conn->state = SERVER_REPLY_STATE_DONE;
-	o_stream_send_str(conn->output, DOVEADM_SERVER_HANDSHAKE);
+	o_stream_nsend_str(conn->output, DOVEADM_SERVER_HANDSHAKE);
 
 	array_append(&conn->server->connections, &conn, 1);
 	server_connection_read_settings(conn);
@@ -372,7 +373,7 @@
 
 	conn->state = SERVER_REPLY_STATE_PRINT;
 	if (conn->authenticated)
-		o_stream_send_str(conn->output, line);
+		o_stream_nsend_str(conn->output, line);
 	else
 		conn->delayed_cmd = p_strdup(conn->pool, line);
 	conn->callback = callback;
--- a/src/imap-login/imap-proxy.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/imap-login/imap-proxy.c	Mon Jun 25 00:01:59 2012 +0300
@@ -130,7 +130,7 @@
 		proxy_write_login(client, str);
 	}
 
-	(void)o_stream_send(output, str_data(str), str_len(str));
+	o_stream_nsend(output, str_data(str), str_len(str));
 	return 0;
 }
 
@@ -201,7 +201,7 @@
 		str_append(str, "\r\n");
 		proxy_free_password(client);
 
-		(void)o_stream_send(output, str_data(str), str_len(str));
+		o_stream_nsend(output, str_data(str), str_len(str));
 		return 0;
 	} else if (strncmp(line, "S ", 2) == 0) {
 		if (strncmp(line, "S OK ", 5) != 0) {
@@ -222,15 +222,14 @@
 		output = login_proxy_get_ostream(client->login_proxy);
 		str = t_str_new(128);
 		proxy_write_login(imap_client, str);
-		(void)o_stream_send(output, str_data(str), str_len(str));
+		o_stream_nsend(output, str_data(str), str_len(str));
 		return 1;
 	} else if (strncmp(line, "L OK ", 5) == 0) {
 		/* Login successful. Send this line to client. */
 		client->proxy_state = IMAP_PROXY_STATE_LOGIN;
 		str = t_str_new(128);
 		client_send_login_reply(imap_client, str, line + 5);
-		(void)o_stream_send(client->output,
-				    str_data(str), str_len(str));
+		o_stream_nsend(client->output, str_data(str), str_len(str));
 
 		(void)client_skip_line(imap_client);
 		client_proxy_finish_destroy_client(client);
--- a/src/imap/cmd-append.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/imap/cmd-append.c	Mon Jun 25 00:01:59 2012 +0300
@@ -418,8 +418,8 @@
 	client->input_skip_line = TRUE;
 
 	if (!nonsync) {
-		o_stream_send(client->output, "+ OK\r\n", 6);
-		o_stream_flush(client->output);
+		o_stream_nsend(client->output, "+ OK\r\n", 6);
+		o_stream_nflush(client->output);
 		o_stream_uncork(client->output);
 		o_stream_cork(client->output);
 	}
@@ -698,8 +698,8 @@
 	}
 
 	if (!nonsync) {
-		o_stream_send(client->output, "+ OK\r\n", 6);
-		o_stream_flush(client->output);
+		o_stream_nsend(client->output, "+ OK\r\n", 6);
+		o_stream_nflush(client->output);
 		o_stream_uncork(client->output);
 		o_stream_cork(client->output);
 	}
--- a/src/imap/cmd-copy.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/imap/cmd-copy.c	Mon Jun 25 00:01:59 2012 +0300
@@ -22,8 +22,8 @@
 	now = time(NULL);
 	last_io = I_MAX(client->last_input, client->last_output);
 	if (now - last_io > MAIL_STORAGE_STAYALIVE_SECS) {
-		o_stream_send_str(client->output, "* OK Hang in there..\r\n");
-		o_stream_flush(client->output);
+		o_stream_nsend_str(client->output, "* OK Hang in there..\r\n");
+		o_stream_nflush(client->output);
 		client->last_output = now;
 	}
 }
--- a/src/imap/cmd-thread.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/imap/cmd-thread.c	Mon Jun 25 00:01:59 2012 +0300
@@ -94,10 +94,8 @@
 		mail_thread_deinit(&ctx);
 	}
 
-	if (ret == 0) {
-		(void)o_stream_send(cmd->client->output,
-				    str_data(str), str_len(str));
-	}
+	if (ret == 0)
+		o_stream_nsend(cmd->client->output, str_data(str), str_len(str));
 	str_free(&str);
 	return ret;
 }
--- a/src/imap/imap-client.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/imap/imap-client.c	Mon Jun 25 00:01:59 2012 +0300
@@ -59,6 +59,7 @@
 	client->input = i_stream_create_fd(fd_in,
 					   set->imap_max_line_length, FALSE);
 	client->output = o_stream_create_fd(fd_out, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(client->output, TRUE);
 
 	o_stream_set_flush_callback(client->output, client_output, client);
 
@@ -267,7 +268,7 @@
 
 	i_info("Disconnected: %s %s", reason, client_stats(client));
 	client->disconnected = TRUE;
-	(void)o_stream_flush(client->output);
+	o_stream_nflush(client->output);
 	o_stream_uncork(client->output);
 
 	i_stream_close(client->input);
@@ -319,10 +320,10 @@
 	if (tag == NULL || *tag == '\0')
 		tag = "*";
 
-	(void)o_stream_send_str(client->output, tag);
-	(void)o_stream_send(client->output, " ", 1);
-	(void)o_stream_send_str(client->output, data);
-	(void)o_stream_send(client->output, "\r\n", 2);
+	o_stream_nsend_str(client->output, tag);
+	o_stream_nsend(client->output, " ", 1);
+	o_stream_nsend_str(client->output, data);
+	o_stream_nsend(client->output, "\r\n", 2);
 
 	client->last_output = ioloop_time;
 }
--- a/src/imap/imap-fetch-body.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/imap/imap-fetch-body.c	Mon Jun 25 00:01:59 2012 +0300
@@ -124,8 +124,7 @@
 	ctx->cur_name = p_strconcat(ctx->pool, "[", body->section, "]", NULL);
 
 	str = get_prefix(ctx, body, ctx->cur_size);
-	if (o_stream_send(ctx->client->output, str_data(str), str_len(str)) < 0)
-		return -1;
+	o_stream_nsend(ctx->client->output, str_data(str), str_len(str));
 
 	ctx->cont_handler = fetch_stream_continue;
 	return ctx->cont_handler(ctx);
@@ -340,8 +339,7 @@
 	if (ctx->first) {
 		str++; ctx->first = FALSE;
 	}
-	if (o_stream_send_str(ctx->client->output, str) < 0)
-		return -1;
+	o_stream_nsend_str(ctx->client->output, str);
 
 	ctx->cur_name = "RFC822";
 	return ctx->cont_handler(ctx);
@@ -362,8 +360,7 @@
 	if (ctx->first) {
 		str++; ctx->first = FALSE;
 	}
-	if (o_stream_send_str(ctx->client->output, str) < 0)
-		return -1;
+	o_stream_nsend_str(ctx->client->output, str);
 
 	ctx->cur_name = "RFC822.HEADER";
 	return ctx->cont_handler(ctx);
@@ -384,8 +381,7 @@
 	if (ctx->first) {
 		str++; ctx->first = FALSE;
 	}
-	if (o_stream_send_str(ctx->client->output, str) < 0)
-		return -1;
+	o_stream_nsend_str(ctx->client->output, str);
 
 	ctx->cur_name = "RFC822.TEXT";
 	return ctx->cont_handler(ctx);
--- a/src/imap/imap-fetch.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/imap/imap-fetch.c	Mon Jun 25 00:01:59 2012 +0300
@@ -318,7 +318,7 @@
 		str_append(str, "* VANISHED (EARLIER) ");
 		imap_write_seq_range(str, &expunged_uids_range);
 		str_append(str, "\r\n");
-		o_stream_send(ctx->client->output, str_data(str), str_len(str));
+		o_stream_nsend(ctx->client->output, str_data(str), str_len(str));
 		str_free(&str);
 	}
 	array_free(&expunged_uids_range);
@@ -521,8 +521,7 @@
 
 		ctx->line_finished = TRUE;
 		ctx->line_partial = FALSE;
-		if (o_stream_send(client->output, ")\r\n", 3) < 0)
-			return -1;
+		o_stream_nsend(client->output, ")\r\n", 3);
 		client->last_output = ioloop_time;
 
 		ctx->cur_mail = NULL;
--- a/src/imap/imap-search.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/imap/imap-search.c	Mon Jun 25 00:01:59 2012 +0300
@@ -177,8 +177,8 @@
 		for (seq = range->seq1; seq <= range->seq2; seq++)
 			str_printfa(str, " %u", seq);
 		if (str_len(str) >= 1024-32) {
-			o_stream_send(ctx->cmd->client->output,
-				      str_data(str), str_len(str));
+			o_stream_nsend(ctx->cmd->client->output,
+				       str_data(str), str_len(str));
 			str_truncate(str, 0);
 		}
 	}
@@ -188,8 +188,7 @@
 			    (unsigned long long)ctx->highest_seen_modseq);
 	}
 	str_append(str, "\r\n");
-	o_stream_send(ctx->cmd->client->output,
-		      str_data(str), str_len(str));
+	o_stream_nsend(ctx->cmd->client->output, str_data(str), str_len(str));
 }
 
 static void
@@ -318,7 +317,7 @@
 			    (unsigned long long)ctx->highest_seen_modseq);
 	}
 	str_append(str, "\r\n");
-	o_stream_send(client->output, str_data(str), str_len(str));
+	o_stream_nsend(client->output, str_data(str), str_len(str));
 	str_free(&str);
 }
 
--- a/src/imap/imap-sync.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/imap/imap-sync.c	Mon Jun 25 00:01:59 2012 +0300
@@ -102,7 +102,7 @@
 		str_append_c(cmd, ')');
 	}
 	str_append(cmd, "\r\n");
-	o_stream_send(ctx->client->output, str_data(cmd), str_len(cmd));
+	o_stream_nsend(ctx->client->output, str_data(cmd), str_len(cmd));
 }
 
 static void imap_sync_send_search_updates(struct imap_sync_context *ctx)
@@ -366,7 +366,7 @@
 			str_printfa(line, ":%u", prev_uid);
 	}
 	str_append(line, "\r\n");
-	o_stream_send(ctx->client->output, str_data(line), str_len(line));
+	o_stream_nsend(ctx->client->output, str_data(line), str_len(line));
 }
 
 int imap_sync_more(struct imap_sync_context *ctx)
--- a/src/imap/mail-storage-callbacks.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/imap/mail-storage-callbacks.c	Mon Jun 25 00:01:59 2012 +0300
@@ -17,8 +17,8 @@
 		const char *str;
 
 		str = t_strconcat("* OK ", text, "\r\n", NULL);
-		o_stream_send_str(client->output, str);
-		o_stream_flush(client->output);
+		o_stream_nsend_str(client->output, str);
+		(void)o_stream_flush(client->output);
 	} T_END;
 }
 
@@ -34,8 +34,8 @@
 		const char *str;
 
 		str = t_strconcat("* NO ", text, "\r\n", NULL);
-		o_stream_send_str(client->output, str);
-		o_stream_flush(client->output);
+		o_stream_nsend_str(client->output, str);
+		(void)o_stream_flush(client->output);
 	} T_END;
 }
 
--- a/src/indexer/indexer-client.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/indexer/indexer-client.c	Mon Jun 25 00:01:59 2012 +0300
@@ -94,7 +94,7 @@
 
 	indexer_queue_append(client->queue, append, args[1], args[2],
 			     max_recent_msgs, ctx);
-	o_stream_send_str(client->output, t_strdup_printf("%u\tOK\n", tag));
+	o_stream_nsend_str(client->output, t_strdup_printf("%u\tOK\n", tag));
 	return 0;
 }
 
@@ -123,7 +123,7 @@
 	}
 
 	indexer_queue_append_optimize(client->queue, args[1], args[2], ctx);
-	o_stream_send_str(client->output, t_strdup_printf("%u\tOK\n", tag));
+	o_stream_nsend_str(client->output, t_strdup_printf("%u\tOK\n", tag));
 	return 0;
 }
 
@@ -192,7 +192,7 @@
 	struct indexer_client_request *ctx = context;
 
 	T_BEGIN {
-		o_stream_send_str(ctx->client->output,
+		o_stream_nsend_str(ctx->client->output,
 			t_strdup_printf("%u\t%d\n", ctx->tag, percentage));
 	} T_END;
 	if (percentage < 0 || percentage == 100) {
@@ -212,6 +212,7 @@
 	client->fd = fd;
 	client->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
 	client->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(client->output, TRUE);
 	client->io = io_add(fd, IO_READ, indexer_client_input, client);
 
 	DLLIST_PREPEND(&clients, client);
--- a/src/indexer/worker-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/indexer/worker-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -198,7 +198,8 @@
 	conn->io = io_add(conn->fd, IO_READ, worker_connection_input, conn);
 	conn->input = i_stream_create_fd(conn->fd, (size_t)-1, FALSE);
 	conn->output = o_stream_create_fd(conn->fd, (size_t)-1, FALSE);
-	o_stream_send_str(conn->output, INDEXER_MASTER_HANDSHAKE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
+	o_stream_nsend_str(conn->output, INDEXER_MASTER_HANDSHAKE);
 	return 0;
 }
 
@@ -246,7 +247,7 @@
 		if (request->optimize)
 			str_append_c(str, 'o');
 		str_append_c(str, '\n');
-		o_stream_send(conn->output, str_data(str), str_len(str));
+		o_stream_nsend(conn->output, str_data(str), str_len(str));
 	} T_END;
 }
 
--- a/src/ipc/client.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/ipc/client.c	Mon Jun 25 00:01:59 2012 +0300
@@ -44,8 +44,8 @@
 	}
 
 	T_BEGIN {
-		o_stream_send_str(client->output,
-				  t_strdup_printf("%c%s\n", chr, line));
+		o_stream_nsend_str(client->output,
+				   t_strdup_printf("%c%s\n", chr, line));
 	} T_END;
 
 	if (status != IPC_CMD_STATUS_REPLY && client->io == NULL) {
@@ -72,7 +72,7 @@
 			data = strchr(id, '\t');
 		}
 		if (data == NULL || data[1] == '\0') {
-			o_stream_send_str(client->output, "-Invalid input\n");
+			o_stream_nsend_str(client->output, "-Invalid input\n");
 			continue;
 		}
 		*data++ = '\0';
@@ -89,14 +89,14 @@
 						    client_cmd_input, client);
 			}
 		} else if (str_to_uint(id, &id_num) < 0) {
-			o_stream_send_str(client->output,
+			o_stream_nsend_str(client->output,
 				t_strdup_printf("-Invalid IPC connection id: %s\n", id));
 			continue;
 		} else if (group == NULL) {
-			o_stream_send_str(client->output,
+			o_stream_nsend_str(client->output,
 				t_strdup_printf("-Unknown IPC group: %s\n", line));
 		} else if ((conn = ipc_connection_lookup_id(group, id_num)) == NULL) {
-			o_stream_send_str(client->output,
+			o_stream_nsend_str(client->output,
 				t_strdup_printf("-Unknown IPC connection id: %u\n", id_num));
 			continue;
 		} else {
@@ -124,6 +124,7 @@
 	client->io = io_add(fd, IO_READ, client_input, client);
 	client->input = i_stream_create_fd(fd, (size_t)-1, FALSE);
 	client->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(client->output, TRUE);
 
 	DLLIST_PREPEND(&clients, client);
 	return client;
--- a/src/ipc/ipc-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/ipc/ipc-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -177,8 +177,9 @@
 	conn->io = io_add(fd, IO_READ, ipc_connection_input, conn);
 	conn->input = i_stream_create_fd(fd, (size_t)-1, FALSE);
 	conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
 	i_array_init(&conn->cmds, 8);
-	o_stream_send_str(conn->output, IPC_SERVER_HANDSHAKE);
+	o_stream_nsend_str(conn->output, IPC_SERVER_HANDSHAKE);
 
 	DLLIST_PREPEND(&conn->group->connections, conn);
 	return conn;
@@ -236,7 +237,7 @@
 	array_append(&conn->cmds, &ipc_cmd, 1);
 
 	T_BEGIN {
-		o_stream_send_str(conn->output,
+		o_stream_nsend_str(conn->output,
 			t_strdup_printf("%u\t%s\n", ipc_cmd->tag, cmd));
 	} T_END;
 }
--- a/src/lib-auth/auth-master.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-auth/auth-master.c	Mon Jun 25 00:01:59 2012 +0300
@@ -397,15 +397,14 @@
 	if (!conn->sent_handshake) {
 		str = t_strdup_printf("VERSION\t%d\t%d\n",
 				      AUTH_PROTOCOL_MAJOR, AUTH_PROTOCOL_MINOR);
-		o_stream_send_str(conn->output, str);
+		o_stream_nsend_str(conn->output, str);
 		conn->sent_handshake = TRUE;
 	}
 
-	o_stream_send_str(conn->output, cmd);
+	o_stream_nsend_str(conn->output, cmd);
 	o_stream_uncork(conn->output);
 
-	if (conn->output->stream_errno != 0) {
-		errno = conn->output->stream_errno;
+	if (o_stream_nfinish(conn->output) < 0) {
 		i_error("write(auth socket) failed: %m");
 		conn->aborted = TRUE;
 	} else {
--- a/src/lib-dict/dict-file.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-dict/dict-file.c	Mon Jun 25 00:01:59 2012 +0300
@@ -512,15 +512,14 @@
 	o_stream_cork(output);
 	iter = hash_table_iterate_init(dict->hash);
 	while (hash_table_iterate(iter, &key, &value)) {
-		(void)o_stream_send_str(output, key);
-		(void)o_stream_send(output, "\n", 1);
-		(void)o_stream_send_str(output, value);
-		(void)o_stream_send(output, "\n", 1);
+		o_stream_nsend_str(output, key);
+		o_stream_nsend(output, "\n", 1);
+		o_stream_nsend_str(output, value);
+		o_stream_nsend(output, "\n", 1);
 	}
-	o_stream_uncork(output);
 	hash_table_iterate_deinit(&iter);
 
-	if (output->stream_errno != 0) {
+	if (o_stream_nfinish(output) < 0) {
 		i_error("write(%s) failed: %m", temp_path);
 		o_stream_destroy(&output);
 		(void)close(fd);
--- a/src/lib-fs/fs-posix.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-fs/fs-posix.c	Mon Jun 25 00:01:59 2012 +0300
@@ -349,9 +349,7 @@
 	struct posix_fs_file *file = (struct posix_fs_file *)_file;
 	int ret = success ? 0 : -1;
 
-	(void)o_stream_flush(_file->output);
-	if (_file->output->last_failed_errno < 0) {
-		errno = _file->output->last_failed_errno;
+	if (o_stream_nfinish(_file->output) < 0) {
 		fs_set_error(_file->fs, "write(%s) failed: %m",
 			     o_stream_get_name(_file->output));
 		ret = -1;
--- a/src/lib-fs/ostream-cmp.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-fs/ostream-cmp.c	Mon Jun 25 00:01:59 2012 +0300
@@ -20,7 +20,7 @@
 		return;
 
 	i_stream_unref(&cstream->input);
-	o_stream_flush(&cstream->ostream.ostream);
+	(void)o_stream_flush(&cstream->ostream.ostream);
 }
 
 bool stream_cmp_block(struct istream *input,
--- a/src/lib-imap-client/imapc-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-imap-client/imapc-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -1294,6 +1294,7 @@
 	conn->fd = fd;
 	conn->input = conn->raw_input = i_stream_create_fd(fd, (size_t)-1, FALSE);
 	conn->output = conn->raw_output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
 
 	if (*conn->client->set.rawlog_dir != '\0' &&
 	    conn->client->set.ssl_mode != IMAPC_CLIENT_SSL_MODE_IMMEDIATE &&
@@ -1627,7 +1628,7 @@
 
 	data = CONST_PTR_OFFSET(cmd->data->data, cmd->send_pos);
 	size = end_pos - cmd->send_pos;
-	o_stream_send(conn->output, data, size);
+	o_stream_nsend(conn->output, data, size);
 	cmd->send_pos = end_pos;
 
 	if (cmd->send_pos == cmd->data->used) {
@@ -1656,7 +1657,7 @@
 {
 	if ((conn->idling || conn->idle_plus_waiting) && !conn->idle_stopping) {
 		conn->idle_stopping = TRUE;
-		o_stream_send_str(conn->output, "DONE\r\n");
+		o_stream_nsend_str(conn->output, "DONE\r\n");
 	}
 }
 
--- a/src/lib-imap/imap-parser.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-imap/imap-parser.c	Mon Jun 25 00:01:59 2012 +0300
@@ -372,8 +372,8 @@
 		}
 
 		if (parser->output != NULL && !parser->literal_nonsync) {
-			o_stream_send(parser->output, "+ OK\r\n", 6);
-			o_stream_flush(parser->output);
+			o_stream_nsend(parser->output, "+ OK\r\n", 6);
+			o_stream_nflush(parser->output);
 		}
 	}
 
--- a/src/lib-index/mail-cache-compress.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-index/mail-cache-compress.c	Mon Jun 25 00:01:59 2012 +0300
@@ -176,7 +176,7 @@
 	hdr.compat_sizeof_uoff_t = sizeof(uoff_t);
 	hdr.indexid = cache->index->indexid;
 	hdr.file_seq = get_next_file_seq(cache, view);
-	o_stream_send(output, &hdr, sizeof(hdr));
+	o_stream_nsend(output, &hdr, sizeof(hdr));
 
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.cache = cache;
@@ -262,7 +262,7 @@
 			ext_offset = output->offset;
 			buffer_write(ctx.buffer, 0, &cache_rec,
 				     sizeof(cache_rec));
-			o_stream_send(output, ctx.buffer->data, cache_rec.size);
+			o_stream_nsend(output, ctx.buffer->data, cache_rec.size);
 		}
 
 		array_append(ext_offsets, &ext_offset, 1);
@@ -271,20 +271,19 @@
 
 	hdr.field_header_offset = mail_index_uint32_to_offset(output->offset);
 	mail_cache_compress_get_fields(&ctx, used_fields_count);
-	o_stream_send(output, ctx.buffer->data, ctx.buffer->used);
+	o_stream_nsend(output, ctx.buffer->data, ctx.buffer->used);
 
 	hdr.used_file_size = output->offset;
 	buffer_free(&ctx.buffer);
 	buffer_free(&ctx.field_seen);
 
 	o_stream_seek(output, 0);
-	o_stream_send(output, &hdr, sizeof(hdr));
+	o_stream_nsend(output, &hdr, sizeof(hdr));
 
 	mail_cache_view_close(&cache_view);
 
-	if (o_stream_flush(output) < 0) {
-		errno = output->stream_errno;
-		mail_cache_set_syscall_error(cache, "o_stream_flush()");
+	if (o_stream_nfinish(output) < 0) {
+		mail_cache_set_syscall_error(cache, "write()");
 		o_stream_destroy(&output);
 		array_free(ext_offsets);
 		return -1;
--- a/src/lib-index/mail-index-strmap.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-index/mail-index-strmap.c	Mon Jun 25 00:01:59 2012 +0300
@@ -884,9 +884,9 @@
 	i_free(renumber_map);
 }
 
-static int mail_index_strmap_write_block(struct mail_index_strmap_view *view,
-					 struct ostream *output,
-					 unsigned int i, uint32_t base_uid)
+static void mail_index_strmap_write_block(struct mail_index_strmap_view *view,
+					  struct ostream *output,
+					  unsigned int i, uint32_t base_uid)
 {
 	const struct mail_index_strmap_rec *recs;
 	const uint32_t *crc32;
@@ -898,7 +898,7 @@
 	/* skip over the block size for now, we don't know it yet */
 	block_offset = output->offset;
 	block_size = 0;
-	o_stream_send(output, &block_size, sizeof(block_size));
+	o_stream_nsend(output, &block_size, sizeof(block_size));
 
 	/* write records */
 	recs = array_get(&view->recs, &count);
@@ -936,13 +936,13 @@
 		}
 
 		mail_index_pack_num(&p, n);
-		o_stream_send(output, packed, p-packed);
+		o_stream_nsend(output, packed, p-packed);
 		for (j = 0; j < uid_rec_count; j++)
-			o_stream_send(output, &crc32[i+j], sizeof(crc32[i+j]));
+			o_stream_nsend(output, &crc32[i+j], sizeof(crc32[i+j]));
 		for (j = 0; j < uid_rec_count; j++) {
 			i_assert(j < 2 || recs[i+j].ref_index == j+1);
-			o_stream_send(output, &recs[i+j].str_idx,
-				      sizeof(recs[i+j].str_idx));
+			o_stream_nsend(output, &recs[i+j].str_idx,
+				       sizeof(recs[i+j].str_idx));
 		}
 		i += uid_rec_count;
 	}
@@ -954,17 +954,15 @@
 
 	end_offset = output->offset;
 	o_stream_seek(output, block_offset);
-	o_stream_send(output, &block_size, sizeof(block_size));
+	o_stream_nsend(output, &block_size, sizeof(block_size));
 	o_stream_seek(output, end_offset);
 
 	if (output->last_failed_errno != 0)
-		return -1;
-	else {
-		i_assert(view->last_added_uid == recs[count-1].uid);
-		view->last_read_uid = recs[count-1].uid;
-		view->last_read_block_offset = output->offset;
-		return 0;
-	}
+		return;
+
+	i_assert(view->last_added_uid == recs[count-1].uid);
+	view->last_read_uid = recs[count-1].uid;
+	view->last_read_block_offset = output->offset;
 }
 
 static void
@@ -980,10 +978,10 @@
 	memset(&hdr, 0, sizeof(hdr));
 	hdr.version = MAIL_INDEX_STRMAP_VERSION;
 	hdr.uid_validity = idx_hdr->uid_validity;
-	o_stream_send(output, &hdr, sizeof(hdr));
+	o_stream_nsend(output, &hdr, sizeof(hdr));
 
 	view->total_ref_count = 0;
-	(void)mail_index_strmap_write_block(view, output, 0, 1);
+	mail_index_strmap_write_block(view, output, 0, 1);
 }
 
 static int mail_index_strmap_recreate(struct mail_index_strmap_view *view)
@@ -1017,8 +1015,7 @@
 	output = o_stream_create_fd(fd, 0, FALSE);
 	o_stream_cork(output);
 	mail_index_strmap_recreate_write(view, output);
-	if (output->last_failed_errno != 0) {
-		errno = output->last_failed_errno;
+	if (o_stream_nfinish(output) < 0) {
 		mail_index_set_error(strmap->index,
 				     "write(%s) failed: %m", temp_path);
 		ret = -1;
@@ -1172,9 +1169,9 @@
 	output = o_stream_create_fd(view->strmap->fd, 0, FALSE);
 	o_stream_seek(output, view->last_read_block_offset);
 	o_stream_cork(output);
-	if (mail_index_strmap_write_block(view, output, i,
-					  view->last_read_uid + 1) < 0) {
-		errno = output->last_failed_errno;
+	mail_index_strmap_write_block(view, output, i,
+				      view->last_read_uid + 1);
+	if (o_stream_nfinish(output) < 0) {
 		mail_index_strmap_set_syscall_error(view->strmap, "write()");
 		ret = -1;
 	}
--- a/src/lib-index/mail-index-write.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-index/mail-index-write.c	Mon Jun 25 00:01:59 2012 +0300
@@ -76,13 +76,13 @@
 	o_stream_cork(output);
 
 	base_size = I_MIN(map->hdr.base_header_size, sizeof(map->hdr));
-	if (o_stream_send(output, &map->hdr, base_size) < 0 ||
-	    o_stream_send(output, CONST_PTR_OFFSET(map->hdr_base, base_size),
-			  map->hdr.header_size - base_size) < 0 ||
-	    o_stream_send(output, map->rec_map->records,
-			  map->rec_map->records_count *
-			  map->hdr.record_size) < 0 ||
-	    o_stream_flush(output) < 0) {
+	o_stream_nsend(output, &map->hdr, base_size);
+	o_stream_nsend(output, CONST_PTR_OFFSET(map->hdr_base, base_size),
+		       map->hdr.header_size - base_size);
+	o_stream_nsend(output, map->rec_map->records,
+		       map->rec_map->records_count * map->hdr.record_size);
+	o_stream_nflush(output);
+	if (o_stream_nfinish(output) < 0) {
 		mail_index_file_set_syscall_error(index, path, "write()");
 		ret = -1;
 	}
--- a/src/lib-lda/duplicate.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-lda/duplicate.c	Mon Jun 25 00:01:59 2012 +0300
@@ -297,7 +297,7 @@
 
 	output = o_stream_create_fd_file(file->new_fd, 0, FALSE);
 	o_stream_cork(output);
-	(void)o_stream_send(output, &hdr, sizeof(hdr));
+	o_stream_nsend(output, &hdr, sizeof(hdr));
 
 	memset(&rec, 0, sizeof(rec));
 	iter = hash_table_iterate_init(file->hash);
@@ -308,15 +308,13 @@
 		rec.id_size = d->id_size;
 		rec.user_size = strlen(d->user);
 
-		(void)o_stream_send(output, &rec, sizeof(rec));
-		(void)o_stream_send(output, d->id, rec.id_size);
-		(void)o_stream_send(output, d->user, rec.user_size);
+		o_stream_nsend(output, &rec, sizeof(rec));
+		o_stream_nsend(output, d->id, rec.id_size);
+		o_stream_nsend(output, d->user, rec.user_size);
 	}
-	o_stream_uncork(output);
 	hash_table_iterate_deinit(&iter);
 
-	if (output->last_failed_errno != 0) {
-		errno = output->last_failed_errno;
+	if (o_stream_nfinish(output) < 0) {
 		i_error("write(%s) failed: %m", file->path);
 		o_stream_unref(&output);
 		file_dotlock_delete(&file->dotlock);
--- a/src/lib-lda/lmtp-client.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-lda/lmtp-client.c	Mon Jun 25 00:01:59 2012 +0300
@@ -252,7 +252,7 @@
 		return -1;
 	} else {
 		client->input_state++;
-		o_stream_send_str(client->output, "DATA\r\n");
+		o_stream_nsend_str(client->output, "DATA\r\n");
 		return 0;
 	}
 }
@@ -349,9 +349,9 @@
 
 	if (client->output_last != '\n') {
 		/* didn't end with CRLF */
-		(void)o_stream_send(client->output, "\r\n", 2);
+		o_stream_nsend(client->output, "\r\n", 2);
 	}
-	(void)o_stream_send(client->output, ".\r\n", 3);
+	o_stream_nsend(client->output, ".\r\n", 3);
 	client->output_finished = TRUE;
 }
 
@@ -359,12 +359,12 @@
 {
 	switch (client->protocol) {
 	case LMTP_CLIENT_PROTOCOL_LMTP:
-		o_stream_send_str(client->output,
+		o_stream_nsend_str(client->output,
 			t_strdup_printf("LHLO %s\r\n",
 					client->set.my_hostname));
 		break;
 	case LMTP_CLIENT_PROTOCOL_SMTP:
-		o_stream_send_str(client->output,
+		o_stream_nsend_str(client->output,
 			t_strdup_printf("EHLO %s\r\n",
 					client->set.my_hostname));
 		break;
@@ -440,7 +440,7 @@
 		return FALSE;
 
 	str_append(str, "\r\n");
-	o_stream_send(client->output, str_data(str), str_len(str));
+	o_stream_nsend(client->output, str_data(str), str_len(str));
 	return TRUE;
 }
 
@@ -482,7 +482,7 @@
 			break;
 		}
 		if (client->input_state == LMTP_INPUT_STATE_LHLO) {
-			o_stream_send_str(client->output,
+			o_stream_nsend_str(client->output,
 				t_strdup_printf("MAIL FROM:%s\r\n",
 						client->set.mail_from));
 		}
@@ -504,7 +504,7 @@
 		}
 		client->input_state++;
 		if (client->data_header != NULL)
-			o_stream_send_str(client->output, client->data_header);
+			o_stream_nsend_str(client->output, client->data_header);
 		lmtp_client_send_data(client);
 		break;
 	case LMTP_INPUT_STATE_DATA:
@@ -593,6 +593,7 @@
 	client->input =
 		i_stream_create_fd(client->fd, LMTP_MAX_LINE_LEN, FALSE);
 	client->output = o_stream_create_fd(client->fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(client->output, TRUE);
 	o_stream_set_flush_callback(client->output, lmtp_client_output, client);
 	/* we're already sending data in ostream, so can't use IO_WRITE here */
 	client->io = io_add(client->fd, IO_READ,
@@ -679,7 +680,7 @@
 
 	rcpt = array_get(&client->recipients, &count);
 	for (i = client->rcpt_next_send_idx; i < count; i++) {
-		o_stream_send_str(client->output,
+		o_stream_nsend_str(client->output,
 			t_strdup_printf("RCPT TO:<%s>\r\n", rcpt[i].address));
 	}
 	client->rcpt_next_send_idx = i;
--- a/src/lib-lda/mail-send.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-lda/mail-send.c	Mon Jun 25 00:01:59 2012 +0300
@@ -154,7 +154,7 @@
 
     /* original message's headers */
     str_printfa(str, "--%s\r\nContent-Type: message/rfc822\r\n\r\n", boundary);
-    o_stream_send(output, str_data(str), str_len(str));
+    o_stream_nsend(output, str_data(str), str_len(str));
 
     if (mail_get_hdr_stream(mail, NULL, &input) == 0) {
 	    /* Note: If you add more headers, they need to be sorted.
@@ -179,7 +179,7 @@
 
     str_truncate(str, 0);
     str_printfa(str, "\r\n\r\n--%s--\r\n", boundary);
-    o_stream_send(output, str_data(str), str_len(str));
+    o_stream_nsend(output, str_data(str), str_len(str));
     return smtp_client_close(smtp_client);
 }
 
@@ -209,7 +209,7 @@
                                           N_ELEMENTS(hide_headers),
 					  null_header_filter_callback, NULL);
 
-    o_stream_send_istream(output, input);
+    (void)o_stream_send_istream(output, input);
     i_stream_unref(&input);
 
     return smtp_client_close(smtp_client);
--- a/src/lib-lda/smtp-client.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-lda/smtp-client.c	Mon Jun 25 00:01:59 2012 +0300
@@ -256,7 +256,7 @@
 		}
 	}
 
-	if (o_stream_flush(smtp_client->output) < 0) {
+	if (o_stream_nfinish(smtp_client->output) < 0) {
 		i_error("write(%s) failed: %m", smtp_client->temp_path);
 		return -1;
 	}
--- a/src/lib-master/anvil-client.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-master/anvil-client.c	Mon Jun 25 00:01:59 2012 +0300
@@ -140,8 +140,9 @@
 	client->fd = fd;
 	client->input = i_stream_create_fd(fd, ANVIL_INBUF_SIZE, FALSE);
 	client->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(client->output, TRUE);
 	client->io = io_add(fd, IO_READ, anvil_input, client);
-	o_stream_send_str(client->output, ANVIL_HANDSHAKE);
+	o_stream_nsend_str(client->output, ANVIL_HANDSHAKE);
 	return 0;
 }
 
@@ -185,7 +186,7 @@
 	iov[0].iov_len = strlen(cmd);
 	iov[1].iov_base = "\n";
 	iov[1].iov_len = 1;
-	o_stream_sendv(client->output, iov, 2);
+	o_stream_nsendv(client->output, iov, 2);
 	return 0;
 }
 
--- a/src/lib-master/ipc-client.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-master/ipc-client.c	Mon Jun 25 00:01:59 2012 +0300
@@ -92,6 +92,7 @@
 	client->io = io_add(client->fd, IO_READ, ipc_client_input, client);
 	client->input = i_stream_create_fd(client->fd, (size_t)-1, FALSE);
 	client->output = o_stream_create_fd(client->fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(client->output, TRUE);
 	return 0;
 }
 
@@ -156,7 +157,7 @@
 	iov[0].iov_len = strlen(cmd);
 	iov[1].iov_base = "\n";
 	iov[1].iov_len = 1;
-	o_stream_sendv(client->output, iov, N_ELEMENTS(iov));
+	o_stream_nsendv(client->output, iov, N_ELEMENTS(iov));
 
 	ipc_cmd = array_append_space(&client->cmds);
 	ipc_cmd->callback = callback;
--- a/src/lib-master/ipc-server.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-master/ipc-server.c	Mon Jun 25 00:01:59 2012 +0300
@@ -111,7 +111,8 @@
 	server->io = io_add(server->fd, IO_READ, ipc_server_input, server);
 	server->input = i_stream_create_fd(server->fd, (size_t)-1, FALSE);
 	server->output = o_stream_create_fd(server->fd, (size_t)-1, FALSE);
-	o_stream_send_str(server->output,
+	o_stream_set_no_error_handling(server->output, TRUE);
+	o_stream_nsend_str(server->output,
 		t_strdup_printf(IPC_SERVER_HANDSHAKE, server->name, my_pid));
 	o_stream_cork(server->output);
 }
@@ -160,14 +161,14 @@
 
 void ipc_cmd_send(struct ipc_cmd *cmd, const char *data)
 {
-	o_stream_send_str(cmd->server->output,
-			  t_strdup_printf("%u\t:%s\n", cmd->tag, data));
+	o_stream_nsend_str(cmd->server->output,
+			   t_strdup_printf("%u\t:%s\n", cmd->tag, data));
 }
 
 static void ipc_cmd_finish(struct ipc_cmd *cmd, const char *line)
 {
-	o_stream_send_str(cmd->server->output,
-			  t_strdup_printf("%u\t%s\n", cmd->tag, line));
+	o_stream_nsend_str(cmd->server->output,
+			   t_strdup_printf("%u\t%s\n", cmd->tag, line));
 	o_stream_uncork(cmd->server->output);
 
 	i_assert(cmd->server->ipc_cmd_refcount > 0);
--- a/src/lib-master/master-instance.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-master/master-instance.c	Mon Jun 25 00:01:59 2012 +0300
@@ -130,6 +130,7 @@
 	struct ostream *output;
 	const struct master_instance *inst;
 	string_t *str = t_str_new(128);
+	int ret = 0;
 
 	output = o_stream_create_fd(fd, 0, FALSE);
 	o_stream_cork(output);
@@ -143,16 +144,14 @@
 		if (inst->config_path != NULL)
 			str_tabescape_write(str, inst->config_path);
 		str_append_c(str, '\n');
-		(void)o_stream_send(output, str_data(str), str_len(str));
+		o_stream_nsend(output, str_data(str), str_len(str));
 	}
-	o_stream_uncork(output);
-	(void)o_stream_flush(output);
-	if (output->last_failed_errno != 0) {
-		errno = output->last_failed_errno;
+	if (o_stream_nfinish(output) < 0) {
 		i_error("write(%s) failed: %m", path);
-		return -1;
+		ret = -1;
 	}
-	return 0;
+	o_stream_destroy(&output);
+	return ret;
 }
 
 static int master_instance_write_init(struct master_instance_list *list,
--- a/src/lib-master/master-login-auth.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-master/master-login-auth.c	Mon Jun 25 00:01:59 2012 +0300
@@ -388,6 +388,7 @@
 	auth->fd = fd;
 	auth->input = i_stream_create_fd(fd, AUTH_MAX_INBUF_SIZE, FALSE);
 	auth->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(auth->output, TRUE);
 	auth->io = io_add(fd, IO_READ, master_login_auth_input, auth);
 	return 0;
 }
@@ -436,7 +437,7 @@
 		    req->client_pid, req->auth_id);
 	binary_to_hex_append(str, req->cookie, sizeof(req->cookie));
 	str_append_c(str, '\n');
-	o_stream_send(auth->output, str_data(str), str_len(str));
+	o_stream_nsend(auth->output, str_data(str), str_len(str));
 }
 
 void master_login_auth_request(struct master_login_auth *auth,
@@ -456,7 +457,7 @@
 				 context);
 			return;
 		}
-		o_stream_send_str(auth->output,
+		o_stream_nsend_str(auth->output,
 			t_strdup_printf("VERSION\t%u\t%u\n",
 					AUTH_MASTER_PROTOCOL_MAJOR_VERSION,
 					AUTH_MASTER_PROTOCOL_MINOR_VERSION));
--- a/src/lib-master/master-login.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-master/master-login.c	Mon Jun 25 00:01:59 2012 +0300
@@ -359,7 +359,7 @@
 	reply.status = errormsg == NULL ? MASTER_AUTH_STATUS_OK :
 		MASTER_AUTH_STATUS_INTERNAL_ERROR;
 	reply.mail_pid = getpid();
-	o_stream_send(conn->output, &reply, sizeof(reply));
+	o_stream_nsend(conn->output, &reply, sizeof(reply));
 
 	if (errormsg != NULL || auth_args[0] == NULL) {
 		if (auth_args != NULL) {
@@ -447,6 +447,7 @@
 	conn->fd = fd;
 	conn->io = io_add(conn->fd, IO_READ, master_login_conn_input, conn);
 	conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
 
 	DLLIST_PREPEND(&login->conns, conn);
 
--- a/src/lib-storage/index/cydir/cydir-save.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-storage/index/cydir/cydir-save.c	Mon Jun 25 00:01:59 2012 +0300
@@ -141,7 +141,7 @@
 		if (o_stream_send_istream(_ctx->output, ctx->input) < 0) {
 			if (!mail_storage_set_error_from_errno(storage)) {
 				mail_storage_set_critical(storage,
-					"o_stream_send_istream(%s) failed: %m",
+					"write(%s) failed: %m",
 					cydir_get_save_path(ctx, ctx->mail_count));
 			}
 			ctx->failed = TRUE;
@@ -162,9 +162,8 @@
 	struct stat st;
 	int ret = 0;
 
-	if (o_stream_flush(ctx->ctx.output) < 0) {
-		mail_storage_set_critical(storage,
-			"o_stream_flush(%s) failed: %m", path);
+	if (o_stream_nfinish(ctx->ctx.output) < 0) {
+		mail_storage_set_critical(storage, "write(%s) failed: %m", path);
 		ret = -1;
 	}
 
--- a/src/lib-storage/index/dbox-common/dbox-file-fix.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-storage/index/dbox-common/dbox-file-fix.c	Mon Jun 25 00:01:59 2012 +0300
@@ -79,7 +79,7 @@
 
 static int
 stream_copy(struct dbox_file *file, struct ostream *output,
-	    const char *path, uoff_t count)
+	    const char *out_path, uoff_t count)
 {
 	struct istream *input;
 	off_t bytes;
@@ -88,17 +88,22 @@
 	bytes = o_stream_send_istream(output, input);
 	i_stream_unref(&input);
 
-	if (bytes < 0) {
+	if (input->stream_errno != 0) {
 		mail_storage_set_critical(&file->storage->storage,
-			"o_stream_send_istream(%s, %s) failed: %m",
-			file->cur_path, path);
+			"read(%s) failed: %m", file->cur_path);
 		return -1;
 	}
+	if (o_stream_nfinish(output) < 0) {
+		mail_storage_set_critical(&file->storage->storage,
+			"write(%s) failed: %m", out_path);
+		return -1;
+	}
+	i_assert(bytes >= 0);
 	if ((uoff_t)bytes != count) {
 		mail_storage_set_critical(&file->storage->storage,
 			"o_stream_send_istream(%s) copied only %"
 			PRIuUOFF_T" of %"PRIuUOFF_T" bytes",
-			path, bytes, count);
+			out_path, bytes, count);
 		return -1;
 	}
 	return 0;
@@ -151,8 +156,8 @@
 		}
 		if (*line == DBOX_METADATA_GUID)
 			*have_guid_r = TRUE;
-		o_stream_send_str(output, line);
-		o_stream_send_str(output, "\n");
+		o_stream_nsend_str(output, line);
+		o_stream_nsend_str(output, "\n");
 	}
 }
 
@@ -238,7 +243,7 @@
 		/* write msg header */
 		if (write_header) {
 			dbox_msg_header_fill(&msg_hdr, msg_size);
-			(void)o_stream_send(output, &msg_hdr, sizeof(msg_hdr));
+			o_stream_nsend(output, &msg_hdr, sizeof(msg_hdr));
 		}
 		/* write msg body */
 		i_assert(file->input->v_offset == body_offset);
@@ -252,7 +257,7 @@
 		ret = message_get_body_size(body_input, &body, &has_nuls);
 		i_stream_unref(&body_input);
 		if (ret < 0) {
-			errno = output->stream_errno;
+			errno = body_input->stream_errno;
 			mail_storage_set_critical(&file->storage->storage,
 				"read(%s) failed: %m", file->cur_path);
 			return -1;
@@ -263,27 +268,28 @@
 		ret = dbox_file_metadata_skip_header(file);
 		if (ret < 0)
 			return -1;
-		o_stream_send_str(output, DBOX_MAGIC_POST);
+		o_stream_nsend_str(output, DBOX_MAGIC_POST);
 		if (ret == 0)
 			have_guid = FALSE;
 		else
 			dbox_file_copy_metadata(file, output, &have_guid);
 		if (!have_guid) {
 			guid_128_generate(guid_128);
-			o_stream_send_str(output,
+			o_stream_nsend_str(output,
 				t_strdup_printf("%c%s\n", DBOX_METADATA_GUID,
 				guid_128_to_string(guid_128)));
 		}
-		o_stream_send_str(output,
+		o_stream_nsend_str(output,
 			t_strdup_printf("%c%llx\n", DBOX_METADATA_VIRTUAL_SIZE,
 					(unsigned long long)body.virtual_size));
-		o_stream_send_str(output, "\n");
-		if (output->stream_errno != 0) {
-			errno = output->stream_errno;
-			mail_storage_set_critical(&file->storage->storage,
-				"write(%s) failed: %m", temp_path);
-			return -1;
-		}
+		o_stream_nsend_str(output, "\n");
+		if (output->stream_errno != 0)
+			break;
+	}
+	if (o_stream_nfinish(output) < 0) {
+		mail_storage_set_critical(&file->storage->storage,
+					  "write(%s) failed: %m", temp_path);
+		ret = -1;
 	}
 	return ret;
 }
@@ -307,7 +313,10 @@
 		return -1;
 
 	output = o_stream_create_fd_file(fd, 0, FALSE);
+	o_stream_cork(output);
 	ret = dbox_file_fix_write_stream(file, start_offset, temp_path, output);
+	if (ret < 0)
+		o_stream_ignore_last_errors(output);
 	o_stream_unref(&output);
 	if (close(fd) < 0) {
 		mail_storage_set_critical(&file->storage->storage,
--- a/src/lib-storage/index/dbox-common/dbox-file.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-storage/index/dbox-common/dbox-file.c	Mon Jun 25 00:01:59 2012 +0300
@@ -519,8 +519,10 @@
 		if (ftruncate(file->fd, ctx->first_append_offset) < 0)
 			dbox_file_set_syscall_error(file, "ftruncate()");
 	}
-	if (ctx->output != NULL)
+	if (ctx->output != NULL) {
+		o_stream_ignore_last_errors(ctx->output);
 		o_stream_unref(&ctx->output);
+	}
 	i_free(ctx);
 
 	if (close_file)
@@ -535,7 +537,7 @@
 	if (ctx->last_flush_offset == ctx->output->offset)
 		return 0;
 
-	if (o_stream_flush(ctx->output) < 0) {
+	if (o_stream_nfinish(ctx->output) < 0) {
 		dbox_file_set_syscall_error(ctx->file, "write()");
 		return -1;
 	}
--- a/src/lib-storage/index/dbox-common/dbox-save.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-storage/index/dbox-common/dbox-save.c	Mon Jun 25 00:01:59 2012 +0300
@@ -55,9 +55,8 @@
 	o_stream_cork(ctx->dbox_output);
 	if (o_stream_send(ctx->dbox_output, &dbox_msg_hdr,
 			  sizeof(dbox_msg_hdr)) < 0) {
-		mail_storage_set_critical(_storage,
-			"o_stream_send(%s) failed: %m", 
-			ctx->cur_file->cur_path);
+		mail_storage_set_critical(_storage, "write(%s) failed: %m",
+					  o_stream_get_name(ctx->dbox_output));
 		ctx->failed = TRUE;
 	}
 	_ctx->output = ctx->dbox_output;
@@ -82,8 +81,8 @@
 		if (o_stream_send_istream(_ctx->output, ctx->input) < 0) {
 			if (!mail_storage_set_error_from_errno(storage)) {
 				mail_storage_set_critical(storage,
-					"o_stream_send_istream(%s) failed: %m",
-					ctx->cur_file->cur_path);
+					"write(%s) failed: %m",
+					o_stream_get_name(_ctx->output));
 			}
 			ctx->failed = TRUE;
 			return -1;
@@ -128,7 +127,7 @@
 	memset(&metadata_hdr, 0, sizeof(metadata_hdr));
 	memcpy(metadata_hdr.magic_post, DBOX_MAGIC_POST,
 	       sizeof(metadata_hdr.magic_post));
-	o_stream_send(output, &metadata_hdr, sizeof(metadata_hdr));
+	o_stream_nsend(output, &metadata_hdr, sizeof(metadata_hdr));
 
 	str = t_str_new(256);
 	if (output_msg_size != ctx->input->v_offset) {
@@ -173,5 +172,5 @@
 	dbox_attachment_save_write_metadata(_ctx, str);
 
 	str_append_c(str, '\n');
-	o_stream_send(output, str_data(str), str_len(str));
+	o_stream_nsend(output, str_data(str), str_len(str));
 }
--- a/src/lib-storage/index/dbox-multi/mdbox-purge.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-storage/index/dbox-multi/mdbox-purge.c	Mon Jun 25 00:01:59 2012 +0300
@@ -105,7 +105,7 @@
 	if ((ret = mdbox_file_read_metadata_hdr(file, &meta_hdr)) <= 0)
 		return ret;
 
-	o_stream_send(output, &meta_hdr, sizeof(meta_hdr));
+	o_stream_nsend(output, &meta_hdr, sizeof(meta_hdr));
 	buf_size = i_stream_get_max_buffer_size(file->input);
 	/* use unlimited line length for metadata */
 	i_stream_set_max_buffer_size(file->input, (size_t)-1);
@@ -114,8 +114,8 @@
 			/* end of metadata */
 			break;
 		}
-		o_stream_send_str(output, line);
-		o_stream_send(output, "\n", 1);
+		o_stream_nsend_str(output, line);
+		o_stream_nsend(output, "\n", 1);
 	}
 	i_stream_set_max_buffer_size(file->input, buf_size);
 
@@ -123,7 +123,7 @@
 		dbox_file_set_corrupted(file, "missing end-of-metadata line");
 		return 0;
 	}
-	o_stream_send(output, "\n", 1);
+	o_stream_nsend(output, "\n", 1);
 	return 1;
 }
 
@@ -217,8 +217,7 @@
 			"read(%s) failed: %m", file->cur_path);
 		return -1;
 	}
-	if (output->stream_errno != 0) {
-		errno = output->stream_errno;
+	if (o_stream_nfinish(output) < 0) {
 		mail_storage_set_critical(&file->storage->storage,
 					  "write(%s) failed: %m",
 					  out_file_append->file->cur_path);
--- a/src/lib-storage/index/dbox-single/sdbox-file.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-storage/index/dbox-single/sdbox-file.c	Mon Jun 25 00:01:59 2012 +0300
@@ -310,10 +310,7 @@
 	output = o_stream_create_fd_file(out_fd, 0, FALSE);
 	i_stream_seek(file->input, 0);
 	while ((ret = o_stream_send_istream(output, file->input)) > 0) ;
-	if (ret == 0)
-		ret = o_stream_flush(output);
-	if (output->stream_errno != 0) {
-		errno = output->stream_errno;
+	if (o_stream_nfinish(output) < 0) {
 		mail_storage_set_critical(storage, "write(%s) failed: %m",
 					  temp_path);
 		ret = -1;
--- a/src/lib-storage/index/imapc/imapc-save.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-storage/index/imapc/imapc-save.c	Mon Jun 25 00:01:59 2012 +0300
@@ -241,11 +241,10 @@
 	ctx->finished = TRUE;
 
 	if (!ctx->failed) {
-		if (o_stream_flush(_ctx->output) < 0) {
+		if (o_stream_nfinish(_ctx->output) < 0) {
 			if (!mail_storage_set_error_from_errno(storage)) {
 				mail_storage_set_critical(storage,
-					"o_stream_flush(%s) failed: %m",
-					ctx->temp_path);
+					"write(%s) failed: %m", ctx->temp_path);
 			}
 			ctx->failed = TRUE;
 		}
--- a/src/lib-storage/index/index-attachment.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-storage/index/index-attachment.c	Mon Jun 25 00:01:59 2012 +0300
@@ -133,14 +133,14 @@
 	else if (strcasecmp(hdr->name, "Content-Disposition") == 0)
 		parse_content_disposition(ctx, hdr);
 
-	o_stream_send(ctx->output, hdr->name, hdr->name_len);
-	o_stream_send(ctx->output, hdr->middle, hdr->middle_len);
-	o_stream_send(ctx->output, hdr->full_value, hdr->full_value_len);
+	o_stream_nsend(ctx->output, hdr->name, hdr->name_len);
+	o_stream_nsend(ctx->output, hdr->middle, hdr->middle_len);
+	o_stream_nsend(ctx->output, hdr->full_value, hdr->full_value_len);
 	if (!hdr->no_newline) {
 		if (hdr->crlf_newline)
-			o_stream_send(ctx->output, "\r\n", 2);
+			o_stream_nsend(ctx->output, "\r\n", 2);
 		else
-			o_stream_send(ctx->output, "\n", 1);
+			o_stream_nsend(ctx->output, "\n", 1);
 	}
 }
 
@@ -221,10 +221,9 @@
 static int save_check_write_error(struct mail_storage *storage,
 				  struct ostream *output)
 {
-	if (output->last_failed_errno == 0)
+	if (o_stream_nfinish(output) == 0)
 		return 0;
 
-	errno = output->last_failed_errno;
 	if (!mail_storage_set_error_from_errno(storage)) {
 		mail_storage_set_critical(storage, "write(%s) failed: %m",
 					  o_stream_get_name(output));
@@ -282,7 +281,7 @@
 			break;
 		}
 		i_stream_skip(base64_input, size);
-		o_stream_send(output, buf->data, buf->used);
+		o_stream_nsend(output, buf->data, buf->used);
 		hash_format_loop(hash, buf->data, buf->used);
 	}
 	if (ret != -1) {
@@ -293,7 +292,6 @@
 
 		failed = TRUE;
 	}
-	(void)o_stream_flush(output);
 	if (save_check_write_error(storage, output) < 0)
 		failed = TRUE;
 
@@ -335,7 +333,7 @@
 	part->temp_fd = outfd;
 
 	if (extra_buf != NULL) {
-		o_stream_send(ctx->output, extra_buf->data, extra_buf->used);
+		o_stream_nsend(ctx->output, extra_buf->data, extra_buf->used);
 		buffer_free(&extra_buf);
 	}
 	hash_format_deinit_free(&part->part_hash);
@@ -359,10 +357,8 @@
 	enum fs_open_flags flags = FS_OPEN_FLAG_MKDIR;
 	int ret = 0;
 
-	if (o_stream_flush(part->output) < 0) {
-		save_check_write_error(storage, part->output);
+	if (save_check_write_error(storage, part->output) < 0)
 		return -1;
-	}
 
 	if (!part->base64_failed) {
 		if (part->base64_state == BASE64_STATE_0 &&
@@ -410,7 +406,7 @@
 	input = i_stream_create_fd(part->temp_fd, IO_BLOCK_SIZE, FALSE);
 	output = fs_write_stream(file);
 	while (i_stream_read_data(input, &data, &size, 0) > 0) {
-		o_stream_send(output, data, size);
+		o_stream_nsend(output, data, size);
 		i_stream_skip(input, size);
 	}
 
@@ -557,7 +553,7 @@
 
 	switch (part->state) {
 	case MAIL_ATTACHMENT_STATE_NO:
-		o_stream_send(ctx->output, block->data, block->size);
+		o_stream_nsend(ctx->output, block->data, block->size);
 		break;
 	case MAIL_ATTACHMENT_STATE_MAYBE:
 		if (part->part_buf == NULL) {
@@ -576,9 +572,9 @@
 		if (index_attachment_save_temp_open(ctx) < 0) {
 			/* failed, fallback to just saving it inline */
 			part->state = MAIL_ATTACHMENT_STATE_NO;
-			o_stream_send(ctx->output, part_buf->data,
-				      part_buf->used);
-			o_stream_send(ctx->output, block->data, block->size);
+			o_stream_nsend(ctx->output, part_buf->data,
+				       part_buf->used);
+			o_stream_nsend(ctx->output, block->data, block->size);
 			break;
 		}
 		part->state = MAIL_ATTACHMENT_STATE_YES;
@@ -586,14 +582,14 @@
 						   part_buf->used);
 		hash_format_loop(part->part_hash,
 				 part_buf->data, part_buf->used);
-		o_stream_send(part->output, part_buf->data, part_buf->used);
+		o_stream_nsend(part->output, part_buf->data, part_buf->used);
 		buffer_set_used_size(part_buf, 0);
 		/* fall through */
 	case MAIL_ATTACHMENT_STATE_YES:
 		index_attachment_try_base64_decode(part, block->data,
 						   block->size);
 		hash_format_loop(part->part_hash, block->data, block->size);
-		o_stream_send(part->output, block->data, block->size);
+		o_stream_nsend(part->output, block->data, block->size);
 		break;
 	}
 }
@@ -626,8 +622,8 @@
 	case MAIL_ATTACHMENT_STATE_MAYBE:
 		/* body part wasn't large enough. write to main file. */
 		if (part->part_buf != NULL) {
-			o_stream_send(ctx->output, part->part_buf->data,
-				      part->part_buf->used);
+			o_stream_nsend(ctx->output, part->part_buf->data,
+				       part->part_buf->used);
 		}
 		break;
 	case MAIL_ATTACHMENT_STATE_YES:
--- a/src/lib-storage/index/maildir/maildir-save.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-storage/index/maildir/maildir-save.c	Mon Jun 25 00:01:59 2012 +0300
@@ -529,10 +529,10 @@
 	}
 
 	path = t_strconcat(ctx->tmpdir, "/", ctx->file_last->tmp_name, NULL);
-	if (!ctx->failed && o_stream_flush(_ctx->output) < 0) {
+	if (!ctx->failed && o_stream_nfinish(_ctx->output) < 0) {
 		if (!mail_storage_set_error_from_errno(storage)) {
 			mail_storage_set_critical(storage,
-				"o_stream_flush(%s) failed: %m", path);
+				"write(%s) failed: %m", path);
 		}
 		ctx->failed = TRUE;
 	}
@@ -562,7 +562,7 @@
 				  &ctx->file_last->vsize) < 0)
 		ctx->file_last->vsize = (uoff_t)-1;
 
-	output_errno = _ctx->output->stream_errno;
+	output_errno = _ctx->output->last_failed_errno;
 	o_stream_destroy(&_ctx->output);
 
 	if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER &&
--- a/src/lib-storage/index/maildir/maildir-uidlist.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c	Mon Jun 25 00:01:59 2012 +0300
@@ -1241,7 +1241,6 @@
 	const unsigned char *p;
 	const char *strp;
 	unsigned int len;
-	int ret;
 
 	i_assert(fd != -1);
 
@@ -1271,7 +1270,7 @@
 			str_append_str(str, uidlist->hdr_extensions);
 		}
 		str_append_c(str, '\n');
-		o_stream_send(output, str_data(str), str_len(str));
+		o_stream_nsend(output, str_data(str), str_len(str));
 	}
 
 	iter = maildir_uidlist_iter_init(uidlist);
@@ -1298,22 +1297,19 @@
 		else
 			str_append_n(str, rec->filename, strp - rec->filename);
 		str_append_c(str, '\n');
-		o_stream_send(output, str_data(str), str_len(str));
+		o_stream_nsend(output, str_data(str), str_len(str));
 	}
 	maildir_uidlist_iter_deinit(&iter);
-	o_stream_flush(output);
 
-	ret = output->stream_errno == 0 ? 0 : -1;
+	if (o_stream_nfinish(output) < 0) {
+		mail_storage_set_critical(storage, "write(%s) failed: %m", path);
+		o_stream_unref(&output);
+		return -1;
+	}
 
 	*file_size_r = output->offset;
 	o_stream_unref(&output);
 
-	if (ret < 0) {
-		mail_storage_set_critical(storage,
-			"o_stream_send(%s) failed: %m", path);
-		return -1;
-	}
-
 	if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
 		if (fdatasync(fd) < 0) {
 			mail_storage_set_critical(storage,
--- a/src/lib-storage/index/mbox/mbox-save.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-storage/index/mbox/mbox-save.c	Mon Jun 25 00:01:59 2012 +0300
@@ -660,7 +660,7 @@
 
 	if (ctx->output != NULL) {
 		/* make sure everything is written */
-		if (o_stream_flush(ctx->output) < 0)
+		if (o_stream_nfinish(ctx->output) < 0)
 			write_error(ctx);
 	}
 
@@ -684,7 +684,7 @@
 
 	if (ctx->failed && ctx->mail_offset != (uoff_t)-1) {
 		/* saving this mail failed - truncate back to beginning of it */
-		(void)o_stream_flush(ctx->output);
+		(void)o_stream_nfinish(ctx->output);
 		if (ftruncate(ctx->mbox->mbox_fd, (off_t)ctx->mail_offset) < 0)
 			mbox_set_syscall_error(ctx->mbox, "ftruncate()");
 		o_stream_seek(ctx->output, ctx->mail_offset);
@@ -722,7 +722,7 @@
 	/* failed, truncate file back to original size. output stream needs to
 	   be flushed before truncating so unref() won't write anything. */
 	if (ctx->output != NULL)
-		o_stream_flush(ctx->output);
+		(void)o_stream_flush(ctx->output);
 
 	if (ftruncate(ctx->mbox->mbox_fd, (off_t)ctx->append_offset) < 0)
 		mbox_set_syscall_error(ctx->mbox, "ftruncate()");
@@ -777,7 +777,8 @@
 
 	if (ctx->output != NULL) {
 		/* flush the final LF */
-		o_stream_flush(ctx->output);
+		if (o_stream_nfinish(ctx->output) < 0)
+			write_error(ctx);
 	}
 	if (mbox->mbox_fd != -1 && !mbox->mbox_writeonly &&
 	    mbox->storage->storage.set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
--- a/src/lib-storage/index/pop3c/pop3c-client.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-storage/index/pop3c/pop3c-client.c	Mon Jun 25 00:01:59 2012 +0300
@@ -256,12 +256,12 @@
 	}
 
 	if (set->master_user == NULL) {
-		o_stream_send_str(client->output,
+		o_stream_nsend_str(client->output,
 			t_strdup_printf("USER %s\r\n", set->username));
 		client->state = POP3C_CLIENT_STATE_USER;
 	} else {
 		client->state = POP3C_CLIENT_STATE_AUTH;
-		o_stream_send_str(client->output, "AUTH PLAIN\r\n");
+		o_stream_nsend_str(client->output, "AUTH PLAIN\r\n");
 	}
 }
 
@@ -320,7 +320,7 @@
 				client->set.host, line);
 			return -1;
 		}
-		o_stream_send_str(client->output,
+		o_stream_nsend_str(client->output,
 			t_strdup_printf("PASS %s\r\n", client->set.password));
 		client->state = POP3C_CLIENT_STATE_PASS;
 		break;
@@ -330,7 +330,7 @@
 				client->set.host, line);
 			return -1;
 		}
-		o_stream_send_str(client->output,
+		o_stream_nsend_str(client->output,
 			pop3c_client_get_sasl_plain_request(client));
 		client->state = POP3C_CLIENT_STATE_PASS;
 		break;
@@ -349,7 +349,7 @@
 		if (!success)
 			return -1;
 
-		o_stream_send_str(client->output, "CAPA\r\n");
+		o_stream_nsend_str(client->output, "CAPA\r\n");
 		client->state = POP3C_CLIENT_STATE_CAPA;
 		break;
 	case POP3C_CLIENT_STATE_CAPA:
@@ -529,6 +529,7 @@
 		i_stream_create_fd(client->fd, POP3C_MAX_INBUF_SIZE, FALSE);
 	client->output = client->raw_output =
 		o_stream_create_fd(client->fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(client->output, TRUE);
 
 	if (*client->set.rawlog_dir != '\0' &&
 	    client->set.ssl_mode != POP3C_CLIENT_SSL_MODE_IMMEDIATE &&
@@ -662,7 +663,7 @@
 
 	if (pop3c_client_flush_asyncs(client, reply_r) < 0)
 		return -1;
-	o_stream_send_str(client->output, cmd);
+	o_stream_nsend_str(client->output, cmd);
 	if (pop3c_client_read_line(client, &line, reply_r) < 0)
 		return -1;
 	if (strncasecmp(line, "+OK", 3) == 0) {
@@ -693,7 +694,7 @@
 		if (pop3c_client_flush_asyncs(client, &error) < 0)
 			return;
 	}
-	o_stream_send_str(client->output, cmd);
+	o_stream_nsend_str(client->output, cmd);
 	client->async_commands++;
 }
 
--- a/src/lib-storage/list/subscription-file.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib-storage/list/subscription-file.c	Mon Jun 25 00:01:59 2012 +0300
@@ -152,8 +152,8 @@
 				}
 			}
 
-			(void)o_stream_send_str(output, line);
-			(void)o_stream_send(output, "\n", 1);
+			o_stream_nsend_str(output, line);
+			o_stream_nsend(output, "\n", 1);
 		}
 		i_stream_destroy(&input);
 	}
@@ -161,12 +161,12 @@
 	if (!failed && set && !found) {
 		/* append subscription */
 		line = t_strconcat(name, "\n", NULL);
-		(void)o_stream_send_str(output, line);
+		o_stream_nsend_str(output, line);
 		changed = TRUE;
 	}
 
 	if (changed && !failed) {
-		if (o_stream_flush(output) < 0) {
+		if (o_stream_nfinish(output) < 0) {
 			subswrite_set_syscall_error(list, "write()", path);
 			failed = TRUE;
 		} else if (mail_set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
--- a/src/lib/ostream-file.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib/ostream-file.c	Mon Jun 25 00:01:59 2012 +0300
@@ -72,7 +72,7 @@
 	struct file_ostream *fstream = (struct file_ostream *)stream;
 
 	/* flush output before really closing it */
-	o_stream_flush(&fstream->ostream.ostream);
+	(void)o_stream_flush(&fstream->ostream.ostream);
 
 	stream_closed(fstream);
 }
--- a/src/lib/ostream-private.h	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib/ostream-private.h	Mon Jun 25 00:01:59 2012 +0300
@@ -36,6 +36,8 @@
 	void *context;
 
 	unsigned int corked:1;
+	unsigned int last_errors_not_checked:1;
+	unsigned int error_handling_disabled:1;
 };
 
 struct ostream *
--- a/src/lib/ostream-rawlog.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib/ostream-rawlog.c	Mon Jun 25 00:01:59 2012 +0300
@@ -14,7 +14,7 @@
 {
 	struct rawlog_ostream *rstream = (struct rawlog_ostream *)stream;
 
-	o_stream_flush(rstream->ostream.parent);
+	(void)o_stream_flush(rstream->ostream.parent);
 	iostream_rawlog_close(&rstream->riostream);
 }
 
--- a/src/lib/ostream.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib/ostream.c	Mon Jun 25 00:01:59 2012 +0300
@@ -31,10 +31,19 @@
 	io_stream_ref(&stream->real_stream->iostream);
 }
 
-void o_stream_unref(struct ostream **stream)
+void o_stream_unref(struct ostream **_stream)
 {
-	io_stream_unref(&(*stream)->real_stream->iostream);
-	*stream = NULL;
+	struct ostream *stream = *_stream;
+
+	if (!stream->real_stream->last_errors_not_checked &&
+	    !stream->real_stream->error_handling_disabled &&
+	    stream->real_stream->iostream.refcount == 1) {
+		i_panic("output stream %s is missing error handling",
+			o_stream_get_name(stream));
+	}
+
+	io_stream_unref(&stream->real_stream->iostream);
+	*_stream = NULL;
 }
 
 void o_stream_close(struct ostream *stream)
@@ -196,6 +205,57 @@
 	return o_stream_send(stream, str, strlen(str));
 }
 
+void o_stream_nsend(struct ostream *stream, const void *data, size_t size)
+{
+	struct const_iovec iov;
+
+	memset(&iov, 0, sizeof(iov));
+	iov.iov_base = data;
+	iov.iov_len = size;
+
+	(void)o_stream_nsendv(stream, &iov, 1);
+}
+
+void o_stream_nsendv(struct ostream *stream, const struct const_iovec *iov,
+		     unsigned int iov_count)
+{
+	if (unlikely(stream->closed))
+		return;
+	(void)o_stream_sendv(stream, iov, iov_count);
+	stream->real_stream->last_errors_not_checked = TRUE;
+}
+
+void o_stream_nsend_str(struct ostream *stream, const char *str)
+{
+	o_stream_nsend(stream, str, strlen(str));
+}
+
+void o_stream_nflush(struct ostream *stream)
+{
+	if (unlikely(stream->closed))
+		return;
+	(void)o_stream_flush(stream);
+	stream->real_stream->last_errors_not_checked = TRUE;
+}
+
+int o_stream_nfinish(struct ostream *stream)
+{
+	o_stream_nflush(stream);
+	stream->real_stream->last_errors_not_checked = FALSE;
+	errno = stream->last_failed_errno;
+	return stream->last_failed_errno != 0 ? -1 : 0;
+}
+
+void o_stream_ignore_last_errors(struct ostream *stream)
+{
+	stream->real_stream->last_errors_not_checked = FALSE;
+}
+
+void o_stream_set_no_error_handling(struct ostream *stream, bool set)
+{
+	stream->real_stream->error_handling_disabled = set;
+}
+
 off_t o_stream_send_istream(struct ostream *outstream,
 			    struct istream *instream)
 {
@@ -406,6 +466,8 @@
 		_stream->callback = parent->real_stream->callback;
 		_stream->context = parent->real_stream->context;
 		_stream->max_buffer_size = parent->real_stream->max_buffer_size;
+		_stream->error_handling_disabled =
+			parent->real_stream->error_handling_disabled;
 	}
 
 	if (_stream->iostream.close == NULL)
--- a/src/lib/ostream.h	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib/ostream.h	Mon Jun 25 00:01:59 2012 +0300
@@ -88,6 +88,26 @@
 ssize_t o_stream_sendv(struct ostream *stream, const struct const_iovec *iov,
 		       unsigned int iov_count);
 ssize_t o_stream_send_str(struct ostream *stream, const char *str);
+/* Send with delayed error handling. o_stream_has_errors() or
+   o_stream_ignore_errors() must be called after these functions before the
+   stream is destroyed. */
+void o_stream_nsend(struct ostream *stream, const void *data, size_t size);
+void o_stream_nsendv(struct ostream *stream, const struct const_iovec *iov,
+		     unsigned int iov_count);
+void o_stream_nsend_str(struct ostream *stream, const char *str);
+void o_stream_nflush(struct ostream *stream);
+/* Flushes the stream and returns -1 if stream->last_failed_errno is
+   non-zero. Marks the stream's error handling as completed. errno is also set
+   to last_failed_errno. */
+int o_stream_nfinish(struct ostream *stream);
+/* Marks the stream's error handling as completed to avoid i_panic() on
+   destroy. */
+void o_stream_ignore_last_errors(struct ostream *stream);
+/* If error handling is disabled, the i_panic() on destroy is never called.
+   This function can be called immediately after the stream is created.
+   When creating wrapper streams, they copy this behavior from the parent
+   stream. */
+void o_stream_set_no_error_handling(struct ostream *stream, bool set);
 /* 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
    blocking.
--- a/src/lib/test-ostream-file.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lib/test-ostream-file.c	Mon Jun 25 00:01:59 2012 +0300
@@ -32,7 +32,7 @@
 	size = (rand() % MAX_BUFSIZE) + 1;
 	random_fill_weak(randbuf, size);
 	memcpy(buf, randbuf, size);
-	o_stream_send(output, buf, size);
+	(void)o_stream_send(output, buf, size);
 
 	for (i = 0; i < 10; i++) {
 		offset = rand() % (MAX_BUFSIZE*3);
@@ -41,10 +41,10 @@
 		memcpy(buf + offset, randbuf, size);
 		o_stream_pwrite(output, randbuf, size, offset);
 		if (rand() % 10 == 0)
-			o_stream_flush(output);
+			(void)o_stream_flush(output);
 	}
 
-	o_stream_flush(output);
+	(void)o_stream_flush(output);
 	o_stream_uncork(output);
 	ret = pread(fd, buf2, sizeof(buf2), 0);
 	if (ret < 0)
--- a/src/lmtp/client.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lmtp/client.c	Mon Jun 25 00:01:59 2012 +0300
@@ -217,6 +217,7 @@
 
 	client->input = i_stream_create_fd(fd_in, CLIENT_MAX_INPUT_SIZE, FALSE);
 	client->output = o_stream_create_fd(fd_out, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(client->output, TRUE);
 
 	client_io_reset(client);
 	client->state_pool = pool_alloconly_create("client state", 4096);
@@ -340,7 +341,7 @@
 		str = t_str_new(256);
 		str_vprintfa(str, fmt, args);
 		str_append(str, "\r\n");
-		o_stream_send(client->output, str_data(str), str_len(str));
+		o_stream_nsend(client->output, str_data(str), str_len(str));
 	} T_END;
 	va_end(args);
 }
--- a/src/lmtp/lmtp-proxy.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/lmtp/lmtp-proxy.c	Mon Jun 25 00:01:59 2012 +0300
@@ -164,8 +164,8 @@
 	for (i = proxy->next_data_reply_idx; i < count; i++) {
 		if (!(rcpt[i]->rcpt_to_failed || rcpt[i]->data_reply_received))
 			break;
-		o_stream_send_str(proxy->client_output,
-				  t_strconcat(rcpt[i]->reply, "\r\n", NULL));
+		o_stream_nsend_str(proxy->client_output,
+				   t_strconcat(rcpt[i]->reply, "\r\n", NULL));
 	}
 	o_stream_uncork(proxy->client_output);
 	proxy->next_data_reply_idx = i;
--- a/src/login-common/client-common-auth.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/login-common/client-common-auth.c	Mon Jun 25 00:01:59 2012 +0300
@@ -486,7 +486,7 @@
 	iov[2].iov_base = "\r\n";
 	iov[2].iov_len = 2;
 
-	(void)o_stream_sendv(client->output, iov, 3);
+	o_stream_nsendv(client->output, iov, 3);
 }
 
 static void
--- a/src/login-common/client-common.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/login-common/client-common.c	Mon Jun 25 00:01:59 2012 +0300
@@ -66,6 +66,7 @@
 		i_stream_create_fd(client->fd, LOGIN_MAX_INBUF_SIZE, FALSE);
 	client->output =
 		o_stream_create_fd(client->fd, LOGIN_MAX_OUTBUF_SIZE, FALSE);
+	o_stream_set_no_error_handling(client->output, TRUE);
 
 	if (login_rawlog_dir != NULL) {
 		if (iostream_rawlog_create(login_rawlog_dir, &client->input,
--- a/src/login-common/login-proxy.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/login-common/login-proxy.c	Mon Jun 25 00:01:59 2012 +0300
@@ -175,6 +175,7 @@
 				   FALSE);
 	proxy->server_output =
 		o_stream_create_fd(proxy->server_fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(proxy->server_output, TRUE);
 
 	proxy->server_io =
 		io_add(proxy->server_fd, IO_READ, proxy_prelogin_input, proxy);
@@ -456,7 +457,7 @@
 	/* send all pending client input to proxy and get rid of the stream */
 	data = i_stream_get_data(client->input, &size);
 	if (size != 0)
-		(void)o_stream_send(proxy->server_output, data, size);
+		o_stream_nsend(proxy->server_output, data, size);
 
 	/* from now on, just do dummy proxying */
 	io_remove(&proxy->server_io);
--- a/src/plugins/acl/acl-backend-vfile-acllist.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/plugins/acl/acl-backend-vfile-acllist.c	Mon Jun 25 00:01:59 2012 +0300
@@ -187,7 +187,7 @@
 			const char *line;
 			line = t_strdup_printf("%s %s\n",
 					       dec2str(acllist.mtime), name);
-			o_stream_send_str(output, line);
+			o_stream_nsend_str(output, line);
 		} T_END;
 	}
 	acl_object_deinit(&aclobj);
@@ -246,6 +246,7 @@
 		return -1;
 	}
 	output = o_stream_create_fd_file(fd, 0, FALSE);
+	o_stream_cork(output);
 
 	ret = 0;
 	acllist_clear(backend, 0);
@@ -261,7 +262,7 @@
 		}
 	}
 
-	if (output->stream_errno != 0) {
+	if (o_stream_nfinish(output) < 0) {
 		i_error("write(%s) failed: %m", str_c(path));
 		ret = -1;
 	}
--- a/src/plugins/acl/acl-backend-vfile.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/plugins/acl/acl-backend-vfile.c	Mon Jun 25 00:01:59 2012 +0300
@@ -1072,17 +1072,17 @@
 	for (i = 0; i < count && !rights[i].global; i++) {
 		if (rights[i].rights != NULL) {
 			vfile_write_right(str, &rights[i], FALSE);
-			o_stream_send(output, str_data(str), str_len(str));
+			o_stream_nsend(output, str_data(str), str_len(str));
 			str_truncate(str, 0);
 		}
 		if (rights[i].neg_rights != NULL) {
 			vfile_write_right(str, &rights[i], TRUE);
-			o_stream_send(output, str_data(str), str_len(str));
+			o_stream_nsend(output, str_data(str), str_len(str));
 			str_truncate(str, 0);
 		}
 	}
 	str_free(&str);
-	if (o_stream_flush(output) < 0) {
+	if (o_stream_nfinish(output) < 0) {
 		i_error("write(%s) failed: %m", path);
 		ret = -1;
 	}
--- a/src/plugins/fts-squat/squat-trie.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/plugins/fts-squat/squat-trie.c	Mon Jun 25 00:01:59 2012 +0300
@@ -590,8 +590,8 @@
 
 	base_offset = ctx->output->offset;
 	child_count = node->child_count;
-	o_stream_send(ctx->output, &child_count, 1);
-	o_stream_send(ctx->output, chars, child_count);
+	o_stream_nsend(ctx->output, &child_count, 1);
+	o_stream_nsend(ctx->output, chars, child_count);
 
 	for (i = 0; i < child_count; i++) {
 		bufp = buf;
@@ -618,17 +618,17 @@
 		if (children[i].leaf_string_length == 0) {
 			/* 4a) unused uids */
 			squat_pack_num(&bufp, children[i].unused_uids << 1);
-			o_stream_send(ctx->output, buf, bufp - buf);
+			o_stream_nsend(ctx->output, buf, bufp - buf);
 		} else {
 			i_assert(node_offsets[i] == 0);
 			/* 4b) unused uids + flag */
 			squat_pack_num(&bufp, (children[i].unused_uids << 1) | 1);
 			/* 5) leaf string length */
 			squat_pack_num(&bufp, children[i].leaf_string_length - 1);
-			o_stream_send(ctx->output, buf, bufp - buf);
-			o_stream_send(ctx->output,
-				      NODE_LEAF_STRING(&children[i]),
-				      children[i].leaf_string_length);
+			o_stream_nsend(ctx->output, buf, bufp - buf);
+			o_stream_nsend(ctx->output,
+				       NODE_LEAF_STRING(&children[i]),
+				       children[i].leaf_string_length);
 		}
 	}
 }
@@ -1642,7 +1642,7 @@
 
 		output = o_stream_create_fd(fd, 0, FALSE);
 		o_stream_cork(output);
-		o_stream_send(output, &trie->hdr, sizeof(trie->hdr));
+		o_stream_nsend(output, &trie->hdr, sizeof(trie->hdr));
 	} else {
 		/* we need to lock only while header is being written */
 		path = trie->path;
@@ -1660,7 +1660,7 @@
 		if (trie->hdr.used_file_size != 0)
 			o_stream_seek(output, trie->hdr.used_file_size);
 		else
-			o_stream_send(output, &trie->hdr, sizeof(trie->hdr));
+			o_stream_nsend(output, &trie->hdr, sizeof(trie->hdr));
 	}
 
 	ctx->output = output;
@@ -1669,7 +1669,7 @@
 
 	/* write 1 byte guard at the end of file, so that we can verify broken
 	   squat_unpack_num() input by checking if data==end */
-	o_stream_send(output, "", 1);
+	o_stream_nsend(output, "", 1);
 
 	if (trie->corrupted)
 		ret = -1;
@@ -1678,10 +1678,9 @@
 	if (ret == 0) {
 		trie->hdr.used_file_size = output->offset;
 		o_stream_seek(output, 0);
-		o_stream_send(output, &trie->hdr, sizeof(trie->hdr));
+		o_stream_nsend(output, &trie->hdr, sizeof(trie->hdr));
 	}
-	if (output->last_failed_errno != 0) {
-		errno = output->last_failed_errno;
+	if (o_stream_nfinish(output) < 0) {
 		i_error("write() to %s failed: %m", path);
 		ret = -1;
 	}
--- a/src/plugins/fts-squat/squat-uidlist.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/plugins/fts-squat/squat-uidlist.c	Mon Jun 25 00:01:59 2012 +0300
@@ -221,10 +221,10 @@
 	if (write_size) {
 		sizebufp = sizebuf;
 		squat_pack_num(&sizebufp, size_value);
-		o_stream_send(output, sizebuf, sizebufp - sizebuf);
+		o_stream_nsend(output, sizebuf, sizebufp - sizebuf);
 	}
-	o_stream_send(output, listbuf, listbufp - listbuf);
-	o_stream_send(output, uidbuf, uid_list_len);
+	o_stream_nsend(output, listbuf, listbufp - listbuf);
+	o_stream_nsend(output, uidbuf, uid_list_len);
 	if (!datastack)
 		i_free(uidbuf);
 
@@ -251,7 +251,7 @@
 			if (list->uid_count == 1) {
 				bufp = buf;
 				squat_pack_num(&bufp, offset);
-				o_stream_send(output, buf, bufp - buf);
+				o_stream_nsend(output, buf, bufp - buf);
 				*size_r = (bufp - buf) << 2 | packed_flags;
 				return 0;
 			}
@@ -716,7 +716,7 @@
 		struct squat_uidlist_file_header hdr;
 
 		memset(&hdr, 0, sizeof(hdr));
-		o_stream_send(ctx->output, &hdr, sizeof(hdr));
+		o_stream_nsend(ctx->output, &hdr, sizeof(hdr));
 	}
 	o_stream_cork(ctx->output);
 	i_array_init(&ctx->lists, 10240);
@@ -756,7 +756,7 @@
 	if (align != 0) {
 		static char null[sizeof(uint32_t)-1] = { 0, };
 
-		o_stream_send(output, null, sizeof(uint32_t) - align);
+		o_stream_nsend(output, null, sizeof(uint32_t) - align);
 	}
 	block_list_offset = output->offset;
 
@@ -764,18 +764,18 @@
 	old_block_count = write_old_blocks ? uidlist->cur_block_count : 0;
 
 	block_offset_count = new_block_count + old_block_count;
-	o_stream_send(output, &block_offset_count, sizeof(block_offset_count));
+	o_stream_nsend(output, &block_offset_count, sizeof(block_offset_count));
 	/* write end indexes */
-	o_stream_send(output, uidlist->cur_block_end_indexes,
-		      old_block_count * sizeof(uint32_t));
-	o_stream_send(output, array_idx(block_end_indexes, 0),
-		      new_block_count * sizeof(uint32_t));
+	o_stream_nsend(output, uidlist->cur_block_end_indexes,
+		       old_block_count * sizeof(uint32_t));
+	o_stream_nsend(output, array_idx(block_end_indexes, 0),
+		       new_block_count * sizeof(uint32_t));
 	/* write offsets */
-	o_stream_send(output, uidlist->cur_block_offsets,
-		      old_block_count * sizeof(uint32_t));
-	o_stream_send(output, array_idx(block_offsets, 0),
-		      new_block_count * sizeof(uint32_t));
-	o_stream_flush(output);
+	o_stream_nsend(output, uidlist->cur_block_offsets,
+		       old_block_count * sizeof(uint32_t));
+	o_stream_nsend(output, array_idx(block_offsets, 0),
+		       new_block_count * sizeof(uint32_t));
+	(void)o_stream_flush(output);
 
 	/* update header - it's written later when trie is locked */
 	ctx->build_hdr.block_list_offset = block_list_offset;
@@ -820,13 +820,13 @@
 		/* write the full size of the uidlists */
 		bufp = buf;
 		squat_pack_num(&bufp, block_offset - start_offset);
-		o_stream_send(ctx->output, buf, bufp - buf);
+		o_stream_nsend(ctx->output, buf, bufp - buf);
 
 		/* write the sizes/flags */
 		for (j = 0; j < max; j++) {
 			bufp = buf;
 			squat_pack_num(&bufp, list_sizes[j]);
-			o_stream_send(ctx->output, buf, bufp - buf);
+			o_stream_nsend(ctx->output, buf, bufp - buf);
 		}
 	}
 
@@ -856,14 +856,12 @@
 
 	if (!ctx->output->closed) {
 		o_stream_seek(ctx->output, 0);
-		o_stream_send(ctx->output,
-			      &ctx->build_hdr, sizeof(ctx->build_hdr));
+		o_stream_nsend(ctx->output,
+			       &ctx->build_hdr, sizeof(ctx->build_hdr));
 		o_stream_seek(ctx->output, ctx->build_hdr.used_file_size);
-		o_stream_flush(ctx->output);
 	}
 
-	if (ctx->output->last_failed_errno != 0) {
-		errno = ctx->output->last_failed_errno;
+	if (o_stream_nfinish(ctx->output) < 0) {
 		i_error("write() to %s failed: %m", ctx->uidlist->path);
 		return -1;
 	}
@@ -891,6 +889,7 @@
 	array_free(&ctx->block_offsets);
 	array_free(&ctx->block_end_indexes);
 	array_free(&ctx->lists);
+	o_stream_ignore_last_errors(ctx->output);
 	o_stream_unref(&ctx->output);
 	i_free(ctx);
 }
@@ -933,7 +932,7 @@
 	o_stream_cork(ctx->output);
 
 	memset(&hdr, 0, sizeof(hdr));
-	o_stream_send(ctx->output, &hdr, sizeof(hdr));
+	o_stream_nsend(ctx->output, &hdr, sizeof(hdr));
 
 	ctx->cur_block_start_offset = ctx->output->offset;
 	i_array_init(&ctx->new_block_offsets,
@@ -962,13 +961,13 @@
 	   ended to current offset. write the size of this area. */
 	bufp = buf;
 	squat_pack_num(&bufp, block_offset - ctx->cur_block_start_offset);
-	o_stream_send(ctx->output, buf, bufp - buf);
+	o_stream_nsend(ctx->output, buf, bufp - buf);
 
 	/* write the sizes/flags */
 	for (i = 0; i < ctx->list_idx; i++) {
 		bufp = buf;
 		squat_pack_num(&bufp, ctx->list_sizes[i]);
-		o_stream_send(ctx->output, buf, bufp - buf);
+		o_stream_nsend(ctx->output, buf, bufp - buf);
 	}
 	ctx->cur_block_start_offset = ctx->output->offset;
 }
@@ -1058,16 +1057,14 @@
 						    &ctx->new_block_end_indexes,
 						    FALSE);
 		o_stream_seek(ctx->output, 0);
-		o_stream_send(ctx->output, &ctx->build_ctx->build_hdr,
-			      sizeof(ctx->build_ctx->build_hdr));
+		o_stream_nsend(ctx->output, &ctx->build_ctx->build_hdr,
+			       sizeof(ctx->build_ctx->build_hdr));
 		o_stream_seek(ctx->output,
 			      ctx->build_ctx->build_hdr.used_file_size);
-		o_stream_flush(ctx->output);
 
 		if (ctx->uidlist->corrupted)
 			ret = -1;
-		else if (ctx->output->last_failed_errno != 0) {
-			errno = ctx->output->last_failed_errno;
+		else if (o_stream_nfinish(ctx->output) < 0) {
 			i_error("write() to %s failed: %m", temp_path);
 			ret = -1;
 		} else if (rename(temp_path, ctx->uidlist->path) < 0) {
@@ -1082,6 +1079,7 @@
 	   let it be used for something more useful. */
 	squat_uidlist_free_from_memory(ctx->uidlist);
 
+	o_stream_ignore_last_errors(ctx->output);
 	o_stream_unref(&ctx->output);
 	if (close(ctx->fd) < 0)
 		i_error("close(%s) failed: %m", temp_path);
--- a/src/plugins/imap-quota/imap-quota-plugin.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/plugins/imap-quota/imap-quota-plugin.c	Mon Jun 25 00:01:59 2012 +0300
@@ -119,8 +119,8 @@
 		client_send_tagline(cmd, "OK No quota.");
 	else {
 		client_send_line(client, str_c(quotaroot_reply));
-		o_stream_send(client->output, str_data(quota_reply),
-			      str_len(quota_reply));
+		o_stream_nsend(client->output, str_data(quota_reply),
+			       str_len(quota_reply));
 		client_send_tagline(cmd, "OK Getquotaroot completed.");
 	}
 	return TRUE;
@@ -156,8 +156,8 @@
 
 	quota_reply = t_str_new(128);
 	quota_reply_write(quota_reply, cmd->client->user, owner, root);
-	o_stream_send(cmd->client->output, str_data(quota_reply),
-		      str_len(quota_reply));
+	o_stream_nsend(cmd->client->output, str_data(quota_reply),
+		       str_len(quota_reply));
 
 	client_send_tagline(cmd, "OK Getquota completed.");
 	return TRUE;
--- a/src/plugins/zlib/doveadm-zlib.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/plugins/zlib/doveadm-zlib.c	Mon Jun 25 00:01:59 2012 +0300
@@ -118,7 +118,7 @@
 	if (ret < 0)
 		i_fatal("read(stdin) failed: %m");
 
-	o_stream_send(client->output, buf, ret);
+	o_stream_nsend(client->output, buf, ret);
 }
 
 static void server_input(struct client *client)
@@ -170,6 +170,7 @@
 	client.fd = fd;
 	client.input = i_stream_create_fd(fd, (size_t)-1, FALSE);
 	client.output = o_stream_create_fd(fd, 0, FALSE);
+	o_stream_set_no_error_handling(client.output, TRUE);
 	client.io_client = io_add(STDIN_FILENO, IO_READ, client_input, &client);
 	client.io_server = io_add(fd, IO_READ, server_input, &client);
 	master_service_run(master_service, NULL);
--- a/src/plugins/zlib/ostream-bzlib.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/plugins/zlib/ostream-bzlib.c	Mon Jun 25 00:01:59 2012 +0300
@@ -24,7 +24,7 @@
 {
 	struct bzlib_ostream *zstream = (struct bzlib_ostream *)stream;
 
-	o_stream_flush(&zstream->ostream.ostream);
+	(void)o_stream_flush(&zstream->ostream.ostream);
 	(void)BZ2_bzCompressEnd(&zstream->zs);
 }
 
--- a/src/plugins/zlib/ostream-zlib.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/plugins/zlib/ostream-zlib.c	Mon Jun 25 00:01:59 2012 +0300
@@ -31,7 +31,7 @@
 {
 	struct zlib_ostream *zstream = (struct zlib_ostream *)stream;
 
-	o_stream_flush(&zstream->ostream.ostream);
+	(void)o_stream_flush(&zstream->ostream.ostream);
 	(void)deflateEnd(&zstream->zs);
 }
 
--- a/src/pop3-login/pop3-proxy.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/pop3-login/pop3-proxy.c	Mon Jun 25 00:01:59 2012 +0300
@@ -40,7 +40,7 @@
 	i_assert(client->common.proxy_ttl > 0);
 	if (client->proxy_xclient) {
 		/* remote supports XCLIENT, send it */
-		(void)o_stream_send_str(output, t_strdup_printf(
+		o_stream_nsend_str(output, t_strdup_printf(
 			"XCLIENT ADDR=%s PORT=%u SESSION=%s TTL=%u\r\n",
 			net_ip2addr(&client->common.ip),
 			client->common.remote_port,
@@ -61,7 +61,7 @@
 		/* master user login - use AUTH PLAIN. */
 		str_append(str, "AUTH PLAIN\r\n");
 	}
-	(void)o_stream_send(output, str_data(str), str_len(str));
+	o_stream_nsend(output, str_data(str), str_len(str));
 }
 
 int pop3_proxy_parse_line(struct client *client, const char *line)
@@ -91,7 +91,7 @@
 		if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0) {
 			proxy_send_login(pop3_client, output);
 		} else {
-			(void)o_stream_send_str(output, "STLS\r\n");
+			o_stream_nsend_str(output, "STLS\r\n");
 			client->proxy_state = POP3_PROXY_STARTTLS;
 		}
 		return 0;
@@ -138,7 +138,7 @@
 			get_plain_auth(client, str);
 			str_append(str, "\r\n");
 		}
-		(void)o_stream_send(output, str_data(str), str_len(str));
+		o_stream_nsend(output, str_data(str), str_len(str));
 		proxy_free_password(client);
 		client->proxy_state = POP3_PROXY_LOGIN2;
 		return 0;
@@ -148,7 +148,7 @@
 
 		/* Login successful. Send this line to client. */
 		line = t_strconcat(line, "\r\n", NULL);
-		(void)o_stream_send_str(client->output, line);
+		o_stream_nsend_str(client->output, line);
 
 		client_proxy_finish_destroy_client(client);
 		return 1;
--- a/src/pop3/pop3-client.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/pop3/pop3-client.c	Mon Jun 25 00:01:59 2012 +0300
@@ -305,6 +305,7 @@
 	client->fd_out = fd_out;
 	client->input = i_stream_create_fd(fd_in, MAX_INBUF_SIZE, FALSE);
 	client->output = o_stream_create_fd(fd_out, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(client->output, TRUE);
 	o_stream_set_flush_callback(client->output, client_output, client);
 
 	p_array_init(&client->module_contexts, client->pool, 5);
--- a/src/pop3/pop3-commands.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/pop3/pop3-commands.c	Mon Jun 25 00:01:59 2012 +0300
@@ -391,13 +391,13 @@
 
 	if (ctx->last != '\n') {
 		/* didn't end with CRLF */
-		(void)o_stream_send(client->output, "\r\n", 2);
+		o_stream_nsend(client->output, "\r\n", 2);
 	}
 
 	if (!ctx->in_body &&
 	    (client->set->parsed_workarounds & WORKAROUND_OE_NS_EOH) != 0) {
 		/* Add the missing end of headers line. */
-		(void)o_stream_send(client->output, "\r\n", 2);
+		o_stream_nsend(client->output, "\r\n", 2);
 	}
 
 	*ctx->byte_counter +=
--- a/src/replication/aggregator/notify-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/replication/aggregator/notify-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -44,7 +44,7 @@
 {
 	struct notify_connection *conn = context;
 
-	o_stream_send_str(conn->output, success ? "+\n" : "-\n");
+	o_stream_nsend_str(conn->output, success ? "+\n" : "-\n");
 	notify_connection_unref(conn);
 }
 
@@ -110,8 +110,10 @@
 	conn->fd = fd;
 	conn->io = io_add(fd, IO_READ, notify_input, conn);
 	conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
-	if (!fifo)
+	if (!fifo) {
 		conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+		o_stream_set_no_error_handling(conn->output, TRUE);
+	}
 
 	DLLIST_PREPEND(&conns, conn);
 }
--- a/src/replication/aggregator/replicator-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/replication/aggregator/replicator-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -172,7 +172,8 @@
 	conn->io = io_add(fd, IO_READ, replicator_input, conn);
 	conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
 	conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
-	(void)o_stream_send_str(conn->output, REPLICATOR_HANDSHAKE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
+	o_stream_nsend_str(conn->output, REPLICATOR_HANDSHAKE);
 	o_stream_set_flush_callback(conn->output, replicator_output, conn);
 }
 
@@ -269,7 +270,7 @@
 	if (conn->fd != -1 &&
 	    o_stream_get_buffer_used_size(conn->output) == 0) {
 		/* we can send data immediately */
-		o_stream_send(conn->output, data, data_len);
+		o_stream_nsend(conn->output, data, data_len);
 	} else if (conn->queue[priority]->used + data_len >=
 		   	REPLICATOR_MEMBUF_MAX_SIZE) {
 		/* FIXME: compress duplicates, start writing to file */
--- a/src/replication/replicator/doveadm-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/replication/replicator/doveadm-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -151,7 +151,8 @@
 	conn->io = io_add(conn->fd, IO_READ, doveadm_input, conn);
 	conn->input = i_stream_create_fd(conn->fd, MAX_INBUF_SIZE, FALSE);
 	conn->output = o_stream_create_fd(conn->fd, (size_t)-1, FALSE);
-	o_stream_send_str(conn->output, DOVEADM_HANDSHAKE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
+	o_stream_nsend_str(conn->output, DOVEADM_HANDSHAKE);
 	return 0;
 }
 
@@ -185,7 +186,7 @@
 		if (full)
 			str_append(cmd, "\t-f");
 		str_append_c(cmd, '\n');
-		o_stream_send(conn->output, str_data(cmd), str_len(cmd));
+		o_stream_nsend(conn->output, str_data(cmd), str_len(cmd));
 	}
 }
 
--- a/src/replication/replicator/notify-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/replication/replicator/notify-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -43,7 +43,7 @@
 {
 	struct notify_sync_request *request = context;
 
-	o_stream_send_str(request->conn->output, t_strdup_printf(
+	o_stream_nsend_str(request->conn->output, t_strdup_printf(
 		"%c\t%u\n", success ? '+' : '-', request->id));
 
 	notify_connection_unref(&request->conn);
@@ -141,6 +141,7 @@
 	conn->fd = fd;
 	conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
 	conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(conn->output, TRUE);
 	conn->io = io_add(fd, IO_READ, notify_connection_input, conn);
 	conn->queue = queue;
 
--- a/src/replication/replicator/replicator-queue.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/replication/replicator/replicator-queue.c	Mon Jun 25 00:01:59 2012 +0300
@@ -342,7 +342,7 @@
 	struct priorityq_item *const *items;
 	unsigned int i, count;
 	string_t *str;
-	int fd, ret;
+	int fd, ret = 0;
 
 	fd = creat(path, 0600);
 	if (fd == -1) {
@@ -364,8 +364,10 @@
 		if (o_stream_send(output, str_data(str), str_len(str)) < 0)
 			break;
 	}
-
-	ret = output->last_failed_errno != 0 ? -1 : 0;
+	if (o_stream_nfinish(output) < 0) {
+		i_error("write(%s) failed: %m", path);
+		ret = -1;
+	}
 	o_stream_destroy(&output);
 	return ret;
 }
--- a/src/ssl-params/main.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/ssl-params/main.c	Mon Jun 25 00:01:59 2012 +0300
@@ -46,9 +46,8 @@
 	struct ostream *output;
 
 	output = o_stream_create_fd(fd, (size_t)-1, TRUE);
-	o_stream_send(output, ssl_params->data, ssl_params->used);
-
-	if (o_stream_get_buffer_used_size(output) == 0)
+	if (o_stream_send(output, ssl_params->data, ssl_params->used) < 0 ||
+	    o_stream_get_buffer_used_size(output) == 0)
 		client_deinit(output);
 	else {
 		o_stream_set_flush_callback(output, client_output_flush,
--- a/src/stats/client-export.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/stats/client-export.c	Mon Jun 25 00:01:59 2012 +0300
@@ -255,7 +255,7 @@
 	mail_command_unref(&client->mail_cmd_iter);
 
 	if (!cmd->header_sent) {
-		o_stream_send_str(client->output,
+		o_stream_nsend_str(client->output,
 			"cmd\targs\tsession\tuser\tlast_update"MAIL_STATS_HEADER);
 		cmd->header_sent = TRUE;
 	}
@@ -282,8 +282,8 @@
 		client_export_timeval(cmd->str, &command->last_update);
 		client_export_mail_stats(cmd->str, &command->stats);
 		str_append_c(cmd->str, '\n');
-		o_stream_send(client->output, str_data(cmd->str),
-			      str_len(cmd->str));
+		o_stream_nsend(client->output, str_data(cmd->str),
+			       str_len(cmd->str));
 	}
 
 	if (command != NULL) {
@@ -303,7 +303,7 @@
 	mail_session_unref(&client->mail_session_iter);
 
 	if (!cmd->header_sent) {
-		o_stream_send_str(client->output,
+		o_stream_nsend_str(client->output,
 			"session\tuser\tip\tservice\tpid\tconnected"
 			"\tlast_update\tnum_cmds"
 			MAIL_STATS_HEADER);
@@ -335,8 +335,8 @@
 		str_printfa(cmd->str, "\t%u", session->num_cmds);
 		client_export_mail_stats(cmd->str, &session->stats);
 		str_append_c(cmd->str, '\n');
-		o_stream_send(client->output, str_data(cmd->str),
-			      str_len(cmd->str));
+		o_stream_nsend(client->output, str_data(cmd->str),
+			       str_len(cmd->str));
 	}
 
 	if (session != NULL) {
@@ -356,7 +356,7 @@
 	mail_user_unref(&client->mail_user_iter);
 
 	if (!cmd->header_sent) {
-		o_stream_send_str(client->output,
+		o_stream_nsend_str(client->output,
 			"user\treset_timestamp\tlast_update"
 			"\tnum_logins\tnum_cmds"MAIL_STATS_HEADER);
 		cmd->header_sent = TRUE;
@@ -376,8 +376,8 @@
 			    user->num_logins, user->num_cmds);
 		client_export_mail_stats(cmd->str, &user->stats);
 		str_append_c(cmd->str, '\n');
-		o_stream_send(client->output, str_data(cmd->str),
-			      str_len(cmd->str));
+		o_stream_nsend(client->output, str_data(cmd->str),
+			       str_len(cmd->str));
 	}
 
 	if (user != NULL) {
@@ -397,7 +397,7 @@
 	mail_domain_unref(&client->mail_domain_iter);
 
 	if (!cmd->header_sent) {
-		o_stream_send_str(client->output,
+		o_stream_nsend_str(client->output,
 			"domain\treset_timestamp\tlast_update"
 			"\tnum_logins\tnum_cmds"MAIL_STATS_HEADER);
 		cmd->header_sent = TRUE;
@@ -417,8 +417,8 @@
 			    domain->num_logins, domain->num_cmds);
 		client_export_mail_stats(cmd->str, &domain->stats);
 		str_append_c(cmd->str, '\n');
-		o_stream_send(client->output, str_data(cmd->str),
-			      str_len(cmd->str));
+		o_stream_nsend(client->output, str_data(cmd->str),
+			       str_len(cmd->str));
 	}
 
 	if (domain != NULL) {
@@ -438,7 +438,7 @@
 	mail_ip_unref(&client->mail_ip_iter);
 
 	if (!cmd->header_sent) {
-		o_stream_send_str(client->output,
+		o_stream_nsend_str(client->output,
 			"ip\treset_timestamp\tlast_update"
 			"\tnum_logins\tnum_cmds"MAIL_STATS_HEADER);
 		cmd->header_sent = TRUE;
@@ -459,8 +459,8 @@
 		str_printfa(cmd->str, "\t%u\t%u", ip->num_logins, ip->num_cmds);
 		client_export_mail_stats(cmd->str, &ip->stats);
 		str_append_c(cmd->str, '\n');
-		o_stream_send(client->output, str_data(cmd->str),
-			      str_len(cmd->str));
+		o_stream_nsend(client->output, str_data(cmd->str),
+			       str_len(cmd->str));
 	}
 
 	if (ip != NULL) {
@@ -475,7 +475,7 @@
 {
 	if (client->cmd_export->export_iter(client) == 0)
 		return 0;
-	o_stream_send_str(client->output, "\n");
+	o_stream_nsend_str(client->output, "\n");
 	return 1;
 }
 
@@ -610,7 +610,7 @@
 	client->cmd_export = cmd;
 	if (!client_export_iter_init(client)) {
 		/* nothing to export */
-		o_stream_send_str(client->output, "\n");
+		o_stream_nsend_str(client->output, "\n");
 		return 1;
 	}
 	client->cmd_more = client_export_more;
--- a/src/stats/client.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/stats/client.c	Mon Jun 25 00:01:59 2012 +0300
@@ -146,6 +146,7 @@
 	client->io = io_add(fd, IO_READ, client_input, client);
 	client->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
 	client->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(client->output, TRUE);
 	o_stream_set_flush_callback(client->output, client_output, client);
 	client->cmd_pool = pool_alloconly_create("cmd pool", 1024);
 
--- a/src/stats/mail-server-connection.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/stats/mail-server-connection.c	Mon Jun 25 00:01:59 2012 +0300
@@ -16,7 +16,6 @@
 struct mail_server_connection {
 	int fd;
 	struct istream *input;
-	struct ostream *output;
 	struct io *io;
 };
 
@@ -88,7 +87,6 @@
 	conn = i_new(struct mail_server_connection, 1);
 	conn->fd = fd;
 	conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
-	conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
 	conn->io = io_add(fd, IO_READ, mail_server_connection_input, conn);
 	return conn;
 }
@@ -101,7 +99,6 @@
 
 	io_remove(&conn->io);
 	i_stream_destroy(&conn->input);
-	o_stream_destroy(&conn->output);
 	if (close(conn->fd) < 0)
 		i_error("close(conn) failed: %m");
 	i_free(conn);
--- a/src/util/rawlog.c	Sun Jun 24 21:43:48 2012 +0300
+++ b/src/util/rawlog.c	Mon Jun 25 00:01:59 2012 +0300
@@ -162,7 +162,7 @@
 
 	ret = net_receive(proxy->server_fd, buf, sizeof(buf));
 	if (ret > 0) {
-		(void)o_stream_send(proxy->client_output, buf, ret);
+		o_stream_nsend(proxy->client_output, buf, ret);
 		proxy_write_out(proxy, buf, ret);
 	} else if (ret <= 0)
 		rawlog_proxy_destroy(proxy);
@@ -183,7 +183,7 @@
 
 	ret = net_receive(proxy->client_in_fd, buf, sizeof(buf));
 	if (ret > 0) {
-		(void)o_stream_send(proxy->server_output, buf, ret);
+		o_stream_nsend(proxy->server_output, buf, ret);
 		proxy_write_in(proxy, buf, ret);
 	} else if (ret < 0)
 		rawlog_proxy_destroy(proxy);
@@ -263,13 +263,15 @@
 	proxy = i_new(struct rawlog_proxy, 1);
 	proxy->server_fd = server_fd;
 	proxy->server_output = o_stream_create_fd(server_fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(proxy->server_output, TRUE);
+	o_stream_set_flush_callback(proxy->server_output, server_output, proxy);
 	proxy->server_io = io_add(server_fd, IO_READ, server_input, proxy);
-	o_stream_set_flush_callback(proxy->server_output, server_output, proxy);
 
 	proxy->client_in_fd = client_in_fd;
 	proxy->client_out_fd = client_out_fd;
 	proxy->client_output =
 		o_stream_create_fd(client_out_fd, (size_t)-1, FALSE);
+	o_stream_set_no_error_handling(proxy->client_output, TRUE);
 	proxy->client_io = io_add(proxy->client_in_fd, IO_READ,
 				  client_input, proxy);
 	o_stream_set_flush_callback(proxy->client_output, client_output, proxy);