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