cmd-append.c revision 183bea41fa640dc8117f3eb45ff935cd81377a84
/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
#include "imap-common.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
#include "str.h"
#include "imap-parser.h"
#include "imap-date.h"
#include "imap-util.h"
#include "imap-commands.h"
/* Don't allow internaldates to be too far in the future. At least with Maildir
they can cause problems with incremental backups since internaldate is
stored in file's mtime. But perhaps there are also some other reasons why
it might not be wanted. */
struct cmd_append_context {
struct client_command_context *cmd;
struct mail_storage *storage;
struct mailbox_transaction_context *t;
struct imap_parser *save_parser;
struct mail_save_context *save_ctx;
unsigned int count;
unsigned int message_input:1;
unsigned int failed:1;
};
{
bool finished;
case -1:
/* disconnected */
/* Reset command so that client_destroy() doesn't try to call
cmd_append_continue_message() anymore. */
return;
case -2:
if (ctx->message_input) {
/* message data, this is handled internally by
mailbox_save_continue() */
break;
}
/* parameter word is longer than max. input buffer size.
this is most likely an error, so skip the new data
until newline is found. */
return;
}
(void)client_handle_unfinished_cmd(cmd);
else
(void)cmd_sync_delayed(client);
if (client->disconnected)
else
}
/* 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. */
bool *nonsync_r)
{
/* [<flags>] */
else
args++;
/* [<internal date>] */
*internal_date_r = NULL;
else {
args++;
}
return FALSE;
}
return TRUE;
}
{
/* we must put back the original flush callback before beginning to
sync (the command is still unfinished at that point) */
}
{
return TRUE;
}
return TRUE;
}
/* finished, but with MULTIAPPEND and LITERAL+ we may get
more messages. */
return cmd_append_continue_parsing(cmd);
}
return FALSE;
}
{
if (!nonsync) {
return TRUE;
}
/* we have to read the nonsynced literal so we don't treat the message
data as commands. */
}
{
const struct imap_arg *flags_list;
enum mail_flags flags;
const char *const *keywords_list;
struct mail_keywords *keywords;
const char *internal_date_str;
int ret, timezone_offset;
unsigned int save_count;
bool nonsync;
return TRUE;
}
/* if error occurs, the CRLF is already read. */
/* [<flags>] [<internal date>] <message literal> */
if (ret == -1) {
return TRUE;
}
if (ret < 0) {
/* need more data */
return FALSE;
}
if (IMAP_ARG_IS_EOL(args)) {
/* last message */
enum mailbox_sync_flags sync_flags;
enum imap_sync_flags imap_flags;
/* eat away the trailing CRLF */
/* we failed earlier, error message is sent */
return TRUE;
}
return TRUE;
}
if (ret < 0) {
return TRUE;
}
if (save_count == 0) {
/* not supported by backend (virtual) */
} else {
}
sync_flags = 0;
} else {
imap_flags = 0;
}
}
}
/* we failed earlier, make sure we just eat nonsync-literal
if it's given. */
}
if (flags_list != NULL) {
&flags, &keywords_list))
if (keywords_list == NULL)
&keywords) < 0) {
}
} else {
flags = 0;
}
if (internal_date_str == NULL) {
/* no time given, default to now. */
timezone_offset = 0;
} else if (!imap_parse_datetime(internal_date_str,
&internal_date, &timezone_offset)) {
}
/* the client specified a time in the future, set it to now. */
timezone_offset = 0;
}
/* no message data, abort */
}
/* save the mail */
if (ret < 0) {
/* save initialization failed */
}
/* after literal comes CRLF, if we fail make sure we eat it away */
if (!nonsync) {
}
return cmd_append_continue_message(cmd);
}
{
int ret;
return TRUE;
}
/* we still have to finish reading the message
from client */
break;
}
break;
}
}
}
/* finished */
/* failed above */
} else if (!all_written) {
/* client disconnected before it finished sending the
whole message. */
}
return TRUE;
}
/* prepare for next message */
return cmd_append_continue_parsing(cmd);
}
return FALSE;
}
static struct mailbox *
{
struct mail_namespace *ns;
enum mailbox_name_status status;
const char *storage_name;
return NULL;
switch (status) {
break;
case MAILBOX_NAME_EXISTS_DIR:
/* fall through */
case MAILBOX_NAME_VALID:
case MAILBOX_NAME_INVALID:
case MAILBOX_NAME_NOINFERIORS:
return NULL;
}
if (mailbox_open(box) < 0) {
mailbox_free(&box);
return NULL;
}
return box;
}
{
struct cmd_append_context *ctx;
const char *mailbox;
/* if transaction is created while its view is synced,
appends aren't allowed for it. */
return FALSE;
}
/* <mailbox> */
return FALSE;
/* we keep the input locked all the time */
else {
}
/* append is special because we're only waiting on client input, not
client output, so disable the standard output handler until we're
finished */
return cmd_append_continue_parsing(cmd);
}