commands-util.c revision a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/* Copyright (C) 2002-2003 Timo Sirainen */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include "common.h"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include "array.h"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include "buffer.h"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include "str.h"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include "str-sanitize.h"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include "mail-storage.h"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include "commands-util.h"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include "imap-parser.h"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include "imap-sync.h"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include "imap-util.h"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include "namespace.h"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/* Maximum length for mailbox name, including it's path. This isn't fully
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync exact since the user can create folder hierarchy with small names, then
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync rename them to larger names. Mail storages should set more strict limits
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync to them, mbox/maildir currently allow paths only up to PATH_MAX. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#define MAILBOX_MAX_NAME_LEN 512
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncstruct mail_storage *
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncclient_find_storage(struct client_command_context *cmd, const char **mailbox)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync struct namespace *ns;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ns = namespace_find(cmd->client->namespaces, mailbox);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (ns != NULL)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return ns->storage;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_send_tagline(cmd, "NO Unknown namespace.");
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncbool client_verify_mailbox_name(struct client_command_context *cmd,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const char *mailbox,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync bool should_exist, bool should_not_exist)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync struct mail_storage *storage;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync struct mailbox_list *list;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync enum mailbox_name_status mailbox_status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const char *p;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync char sep;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync storage = client_find_storage(cmd, &mailbox);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (storage == NULL)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* make sure it even looks valid */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync sep = mail_storage_get_hierarchy_sep(storage);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (*mailbox == '\0') {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_send_tagline(cmd, "NO Empty mailbox name.");
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* make sure two hierarchy separators aren't next to each others */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (p = mailbox+1; *p != '\0'; p++) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (p[0] == sep && p[-1] == sep) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_send_tagline(cmd, "NO Invalid mailbox name.");
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (strlen(mailbox) > MAILBOX_MAX_NAME_LEN) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_send_tagline(cmd, "NO Mailbox name too long.");
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* check what our storage thinks of it */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync list = mail_storage_get_list(storage);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (mailbox_list_get_mailbox_name_status(list, mailbox,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync &mailbox_status) < 0) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_send_storage_error(cmd, storage);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync switch (mailbox_status) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync case MAILBOX_NAME_EXISTS:
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (should_exist || !should_not_exist)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return TRUE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_send_tagline(cmd, "NO Mailbox exists.");
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync break;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync case MAILBOX_NAME_VALID:
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (!should_exist)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return TRUE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_send_tagline(cmd, t_strconcat(
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync "NO [TRYCREATE] Mailbox doesn't exist: ",
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync str_sanitize(mailbox, MAILBOX_MAX_NAME_LEN), NULL));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync break;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync case MAILBOX_NAME_INVALID:
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_send_tagline(cmd, t_strconcat(
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync "NO Invalid mailbox name: ",
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync str_sanitize(mailbox, MAILBOX_MAX_NAME_LEN), NULL));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync break;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync case MAILBOX_NAME_NOINFERIORS:
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_send_tagline(cmd,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync "NO Mailbox parent doesn't allow inferior mailboxes.");
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync break;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync default:
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync i_unreached();
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncbool client_verify_open_mailbox(struct client_command_context *cmd)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (cmd->client->mailbox != NULL)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return TRUE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_send_tagline(cmd, "BAD No mailbox selected.");
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncvoid client_send_storage_error(struct client_command_context *cmd,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync struct mail_storage *storage)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const char *error;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync bool syntax, temporary_error;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (cmd->client->mailbox != NULL &&
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mailbox_is_inconsistent(cmd->client->mailbox)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* we can't do forced CLOSE, so have to disconnect */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_disconnect_with_error(cmd->client,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync "Mailbox is in inconsistent state, please relogin.");
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync error = mail_storage_get_last_error(storage, &syntax, &temporary_error);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_send_tagline(cmd,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync t_strconcat(syntax ? "BAD " : "NO ", error, NULL));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncvoid client_send_untagged_storage_error(struct client *client,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync struct mail_storage *storage)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const char *error;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync bool syntax, temporary_error;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (client->mailbox != NULL &&
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mailbox_is_inconsistent(client->mailbox)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* we can't do forced CLOSE, so have to disconnect */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_disconnect_with_error(client,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync "Mailbox is in inconsistent state, please relogin.");
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync error = mail_storage_get_last_error(storage, &syntax, &temporary_error);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_send_line(client,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync t_strconcat(syntax ? "* BAD " : "* NO ", error, NULL));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncstatic bool is_valid_keyword(struct client_command_context *cmd,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const char *keyword)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const char *const *names;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync unsigned int i, count;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* if it already exists, skip validity checks */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (array_is_created(&cmd->client->keywords.keywords)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync names = array_get(&cmd->client->keywords.keywords, &count);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (i = 0; i < count; i++) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (strcasecmp(names[i], keyword) == 0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return TRUE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (strlen(keyword) > max_keyword_length) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_send_tagline(cmd,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync t_strdup_printf("BAD Invalid keyword name '%s': "
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync "Maximum length is %u characters",
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync keyword, max_keyword_length));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return TRUE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncbool client_parse_mail_flags(struct client_command_context *cmd,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync struct imap_arg *args, enum mail_flags *flags_r,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const char *const **keywords_r)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const char *const *keywords;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync char *atom;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync buffer_t *buffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync size_t size, i;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *flags_r = 0;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *keywords_r = NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync buffer = buffer_create_dynamic(cmd->pool, 256);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync while (args->type != IMAP_ARG_EOL) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (args->type != IMAP_ARG_ATOM) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_send_command_error(cmd,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync "Flags list contains non-atoms.");
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync atom = IMAP_ARG_STR(args);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (*atom == '\\') {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* system flag */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync str_ucase(atom);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (strcmp(atom, "\\ANSWERED") == 0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *flags_r |= MAIL_ANSWERED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else if (strcmp(atom, "\\FLAGGED") == 0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *flags_r |= MAIL_FLAGGED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else if (strcmp(atom, "\\DELETED") == 0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *flags_r |= MAIL_DELETED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else if (strcmp(atom, "\\SEEN") == 0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *flags_r |= MAIL_SEEN;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else if (strcmp(atom, "\\DRAFT") == 0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *flags_r |= MAIL_DRAFT;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_send_tagline(cmd, t_strconcat(
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync "BAD Invalid system flag ",
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync atom, NULL));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync } else {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* keyword - first make sure it's not a duplicate */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync keywords = buffer_get_data(buffer, &size);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync size /= sizeof(const char *);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (i = 0; i < size; i++) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (strcasecmp(keywords[i], atom) == 0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync break;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (i == size) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (!is_valid_keyword(cmd, atom))
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync buffer_append(buffer, &atom, sizeof(atom));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync args++;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync atom = NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync buffer_append(buffer, &atom, sizeof(atom));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *keywords_r = buffer->used == sizeof(atom) ? NULL :
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync buffer_get_data(buffer, NULL);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return TRUE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncstatic const char *get_keywords_string(const ARRAY_TYPE(keywords) *keywords)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync string_t *str;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const char *const *names;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync unsigned int i, count;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (array_count(keywords) == 0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return "";
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync str = t_str_new(256);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync names = array_get(keywords, &count);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (i = 0; i < count; i++) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync str_append_c(str, ' ');
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync str_append(str, names[i]);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return str_c(str);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#define SYSTEM_FLAGS "\\Answered \\Flagged \\Deleted \\Seen \\Draft"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncvoid client_send_mailbox_flags(struct client *client, struct mailbox *box,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const ARRAY_TYPE(keywords) *keywords)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const char *str;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync str = get_keywords_string(keywords);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_send_line(client,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync t_strconcat("* FLAGS ("SYSTEM_FLAGS, str, ")", NULL));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (mailbox_is_readonly(box)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_send_line(client, "* OK [PERMANENTFLAGS ()] "
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync "Read-only mailbox.");
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync } else {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync client_send_line(client,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync t_strconcat("* OK [PERMANENTFLAGS ("SYSTEM_FLAGS, str,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mailbox_allow_new_keywords(box) ?
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync " \\*" : "", ")] Flags permitted.", NULL));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncbool client_save_keywords(struct mailbox_keywords *dest,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const ARRAY_TYPE(keywords) *keywords)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const char *const *names, *const *old_names;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync unsigned int i, count, old_count;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync bool changed;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync names = array_get(keywords, &count);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* first check if anything changes */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (!array_is_created(&dest->keywords))
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync changed = count != 0;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync old_names = array_get(&dest->keywords, &old_count);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (count != old_count)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync changed = TRUE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync changed = FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (i = 0; i < count; i++) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (strcmp(names[i], old_names[i]) != 0) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync changed = TRUE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync break;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (!changed)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync p_clear(dest->pool);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync p_array_init(&dest->keywords, dest->pool, array_count(keywords));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (i = 0; i < count; i++) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const char *name = p_strdup(dest->pool, names[i]);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync array_append(&dest->keywords, &name, 1);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return TRUE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncbool mailbox_equals(struct mailbox *box1, struct mail_storage *storage2,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const char *name2)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync struct mail_storage *storage1 = mailbox_get_storage(box1);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const char *name1;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (storage1 != storage2)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync name1 = mailbox_get_name(box1);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (strcmp(name1, name2) == 0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return TRUE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return strcasecmp(name1, "INBOX") == 0 &&
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync strcasecmp(name2, "INBOX") == 0;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncvoid msgset_generator_init(struct msgset_generator_context *ctx, string_t *str)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync memset(ctx, 0, sizeof(*ctx));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ctx->str = str;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ctx->last_uid = (uint32_t)-1;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncvoid msgset_generator_next(struct msgset_generator_context *ctx, uint32_t uid)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (uid != ctx->last_uid+1) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (ctx->first_uid == 0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else if (ctx->first_uid == ctx->last_uid)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync str_printfa(ctx->str, "%u,", ctx->first_uid);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync str_printfa(ctx->str, "%u:%u,",
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ctx->first_uid, ctx->last_uid);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ctx->first_uid = uid;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ctx->last_uid = uid;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncvoid msgset_generator_finish(struct msgset_generator_context *ctx)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (ctx->first_uid == ctx->last_uid)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync str_printfa(ctx->str, "%u", ctx->first_uid);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync str_printfa(ctx->str, "%u:%u", ctx->first_uid, ctx->last_uid);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync