dovecot-2.2: imap: Implemented CATENATE extension.
dovecot at dovecot.org
dovecot at dovecot.org
Sat Jun 2 19:02:27 EEST 2012
details: http://hg.dovecot.org/dovecot-2.2/rev/5344ff4215b4
changeset: 14592:5344ff4215b4
user: Stephan Bosch <stephan at rename-it.nl>
date: Sat Jun 02 18:14:16 2012 +0300
description:
imap: Implemented CATENATE extension.
diffstat:
README | 1 +
configure.in | 2 +-
src/imap/cmd-append.c | 633 +++++++++++++++++++++++++++++++++++--------------
3 files changed, 453 insertions(+), 183 deletions(-)
diffs (truncated from 793 to 300 lines):
diff -r 07e6ca397a72 -r 5344ff4215b4 README
--- a/README Sat Jun 02 17:56:27 2012 +0300
+++ b/README Sat Jun 02 18:14:16 2012 +0300
@@ -40,6 +40,7 @@
3691 - IMAP4 UNSELECT command
4314 - IMAP4 Access Control List (ACL) Extension
4315 - IMAP UIDPLUS extension
+ 4469 - IMAP CATENATE Extension
4551 - IMAP Extension for Conditional STORE Operation
or Quick Flag Changes Resynchronization
4731 - IMAP4 Extension to SEARCH Command for Controlling
diff -r 07e6ca397a72 -r 5344ff4215b4 configure.in
--- a/configure.in Sat Jun 02 17:56:27 2012 +0300
+++ b/configure.in Sat Jun 02 18:14:16 2012 +0300
@@ -2704,7 +2704,7 @@
dnl IDLE doesn't really belong to banner. It's there just to make Blackberries
dnl happy, because otherwise BIS server disables push email.
capability_banner="IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE"
-capability="$capability_banner SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS MULTIAPPEND UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS SPECIAL-USE"
+capability="$capability_banner SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS SPECIAL-USE"
AC_DEFINE_UNQUOTED(CAPABILITY_STRING, "$capability", IMAP capabilities)
AC_DEFINE_UNQUOTED(CAPABILITY_BANNER_STRING, "$capability_banner", IMAP capabilities advertised in banner)
diff -r 07e6ca397a72 -r 5344ff4215b4 src/imap/cmd-append.c
--- a/src/imap/cmd-append.c Sat Jun 02 17:56:27 2012 +0300
+++ b/src/imap/cmd-append.c Sat Jun 02 18:14:16 2012 +0300
@@ -3,12 +3,14 @@
#include "imap-common.h"
#include "ioloop.h"
#include "istream.h"
+#include "istream-chain.h"
#include "ostream.h"
#include "str.h"
#include "imap-parser.h"
#include "imap-date.h"
#include "imap-util.h"
#include "imap-commands.h"
+#include "imap-msgpart-url.h"
#include <sys/time.h>
@@ -26,14 +28,19 @@
struct mailbox_transaction_context *t;
time_t started;
+ struct istream_chain *catchain;
+ uoff_t cat_msg_size;
+
struct istream *input;
- uoff_t msg_size;
+ struct istream *litinput;
+ uoff_t literal_size;
struct imap_parser *save_parser;
struct mail_save_context *save_ctx;
unsigned int count;
unsigned int message_input:1;
+ unsigned int catenate:1;
unsigned int failed:1;
};
@@ -50,7 +57,7 @@
ctx->count, secs);
if (ctx->input != NULL) {
str_printfa(str, ", %"PRIuUOFF_T"/%"PRIuUOFF_T" bytes",
- ctx->input->v_offset, ctx->msg_size);
+ ctx->input->v_offset, ctx->literal_size);
}
str_append_c(str, ')');
return str_c(str);
@@ -112,37 +119,6 @@
client_continue_pending_input(client);
}
-/* 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(const struct imap_arg *args,
- const struct imap_arg **flags_r,
- const char **internal_date_r, uoff_t *msg_size_r,
- bool *nonsync_r)
-{
- /* [<flags>] */
- if (!imap_arg_get_list(args, flags_r))
- *flags_r = NULL;
- else
- args++;
-
- /* [<internal date>] */
- if (args->type != IMAP_ARG_STRING)
- *internal_date_r = NULL;
- else {
- *internal_date_r = imap_arg_as_astring(args);
- args++;
- }
-
- if (!imap_arg_get_literal_size(args, msg_size_r)) {
- *nonsync_r = FALSE;
- return FALSE;
- }
-
- *nonsync_r = args->type == IMAP_ARG_LITERAL_SIZE_NONSYNC;
- return TRUE;
-}
-
static void cmd_append_finish(struct cmd_append_context *ctx)
{
imap_parser_unref(&ctx->save_parser);
@@ -155,6 +131,8 @@
o_stream_set_flush_callback(ctx->client->output,
client_output, ctx->client);
+ if (ctx->litinput != NULL)
+ i_stream_unref(&ctx->litinput);
if (ctx->input != NULL)
i_stream_unref(&ctx->input);
if (ctx->save_ctx != NULL)
@@ -184,11 +162,10 @@
return TRUE;
}
- if (ctx->input->v_offset == ctx->msg_size) {
+ if (ctx->litinput->v_offset == ctx->literal_size) {
/* finished, but with MULTIAPPEND and LITERAL+ we may get
more messages. */
- i_stream_unref(&ctx->input);
- ctx->input = NULL;
+ i_stream_unref(&ctx->litinput);
ctx->message_input = FALSE;
imap_parser_reset(ctx->save_parser);
@@ -210,7 +187,7 @@
/* we have to read the nonsynced literal so we don't treat the message
data as commands. */
- ctx->input = i_stream_create_limit(ctx->client->input, ctx->msg_size);
+ ctx->input = i_stream_create_limit(ctx->client->input, ctx->literal_size);
ctx->message_input = TRUE;
ctx->cmd->func = cmd_append_continue_cancel;
@@ -218,20 +195,405 @@
return cmd_append_continue_cancel(ctx->cmd);
}
+static int
+cmd_append_catenate(struct client_command_context *cmd,
+ const struct imap_arg *args, bool *nonsync_r)
+{
+ struct client *client = cmd->client;
+ struct cmd_append_context *ctx = cmd->context;
+ struct imap_msgpart_url *mpurl;
+ const char *catpart, *error;
+ uoff_t newsize;
+ int ret;
+
+ *nonsync_r = FALSE;
+
+ /* Handle URLs until a TEXT literal is encountered */
+ while (imap_arg_get_atom(args, &catpart)) {
+ const char *caturl;
+
+ if (strcasecmp(catpart, "URL") == 0 ) {
+ /* URL <url> */
+ args++;
+ if (!imap_arg_get_astring(args, &caturl))
+ break;
+ if (ctx->failed)
+ return -1;
+
+ mpurl = imap_msgpart_url_parse(client->user, client->mailbox, caturl, &error);
+ if (mpurl == NULL) {
+ /* invalid url, abort */
+ client_send_tagline(cmd,
+ t_strdup_printf("NO [BADURL %s] %s.", caturl, error));
+ return -1;
+ }
+
+ if (cmd->cancel) {
+ imap_msgpart_url_free(&mpurl);
+ cmd_append_finish(ctx);
+ return 1;
+ }
+
+ /* catenate URL */
+ if (ctx->save_ctx != NULL) {
+ struct istream *input = NULL;
+ uoff_t size;
+
+ if (!imap_msgpart_url_read_part(mpurl, &input, &size, &error)) {
+ /* invalid url, abort */
+ client_send_tagline(cmd,
+ t_strdup_printf("NO [BADURL %s] %s.", caturl, error));
+ return -1;
+ }
+
+ newsize = ctx->cat_msg_size + size;
+ if (newsize < ctx->cat_msg_size) {
+ client_send_tagline(cmd,
+ "NO [TOOBIG] Composed message grows too big.");
+ imap_msgpart_url_free(&mpurl);
+ return -1;
+ }
+
+ if (input != NULL) {
+ ctx->cat_msg_size = newsize;
+ i_stream_chain_append(ctx->catchain, input);
+
+ while (!input->eof) {
+ ret = i_stream_read(ctx->input);
+ if (mailbox_save_continue(ctx->save_ctx) < 0) {
+ /* we still have to finish reading the message
+ from client */
+ mailbox_save_cancel(&ctx->save_ctx);
+ break;
+ }
+ if (ret == -1 || ret == 0)
+ break;
+ }
+
+ if (!input->eof) {
+ client_send_tagline(cmd, t_strdup_printf(
+ "NO [BADURL %s] Failed to read all data.", caturl));
+ imap_msgpart_url_free(&mpurl);
+ return -1;
+ }
+ }
+ }
+ imap_msgpart_url_free(&mpurl);
+ } else if (strcasecmp(catpart, "TEXT") == 0) {
+ /* TEXT <literal> */
+ args++;
+ if (!imap_arg_get_literal_size(args, &ctx->literal_size))
+ break;
+
+ *nonsync_r = args->type == IMAP_ARG_LITERAL_SIZE_NONSYNC;
+ if (ctx->failed) {
+ /* we failed earlier, make sure we just eat
+ nonsync-literal if it's given. */
+ return -1;
+ }
+
+ newsize = ctx->cat_msg_size + ctx->literal_size;
+ if (newsize < ctx->cat_msg_size) {
+ client_send_tagline(cmd,
+ "NO [TOOBIG] Composed message grows too big.");
+ return -1;
+ }
+
+ /* save the mail */
+ ctx->cat_msg_size = newsize;
+ ctx->litinput = i_stream_create_limit(client->input, ctx->literal_size);
+ i_stream_chain_append(ctx->catchain, ctx->litinput);
+ return 1;
+ } else {
+ break;
+ }
+ args++;
+ }
+
+ if (IMAP_ARG_IS_EOL(args)) {
+ /* ")" */
+ return 0;
+ }
+ client_send_command_error(cmd, "Invalid arguments.");
+ return -1;
+}
+
+static void cmd_append_finish_catenate(struct client_command_context *cmd)
+{
+ struct cmd_append_context *ctx = cmd->context;
+
+ i_stream_chain_append(ctx->catchain, NULL);
+ i_stream_unref(&ctx->input);
+ ctx->input = NULL;
+ ctx->catenate = FALSE;
+
+ if (mailbox_save_finish(&ctx->save_ctx) < 0) {
+ ctx->failed = TRUE;
+ client_send_storage_error(cmd, ctx->storage);
+ }
+}
+
+static bool cmd_append_continue_catenate(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+ struct cmd_append_context *ctx = cmd->context;
+ const struct imap_arg *args;
+ const char *msg;
+ bool fatal, nonsync = FALSE;
+ int ret;
+
+ if (cmd->cancel) {
+ cmd_append_finish(ctx);
+ return TRUE;
+ }
+
+ ret = imap_parser_read_args(ctx->save_parser, 0,
+ IMAP_PARSE_FLAG_LITERAL_SIZE |
+ IMAP_PARSE_FLAG_INSIDE_LIST, &args);
More information about the dovecot-cvs
mailing list