소스 검색

Merge branch 'isync_1_2_branch'

Conflicts:
	configure.ac
	src/drv_imap.c
Oswald Buddenhagen 10 년 전
부모
커밋
bcd43e2c66
7개의 변경된 파일145개의 추가작업 그리고 149개의 파일을 삭제
  1. 1 1
      README
  2. 0 3
      TODO
  3. 22 12
      configure.ac
  4. 53 63
      src/drv_imap.c
  5. 48 48
      src/mbsync.1
  6. 16 19
      src/socket.c
  7. 5 3
      src/socket.h

+ 1 - 1
README

@@ -61,7 +61,7 @@ isync executable still exists; it is a compatibility wrapper around mbsync.
 
 
 * Requirements
 * Requirements
 
 
-    Berkley DB 4.2+ (optional)
+    Berkeley DB 4.1+ (optional)
     OpenSSL for TLS/SSL support (optional)
     OpenSSL for TLS/SSL support (optional)
 
 
 * Installation
 * Installation

+ 0 - 3
TODO

@@ -3,9 +3,6 @@ f{,data}sync() usage could be optimized by batching the calls.
 add some marker about message being already [remotely] trashed.
 add some marker about message being already [remotely] trashed.
 real transactions would be certainly not particularly useful ...
 real transactions would be certainly not particularly useful ...
 
 
-make sync_chans() aware of servers, so a bad server (e.g., wrong password)
-won't cause the same error message for every attached store.
-
 make SSL (connect) timeouts produce a bit more than "Unidentified socket error".
 make SSL (connect) timeouts produce a bit more than "Unidentified socket error".
 
 
 uidvalidity lock timeout handling would be a good idea.
 uidvalidity lock timeout handling would be a good idea.

+ 22 - 12
configure.ac

@@ -139,26 +139,36 @@ if test "x$ob_cv_with_sasl" != xno; then
 fi
 fi
 AC_SUBST(SASL_LIBS)
 AC_SUBST(SASL_LIBS)
 
 
-AC_CACHE_CHECK([for Berkley DB >= 4.2], ac_cv_berkdb4,
+AC_CACHE_CHECK([for Berkeley DB >= 4.1], ac_cv_berkdb4,
   [ac_cv_berkdb4=no
   [ac_cv_berkdb4=no
+    sav_LDFLAGS=$LDFLAGS
+    LDFLAGS="$LDFLAGS -ldb"
    AC_TRY_LINK([#include <db.h>],
    AC_TRY_LINK([#include <db.h>],
                [DB *db;
                [DB *db;
+	        db_create(&db, 0, 0);
 	        db->truncate(db, 0, 0, 0);
 	        db->truncate(db, 0, 0, 0);
 	        db->open(db, 0, "foo", "foo", DB_HASH, DB_CREATE, 0)],
 	        db->open(db, 0, "foo", "foo", DB_HASH, DB_CREATE, 0)],
-	       [ac_cv_berkdb4=yes])])
+	       [ac_cv_berkdb4=yes])
+    LDFLAGS=$sav_LDFLAGS
+  ])
 if test "x$ac_cv_berkdb4" = xyes; then
 if test "x$ac_cv_berkdb4" = xyes; then
   AC_SUBST([DB_LIBS], ["-ldb"])
   AC_SUBST([DB_LIBS], ["-ldb"])
-  AC_DEFINE(USE_DB, 1, [if Berkley DB should be used])
+  AC_DEFINE(USE_DB, 1, [if Berkeley DB should be used])
 fi
 fi
 
 
 have_zlib=
 have_zlib=
-AC_CHECK_LIB([z], [deflate],
-    [AC_CHECK_HEADER(zlib.h,
-        [have_zlib=1
-         AC_SUBST([Z_LIBS], ["-lz"])
-         AC_DEFINE([HAVE_LIBZ], 1, [if you have the zlib library])]
-     )]
-)
+AC_ARG_WITH(zlib,
+  AS_HELP_STRING([--with-zlib], [use zlib [detect]]),
+  [ob_cv_with_zlib=$withval])
+if test "x$ob_cv_with_zlib" != xno; then
+  AC_CHECK_LIB([z], [deflate],
+      [AC_CHECK_HEADER(zlib.h,
+          [have_zlib=1
+           AC_SUBST([Z_LIBS], ["-lz"])
+           AC_DEFINE([HAVE_LIBZ], 1, [if you have the zlib library])]
+       )]
+  )
+fi
 
 
 AC_ARG_ENABLE(compat,
 AC_ARG_ENABLE(compat,
   AC_HELP_STRING([--disable-compat], [don't include isync compatibility wrapper [no]]),
   AC_HELP_STRING([--disable-compat], [don't include isync compatibility wrapper [no]]),
@@ -189,8 +199,8 @@ else
     AC_MSG_RESULT([Not using zlib])
     AC_MSG_RESULT([Not using zlib])
 fi
 fi
 if test "x$ac_cv_berkdb4" = xyes; then
 if test "x$ac_cv_berkdb4" = xyes; then
-    AC_MSG_RESULT([Using Berkley DB])
+    AC_MSG_RESULT([Using Berkeley DB])
 else
 else
-    AC_MSG_RESULT([Not using Berkley DB])
+    AC_MSG_RESULT([Not using Berkeley DB])
 fi
 fi
 AC_MSG_RESULT()
 AC_MSG_RESULT()

+ 53 - 63
src/drv_imap.c

@@ -267,7 +267,7 @@ done_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd, int response )
 	free( cmd );
 	free( cmd );
 }
 }
 
 
-static int
+static void
 send_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd )
 send_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd )
 {
 {
 	int bufl, litplus, iovcnt = 1;
 	int bufl, litplus, iovcnt = 1;
@@ -313,8 +313,7 @@ send_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd )
 		iov[2].takeOwn = KeepOwn;
 		iov[2].takeOwn = KeepOwn;
 		iovcnt = 3;
 		iovcnt = 3;
 	}
 	}
-	if (socket_write( &ctx->conn, iov, iovcnt ) < 0)
-		goto bail;
+	socket_write( &ctx->conn, iov, iovcnt );
 	if (cmd->param.to_trash && ctx->trashnc == TrashUnknown)
 	if (cmd->param.to_trash && ctx->trashnc == TrashUnknown)
 		ctx->trashnc = TrashChecking;
 		ctx->trashnc = TrashChecking;
 	cmd->next = 0;
 	cmd->next = 0;
@@ -322,15 +321,10 @@ send_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd )
 	ctx->in_progress_append = &cmd->next;
 	ctx->in_progress_append = &cmd->next;
 	ctx->num_in_progress++;
 	ctx->num_in_progress++;
 	socket_expect_read( &ctx->conn, 1 );
 	socket_expect_read( &ctx->conn, 1 );
-	return 0;
-
-  bail:
-	done_imap_cmd( ctx, cmd, RESP_CANCEL );
-	return -1;
 }
 }
 
 
 static int
 static int
-cmd_submittable( imap_store_t *ctx, struct imap_cmd *cmd )
+cmd_sendable( imap_store_t *ctx, struct imap_cmd *cmd )
 {
 {
 	struct imap_cmd *cmdp;
 	struct imap_cmd *cmdp;
 
 
@@ -343,18 +337,16 @@ cmd_submittable( imap_store_t *ctx, struct imap_cmd *cmd )
 	       ctx->num_in_progress < ((imap_store_conf_t *)ctx->gen.conf)->server->max_in_progress;
 	       ctx->num_in_progress < ((imap_store_conf_t *)ctx->gen.conf)->server->max_in_progress;
 }
 }
 
 
-static int
+static void
 flush_imap_cmds( imap_store_t *ctx )
 flush_imap_cmds( imap_store_t *ctx )
 {
 {
 	struct imap_cmd *cmd;
 	struct imap_cmd *cmd;
 
 
-	while ((cmd = ctx->pending) && cmd_submittable( ctx, cmd )) {
+	if ((cmd = ctx->pending) && cmd_sendable( ctx, cmd )) {
 		if (!(ctx->pending = cmd->next))
 		if (!(ctx->pending = cmd->next))
 			ctx->pending_append = &ctx->pending;
 			ctx->pending_append = &ctx->pending;
-		if (send_imap_cmd( ctx, cmd ) < 0)
-			return -1;
+		send_imap_cmd( ctx, cmd );
 	}
 	}
-	return 0;
 }
 }
 
 
 static void
 static void
@@ -370,7 +362,7 @@ cancel_pending_imap_cmds( imap_store_t *ctx )
 }
 }
 
 
 static void
 static void
-cancel_submitted_imap_cmds( imap_store_t *ctx )
+cancel_sent_imap_cmds( imap_store_t *ctx )
 {
 {
 	struct imap_cmd *cmd;
 	struct imap_cmd *cmd;
 
 
@@ -382,7 +374,7 @@ cancel_submitted_imap_cmds( imap_store_t *ctx )
 	}
 	}
 }
 }
 
 
-static int
+static void
 submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd )
 submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd )
 {
 {
 	assert( ctx );
 	assert( ctx );
@@ -390,7 +382,7 @@ submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd )
 	assert( cmd );
 	assert( cmd );
 	assert( cmd->param.done );
 	assert( cmd->param.done );
 
 
-	if ((ctx->pending && !cmd->param.high_prio) || !cmd_submittable( ctx, cmd )) {
+	if ((ctx->pending && !cmd->param.high_prio) || !cmd_sendable( ctx, cmd )) {
 		if (ctx->pending && cmd->param.high_prio) {
 		if (ctx->pending && cmd->param.high_prio) {
 			cmd->next = ctx->pending;
 			cmd->next = ctx->pending;
 			ctx->pending = cmd;
 			ctx->pending = cmd;
@@ -399,10 +391,9 @@ submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd )
 			*ctx->pending_append = cmd;
 			*ctx->pending_append = cmd;
 			ctx->pending_append = &cmd->next;
 			ctx->pending_append = &cmd->next;
 		}
 		}
-		return 0;
+	} else {
+		send_imap_cmd( ctx, cmd );
 	}
 	}
-
-	return send_imap_cmd( ctx, cmd );
 }
 }
 
 
 /* Minimal printf() replacement that supports an %\s format sequence to print backslash-escaped
 /* Minimal printf() replacement that supports an %\s format sequence to print backslash-escaped
@@ -487,7 +478,7 @@ imap_vprintf( const char *fmt, va_list ap )
 	}
 	}
 }
 }
 
 
-static int
+static void
 imap_exec( imap_store_t *ctx, struct imap_cmd *cmdp,
 imap_exec( imap_store_t *ctx, struct imap_cmd *cmdp,
            void (*done)( imap_store_t *ctx, struct imap_cmd *cmd, int response ),
            void (*done)( imap_store_t *ctx, struct imap_cmd *cmd, int response ),
            const char *fmt, ... )
            const char *fmt, ... )
@@ -500,7 +491,7 @@ imap_exec( imap_store_t *ctx, struct imap_cmd *cmdp,
 	va_start( ap, fmt );
 	va_start( ap, fmt );
 	cmdp->cmd = imap_vprintf( fmt, ap );
 	cmdp->cmd = imap_vprintf( fmt, ap );
 	va_end( ap );
 	va_end( ap );
-	return submit_imap_cmd( ctx, cmdp );
+	submit_imap_cmd( ctx, cmdp );
 }
 }
 
 
 static void
 static void
@@ -1337,8 +1328,7 @@ imap_socket_read( void *aux )
 				iov[1].buf = "\r\n";
 				iov[1].buf = "\r\n";
 				iov[1].len = 2;
 				iov[1].len = 2;
 				iov[1].takeOwn = KeepOwn;
 				iov[1].takeOwn = KeepOwn;
-				if (socket_write( &ctx->conn, iov, 2 ) < 0)
-					return;
+				socket_write( &ctx->conn, iov, 2 );
 			} else if (cmdp->param.cont) {
 			} else if (cmdp->param.cont) {
 				if (cmdp->param.cont( ctx, cmdp, cmd ))
 				if (cmdp->param.cont( ctx, cmdp, cmd ))
 					return;
 					return;
@@ -1376,9 +1366,8 @@ imap_socket_read( void *aux )
 						cmd2->orig_cmd = cmdp;
 						cmd2->orig_cmd = cmdp;
 						cmd2->gen.param.high_prio = 1;
 						cmd2->gen.param.high_prio = 1;
 						p = strchr( cmdp->cmd, '"' );
 						p = strchr( cmdp->cmd, '"' );
-						if (imap_exec( ctx, &cmd2->gen, get_cmd_result_p2,
-						               "CREATE %.*s", imap_strchr( p + 1, '"' ) - p + 1, p ) < 0)
-							return;
+						imap_exec( ctx, &cmd2->gen, get_cmd_result_p2,
+						           "CREATE %.*s", imap_strchr( p + 1, '"' ) - p + 1, p );
 						continue;
 						continue;
 					}
 					}
 					resp = RESP_NO;
 					resp = RESP_NO;
@@ -1387,7 +1376,11 @@ imap_socket_read( void *aux )
 				} else /*if (!strcmp( "BAD", arg ))*/
 				} else /*if (!strcmp( "BAD", arg ))*/
 					resp = RESP_CANCEL;
 					resp = RESP_CANCEL;
 				error( "IMAP command '%s' returned an error: %s %s\n",
 				error( "IMAP command '%s' returned an error: %s %s\n",
-				       !starts_with( cmdp->cmd, -1, "LOGIN", 5 ) ? cmdp->cmd : "LOGIN <user> <pass>",
+				       starts_with( cmdp->cmd, -1, "LOGIN", 5 ) ?
+				           "LOGIN <user> <pass>" :
+				           starts_with( cmdp->cmd, -1, "AUTHENTICATE PLAIN", 18 ) ?
+				               "AUTHENTICATE PLAIN <authdata>" :
+				                cmdp->cmd,
 				       arg, cmd ? cmd : "" );
 				       arg, cmd ? cmd : "" );
 			}
 			}
 		  doresp:
 		  doresp:
@@ -1405,8 +1398,7 @@ imap_socket_read( void *aux )
 				return;
 				return;
 			}
 			}
 		}
 		}
-		if (flush_imap_cmds( ctx ) < 0)
-			return;
+		flush_imap_cmds( ctx );
 	}
 	}
 	imap_invoke_bad_callback( ctx );
 	imap_invoke_bad_callback( ctx );
 }
 }
@@ -1440,7 +1432,7 @@ imap_cancel_store( store_t *gctx )
 	sasl_dispose( &ctx->sasl );
 	sasl_dispose( &ctx->sasl );
 #endif
 #endif
 	socket_close( &ctx->conn );
 	socket_close( &ctx->conn );
-	cancel_submitted_imap_cmds( ctx );
+	cancel_sent_imap_cmds( ctx );
 	cancel_pending_imap_cmds( ctx );
 	cancel_pending_imap_cmds( ctx );
 	free_generic_messages( ctx->gen.msgs );
 	free_generic_messages( ctx->gen.msgs );
 	free_string_list( ctx->gen.boxes );
 	free_string_list( ctx->gen.boxes );
@@ -1603,7 +1595,7 @@ imap_open_store( store_conf_t *conf, const char *label,
 
 
 	socket_init( &ctx->conn, &srvc->sconf,
 	socket_init( &ctx->conn, &srvc->sconf,
 	             (void (*)( void * ))imap_invoke_bad_callback,
 	             (void (*)( void * ))imap_invoke_bad_callback,
-	             imap_socket_read, (int (*)(void *))flush_imap_cmds, ctx );
+	             imap_socket_read, (void (*)(void *))flush_imap_cmds, ctx );
 	socket_connect( &ctx->conn, imap_open_store_connected );
 	socket_connect( &ctx->conn, imap_open_store_connected );
 }
 }
 
 
@@ -1929,7 +1921,8 @@ do_sasl_auth( imap_store_t *ctx, struct imap_cmd *cmdp ATTR_UNUSED, const char *
 	iov[iovcnt].len = 2;
 	iov[iovcnt].len = 2;
 	iov[iovcnt].takeOwn = KeepOwn;
 	iov[iovcnt].takeOwn = KeepOwn;
 	iovcnt++;
 	iovcnt++;
-	return socket_write( &ctx->conn, iov, iovcnt );
+	socket_write( &ctx->conn, iov, iovcnt );
+	return 0;
 
 
   bail:
   bail:
 	imap_open_store_bail( ctx, FAIL_FINAL );
 	imap_open_store_bail( ctx, FAIL_FINAL );
@@ -2289,7 +2282,7 @@ imap_prepare_load_box( store_t *gctx, int opts )
 	gctx->opts = opts;
 	gctx->opts = opts;
 }
 }
 
 
-static int imap_submit_load( imap_store_t *, const char *, int, struct imap_cmd_refcounted_state * );
+static void imap_submit_load( imap_store_t *, const char *, int, struct imap_cmd_refcounted_state * );
 
 
 static void
 static void
 imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int *excs, int nexcs,
 imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int *excs, int nexcs,
@@ -2316,16 +2309,14 @@ imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int *excs, int
 				if (i != j)
 				if (i != j)
 					bl += sprintf( buf + bl, ":%d", excs[i] );
 					bl += sprintf( buf + bl, ":%d", excs[i] );
 			}
 			}
-			if (imap_submit_load( ctx, buf, 0, sts ) < 0)
-				goto done;
+			imap_submit_load( ctx, buf, 0, sts );
 		}
 		}
 		if (maxuid == INT_MAX)
 		if (maxuid == INT_MAX)
 			maxuid = ctx->gen.uidnext ? ctx->gen.uidnext - 1 : 1000000000;
 			maxuid = ctx->gen.uidnext ? ctx->gen.uidnext - 1 : 1000000000;
 		if (maxuid >= minuid) {
 		if (maxuid >= minuid) {
 			if ((ctx->gen.opts & OPEN_FIND) && minuid < newuid) {
 			if ((ctx->gen.opts & OPEN_FIND) && minuid < newuid) {
 				sprintf( buf, "%d:%d", minuid, newuid - 1 );
 				sprintf( buf, "%d:%d", minuid, newuid - 1 );
-				if (imap_submit_load( ctx, buf, 0, sts ) < 0)
-					goto done;
+				imap_submit_load( ctx, buf, 0, sts );
 				if (newuid > maxuid)
 				if (newuid > maxuid)
 					goto done;
 					goto done;
 				sprintf( buf, "%d:%d", newuid, maxuid );
 				sprintf( buf, "%d:%d", newuid, maxuid );
@@ -2340,14 +2331,14 @@ imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int *excs, int
 	}
 	}
 }
 }
 
 
-static int
+static void
 imap_submit_load( imap_store_t *ctx, const char *buf, int tuids, struct imap_cmd_refcounted_state *sts )
 imap_submit_load( imap_store_t *ctx, const char *buf, int tuids, struct imap_cmd_refcounted_state *sts )
 {
 {
-	return imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_refcounted_done_box,
-	                  "UID FETCH %s (UID%s%s%s)", buf,
-	                  (ctx->gen.opts & OPEN_FLAGS) ? " FLAGS" : "",
-	                  (ctx->gen.opts & OPEN_SIZE) ? " RFC822.SIZE" : "",
-	                  tuids ? " BODY.PEEK[HEADER.FIELDS (X-TUID)]" : "");
+	imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_refcounted_done_box,
+	           "UID FETCH %s (UID%s%s%s)", buf,
+	           (ctx->gen.opts & OPEN_FLAGS) ? " FLAGS" : "",
+	           (ctx->gen.opts & OPEN_SIZE) ? " RFC822.SIZE" : "",
+	           tuids ? " BODY.PEEK[HEADER.FIELDS (X-TUID)]" : "");
 }
 }
 
 
 /******************* imap_fetch_msg *******************/
 /******************* imap_fetch_msg *******************/
@@ -2404,15 +2395,15 @@ imap_make_flags( int flags, char *buf )
 	return d;
 	return d;
 }
 }
 
 
-static int
+static void
 imap_flags_helper( imap_store_t *ctx, int uid, char what, int flags,
 imap_flags_helper( imap_store_t *ctx, int uid, char what, int flags,
                    struct imap_cmd_refcounted_state *sts )
                    struct imap_cmd_refcounted_state *sts )
 {
 {
 	char buf[256];
 	char buf[256];
 
 
 	buf[imap_make_flags( flags, buf )] = 0;
 	buf[imap_make_flags( flags, buf )] = 0;
-	return imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_set_flags_p2,
-	                  "UID STORE %d %cFLAGS.SILENT %s", uid, what, buf );
+	imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_set_flags_p2,
+	           "UID STORE %d %cFLAGS.SILENT %s", uid, what, buf );
 }
 }
 
 
 static void
 static void
@@ -2430,8 +2421,10 @@ imap_set_msg_flags( store_t *gctx, message_t *msg, int uid, int add, int del,
 	}
 	}
 	if (add || del) {
 	if (add || del) {
 		struct imap_cmd_refcounted_state *sts = imap_refcounted_new_state( cb, aux );
 		struct imap_cmd_refcounted_state *sts = imap_refcounted_new_state( cb, aux );
-		if ((add && imap_flags_helper( ctx, uid, '+', add, sts ) < 0) ||
-		    (del && imap_flags_helper( ctx, uid, '-', del, sts ) < 0)) {}
+		if (add)
+			imap_flags_helper( ctx, uid, '+', add, sts );
+		if (del)
+			imap_flags_helper( ctx, uid, '-', del, sts );
 		imap_refcounted_done( sts );
 		imap_refcounted_done( sts );
 	} else {
 	} else {
 		cb( DRV_OK, aux );
 		cb( DRV_OK, aux );
@@ -2482,9 +2475,8 @@ imap_close_box( store_t *gctx,
 			}
 			}
 			if (!bl)
 			if (!bl)
 				break;
 				break;
-			if (imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_refcounted_done_box,
-			               "UID EXPUNGE %s", buf ) < 0)
-				break;
+			imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_refcounted_done_box,
+			           "UID EXPUNGE %s", buf );
 		}
 		}
 		imap_refcounted_done( sts );
 		imap_refcounted_done( sts );
 	} else {
 	} else {
@@ -2625,13 +2617,12 @@ imap_list_store( store_t *gctx, int flags,
 	imap_store_t *ctx = (imap_store_t *)gctx;
 	imap_store_t *ctx = (imap_store_t *)gctx;
 	struct imap_cmd_refcounted_state *sts = imap_refcounted_new_state( cb, aux );
 	struct imap_cmd_refcounted_state *sts = imap_refcounted_new_state( cb, aux );
 
 
-	if (((flags & LIST_PATH) && (!(flags & LIST_INBOX) || !is_inbox( ctx, ctx->prefix, -1 )) &&
-	     imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_refcounted_done_box,
-	                "LIST \"\" \"%\\s*\"", ctx->prefix ) < 0) ||
-	    ((flags & LIST_INBOX) && (!(flags & LIST_PATH) || *ctx->prefix) &&
-	     imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_refcounted_done_box,
-	                "LIST \"\" INBOX*" ) < 0))
-		{}
+	if ((flags & LIST_PATH) && (!(flags & LIST_INBOX) || !is_inbox( ctx, ctx->prefix, -1 )))
+		imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_refcounted_done_box,
+		           "LIST \"\" \"%\\s*\"", ctx->prefix );
+	if ((flags & LIST_INBOX) && (!(flags & LIST_PATH) || *ctx->prefix))
+		imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_refcounted_done_box,
+		           "LIST \"\" INBOX*" );
 	imap_refcounted_done( sts );
 	imap_refcounted_done( sts );
 }
 }
 
 
@@ -2695,8 +2686,9 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
 	/* Legacy SSL options */
 	/* Legacy SSL options */
 	int require_ssl = -1, use_imaps = -1;
 	int require_ssl = -1, use_imaps = -1;
 	int use_sslv2 = -1, use_sslv3 = -1, use_tlsv1 = -1, use_tlsv11 = -1, use_tlsv12 = -1;
 	int use_sslv2 = -1, use_sslv3 = -1, use_tlsv1 = -1, use_tlsv11 = -1, use_tlsv12 = -1;
-	int require_cram = -1;
 #endif
 #endif
+	/* Legacy SASL option */
+	int require_cram = -1;
 
 
 	if (!strcasecmp( "IMAPAccount", cfg->cmd )) {
 	if (!strcasecmp( "IMAPAccount", cfg->cmd )) {
 		server = nfcalloc( sizeof(*server) );
 		server = nfcalloc( sizeof(*server) );
@@ -2829,6 +2821,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
 			use_tlsv11 = parse_bool( cfg );
 			use_tlsv11 = parse_bool( cfg );
 		else if (!strcasecmp( "UseTLSv1.2", cfg->cmd ))
 		else if (!strcasecmp( "UseTLSv1.2", cfg->cmd ))
 			use_tlsv12 = parse_bool( cfg );
 			use_tlsv12 = parse_bool( cfg );
+#endif
 		else if (!strcasecmp( "AuthMech", cfg->cmd ) ||
 		else if (!strcasecmp( "AuthMech", cfg->cmd ) ||
 		         !strcasecmp( "AuthMechs", cfg->cmd )) {
 		         !strcasecmp( "AuthMechs", cfg->cmd )) {
 			arg = cfg->val;
 			arg = cfg->val;
@@ -2837,7 +2830,6 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
 			while ((arg = get_arg( cfg, ARG_OPTIONAL, 0 )));
 			while ((arg = get_arg( cfg, ARG_OPTIONAL, 0 )));
 		} else if (!strcasecmp( "RequireCRAM", cfg->cmd ))
 		} else if (!strcasecmp( "RequireCRAM", cfg->cmd ))
 			require_cram = parse_bool( cfg );
 			require_cram = parse_bool( cfg );
-#endif
 		else if (!strcasecmp( "Tunnel", cfg->cmd ))
 		else if (!strcasecmp( "Tunnel", cfg->cmd ))
 			server->sconf.tunnel = nfstrdup( cfg->val );
 			server->sconf.tunnel = nfstrdup( cfg->val );
 		else if (store) {
 		else if (store) {
@@ -2917,7 +2909,6 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
 				server->ssl_type = server->sconf.tunnel ? SSL_None : SSL_STARTTLS;
 				server->ssl_type = server->sconf.tunnel ? SSL_None : SSL_STARTTLS;
 		}
 		}
 #endif
 #endif
-#ifdef HAVE_LIBSSL
 		if (require_cram >= 0) {
 		if (require_cram >= 0) {
 			if (server->auth_mechs) {
 			if (server->auth_mechs) {
 				error( "%s '%s': The deprecated RequireCRAM option is mutually exlusive with AuthMech.\n", type, name );
 				error( "%s '%s': The deprecated RequireCRAM option is mutually exlusive with AuthMech.\n", type, name );
@@ -2928,7 +2919,6 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
 			if (require_cram)
 			if (require_cram)
 				add_string_list(&server->auth_mechs, "CRAM-MD5");
 				add_string_list(&server->auth_mechs, "CRAM-MD5");
 		}
 		}
-#endif
 		if (!server->auth_mechs)
 		if (!server->auth_mechs)
 			add_string_list( &server->auth_mechs, "*" );
 			add_string_list( &server->auth_mechs, "*" );
 		if (!server->sconf.port)
 		if (!server->sconf.port)

+ 48 - 48
src/mbsync.1

@@ -192,17 +192,17 @@ See \fBRECOMMENDATIONS\fR and \fBINHERENT PROBLEMS\fR below.
 (Default: none)
 (Default: none)
 ..
 ..
 .TP
 .TP
-\fBTrashNewOnly\fR \fIyes\fR|\fIno\fR
+\fBTrashNewOnly\fR \fByes\fR|\fBno\fR
 When trashing, copy only not yet propagated messages. This makes sense if the
 When trashing, copy only not yet propagated messages. This makes sense if the
-remote Store has a \fBTrash\fR as well (with \fBTrashNewOnly\fR \fIno\fR).
-(Default: \fIno\fR)
+remote Store has a \fBTrash\fR as well (with \fBTrashNewOnly\fR \fBno\fR).
+(Default: \fBno\fR)
 ..
 ..
 .TP
 .TP
-\fBTrashRemoteNew\fR \fIyes\fR|\fIno\fR
+\fBTrashRemoteNew\fR \fByes\fR|\fBno\fR
 When expunging the remote Store, copy not yet propagated messages to this
 When expunging the remote Store, copy not yet propagated messages to this
 Store's \fBTrash\fR. When using this, the remote Store does not need an own
 Store's \fBTrash\fR. When using this, the remote Store does not need an own
 \fBTrash\fR at all, yet all messages are archived.
 \fBTrash\fR at all, yet all messages are archived.
-(Default: \fIno\fR)
+(Default: \fBno\fR)
 ..
 ..
 .SS Maildir Stores
 .SS Maildir Stores
 The reference point for relative \fBPath\fRs is the current working directory.
 The reference point for relative \fBPath\fRs is the current working directory.
@@ -237,11 +237,11 @@ Use \fBmdconvert\fR to convert mailboxes from one scheme to the other.
 Define the Maildir Store \fIname\fR, opening a section for its parameters.
 Define the Maildir Store \fIname\fR, opening a section for its parameters.
 ..
 ..
 .TP
 .TP
-\fBAltMap\fR \fIyes\fR|\fIno\fR
+\fBAltMap\fR \fByes\fR|\fBno\fR
 Use the \fBalternative\fR UID storage scheme for mailboxes in this Store.
 Use the \fBalternative\fR UID storage scheme for mailboxes in this Store.
 This does not affect mailboxes that do already have a UID storage scheme;
 This does not affect mailboxes that do already have a UID storage scheme;
 use \fBmdconvert\fR to change it.
 use \fBmdconvert\fR to change it.
-(Default: \fIno\fR)
+(Default: \fBno\fR)
 ..
 ..
 .TP
 .TP
 \fBInbox\fR \fIpath\fR
 \fBInbox\fR \fIpath\fR
@@ -286,7 +286,7 @@ Define the IMAP4 Account \fIname\fR, opening a section for its parameters.
 Specify the DNS name or IP address of the IMAP server.
 Specify the DNS name or IP address of the IMAP server.
 .br
 .br
 If \fBTunnel\fR is used, this setting is needed only if \fBSSLType\fR is
 If \fBTunnel\fR is used, this setting is needed only if \fBSSLType\fR is
-not \fINone\fR and \fBCertificateFile\fR is not used,
+not \fBNone\fR and \fBCertificateFile\fR is not used,
 in which case the host name is used for certificate subject verification.
 in which case the host name is used for certificate subject verification.
 ..
 ..
 .TP
 .TP
@@ -309,7 +309,7 @@ Specify the login name on the IMAP server.
 .TP
 .TP
 \fBPass\fR \fIpassword\fR
 \fBPass\fR \fIpassword\fR
 Specify the password for \fIusername\fR on the IMAP server.
 Specify the password for \fIusername\fR on the IMAP server.
-Note that this option is \fBNOT\fR required.
+Note that this option is \fInot\fR required.
 If neither a password nor a password command is specified in the
 If neither a password nor a password command is specified in the
 configuration file, \fBmbsync\fR will prompt you for a password.
 configuration file, \fBmbsync\fR will prompt you for a password.
 ..
 ..
@@ -341,21 +341,21 @@ of this list, the list supplied by the server, and the installed SASL modules.
 (Default: \fB*\fR)
 (Default: \fB*\fR)
 ..
 ..
 .TP
 .TP
-\fBSSLType\fR {\fINone\fR|\fISTARTTLS\fR|\fIIMAPS\fR}
+\fBSSLType\fR {\fBNone\fR|\fBSTARTTLS\fR|\fBIMAPS\fR}
 Select the connection security/encryption method:
 Select the connection security/encryption method:
 .br
 .br
-\fINone\fR - no security.
+\fBNone\fR - no security.
 This is the default when \fBTunnel\fR is set, as tunnels are usually secure.
 This is the default when \fBTunnel\fR is set, as tunnels are usually secure.
 .br
 .br
-\fISTARTTLS\fR - security is established via the STARTTLS extension
+\fBSTARTTLS\fR - security is established via the STARTTLS extension
 after connecting the regular IMAP port 143. Most servers support this,
 after connecting the regular IMAP port 143. Most servers support this,
 so it is the default (unless a tunnel is used).
 so it is the default (unless a tunnel is used).
 .br
 .br
-\fIIMAPS\fR - security is established by starting SSL/TLS negotiation
+\fBIMAPS\fR - security is established by starting SSL/TLS negotiation
 right after connecting the secure IMAP port 993.
 right after connecting the secure IMAP port 993.
 ..
 ..
 .TP
 .TP
-\fBSSLVersions\fR [\fISSLv2\fR] [\fISSLv3\fR] [\fITLSv1\fR] [\fITLSv1.1\fR] [\fITLSv1.2\fR]
+\fBSSLVersions\fR [\fBSSLv2\fR] [\fBSSLv3\fR] [\fBTLSv1\fR] [\fBTLSv1.1\fR] [\fBTLSv1.2\fR]
 Select the acceptable SSL/TLS versions.
 Select the acceptable SSL/TLS versions.
 Use of SSLv2 is strongly discouraged for security reasons, but might be the
 Use of SSLv2 is strongly discouraged for security reasons, but might be the
 only option on some very old servers.
 only option on some very old servers.
@@ -363,9 +363,9 @@ Generally, the newest TLS version is recommended, but as this confuses some
 servers, \fBTLSv1\fR is the default.
 servers, \fBTLSv1\fR is the default.
 ..
 ..
 .TP
 .TP
-\fBSystemCertificates\fR \fIyes\fR|\fIno\fR
+\fBSystemCertificates\fR \fByes\fR|\fBno\fR
 Whether the system's default root cerificate store should be loaded.
 Whether the system's default root cerificate store should be loaded.
-(Default: \fIyes\fR)
+(Default: \fByes\fR)
 ..
 ..
 .TP
 .TP
 \fBCertificateFile\fR \fIpath\fR
 \fBCertificateFile\fR \fIpath\fR
@@ -407,18 +407,18 @@ directly in the Store's section - this makes sense if an Account is used for
 one Store only anyway.
 one Store only anyway.
 ..
 ..
 .TP
 .TP
-\fBUseNamespace\fR \fIyes\fR|\fIno\fR
+\fBUseNamespace\fR \fByes\fR|\fBno\fR
 Selects whether the server's first "personal" NAMESPACE should be prefixed to
 Selects whether the server's first "personal" NAMESPACE should be prefixed to
 mailbox names. Disabling this makes sense for some broken IMAP servers.
 mailbox names. Disabling this makes sense for some broken IMAP servers.
 This option is meaningless if a \fBPath\fR was specified.
 This option is meaningless if a \fBPath\fR was specified.
-(Default: \fIyes\fR)
+(Default: \fByes\fR)
 ..
 ..
 .TP
 .TP
 \fBPathDelimiter\fR \fIdelim\fR
 \fBPathDelimiter\fR \fIdelim\fR
 Specify the server's hierarchy delimiter.
 Specify the server's hierarchy delimiter.
 (Default: taken from the server's first "personal" NAMESPACE)
 (Default: taken from the server's first "personal" NAMESPACE)
 .br
 .br
-Do \fBNOT\fR abuse this to re-interpret the hierarchy.
+Do \fInot\fR abuse this to re-interpret the hierarchy.
 Use \fBFlatten\fR instead.
 Use \fBFlatten\fR instead.
 ..
 ..
 .SS Channels
 .SS Channels
@@ -471,56 +471,56 @@ If \fIcount\fR is 0, the maximum number of messages is \fBunlimited\fR
 (Default: \fI0\fR).
 (Default: \fI0\fR).
 ..
 ..
 .TP
 .TP
-\fBExpireUnread\fR \fIyes\fR|\fIno\fR
+\fBExpireUnread\fR \fByes\fR|\fBno\fR
 Selects whether unread messages should be affected by \fBMaxMessages\fR.
 Selects whether unread messages should be affected by \fBMaxMessages\fR.
 Normally, unread messages are considered important and thus never expired.
 Normally, unread messages are considered important and thus never expired.
 This ensures that you never miss new messages even after an extended absence.
 This ensures that you never miss new messages even after an extended absence.
 However, if your archive contains large amounts of unread messages by design,
 However, if your archive contains large amounts of unread messages by design,
 treating them as important would practically defeat \fBMaxMessages\fR. In this
 treating them as important would practically defeat \fBMaxMessages\fR. In this
 case you need to enable this option.
 case you need to enable this option.
-(Default: \fIno\fR).
+(Default: \fBno\fR).
 ..
 ..
 .TP
 .TP
-\fBSync\fR {\fINone\fR|[\fIPull\fR] [\fIPush\fR] [\fINew\fR] [\fIReNew\fR] [\fIDelete\fR] [\fIFlags\fR]|\fIAll\fR}
+\fBSync\fR {\fBNone\fR|[\fBPull\fR] [\fBPush\fR] [\fBNew\fR] [\fBReNew\fR] [\fBDelete\fR] [\fBFlags\fR]|\fBAll\fR}
 Select the synchronization operation(s) to perform:
 Select the synchronization operation(s) to perform:
 .br
 .br
-\fIPull\fR - propagate changes from Master to Slave.
+\fBPull\fR - propagate changes from Master to Slave.
 .br
 .br
-\fIPush\fR - propagate changes from Slave to Master.
+\fBPush\fR - propagate changes from Slave to Master.
 .br
 .br
-\fINew\fR - propagate newly appeared messages.
+\fBNew\fR - propagate newly appeared messages.
 .br
 .br
-\fIReNew\fR - previously refused messages are re-evaluated for propagation.
+\fBReNew\fR - previously refused messages are re-evaluated for propagation.
 Useful after flagging affected messages in the source Store or enlarging
 Useful after flagging affected messages in the source Store or enlarging
 MaxSize in the destination Store.
 MaxSize in the destination Store.
 .br
 .br
-\fIDelete\fR - propagate message deletions. This applies only to messages that
+\fBDelete\fR - propagate message deletions. This applies only to messages that
 are actually gone, i.e., were expunged. The affected messages in the remote
 are actually gone, i.e., were expunged. The affected messages in the remote
 Store are marked as deleted only, i.e., they won't be really deleted until
 Store are marked as deleted only, i.e., they won't be really deleted until
 that Store is expunged.
 that Store is expunged.
 .br
 .br
-\fIFlags\fR - propagate flag changes. Note that Deleted/Trashed is a flag as
+\fBFlags\fR - propagate flag changes. Note that Deleted/Trashed is a flag as
 well; this is particularly interesting if you use \fBmutt\fR with the
 well; this is particularly interesting if you use \fBmutt\fR with the
 maildir_trash option.
 maildir_trash option.
 .br
 .br
-\fIAll\fR (\fB--full\fR on the command line) - all of the above.
+\fBAll\fR (\fB--full\fR on the command line) - all of the above.
 This is the global default.
 This is the global default.
 .br
 .br
-\fINone\fR (\fB--noop\fR on the command line) - don't propagate anything.
+\fBNone\fR (\fB--noop\fR on the command line) - don't propagate anything.
 Useful if you want to expunge only.
 Useful if you want to expunge only.
 .IP
 .IP
-\fIPull\fR and \fIPush\fR are direction flags, while \fINew\fR, \fIReNew\fR,
-\fIDelete\fR and \fIFlags\fR are type flags. The two flag classes make up a
+\fBPull\fR and \fBPush\fR are direction flags, while \fBNew\fR, \fBReNew\fR,
+\fBDelete\fR and \fBFlags\fR are type flags. The two flag classes make up a
 two-dimensional matrix (a table). Its cells are the individual actions to
 two-dimensional matrix (a table). Its cells are the individual actions to
 perform. There are two styles of asserting the cells:
 perform. There are two styles of asserting the cells:
 .br
 .br
 In the first style, the flags select entire rows/colums in the matrix. Only
 In the first style, the flags select entire rows/colums in the matrix. Only
 the cells which are selected both horizontally and vertically are asserted.
 the cells which are selected both horizontally and vertically are asserted.
 Specifying no flags from a class is like specifying all flags from this class.
 Specifying no flags from a class is like specifying all flags from this class.
-For example, "\fBSync\fR\ \fIPull\fR\ \fINew\fR\ \fIFlags\fR" will propagate
+For example, "\fBSync\fR\ \fBPull\fR\ \fBNew\fR\ \fBFlags\fR" will propagate
 new messages and flag changes from the Master to the Slave,
 new messages and flag changes from the Master to the Slave,
-"\fBSync\fR\ \fINew\fR\ \fIDelete\fR" will propagate message arrivals and
-deletions both ways, and "\fBSync\fR\ \fIPush\fR" will propagate all changes
+"\fBSync\fR\ \fBNew\fR\ \fBDelete\fR" will propagate message arrivals and
+deletions both ways, and "\fBSync\fR\ \fBPush\fR" will propagate all changes
 from the Slave to the Master.
 from the Slave to the Master.
 .br
 .br
 In the second style, direction flags are concatenated with type flags; every
 In the second style, direction flags are concatenated with type flags; every
@@ -528,22 +528,22 @@ compound flag immediately asserts a cell in the matrix. In addition to at least
 one compound flag, the individual flags can be used as well, but as opposed to
 one compound flag, the individual flags can be used as well, but as opposed to
 the first style, they immediately assert all cells in their respective
 the first style, they immediately assert all cells in their respective
 row/column. For example,
 row/column. For example,
-"\fBSync\fR\ \fIPullNew\fR\ \fIPullDelete\fR\ \fIPush\fR" will propagate
+"\fBSync\fR\ \fBPullNew\fR\ \fBPullDelete\fR\ \fBPush\fR" will propagate
 message arrivals and deletions from the Master to the Slave and any changes
 message arrivals and deletions from the Master to the Slave and any changes
 from the Slave to the Master.
 from the Slave to the Master.
 Note that it is not allowed to assert a cell in two ways, e.g.
 Note that it is not allowed to assert a cell in two ways, e.g.
-"\fBSync\fR\ \fIPullNew\fR\ \fIPull\fR" and
-"\fBSync\fR\ \fIPullNew\fR\ \fIDelete\fR\ \fIPush\fR" induce error messages.
+"\fBSync\fR\ \fBPullNew\fR\ \fBPull\fR" and
+"\fBSync\fR\ \fBPullNew\fR\ \fBDelete\fR\ \fBPush\fR" induce error messages.
 ..
 ..
 .TP
 .TP
-\fBCreate\fR {\fINone\fR|\fIMaster\fR|\fISlave\fR|\fIBoth\fR}
+\fBCreate\fR {\fBNone\fR|\fBMaster\fR|\fBSlave\fR|\fBBoth\fR}
 Automatically create missing mailboxes [on the Master/Slave].
 Automatically create missing mailboxes [on the Master/Slave].
 Otherwise print an error message and skip that mailbox pair if a mailbox
 Otherwise print an error message and skip that mailbox pair if a mailbox
 and the corresponding sync state does not exist.
 and the corresponding sync state does not exist.
-(Global default: \fINone\fR)
+(Global default: \fBNone\fR)
 ..
 ..
 .TP
 .TP
-\fBRemove\fR {\fINone\fR|\fIMaster\fR|\fISlave\fR|\fIBoth\fR}
+\fBRemove\fR {\fBNone\fR|\fBMaster\fR|\fBSlave\fR|\fBBoth\fR}
 Propagate mailbox deletions [to the Master/Slave].
 Propagate mailbox deletions [to the Master/Slave].
 Otherwise print an error message and skip that mailbox pair if a mailbox
 Otherwise print an error message and skip that mailbox pair if a mailbox
 does not exist but the corresponding sync state does.
 does not exist but the corresponding sync state does.
@@ -553,23 +553,23 @@ mark them as deleted. This ensures compatibility with \fBSyncState *\fR.
 .br
 .br
 Note that for safety, non-empty mailboxes are never deleted.
 Note that for safety, non-empty mailboxes are never deleted.
 .br
 .br
-(Global default: \fINone\fR)
+(Global default: \fBNone\fR)
 ..
 ..
 .TP
 .TP
-\fBExpunge\fR {\fINone\fR|\fIMaster\fR|\fISlave\fR|\fIBoth\fR}
+\fBExpunge\fR {\fBNone\fR|\fBMaster\fR|\fBSlave\fR|\fBBoth\fR}
 Permanently remove all messages [on the Master/Slave] marked for deletion.
 Permanently remove all messages [on the Master/Slave] marked for deletion.
 See \fBRECOMMENDATIONS\fR below.
 See \fBRECOMMENDATIONS\fR below.
-(Global default: \fINone\fR)
+(Global default: \fBNone\fR)
 ..
 ..
 .TP
 .TP
-\fBCopyArrivalDate\fR {\fIyes\fR|\fIno\fR}
+\fBCopyArrivalDate\fR {\fByes\fR|\fBno\fR}
 Selects whether their arrival time should be propagated together with
 Selects whether their arrival time should be propagated together with
 the messages.
 the messages.
 Enabling this makes sense in order to keep the time stamp based message
 Enabling this makes sense in order to keep the time stamp based message
 sorting intact.
 sorting intact.
 Note that IMAP does not guarantee that the time stamp (termed \fBinternal
 Note that IMAP does not guarantee that the time stamp (termed \fBinternal
 date\fR) is actually the arrival time, but it is usually close enough.
 date\fR) is actually the arrival time, but it is usually close enough.
-(Default: \fIno\fR)
+(Default: \fBno\fR)
 ..
 ..
 .P
 .P
 \fBSync\fR, \fBCreate\fR, \fBRemove\fR, \fBExpunge\fR,
 \fBSync\fR, \fBCreate\fR, \fBRemove\fR, \fBExpunge\fR,
@@ -615,7 +615,7 @@ times within a Group.
 ..
 ..
 .SS Global Options
 .SS Global Options
 .TP
 .TP
-\fBFSync\fR \fIyes\fR|\fIno\fR
+\fBFSync\fR \fByes\fR|\fBno\fR
 .br
 .br
 Selects whether \fBmbsync\fR performs forced flushing, which determines
 Selects whether \fBmbsync\fR performs forced flushing, which determines
 the level of data safety after system crashes and power outages.
 the level of data safety after system crashes and power outages.
@@ -624,7 +624,7 @@ data=ordered mode.
 Enabling it is a wise choice for file systems mounted with data=writeback,
 Enabling it is a wise choice for file systems mounted with data=writeback,
 in particular modern systems like ext4, btrfs and xfs. The performance impact
 in particular modern systems like ext4, btrfs and xfs. The performance impact
 on older file systems may be disproportionate.
 on older file systems may be disproportionate.
-(Default: \fIyes\fR)
+(Default: \fByes\fR)
 ..
 ..
 .TP
 .TP
 \fBFieldDelimiter\fR \fIdelim\fR
 \fBFieldDelimiter\fR \fIdelim\fR

+ 16 - 19
src/socket.c

@@ -80,7 +80,7 @@ ssl_return( const char *func, conn_t *conn, int ret )
 				/* Callers take the short path out, so signal higher layers from here. */
 				/* Callers take the short path out, so signal higher layers from here. */
 				conn->state = SCK_EOF;
 				conn->state = SCK_EOF;
 				conn->read_callback( conn->callback_aux );
 				conn->read_callback( conn->callback_aux );
-				return 0;
+				return -1;
 			}
 			}
 			sys_error( "Socket error: secure %s %s", func, conn->name );
 			sys_error( "Socket error: secure %s %s", func, conn->name );
 		} else {
 		} else {
@@ -771,6 +771,7 @@ do_queued_write( conn_t *conn )
 			return -1;
 			return -1;
 		if (n != len) {
 		if (n != len) {
 			conn->write_offset += n;
 			conn->write_offset += n;
+			conn->writing = 1;
 			return 0;
 			return 0;
 		}
 		}
 		conn->write_offset = 0;
 		conn->write_offset = 0;
@@ -780,7 +781,9 @@ do_queued_write( conn_t *conn )
 	if (conn->ssl && SSL_pending( conn->ssl ))
 	if (conn->ssl && SSL_pending( conn->ssl ))
 		conf_wakeup( &conn->ssl_fake, 0 );
 		conf_wakeup( &conn->ssl_fake, 0 );
 #endif
 #endif
-	return conn->write_callback( conn->callback_aux );
+	conn->writing = 0;
+	conn->write_callback( conn->callback_aux );
+	return -1;
 }
 }
 
 
 static void
 static void
@@ -803,6 +806,8 @@ do_flush( conn_t *conn )
 #ifdef HAVE_LIBZ
 #ifdef HAVE_LIBZ
 	if (conn->out_z) {
 	if (conn->out_z) {
 		int buf_avail = conn->append_avail;
 		int buf_avail = conn->append_avail;
+		if (!conn->z_written)
+			return;
 		do {
 		do {
 			if (!bc) {
 			if (!bc) {
 				buf_avail = WRITE_CHUNK_SIZE;
 				buf_avail = WRITE_CHUNK_SIZE;
@@ -828,6 +833,7 @@ do_flush( conn_t *conn )
 		} while (!conn->out_z->avail_out);
 		} while (!conn->out_z->avail_out);
 		conn->append_buf = bc;
 		conn->append_buf = bc;
 		conn->append_avail = buf_avail;
 		conn->append_avail = buf_avail;
+		conn->z_written = 0;
 	} else
 	} else
 #endif
 #endif
 	if (bc) {
 	if (bc) {
@@ -839,15 +845,15 @@ do_flush( conn_t *conn )
 	}
 	}
 }
 }
 
 
-int
+void
 socket_write( conn_t *conn, conn_iovec_t *iov, int iovcnt )
 socket_write( conn_t *conn, conn_iovec_t *iov, int iovcnt )
 {
 {
 	int i, buf_avail, len, offset = 0, total = 0;
 	int i, buf_avail, len, offset = 0, total = 0;
-	buff_chunk_t *bc, *exwb = conn->write_buf;
+	buff_chunk_t *bc;
 
 
 	for (i = 0; i < iovcnt; i++)
 	for (i = 0; i < iovcnt; i++)
 		total += iov[i].len;
 		total += iov[i].len;
-	if (total >= WRITE_CHUNK_SIZE && pending_wakeup( &conn->fd_fake )) {
+	if (total >= WRITE_CHUNK_SIZE) {
 		/* If the new data is too big, queue the pending buffer to avoid latency. */
 		/* If the new data is too big, queue the pending buffer to avoid latency. */
 		do_flush( conn );
 		do_flush( conn );
 	}
 	}
@@ -886,6 +892,7 @@ socket_write( conn_t *conn, conn_iovec_t *iov, int iovcnt )
 				bc->len = (char *)conn->out_z->next_out - bc->data;
 				bc->len = (char *)conn->out_z->next_out - bc->data;
 				buf_avail = conn->out_z->avail_out;
 				buf_avail = conn->out_z->avail_out;
 				len -= conn->out_z->avail_in;
 				len -= conn->out_z->avail_in;
+				conn->z_written = 1;
 			} else
 			} else
 #endif
 #endif
 			{
 			{
@@ -914,17 +921,7 @@ socket_write( conn_t *conn, conn_iovec_t *iov, int iovcnt )
 #ifdef HAVE_LIBZ
 #ifdef HAVE_LIBZ
 	conn->append_avail = buf_avail;
 	conn->append_avail = buf_avail;
 #endif
 #endif
-	/* Queue the pending write once the main loop goes idle. */
-	conf_wakeup( &conn->fd_fake,
-#ifdef HAVE_LIBZ
-	             /* Always give zlib a chance to flush its internal buffer. */
-	             conn->out_z ||
-#endif
-	             bc ? 0 : -1 );
-	/* If no writes were queued before, ensure that flushing commences. */
-	if (!exwb)
-		return do_queued_write( conn );
-	return 0;
+	conf_wakeup( &conn->fd_fake, 0 );
 }
 }
 
 
 static void
 static void
@@ -979,10 +976,10 @@ socket_fake_cb( void *aux )
 {
 {
 	conn_t *conn = (conn_t *)aux;
 	conn_t *conn = (conn_t *)aux;
 
 
-	buff_chunk_t *exwb = conn->write_buf;
+	/* Ensure that a pending write gets queued. */
 	do_flush( conn );
 	do_flush( conn );
-	/* If no writes were queued before, ensure that flushing commences. */
-	if (!exwb)
+	/* If no writes are ongoing, start writing now. */
+	if (!conn->writing)
 		do_queued_write( conn );
 		do_queued_write( conn );
 }
 }
 
 

+ 5 - 3
src/socket.h

@@ -84,11 +84,12 @@ typedef struct {
 #ifdef HAVE_LIBZ
 #ifdef HAVE_LIBZ
 	z_streamp in_z, out_z;
 	z_streamp in_z, out_z;
 	wakeup_t z_fake;
 	wakeup_t z_fake;
+	int z_written;
 #endif
 #endif
 
 
 	void (*bad_callback)( void *aux ); /* async fail while sending or listening */
 	void (*bad_callback)( void *aux ); /* async fail while sending or listening */
 	void (*read_callback)( void *aux ); /* data available for reading */
 	void (*read_callback)( void *aux ); /* data available for reading */
-	int (*write_callback)( void *aux ); /* all *queued* data was sent */
+	void (*write_callback)( void *aux ); /* all *queued* data was sent */
 	union {
 	union {
 		void (*connect)( int ok, void *aux );
 		void (*connect)( int ok, void *aux );
 		void (*starttls)( int ok, void *aux );
 		void (*starttls)( int ok, void *aux );
@@ -102,6 +103,7 @@ typedef struct {
 	/* writing */
 	/* writing */
 	buff_chunk_t *append_buf; /* accumulating buffer */
 	buff_chunk_t *append_buf; /* accumulating buffer */
 	buff_chunk_t *write_buf, **write_buf_append; /* buffer head & tail */
 	buff_chunk_t *write_buf, **write_buf_append; /* buffer head & tail */
+	int writing;
 #ifdef HAVE_LIBZ
 #ifdef HAVE_LIBZ
 	int append_avail; /* space left in accumulating buffer */
 	int append_avail; /* space left in accumulating buffer */
 #endif
 #endif
@@ -123,7 +125,7 @@ static INLINE void socket_init( conn_t *conn,
                                 const server_conf_t *conf,
                                 const server_conf_t *conf,
                                 void (*bad_callback)( void *aux ),
                                 void (*bad_callback)( void *aux ),
                                 void (*read_callback)( void *aux ),
                                 void (*read_callback)( void *aux ),
-                                int (*write_callback)( void *aux ),
+                                void (*write_callback)( void *aux ),
                                 void *aux )
                                 void *aux )
 {
 {
 	conn->conf = conf;
 	conn->conf = conf;
@@ -148,6 +150,6 @@ typedef struct conn_iovec {
 	int len;
 	int len;
 	ownership_t takeOwn;
 	ownership_t takeOwn;
 } conn_iovec_t;
 } conn_iovec_t;
-int socket_write( conn_t *sock, conn_iovec_t *iov, int iovcnt );
+void socket_write( conn_t *sock, conn_iovec_t *iov, int iovcnt );
 
 
 #endif
 #endif