This is needed for the new IMAP LIST-MYRIGHTS capability (RFC 8440).
#include "imap-commands.h"
#include "imap-list.h"
+struct cmd_list_return_flag {
+ const struct imap_list_return_flag *flag;
+
+ void *context;
+};
+
struct cmd_list_context {
struct client_command_context *cmd;
struct mail_user *user;
enum mailbox_list_iter_flags list_flags;
struct imap_status_items status_items;
+ ARRAY(struct cmd_list_return_flag) return_flags;
struct mailbox_list_iterate_context *list_iter;
enum mailbox_list_iter_flags list_flags = 0;
const struct imap_arg *list_args;
const char *str;
+ const struct imap_list_return_flag *flag;
+ void *flag_context;
+ int ret;
while (!IMAP_ARG_IS_EOL(args)) {
if (!imap_arg_get_atom(args, &str)) {
return FALSE;
ctx->used_status = TRUE;
args++;
+ } else if ((ret = imap_list_return_flag_parse(
+ ctx->cmd, str, &args, &flag, &flag_context)) > 0) {
+ struct cmd_list_return_flag *flag_data;
+
+ if (!array_is_created(&ctx->return_flags)) {
+ p_array_init(&ctx->return_flags,
+ ctx->cmd->pool, 8);
+ }
+ flag_data = array_append_space(&ctx->return_flags);
+ flag_data->flag = flag;
+ flag_data->context = flag_context;
+ } else if (ret < 0) {
+ return FALSE;
} else {
/* skip also optional list value */
client_send_command_error(ctx->cmd,
&ctx->status_items, &result);
}
+static bool
+list_has_options(struct cmd_list_context *ctx)
+{
+ if (ctx->used_status)
+ return TRUE;
+ return array_is_created(&ctx->return_flags);
+}
+
+static void
+list_send_options(struct cmd_list_context *ctx,
+ const struct imap_list_return_flag_params *params)
+{
+ struct client_command_context *cmd = ctx->cmd;
+
+ if (ctx->used_status)
+ list_send_status(ctx, params);
+
+ if (array_is_created(&ctx->return_flags)) {
+ const struct cmd_list_return_flag *rflag;
+
+ array_foreach(&ctx->return_flags, rflag) {
+ imap_list_return_flag_send(cmd, rflag->flag,
+ rflag->context, params);
+ }
+ }
+}
+
static bool cmd_list_continue(struct client_command_context *cmd)
{
struct cmd_list_context *ctx = cmd->context;
if (ret < 0)
return TRUE;
- /* send STATUS response */
- if (ctx->used_status) {
+ /* send optional responses (if any) */
+ if (list_has_options(ctx)) {
struct imap_list_return_flag_params params = {
.name = name,
.mutf7_name = str_c(mutf7_name),
params.name);
T_BEGIN {
- list_send_status(ctx, ¶ms);
+ list_send_options(ctx, ¶ms);
} T_END;
}
if (ret == 0) {
#include "str.h"
#include "imap-list.h"
+static ARRAY(const struct imap_list_return_flag *) return_flags;
+
+void imap_list_return_flag_register(const struct imap_list_return_flag *rflag)
+{
+ array_push_back(&return_flags, &rflag);
+}
+
+void imap_list_return_flag_unregister(const struct imap_list_return_flag *rflag)
+{
+ unsigned int i;
+
+ if (array_lsearch_ptr_idx(&return_flags, rflag, &i)) {
+ array_delete(&return_flags, i, 1);
+ return;
+ }
+
+ i_panic("Trying to unregister unknown IMAP LIST RETURN flag '%s'",
+ rflag->identifier);
+}
+
+int imap_list_return_flag_parse(struct client_command_context *cmd,
+ const char *flag, const struct imap_arg **args,
+ const struct imap_list_return_flag **rflag_r,
+ void **context_r)
+{
+ const struct imap_list_return_flag *const *rflags;
+ unsigned int i, count;
+
+ rflags = array_get(&return_flags, &count);
+ for (i = 0; i < count; i++) {
+ if (strcasecmp(rflags[i]->identifier, flag) == 0)
+ break;
+ }
+
+ if (i == count)
+ return 0;
+
+ *context_r = NULL;
+ if (rflags[i]->parse != NULL) {
+ const struct imap_arg *list_args = NULL;
+
+ if (imap_arg_get_list(*args, &list_args))
+ (*args)++;
+ if (rflags[i]->parse(cmd, list_args, context_r) < 0)
+ return -1;
+ }
+
+ *rflag_r = rflags[i];
+ return 1;
+}
+
+void imap_list_return_flag_send(
+ struct client_command_context *cmd,
+ const struct imap_list_return_flag *rflag, void *context,
+ const struct imap_list_return_flag_params *params)
+{
+ rflag->send(cmd, context, params);
+}
+
bool imap_mailbox_flags2str(string_t *str, enum mailbox_info_flags flags)
{
size_t orig_len = str_len(str);
str_truncate(str, str_len(str)-1);
return TRUE;
}
+
+void imap_list_init(void)
+{
+ i_array_init(&return_flags, 8);
+}
+
+void imap_list_deinit(void)
+{
+ array_free(&return_flags);
+}
struct mail_namespace *ns;
};
+struct imap_list_return_flag {
+ const char *identifier;
+
+ int (*parse)(struct client_command_context *cmd,
+ const struct imap_arg *args, void **context_r);
+ void (*send)(struct client_command_context *cmd, void *context,
+ const struct imap_list_return_flag_params *params);
+};
+
+void imap_list_return_flag_register(const struct imap_list_return_flag *rflag);
+void imap_list_return_flag_unregister(const struct imap_list_return_flag *rflag);
+
+int imap_list_return_flag_parse(struct client_command_context *cmd,
+ const char *flag, const struct imap_arg **args,
+ const struct imap_list_return_flag **rflag_r,
+ void **context_r);
+void imap_list_return_flag_send(
+ struct client_command_context *cmd,
+ const struct imap_list_return_flag *rflag, void *context,
+ const struct imap_list_return_flag_params *params);
+
/* Returns TRUE if anything was added to the string. */
bool imap_mailbox_flags2str(string_t *str, enum mailbox_info_flags flags);
+void imap_list_init(void);
+void imap_list_deinit(void);
+
#endif
#include "imap-commands.h"
#include "imap-feature.h"
#include "imap-fetch.h"
+#include "imap-list.h"
#include <stdio.h>
#include <unistd.h>
imap_features_init();
clients_init();
imap_master_clients_init();
+ imap_list_init();
/* this is needed before settings are read */
verbose_proctitle = !IS_STANDALONE() &&
getenv(MASTER_VERBOSE_PROCTITLE_ENV) != NULL;
login_server_deinit(&login_server);
mail_storage_service_deinit(&storage_service);
+ imap_list_deinit();
imap_fetch_handlers_deinit();
imap_features_deinit();