imap-commands.c revision 3032fe1c7b066780a5d3e3c34d5157b03494cec4
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen#include "imap-common.h"
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen#include "array.h"
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen#include "buffer.h"
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen#include "imap-commands.h"
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen#include <stdlib.h>
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainenstatic const struct command imap4rev1_commands[] = {
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "CAPABILITY", cmd_capability, 0 },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "LOGOUT", cmd_logout, COMMAND_FLAG_BREAKS_MAILBOX },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "NOOP", cmd_noop, COMMAND_FLAG_BREAKS_SEQS },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "APPEND", cmd_append, COMMAND_FLAG_BREAKS_SEQS },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "EXAMINE", cmd_examine, COMMAND_FLAG_BREAKS_MAILBOX },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "CREATE", cmd_create, 0 },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "DELETE", cmd_delete, COMMAND_FLAG_BREAKS_MAILBOX |
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen COMMAND_FLAG_USE_NONEXISTENT },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "RENAME", cmd_rename, COMMAND_FLAG_USE_NONEXISTENT },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "LIST", cmd_list, 0 },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "LSUB", cmd_lsub, 0 },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "SELECT", cmd_select, COMMAND_FLAG_BREAKS_MAILBOX },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "STATUS", cmd_status, 0 },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "SUBSCRIBE", cmd_subscribe, 0 },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "UNSUBSCRIBE", cmd_unsubscribe, COMMAND_FLAG_USE_NONEXISTENT },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "CHECK", cmd_check, COMMAND_FLAG_BREAKS_SEQS },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "CLOSE", cmd_close, COMMAND_FLAG_BREAKS_MAILBOX },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "COPY", cmd_copy, COMMAND_FLAG_USES_SEQS |
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen COMMAND_FLAG_BREAKS_SEQS },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "EXPUNGE", cmd_expunge, COMMAND_FLAG_BREAKS_SEQS },
2bd58dc6e7c991c86713a4b91f9db468abe734a4Aki Tuomi { "FETCH", cmd_fetch, COMMAND_FLAG_USES_SEQS },
2bd58dc6e7c991c86713a4b91f9db468abe734a4Aki Tuomi { "SEARCH", cmd_search, COMMAND_FLAG_USES_SEQS },
2bd58dc6e7c991c86713a4b91f9db468abe734a4Aki Tuomi { "STORE", cmd_store, COMMAND_FLAG_USES_SEQS },
2bd58dc6e7c991c86713a4b91f9db468abe734a4Aki Tuomi { "UID", cmd_uid, 0 },
2bd58dc6e7c991c86713a4b91f9db468abe734a4Aki Tuomi { "UID COPY", cmd_copy, COMMAND_FLAG_BREAKS_SEQS },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "UID FETCH", cmd_fetch, COMMAND_FLAG_BREAKS_SEQS },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "UID SEARCH", cmd_search, COMMAND_FLAG_BREAKS_SEQS },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "UID STORE", cmd_store, COMMAND_FLAG_BREAKS_SEQS }
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen};
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen#define IMAP4REV1_COMMANDS_COUNT N_ELEMENTS(imap4rev1_commands)
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainenstatic const struct command imap_ext_commands[] = {
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "CANCELUPDATE", cmd_cancelupdate,0 },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "ENABLE", cmd_enable, 0 },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "ID", cmd_id, 0 },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "IDLE", cmd_idle, COMMAND_FLAG_BREAKS_SEQS |
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen COMMAND_FLAG_REQUIRES_SYNC },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "NAMESPACE", cmd_namespace, 0 },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "SORT", cmd_sort, COMMAND_FLAG_USES_SEQS },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "THREAD", cmd_thread, COMMAND_FLAG_USES_SEQS },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "UID EXPUNGE", cmd_uid_expunge, COMMAND_FLAG_BREAKS_SEQS },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "UID SORT", cmd_sort, COMMAND_FLAG_BREAKS_SEQS },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "UID THREAD", cmd_thread, COMMAND_FLAG_BREAKS_SEQS },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "UNSELECT", cmd_unselect, COMMAND_FLAG_BREAKS_MAILBOX },
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen { "X-CANCEL", cmd_x_cancel, 0 }
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen};
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen#define IMAP_EXT_COMMANDS_COUNT N_ELEMENTS(imap_ext_commands)
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen
65a1c01472ebf88b9f5bbd6636827902936d5497Timo SirainenARRAY_TYPE(command) imap_commands;
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainenstatic bool commands_unsorted;
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainenvoid command_register(const char *name, command_func_t *func,
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen enum command_flags flags)
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen{
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen struct command cmd;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen memset(&cmd, 0, sizeof(cmd));
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen cmd.name = name;
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen cmd.func = func;
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen cmd.flags = flags;
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen array_append(&imap_commands, &cmd, 1);
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen
80e80d414f8fa748d2d10c40db423922968a11ccTimo Sirainen commands_unsorted = TRUE;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen}
80e80d414f8fa748d2d10c40db423922968a11ccTimo Sirainen
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainenvoid command_unregister(const char *name)
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen{
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen const struct command *cmd;
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen unsigned int i, count;
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen cmd = array_get(&imap_commands, &count);
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen for (i = 0; i < count; i++) {
48b28b91852a975a495a6fe82f5db5b35333500aTimo Sirainen if (strcasecmp(cmd[i].name, name) == 0) {
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen array_delete(&imap_commands, i, 1);
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen return;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen }
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen }
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen i_error("Trying to unregister unknown command '%s'", name);
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen}
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainenvoid command_register_array(const struct command *cmdarr, unsigned int count)
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen{
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen commands_unsorted = TRUE;
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen array_append(&imap_commands, cmdarr, count);
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen}
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainenvoid command_unregister_array(const struct command *cmdarr, unsigned int count)
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen{
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen while (count > 0) {
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen command_unregister(cmdarr->name);
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen count--; cmdarr++;
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen }
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen}
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainenstatic int command_cmp(const struct command *c1, const struct command *c2)
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen{
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen return strcasecmp(c1->name, c2->name);
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen}
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainenstatic int command_bsearch(const char *name, const struct command *cmd)
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen{
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen return strcasecmp(name, cmd->name);
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen}
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainenstruct command *command_find(const char *name)
65a1c01472ebf88b9f5bbd6636827902936d5497Timo Sirainen{
38f53f9d3eda5002b3478f7679d352ee4da60d2fAki Tuomi if (commands_unsorted) {
38f53f9d3eda5002b3478f7679d352ee4da60d2fAki Tuomi array_sort(&imap_commands, command_cmp);
38f53f9d3eda5002b3478f7679d352ee4da60d2fAki Tuomi commands_unsorted = FALSE;
38f53f9d3eda5002b3478f7679d352ee4da60d2fAki Tuomi }
38f53f9d3eda5002b3478f7679d352ee4da60d2fAki Tuomi
return array_bsearch(&imap_commands, name, command_bsearch);
}
void commands_init(void)
{
i_array_init(&imap_commands, 64);
commands_unsorted = FALSE;
command_register_array(imap4rev1_commands, IMAP4REV1_COMMANDS_COUNT);
command_register_array(imap_ext_commands, IMAP_EXT_COMMANDS_COUNT);
}
void commands_deinit(void)
{
command_unregister_array(imap4rev1_commands, IMAP4REV1_COMMANDS_COUNT);
command_unregister_array(imap_ext_commands, IMAP_EXT_COMMANDS_COUNT);
array_free(&imap_commands);
}