[dovecot-cvs] dovecot/src/imap client.c,1.21,1.22 cmd-append.c,1.19,1.20 cmd-copy.c,1.5,1.6 common.h,1.2,1.3

cras at procontrol.fi cras at procontrol.fi
Wed Jan 22 21:23:30 EET 2003


Update of /home/cvs/dovecot/src/imap
In directory danu:/tmp/cvs-serv16040/src/imap

Modified Files:
	client.c cmd-append.c cmd-copy.c common.h 
Log Message:
Support for MULTIAPPEND extension. COPY now behaves like spec says - if it
fails, none of the messages are copied. maildir_copy_with_hardlinks didn't
actually work.



Index: client.c
===================================================================
RCS file: /home/cvs/dovecot/src/imap/client.c,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- client.c	21 Jan 2003 11:17:43 -0000	1.21
+++ client.c	22 Jan 2003 19:23:28 -0000	1.22
@@ -12,10 +12,6 @@
 /* max. size of one parameter in line */
 #define MAX_INBUF_SIZE 8192
 
-/* max. number of IMAP argument elements to accept. The maximum memory usage
-   for command from user is around MAX_INBUF_SIZE * MAX_IMAP_ARG_ELEMENTS */
-#define MAX_IMAP_ARG_ELEMENTS 128
-
 /* If we can't send a buffer in a minute, disconnect the client */
 #define CLIENT_OUTPUT_TIMEOUT (60*1000)
 
@@ -164,6 +160,8 @@
 {
 	int ret;
 
+	i_assert(count <= INT_MAX);
+
 	ret = imap_parser_read_args(client->parser, count, flags, args);
 	if (ret >= (int)count) {
 		/* all parameters read successfully */
@@ -193,11 +191,15 @@
 	for (i = 0; i < count; i++) {
 		const char **ret = va_arg(va, const char **);
 
+		if (imap_args[i].type == IMAP_ARG_EOL) {
+			client_send_command_error(client, "Missing arguments.");
+			break;
+		}
+
 		str = imap_arg_string(&imap_args[i]);
 		if (str == NULL) {
-			client_send_command_error(client, "Missing arguments.");
-			va_end(va);
-			return FALSE;
+			client_send_command_error(client, "Invalid arguments.");
+			break;
 		}
 
 		if (ret != NULL)
@@ -205,7 +207,7 @@
 	}
 	va_end(va);
 
-	return TRUE;
+	return i == count;
 }
 
 static void client_reset_command(struct client *client)
@@ -219,12 +221,6 @@
         imap_parser_reset(client->parser);
 }
 
-static void client_command_finished(struct client *client)
-{
-	client->input_skip_line = TRUE;
-        client_reset_command(client);
-}
-
 /* Skip incoming data until newline is found,
    returns TRUE if newline was found. */
 static int client_skip_line(struct client *client)
@@ -249,9 +245,10 @@
 {
         if (client->cmd_func != NULL) {
 		/* command is being executed - continue it */
+		client->input_skip_line = TRUE;
 		if (client->cmd_func(client) || client->cmd_error) {
 			/* command execution was finished */
-			client_command_finished(client);
+			client_reset_command(client);
                         client->bad_counter = 0;
 			return TRUE;
 		}
@@ -292,11 +289,13 @@
 		/* unknown command */
 		client_send_command_error(client, t_strconcat(
 			"Unknown command '", client->cmd_name, "'", NULL));
-		client_command_finished(client);
+		client->input_skip_line = TRUE;
+		client_reset_command(client);
 	} else {
+		client->input_skip_line = TRUE;
 		if (client->cmd_func(client) || client->cmd_error) {
 			/* command execution was finished */
-			client_command_finished(client);
+			client_reset_command(client);
                         client->bad_counter = 0;
 		}
 	}
@@ -323,7 +322,7 @@
 		client->input_skip_line = TRUE;
 
 		client_send_command_error(client, "Too long argument.");
-		client_command_finished(client);
+		client_reset_command(client);
 		break;
 	}
 

Index: cmd-append.c
===================================================================
RCS file: /home/cvs/dovecot/src/imap/cmd-append.c,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- cmd-append.c	20 Jan 2003 14:52:51 -0000	1.19
+++ cmd-append.c	22 Jan 2003 19:23:28 -0000	1.20
@@ -2,6 +2,7 @@
 
 #include "common.h"
 #include "ioloop.h"
+#include "istream.h"
 #include "ostream.h"
 #include "commands.h"
 #include "imap-parser.h"
@@ -12,107 +13,50 @@
 /* Returns -1 = error, 0 = need more data, 1 = successful. flags and
    internal_date may be NULL as a result, but mailbox and msg_size are always
    set when successful. */
-static int validate_args(struct client *client, const char **mailbox,
-			 struct imap_arg_list **flags,
-			 const char **internal_date,
-			 uoff_t *msg_size, unsigned int count)
+static int validate_args(struct imap_arg *args, struct imap_arg_list **flags,
+			 const char **internal_date, uoff_t *msg_size)
 {
-	struct imap_arg *args;
-
-	i_assert(count >= 2 && count <= 4);
-
-	*flags = NULL;
-	*internal_date = NULL;
-
-	if (!client_read_args(client, count, IMAP_PARSE_FLAG_LITERAL_SIZE,
-			      &args))
-		return 0;
-
-	switch (count) {
-	case 2:
-		/* do we have flags or internal date parameter? */
-		if (args[1].type == IMAP_ARG_LIST ||
-		    args[1].type == IMAP_ARG_STRING)
-			return validate_args(client, mailbox, flags,
-					     internal_date, msg_size, 3);
-
-		break;
-	case 3:
-		/* do we have both flags and internal date? */
-		if (args[1].type == IMAP_ARG_LIST &&
-		    args[2].type == IMAP_ARG_STRING)
-			return validate_args(client, mailbox, flags,
-					     internal_date, msg_size, 4);
-
-		if (args[1].type == IMAP_ARG_LIST)
-			*flags = IMAP_ARG_LIST(&args[1]);
-		else if (args[1].type == IMAP_ARG_STRING)
-			*internal_date = IMAP_ARG_STR(&args[1]);
-		else
-			return -1;
-		break;
-	case 4:
-		/* we have all parameters */
-		*flags = IMAP_ARG_LIST(&args[1]);
-		*internal_date = IMAP_ARG_STR(&args[2]);
-		break;
-	default:
-                i_unreached();
+	/* [<flags>] */
+	if (args->type != IMAP_ARG_LIST)
+		*flags = NULL;
+	else {
+		*flags = IMAP_ARG_LIST(args);
+		args++;
 	}
 
-	/* check that mailbox and message arguments are ok */
-	*mailbox = imap_arg_string(&args[0]);
-	if (*mailbox == NULL)
-		return -1;
+	/* [<internal date>] */
+	if (args->type != IMAP_ARG_STRING)
+		*internal_date = NULL;
+	else {
+		*internal_date = IMAP_ARG_STR(args);
+		args++;
+	}
 
-	if (args[count-1].type != IMAP_ARG_LITERAL_SIZE)
-		return -1;
+	if (args->type != IMAP_ARG_LITERAL_SIZE)
+		return FALSE;
 
-	*msg_size = IMAP_ARG_LITERAL_SIZE(&args[count-1]);
-	return 1;
+	*msg_size = IMAP_ARG_LITERAL_SIZE(args);
+	return TRUE;
 }
 
 int cmd_append(struct client *client)
 {
-	struct imap_arg_list *flags_list;
 	struct mailbox *box;
+	struct mail_save_context *ctx;
+	struct imap_parser *save_parser;
+	struct imap_arg *args;
+	struct imap_arg_list *flags_list;
 	struct mail_full_flags flags;
 	time_t internal_date;
 	const char *mailbox, *internal_date_str;
 	uoff_t msg_size;
-	int failed, timezone_offset;
+	unsigned int count;
+	int ret, failed, timezone_offset;
 
-	/* <mailbox> [<flags>] [<internal date>] <message literal> */
-	switch (validate_args(client, &mailbox, &flags_list,
-			      &internal_date_str, &msg_size, 2)) {
-	case -1:
-		/* error */
-		client_send_command_error(client, NULL);
-		return TRUE;
-	case 0:
-		/* need more data */
+	/* <mailbox> */
+	if (!client_read_string_args(client, 1, &mailbox))
 		return FALSE;
-	}
 
-	if (flags_list != NULL) {
-		if (!client_parse_mail_flags(client, flags_list->args,
-					     &flags))
-			return TRUE;
-	} else {
-		memset(&flags, 0, sizeof(flags));
-	}
-
-	if (internal_date_str == NULL) {
-		/* no time given, default to now. */
-		internal_date = ioloop_time;
-                timezone_offset = ioloop_timezone.tz_minuteswest;
-	} else if (!imap_parse_datetime(internal_date_str, &internal_date,
-					&timezone_offset)) {
-		client_send_tagline(client, "BAD Invalid internal date.");
-		return TRUE;
-	}
-
-	/* open the mailbox */
 	if (!client_verify_mailbox_name(client, mailbox, TRUE, FALSE))
 		return TRUE;
 
@@ -123,17 +67,120 @@
 		return TRUE;
 	}
 
-	o_stream_send(client->output, "+ OK\r\n", 6);
-	o_stream_flush(client->output);
+	ctx = box->save_init(box, TRUE);
+	if (ctx == NULL) {
+		client_send_storage_error(client);
+		return TRUE;
+	}
 
-	/* save the mail */
-	failed = !box->save(box, &flags, internal_date, timezone_offset,
-			    client->input, msg_size);
-	box->close(box);
+	/* if error occurs, the CRLF is already read. */
+	client->input_skip_line = FALSE;
 
-	if (failed) {
+	count = 0;
+	failed = TRUE;
+	save_parser = imap_parser_create(client->input, client->output,
+					 0, MAX_IMAP_ARG_ELEMENTS);
+
+	for (;;) {
+		/* [<flags>] [<internal date>] <message literal> */
+		imap_parser_reset(save_parser);
+		for (;;) {
+			ret = imap_parser_read_args(save_parser, 0,
+						   IMAP_PARSE_FLAG_LITERAL_SIZE,
+						   &args);
+			if (ret >= 0)
+				break;
+			if (ret == -1) {
+				client_send_command_error(client,
+					imap_parser_get_error(save_parser));
+				break;
+			}
+
+			/* need more data */
+			ret = i_stream_read(client->input);
+			if (ret == -2) {
+				client_send_command_error(client,
+							  "Too long argument.");
+				break;
+			}
+			if (ret < 0) {
+				/* disconnected */
+				client->cmd_error = TRUE;
+				break;
+			}
+		}
+
+		if (client->cmd_error)
+			break;
+
+		if (args->type == IMAP_ARG_EOL) {
+			/* last one */
+			if (count > 0)
+				failed = FALSE;
+			client->input_skip_line = TRUE;
+			break;
+		}
+
+		if (!validate_args(args, &flags_list, &internal_date_str,
+				   &msg_size)) {
+			/* error */
+			client_send_command_error(client, "Invalid arguments.");
+			break;
+		}
+
+		if (flags_list != NULL) {
+			if (!client_parse_mail_flags(client, flags_list->args,
+						     &flags))
+				break;
+		} else {
+			memset(&flags, 0, sizeof(flags));
+		}
+
+		if (internal_date_str == NULL) {
+			/* no time given, default to now. */
+			internal_date = ioloop_time;
+			timezone_offset = ioloop_timezone.tz_minuteswest;
+		} else if (!imap_parse_datetime(internal_date_str,
+						&internal_date,
+						&timezone_offset)) {
+			client_send_tagline(client,
+					    "BAD Invalid internal date.");
+			break;
+		}
+
+		if (msg_size == 0) {
+			/* no message data, abort */
+			client_send_tagline(client, "NO Append aborted.");
+			break;
+		}
+
+		o_stream_send(client->output, "+ OK\r\n", 6);
+		o_stream_flush(client->output);
+
+		/* save the mail */
+		i_stream_set_read_limit(client->input,
+					client->input->v_offset + msg_size);
+		if (!box->save_next(ctx, &flags, internal_date,
+				    timezone_offset, client->input)) {
+			client_send_storage_error(client);
+			break;
+		}
+		i_stream_set_read_limit(client->input, 0);
+
+		if (client->input->closed)
+			break;
+
+		count++;
+	}
+
+	if (!box->save_deinit(ctx, failed)) {
+		failed = TRUE;
 		client_send_storage_error(client);
-	} else {
+	}
+
+	box->close(box);
+
+	if (!failed) {
 		client_sync_full(client);
 		client_send_tagline(client, "OK Append completed.");
 	}

Index: cmd-copy.c
===================================================================
RCS file: /home/cvs/dovecot/src/imap/cmd-copy.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- cmd-copy.c	5 Jan 2003 13:09:51 -0000	1.5
+++ cmd-copy.c	22 Jan 2003 19:23:28 -0000	1.6
@@ -7,6 +7,7 @@
 {
 	struct mailbox *destbox;
 	const char *messageset, *mailbox;
+	int ret;
 
 	/* <message set> <mailbox> */
 	if (!client_read_string_args(client, 2, &messageset, &mailbox))
@@ -27,11 +28,16 @@
 	}
 
 	/* copy the mail */
-	if (client->mailbox->copy(client->mailbox, destbox,
-				  messageset, client->cmd_uid)) {
-                client_sync_full(client);
+	ret = client->mailbox->copy(client->mailbox, destbox,
+				    messageset, client->cmd_uid);
+
+	/* sync always - if COPY fails because of expunges they'll get
+	   synced here */
+	client_sync_full(client);
+
+	if (ret)
 		client_send_tagline(client, "OK Copy completed.");
-	} else
+	else
 		client_send_storage_error(client);
 
 	destbox->close(destbox);

Index: common.h
===================================================================
RCS file: /home/cvs/dovecot/src/imap/common.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- common.h	5 Jan 2003 13:09:51 -0000	1.2
+++ common.h	22 Jan 2003 19:23:28 -0000	1.3
@@ -4,6 +4,10 @@
 #include "lib.h"
 #include "client.h"
 
+/* max. number of IMAP argument elements to accept. The maximum memory usage
+   for command from user is around MAX_INBUF_SIZE * MAX_IMAP_ARG_ELEMENTS */
+#define MAX_IMAP_ARG_ELEMENTS 128
+
 extern struct ioloop *ioloop;
 
 #endif




More information about the dovecot-cvs mailing list