imap-commands.c revision 5735ada0f82788ee1b5228978d5bd8dad5a04219
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "imap-common.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include "array.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include "buffer.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include "imap-commands.h"
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include <stdlib.h>
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic const struct command imap4rev1_commands[] = {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "CAPABILITY", cmd_capability, 0 },
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen { "LOGOUT", cmd_logout, COMMAND_FLAG_BREAKS_MAILBOX },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "NOOP", cmd_noop, COMMAND_FLAG_BREAKS_SEQS },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "APPEND", cmd_append, COMMAND_FLAG_BREAKS_SEQS },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "EXAMINE", cmd_examine, COMMAND_FLAG_BREAKS_MAILBOX },
25d624dd86700c82cd28427f3d3bebe7c8f7f459Timo Sirainen { "CREATE", cmd_create, 0 },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "DELETE", cmd_delete, 0 },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "RENAME", cmd_rename, 0 },
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen { "LIST", cmd_list, 0 },
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen { "LSUB", cmd_lsub, 0 },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "SELECT", cmd_select, COMMAND_FLAG_BREAKS_MAILBOX },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "STATUS", cmd_status, 0 },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "SUBSCRIBE", cmd_subscribe, 0 },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "UNSUBSCRIBE", cmd_unsubscribe, 0 },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "CHECK", cmd_check, COMMAND_FLAG_BREAKS_SEQS },
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen { "CLOSE", cmd_close, COMMAND_FLAG_BREAKS_MAILBOX },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "COPY", cmd_copy, COMMAND_FLAG_USES_SEQS |
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen COMMAND_FLAG_BREAKS_SEQS },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "EXPUNGE", cmd_expunge, COMMAND_FLAG_BREAKS_SEQS },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "FETCH", cmd_fetch, COMMAND_FLAG_USES_SEQS },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "SEARCH", cmd_search, COMMAND_FLAG_USES_SEQS },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "STORE", cmd_store, COMMAND_FLAG_USES_SEQS },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "UID", cmd_uid, 0 },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "UID COPY", cmd_copy, COMMAND_FLAG_BREAKS_SEQS },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "UID FETCH", cmd_fetch, COMMAND_FLAG_BREAKS_SEQS },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "UID SEARCH", cmd_search, COMMAND_FLAG_BREAKS_SEQS },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "UID STORE", cmd_store, COMMAND_FLAG_BREAKS_SEQS }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen};
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#define IMAP4REV1_COMMANDS_COUNT N_ELEMENTS(imap4rev1_commands)
04870054863757edf048c81dcce3c5e7dec453cdTimo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic const struct command imap_ext_commands[] = {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "CANCELUPDATE", cmd_cancelupdate,0 },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "ENABLE", cmd_enable, 0 },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "ID", cmd_id, 0 },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "IDLE", cmd_idle, COMMAND_FLAG_BREAKS_SEQS |
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen COMMAND_FLAG_REQUIRES_SYNC },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "NAMESPACE", cmd_namespace, 0 },
15a07b47846c47a81d69a14d649564e222d6f742Timo Sirainen { "SORT", cmd_sort, COMMAND_FLAG_USES_SEQS },
15a07b47846c47a81d69a14d649564e222d6f742Timo Sirainen { "THREAD", cmd_thread, COMMAND_FLAG_USES_SEQS },
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen { "UID EXPUNGE", cmd_uid_expunge, COMMAND_FLAG_BREAKS_SEQS },
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen { "UID SORT", cmd_sort, COMMAND_FLAG_BREAKS_SEQS },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "UID THREAD", cmd_thread, COMMAND_FLAG_BREAKS_SEQS },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "UNSELECT", cmd_unselect, COMMAND_FLAG_BREAKS_MAILBOX },
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen { "X-CANCEL", cmd_x_cancel, 0 }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen};
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#define IMAP_EXT_COMMANDS_COUNT N_ELEMENTS(imap_ext_commands)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo SirainenARRAY_TYPE(command) imap_commands;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenstatic bool commands_unsorted;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenvoid command_register(const char *name, command_func_t *func,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen enum command_flags flags)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct command cmd;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen memset(&cmd, 0, sizeof(cmd));
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen cmd.name = name;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen cmd.func = func;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen cmd.flags = flags;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen array_append(&imap_commands, &cmd, 1);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen commands_unsorted = TRUE;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid command_unregister(const char *name)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const struct command *cmd;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen unsigned int i, count;
e1203014de25c8c3d3975a9f4b4a04616df4bba2Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen cmd = array_get(&imap_commands, &count);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen for (i = 0; i < count; i++) {
e1203014de25c8c3d3975a9f4b4a04616df4bba2Timo Sirainen if (strcasecmp(cmd[i].name, name) == 0) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen array_delete(&imap_commands, i, 1);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_error("Trying to unregister unknown command '%s'", name);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid command_register_array(const struct command *cmdarr, unsigned int count)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen commands_unsorted = TRUE;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen array_append(&imap_commands, cmdarr, count);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid command_unregister_array(const struct command *cmdarr, unsigned int count)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen while (count > 0) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen command_unregister(cmdarr->name);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen count--; cmdarr++;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic int command_cmp(const void *p1, const void *p2)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const struct command *c1 = p1, *c2 = p2;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return strcasecmp(c1->name, c2->name);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic int command_bsearch(const void *name, const void *cmd_p)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const struct command *cmd = cmd_p;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return strcasecmp(name, cmd->name);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstruct command *command_find(const char *name)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen void *base;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen unsigned int count;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen base = array_get_modifiable(&imap_commands, &count);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (commands_unsorted) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen qsort(base, count, sizeof(struct command), command_cmp);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen commands_unsorted = FALSE;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return bsearch(name, base, count, sizeof(struct command),
3a9eb305fd4aad5502cb7e64625874385ab5bc19Timo Sirainen command_bsearch);
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen}
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid commands_init(void)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_array_init(&imap_commands, 64);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen commands_unsorted = FALSE;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen command_register_array(imap4rev1_commands, IMAP4REV1_COMMANDS_COUNT);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen command_register_array(imap_ext_commands, IMAP_EXT_COMMANDS_COUNT);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid commands_deinit(void)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen command_unregister_array(imap4rev1_commands, IMAP4REV1_COMMANDS_COUNT);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen command_unregister_array(imap_ext_commands, IMAP_EXT_COMMANDS_COUNT);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen array_free(&imap_commands);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen