[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