Mercurial > dovecot > core-2.2
view src/imap/cmd-append.c @ 2350:1371d41c375f HEAD
Moved namespace and hierarchy separator handling to imap-specific code. LIST
now shows non-hidden namespaces in the LIST reply.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Fri, 23 Jul 2004 00:20:00 +0300 |
parents | c01f238a37a0 |
children | d141e1bfdd63 |
line wrap: on
line source
/* Copyright (C) 2002 Timo Sirainen */ #include "common.h" #include "ioloop.h" #include "istream.h" #include "ostream.h" #include "str.h" #include "commands.h" #include "imap-parser.h" #include "imap-date.h" #include "mail-storage.h" #include <sys/time.h> /* 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 imap_arg *args, struct imap_arg_list **flags, const char **internal_date, uoff_t *msg_size, int *nonsync) { /* [<flags>] */ if (args->type != IMAP_ARG_LIST) *flags = NULL; else { *flags = IMAP_ARG_LIST(args); args++; } /* [<internal date>] */ if (args->type != IMAP_ARG_STRING) *internal_date = NULL; else { *internal_date = IMAP_ARG_STR(args); args++; } if (args->type != IMAP_ARG_LITERAL_SIZE && args->type != IMAP_ARG_LITERAL_SIZE_NONSYNC) return FALSE; *nonsync = args->type == IMAP_ARG_LITERAL_SIZE_NONSYNC; *msg_size = IMAP_ARG_LITERAL_SIZE(args); return TRUE; } int cmd_append(struct client *client) { struct mail_storage *storage; struct mailbox *box; struct mailbox_status status; struct mailbox_transaction_context *t; struct imap_parser *save_parser; struct imap_arg *args; struct imap_arg_list *flags_list; struct mailbox_keywords old_flags; struct mail_full_flags flags; struct istream *input; time_t internal_date; const char *mailbox, *internal_date_str; uoff_t msg_size; unsigned int count; int ret, failed, timezone_offset, nonsync; /* <mailbox> */ if (!client_read_string_args(client, 1, &mailbox)) return FALSE; if (!client_verify_mailbox_name(client, mailbox, TRUE, FALSE)) return TRUE; storage = client_find_storage(client, &mailbox); if (storage == NULL) return TRUE; if (client->mailbox != NULL && mailbox_name_equals(mailbox_get_name(client->mailbox), mailbox)) box = client->mailbox; else { box = mailbox_open(storage, mailbox, MAILBOX_OPEN_FAST | MAILBOX_OPEN_KEEP_RECENT); if (box == NULL) { client_send_storage_error(client, storage); return TRUE; } } if (mailbox_get_status(box, STATUS_KEYWORDS, &status) < 0) { client_send_storage_error(client, storage); mailbox_close(box); return TRUE; } memset(&old_flags, 0, sizeof(old_flags)); old_flags.pool = pool_datastack_create(); client_save_keywords(&old_flags, status.keywords, status.keywords_count); t = mailbox_transaction_begin(box, FALSE); /* if error occurs, the CRLF is already read. */ client->input_skip_line = FALSE; count = 0; failed = TRUE; save_parser = imap_parser_create(client->input, client->output, imap_max_line_length); 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, NULL); 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, &nonsync)) { /* error */ client_send_command_error(client, "Invalid arguments."); break; } if (flags_list != NULL) { if (!client_parse_mail_flags(client, flags_list->args, &old_flags, &flags)) break; } else { memset(&flags, 0, sizeof(flags)); } if (internal_date_str == NULL) { /* no time given, default to now. */ internal_date = (time_t)-1; timezone_offset = 0; } 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; } if (!nonsync) { o_stream_send(client->output, "+ OK\r\n", 6); o_stream_flush(client->output); } /* save the mail */ input = i_stream_create_limit(default_pool, client->input, client->input->v_offset, msg_size); if (mailbox_save(t, &flags, internal_date, timezone_offset, NULL, input, NULL) < 0) { i_stream_unref(input); client_send_storage_error(client, storage); break; } i_stream_unref(input); if (client->input->closed) break; count++; } imap_parser_destroy(save_parser); if (failed) mailbox_transaction_rollback(t); else { if (mailbox_transaction_commit(t) < 0) { failed = TRUE; client_send_storage_error(client, storage); } } if (box != client->mailbox) mailbox_close(box); if (!failed) { client_sync_full(client); client_send_tagline(client, "OK Append completed."); } return TRUE; }