diff --git a/TODO b/TODO
index 95355fffe946a2b06ced0a1300d746b62d07345f..6a1f322c1c9b94619d75bdb3fe4c49491ec89c13 100644
--- a/TODO
+++ b/TODO
@@ -10,8 +10,6 @@ Current activities:
 
 Next (in order of descending priority/precedence):
 
-* Enforce ManageSieve protocol syntax better with some of the commands. Some 
-  commands still allow spurious extra arguments.
 * Code cleanup:
 	- Review all FIXMEs 
 
diff --git a/src/managesieve/cmd-capability.c b/src/managesieve/cmd-capability.c
index 38761610cfb1b9a319532a566a64e72f0648d0e8..33638f6587049f1696e323b2bafe538c62fb16f6 100644
--- a/src/managesieve/cmd-capability.c
+++ b/src/managesieve/cmd-capability.c
@@ -17,6 +17,10 @@ bool cmd_capability(struct client_command_context *cmd)
 	const char *sievecap, *notifycap;
 	unsigned int max_redirects;
 
+	/* no arguments */
+	if ( !client_read_no_args(cmd) )
+		return FALSE;
+
 	o_stream_cork(client->output);
 
 	T_BEGIN {
diff --git a/src/managesieve/cmd-deletescript.c b/src/managesieve/cmd-deletescript.c
index 60b3fec6083e51f812c1dfc7fbeaa475829c75a4..414f5b721f3af63826c18f72a5c2e1ddb9bf41f7 100644
--- a/src/managesieve/cmd-deletescript.c
+++ b/src/managesieve/cmd-deletescript.c
@@ -17,7 +17,7 @@ bool cmd_deletescript(struct client_command_context *cmd)
 	struct sieve_script *script;
 
 	/* <scrip name>*/
-	if (!client_read_string_args(cmd, 1, &scriptname))
+	if ( !client_read_string_args(cmd, 1, TRUE, &scriptname) )
 		return FALSE;
 
 	script = sieve_storage_script_init(storage, scriptname);
diff --git a/src/managesieve/cmd-getscript.c b/src/managesieve/cmd-getscript.c
index 570032c573edf050cedd0bcf93dafe8fcfa19870..cb1653d2cbcf12f633c62f8be1ab0b9cd6911faf 100644
--- a/src/managesieve/cmd-getscript.c
+++ b/src/managesieve/cmd-getscript.c
@@ -90,7 +90,7 @@ bool cmd_getscript(struct client_command_context *cmd)
 	enum sieve_error error;
 
 	/* <scriptname> */
-	if (!client_read_string_args(cmd, 1, &scriptname))
+	if ( !client_read_string_args(cmd, 1, TRUE, &scriptname) )
 		return FALSE;
 
 	ctx = p_new(cmd->pool, struct cmd_getscript_context, 1);
diff --git a/src/managesieve/cmd-havespace.c b/src/managesieve/cmd-havespace.c
index 0a51260b33d495732b48b9e2baefb00e6ec33590..7fec4a9a223e714e550a26426be8a6a0a9073ec7 100644
--- a/src/managesieve/cmd-havespace.c
+++ b/src/managesieve/cmd-havespace.c
@@ -20,17 +20,11 @@ bool cmd_havespace(struct client_command_context *cmd)
 	struct managesieve_arg *args;
 	const char *scriptname;
 	uoff_t size;
-	int ret;
 
 	/* <scriptname> <size> */
-	if (!(ret=client_read_args(cmd, 2, 0, &args)))
+	if ( !client_read_args(cmd, 2, 0, TRUE, &args) )
 	  return FALSE;
 
-	if ( ret > 2 ) {
-		client_send_no(client, "Too many arguments");
-		return TRUE;
-	}
-
 	if ( (scriptname = managesieve_arg_string(&args[0])) == NULL ) {
 		client_send_no(client, "Invalid string for scriptname.");
 		return TRUE;
diff --git a/src/managesieve/cmd-listscripts.c b/src/managesieve/cmd-listscripts.c
index 7737bfdb5b84ded6c69fc1fdd403a3343df91cef..363f26bad9decad0f5a51d57bcfe8c81a6b2fa36 100644
--- a/src/managesieve/cmd-listscripts.c
+++ b/src/managesieve/cmd-listscripts.c
@@ -20,6 +20,10 @@ bool cmd_listscripts(struct client_command_context *cmd)
 	bool active;
 	string_t *str;
 
+	/* no arguments */
+	if ( !client_read_no_args(cmd) )
+		return FALSE;
+
 	if ( (ctx = sieve_storage_list_init(client->storage))
 		== NULL ) {
 		client_send_storage_error(client, client->storage);
diff --git a/src/managesieve/cmd-logout.c b/src/managesieve/cmd-logout.c
index 996ea799790ca34a22bff4ff35088b8182009cd5..8949511ae600e4326bd8fca5234b95057317f099 100644
--- a/src/managesieve/cmd-logout.c
+++ b/src/managesieve/cmd-logout.c
@@ -11,6 +11,10 @@ bool cmd_logout(struct client_command_context *cmd)
 {
 	struct client *client = cmd->client;
 
+	/* no arguments */
+	if ( !client_read_no_args(cmd) )
+		return FALSE;
+
 	client_send_line(client, "OK \"Logout completed.\"");
 	client_disconnect(client, "Logged out");
 	return TRUE;
diff --git a/src/managesieve/cmd-noop.c b/src/managesieve/cmd-noop.c
index 5cc34a3888d140e961bb35705a984b359974d086..26cf914ee72425a78fbc68c8eafba3ac3ee81c18 100644
--- a/src/managesieve/cmd-noop.c
+++ b/src/managesieve/cmd-noop.c
@@ -17,17 +17,11 @@ bool cmd_noop(struct client_command_context *cmd)
 	struct managesieve_arg *args;
 	const char *text;
 	string_t *resp_code;
-	int ret;
 
 	/* [<echo string>] */
-	if (!(ret=client_read_args(cmd, 0, 0, &args)))
+	if ( !client_read_args(cmd, 0, 0, FALSE, &args) )
 		return FALSE;
 
-	if ( ret > 1 ) {
-		client_send_no(client, "Too many arguments");
-		return TRUE;
-	}
-
 	if ( args[0].type == MANAGESIEVE_ARG_EOL ) {
 		client_send_ok(client, "NOOP Completed");
 		return TRUE;
@@ -38,6 +32,11 @@ bool cmd_noop(struct client_command_context *cmd)
 		return TRUE;
 	}
 
+	if ( args[1].type != MANAGESIEVE_ARG_EOL ) {
+		client_send_command_error(cmd, "Too many arguments.");
+		return TRUE;
+	}
+
 	resp_code = t_str_new(256);
 	str_append(resp_code, "TAG ");
 	managesieve_quote_append_string(resp_code, text, FALSE);
diff --git a/src/managesieve/cmd-renamescript.c b/src/managesieve/cmd-renamescript.c
index 5ebc378bcb16c8a7eea4e5f11a5c10302429bbc3..57edac30bec2b800ef58efdf1783ca97211d998f 100644
--- a/src/managesieve/cmd-renamescript.c
+++ b/src/managesieve/cmd-renamescript.c
@@ -18,7 +18,7 @@ bool cmd_renamescript(struct client_command_context *cmd)
 	struct sieve_script *script;
 
 	/* <oldname> <newname> */
-	if (!client_read_string_args(cmd, 2, &scriptname, &newname))
+	if (!client_read_string_args(cmd, 2, TRUE, &scriptname, &newname))
 		return FALSE;
 
 	script = sieve_storage_script_init(storage, scriptname);
diff --git a/src/managesieve/cmd-setactive.c b/src/managesieve/cmd-setactive.c
index 288d99d2a550ac66f0f5f1adab83ca92fb3c49b9..ce34ad135322fabb03fa398bd59d4f95823d650c 100644
--- a/src/managesieve/cmd-setactive.c
+++ b/src/managesieve/cmd-setactive.c
@@ -18,7 +18,7 @@ bool cmd_setactive(struct client_command_context *cmd)
 	int ret;
 
 	/* <scriptname> */
-	if (!client_read_string_args(cmd, 1, &scriptname))
+	if ( !client_read_string_args(cmd, 1, TRUE, &scriptname) )
 		return FALSE;
 
 	if ( *scriptname != '\0' ) {
diff --git a/src/managesieve/managesieve-client.c b/src/managesieve/managesieve-client.c
index e505f8750245f32cf766e302d70e25dec177c8a6..be8db57864e7f72c2b1bfa036e1c317919df129f 100644
--- a/src/managesieve/managesieve-client.c
+++ b/src/managesieve/managesieve-client.c
@@ -412,14 +412,28 @@ void client_send_storage_error
 }
 
 bool client_read_args(struct client_command_context *cmd, unsigned int count,
-		      unsigned int flags, struct managesieve_arg **args_r)
+	unsigned int flags, bool no_more, struct managesieve_arg **args_r)
 {
+	struct managesieve_arg *dummy_args_r = NULL;
 	int ret;
 
+	if ( args_r == NULL ) args_r = &dummy_args_r; 
+
 	i_assert(count <= INT_MAX);
 
-	ret = managesieve_parser_read_args(cmd->client->parser, count, flags, args_r);
-	if (ret >= (int)count) {
+	ret = managesieve_parser_read_args
+		(cmd->client->parser, ( no_more ? 0 : count ), flags, args_r);
+	if ( ret >= 0 ) {
+		if ( count > 0 || no_more ) {
+			if ( ret < (int)count ) {
+				client_send_command_error(cmd, "Missing arguments.");
+				return FALSE;
+			} else if ( no_more && ret > (int)count ) {
+				client_send_command_error(cmd, "Too many arguments.");
+				return FALSE;
+			}
+		}
+	
 		/* all parameters read successfully */
 		return TRUE;
 	} else if (ret == -2) {
@@ -430,15 +444,14 @@ bool client_read_args(struct client_command_context *cmd, unsigned int count,
 		}
 		return FALSE;
 	} else {
-		/* error, or missing arguments */
-		client_send_command_error(cmd, ret < 0 ? NULL :
-					  "Missing arguments");
+		/* error */
+		client_send_command_error(cmd, NULL);
 		return FALSE;
 	}
 }
 
 bool client_read_string_args(struct client_command_context *cmd,
-			     unsigned int count, ...)
+			     unsigned int count, bool no_more, ...)
 {
 	struct managesieve_arg *managesieve_args;
 	va_list va;
@@ -446,10 +459,10 @@ bool client_read_string_args(struct client_command_context *cmd,
 	unsigned int i;
 	bool result = TRUE;
 
-	if (!client_read_args(cmd, count, 0, &managesieve_args))
+	if (!client_read_args(cmd, count, 0, no_more, &managesieve_args))
 		return FALSE;
 
-	va_start(va, count);
+	va_start(va, no_more);
 	for (i = 0; i < count; i++) {
 		const char **ret = va_arg(va, const char **);
 
@@ -471,11 +484,6 @@ bool client_read_string_args(struct client_command_context *cmd,
 	}
 	va_end(va);
 
-	if (result && managesieve_args[i].type != MANAGESIEVE_ARG_EOL) {
-		client_send_command_error(cmd, "Too many arguments.");
-		result = FALSE;
-	}
-
 	return result;
 }
 
diff --git a/src/managesieve/managesieve-client.h b/src/managesieve/managesieve-client.h
index 32db5e02eb060853ec50cc30b9622ac6e4eb2e2d..1c31d7ef69578298bc46ec1f7d742e3631a2f174 100644
--- a/src/managesieve/managesieve-client.h
+++ b/src/managesieve/managesieve-client.h
@@ -114,11 +114,17 @@ void client_send_storage_error(struct client *client,
 /* Read a number of arguments. Returns TRUE if everything was read or
    FALSE if either needs more data or error occurred. */
 bool client_read_args(struct client_command_context *cmd, unsigned int count,
-		      unsigned int flags, struct managesieve_arg **args_r);
+		      unsigned int flags, bool no_more, struct managesieve_arg **args_r);
 /* Reads a number of string arguments. ... is a list of pointers where to
    store the arguments. */
 bool client_read_string_args(struct client_command_context *cmd,
-			     unsigned int count, ...);
+			     unsigned int count, bool no_more, ...);
+
+static inline bool client_read_no_args
+(struct client_command_context *cmd)
+{
+	return client_read_args(cmd, 0, 0, TRUE, NULL);
+}
 
 void _client_reset_command(struct client *client);
 void client_input(struct client *client);