Mercurial > dovecot > core-2.2
changeset 2425:8267d11cacfb HEAD
LIST command interrupts itself when output buffer gets full and continues
again when there's space.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 18 Aug 2004 08:13:47 +0300 |
parents | ab170ee24eb2 |
children | d47a550fc23b |
files | src/imap/client.c src/imap/client.h src/imap/cmd-list.c src/imap/commands-util.c |
diffstat | 4 files changed, 198 insertions(+), 142 deletions(-) [+] |
line wrap: on
line diff
--- a/src/imap/client.c Wed Aug 18 08:10:45 2004 +0300 +++ b/src/imap/client.c Wed Aug 18 08:13:47 2004 +0300 @@ -96,13 +96,23 @@ client_disconnect(client); } -void client_send_line(struct client *client, const char *data) +int client_send_line(struct client *client, const char *data) { + struct const_iovec iov[2]; + if (client->output->closed) - return; + return -1; - (void)o_stream_send_str(client->output, data); - (void)o_stream_send(client->output, "\r\n", 2); + iov[0].iov_base = data; + iov[0].iov_len = strlen(data); + iov[1].iov_base = "\r\n"; + iov[1].iov_len = 2; + + if (o_stream_sendv(client->output, iov, 2) < 0) + return -1; + + return o_stream_get_buffer_used_size(client->output) < + CLIENT_OUTPUT_OPTIMAL_SIZE; } void client_send_tagline(struct client *client, const char *data)
--- a/src/imap/client.h Wed Aug 18 08:10:45 2004 +0300 +++ b/src/imap/client.h Wed Aug 18 08:13:47 2004 +0300 @@ -56,8 +56,9 @@ void client_disconnect(struct client *client); void client_disconnect_with_error(struct client *client, const char *msg); -/* Send a line of data to client */ -void client_send_line(struct client *client, const char *data); +/* Send a line of data to client. Returns 1 if ok, 0 if buffer is getting full, + -1 if error */ +int client_send_line(struct client *client, const char *data); /* Send line of data to client, prefixed with client->tag */ void client_send_tagline(struct client *client, const char *data);
--- a/src/imap/cmd-list.c Wed Aug 18 08:10:45 2004 +0300 +++ b/src/imap/cmd-list.c Wed Aug 18 08:13:47 2004 +0300 @@ -1,4 +1,4 @@ -/* Copyright (C) 2002 Timo Sirainen */ +/* Copyright (C) 2002-2004 Timo Sirainen */ #include "common.h" #include "str.h" @@ -13,6 +13,21 @@ _MAILBOX_LIST_LISTEXT = 0x0800000 }; +struct cmd_list_context { + const char *ref; + const char *mask; + enum mailbox_list_flags list_flags; + + struct namespace *ns; + struct mailbox_list_context *list_ctx; + struct imap_match_glob *glob; + + unsigned int lsub:1; + unsigned int inbox:1; + unsigned int inbox_found:1; + unsigned int match_inbox:1; +}; + static const char * mailbox_flags2str(enum mailbox_flags flags, enum mailbox_list_flags list_flags) { @@ -77,64 +92,69 @@ } static int -list_namespace_mailboxes(struct client *client, struct imap_match_glob *glob, - struct namespace *ns, struct mailbox_list_context *ctx, - int lsub, int match_inbox, - enum mailbox_list_flags list_flags) +list_namespace_mailboxes(struct client *client, struct cmd_list_context *ctx) { struct mailbox_list *list; const char *name; string_t *str, *name_str; - int inbox_found = FALSE; + int ret; t_push(); str = t_str_new(256); name_str = t_str_new(256); - while ((list = mail_storage_mailbox_list_next(ctx)) != NULL) { + while ((list = mail_storage_mailbox_list_next(ctx->list_ctx)) != NULL) { str_truncate(name_str, 0); - str_append(name_str, ns->prefix); + str_append(name_str, ctx->ns->prefix); str_append(name_str, list->name); - if (ns->sep != ns->real_sep) { + if (ctx->ns->sep != ctx->ns->real_sep) { char *p = str_c_modifyable(name_str); for (; *p != '\0'; p++) { - if (*p == ns->real_sep) - *p = ns->sep; + if (*p == ctx->ns->real_sep) + *p = ctx->ns->sep; } } name = str_c(name_str); - if (*ns->prefix != '\0') { + if (*ctx->ns->prefix != '\0') { /* With masks containing '*' we do the checks here so prefix is included in matching */ - if (glob != NULL && - imap_match(glob, name) != IMAP_MATCH_YES) + if (ctx->glob != NULL && + imap_match(ctx->glob, name) != IMAP_MATCH_YES) continue; } else if (strcasecmp(list->name, "INBOX") == 0) { - if (!ns->inbox) + if (!ctx->ns->inbox) continue; name = "INBOX"; - inbox_found = TRUE; + ctx->inbox_found = TRUE; } str_truncate(str, 0); - str_printfa(str, "* %s (%s) \"%s\" ", lsub ? "LSUB" : "LIST", - mailbox_flags2str(list->flags, list_flags), - ns->sep_str); + str_printfa(str, "* %s (%s) \"%s\" ", + ctx->lsub ? "LSUB" : "LIST", + mailbox_flags2str(list->flags, ctx->list_flags), + ctx->ns->sep_str); imap_quote_append_string(str, name, FALSE); - client_send_line(client, str_c(str)); + if (client_send_line(client, str_c(str)) == 0) { + /* buffer is full, continue later */ + t_pop(); + return 0; + } } - if (!inbox_found && ns->inbox && match_inbox) { + if (!ctx->inbox_found && ctx->ns->inbox && ctx->match_inbox) { /* INBOX always exists */ str_truncate(str, 0); - str_printfa(str, "* LIST () \"%s\" \"INBOX\"", ns->sep_str); + str_printfa(str, "* LIST (\\Unmarked) \"%s\" \"INBOX\"", + ctx->ns->sep_str); client_send_line(client, str_c(str)); } t_pop(); - return mail_storage_mailbox_list_deinit(ctx); + ret = mail_storage_mailbox_list_deinit(ctx->list_ctx); + ctx->list_ctx = NULL; + return ret < 0 ? -1 : 1; } static void skip_prefix(const char **prefix, const char **mask, int inbox) @@ -153,130 +173,142 @@ } } -static int list_mailboxes(struct client *client, - const char *ref, const char *mask, int lsub, - enum mailbox_list_flags list_flags) +static void +list_namespace_init(struct client *client, struct cmd_list_context *ctx) { - struct namespace *ns; - struct mailbox_list_context *ctx; - struct imap_match_glob *glob; + struct namespace *ns = ctx->ns; + const char *cur_prefix, *cur_ref, *cur_mask; enum imap_match_result match; - const char *cur_prefix, *cur_ref, *cur_mask; + unsigned int count; size_t len; - int inbox, match_inbox; - - inbox = strncasecmp(ref, "INBOX", 5) == 0 || - (*ref == '\0' && strncasecmp(mask, "INBOX", 5) == 0); - - for (ns = client->namespaces; ns != NULL; ns = ns->next) { - t_push(); - cur_prefix = ns->prefix; - cur_ref = ref; - cur_mask = mask; - if (*ref != '\0') { - skip_prefix(&cur_prefix, &cur_ref, inbox); - if (*cur_ref != '\0' && *cur_prefix != '\0') { - /* reference parameter didn't match with - namespace prefix. skip this. */ - t_pop(); - continue; - } - } + cur_prefix = ns->prefix; + cur_ref = ctx->ref; + cur_mask = ctx->mask; - if (*cur_ref == '\0' && *cur_prefix != '\0') { - skip_prefix(&cur_prefix, &cur_mask, - inbox && cur_ref == ref); - } + if (*ctx->ref != '\0') { + skip_prefix(&cur_prefix, &cur_ref, ctx->inbox); - glob = imap_match_init(pool_datastack_create(), mask, - inbox && cur_ref == ref, ns->sep); - match_inbox = imap_match(glob, "INBOX") == IMAP_MATCH_YES; - - if (*cur_ref != '\0' || *cur_prefix == '\0') - match = IMAP_MATCH_CHILDREN; - else { - len = strlen(cur_prefix); - if (cur_prefix[len-1] == ns->sep) - cur_prefix = t_strndup(cur_prefix, len-1); - match = ns->hidden ? IMAP_MATCH_NO : - imap_match(glob, cur_prefix); + if (*cur_ref != '\0' && *cur_prefix != '\0') { + /* reference parameter didn't match with + namespace prefix. skip this. */ + return; + } + } - if (match == IMAP_MATCH_YES) { - /* The prefix itself matches */ - string_t *str = t_str_new(128); - str_printfa(str, "* LIST (%s) \"%s\" ", - mailbox_flags2str(MAILBOX_PLACEHOLDER, - list_flags), - ns->sep_str); - len = strlen(ns->prefix); - imap_quote_append_string(str, - t_strndup(ns->prefix, len-1), FALSE); - client_send_line(client, str_c(str)); - } - } + if (*cur_ref == '\0' && *cur_prefix != '\0') { + skip_prefix(&cur_prefix, &cur_mask, + ctx->inbox && cur_ref == ctx->ref); + } - if (match >= 0) { - unsigned int count = 0; - if (*cur_prefix != '\0') { - /* we'll have to fix mask */ - for (; *cur_prefix != '\0'; cur_prefix++) { - if (*cur_prefix == ns->sep) - count++; - } - if (count == 0) - count = 1; + ctx->glob = imap_match_init(client->cmd_pool, ctx->mask, + ctx->inbox && cur_ref == ctx->ref, ns->sep); - while (count > 0) { - if (*cur_ref != '\0') { - while (*cur_ref != '\0' && - *cur_ref++ != ns->sep) - ; - } else { - while (*cur_mask != '\0' && - *cur_mask != '*' && - *cur_mask != ns->sep) - cur_mask++; - if (*cur_mask == '*') { - cur_mask = "*"; - break; - } - if (*cur_mask == '\0') - break; - cur_mask++; - } - count--; - } - } + if (*cur_ref != '\0' || *cur_prefix == '\0') + match = IMAP_MATCH_CHILDREN; + else { + len = strlen(cur_prefix); + if (cur_prefix[len-1] == ns->sep) + cur_prefix = t_strndup(cur_prefix, len-1); + match = ns->hidden ? IMAP_MATCH_NO : + imap_match(ctx->glob, cur_prefix); - if (*cur_mask != '*' || strcmp(mask, "*") == 0) - glob = NULL; - - cur_ref = namespace_fix_sep(ns, cur_ref); - cur_mask = namespace_fix_sep(ns, cur_mask); - - ctx = mail_storage_mailbox_list_init(ns->storage, - cur_ref, cur_mask, - list_flags); - if (list_namespace_mailboxes(client, glob, ns, ctx, - lsub, match_inbox, - list_flags) < 0) { - client_send_storage_error(client, ns->storage); - t_pop(); - return -1; - } + if (match == IMAP_MATCH_YES) { + /* The prefix itself matches */ + string_t *str = t_str_new(128); + str_printfa(str, "* LIST (%s) \"%s\" ", + mailbox_flags2str(MAILBOX_PLACEHOLDER, + ctx->list_flags), + ns->sep_str); + len = strlen(ns->prefix); + imap_quote_append_string(str, + t_strndup(ns->prefix, len-1), FALSE); + client_send_line(client, str_c(str)); } - t_pop(); } - return 0; + if (match < 0) + return; + + count = 0; + if (*cur_prefix != '\0') { + /* we'll have to fix mask */ + for (; *cur_prefix != '\0'; cur_prefix++) { + if (*cur_prefix == ns->sep) + count++; + } + if (count == 0) + count = 1; + + while (count > 0) { + if (*cur_ref != '\0') { + while (*cur_ref != '\0' && + *cur_ref++ != ns->sep) + ; + } else { + while (*cur_mask != '\0' && *cur_mask != '*' && + *cur_mask != ns->sep) + cur_mask++; + + if (*cur_mask == '*') { + cur_mask = "*"; + break; + } + if (*cur_mask == '\0') + break; + cur_mask++; + } + count--; + } + } + + ctx->match_inbox = imap_match(ctx->glob, "INBOX") == IMAP_MATCH_YES; + + if (*cur_mask != '*' || strcmp(ctx->mask, "*") == 0) { + /* a) we don't have '*' in mask + b) we want to display everything + + we don't need to do separate matching ourself */ + ctx->glob = NULL; + } + + cur_ref = namespace_fix_sep(ns, cur_ref); + cur_mask = namespace_fix_sep(ns, cur_mask); + + ctx->list_ctx = mail_storage_mailbox_list_init(ns->storage, + cur_ref, cur_mask, + ctx->list_flags); +} + +static int cmd_list_continue(struct client *client) +{ + struct cmd_list_context *ctx = client->cmd_context; + int ret; + + for (; ctx->ns != NULL; ctx->ns = ctx->ns->next) { + if (ctx->list_ctx == NULL) + list_namespace_init(client, ctx); + + if ((ret = list_namespace_mailboxes(client, ctx)) < 0) { + client_send_storage_error(client, ctx->ns->storage); + return TRUE; + } + if (ret == 0) + return FALSE; + } + + client_send_tagline(client, !ctx->lsub ? + "OK List completed." : + "OK Lsub completed."); + return TRUE; } int _cmd_list_full(struct client *client, int lsub) { struct namespace *ns; struct imap_arg *args; - enum mailbox_list_flags list_flags; + enum mailbox_list_flags list_flags; + struct cmd_list_context *ctx; const char *ref, *mask; /* [(<options>)] <reference> <mailbox wildcards> */ @@ -323,14 +355,28 @@ "* LIST (\\Noselect) \"", ns->sep_str, "\" \"\"", NULL)); } + client_send_tagline(client, "OK List completed."); } else { - if (list_mailboxes(client, ref, mask, lsub, list_flags) < 0) - return TRUE; + ctx = p_new(client->cmd_pool, struct cmd_list_context, 1); + ctx->ref = ref; + ctx->mask = mask; + ctx->list_flags = list_flags; + ctx->lsub = lsub; + ctx->inbox = strncasecmp(ref, "INBOX", 5) == 0 || + (*ref == '\0' && strncasecmp(mask, "INBOX", 5) == 0); + ctx->ns = client->namespaces; + + client->cmd_context = ctx; + if (!cmd_list_continue(client)) { + /* unfinished */ + client->command_pending = TRUE; + client->cmd_func = cmd_list_continue; + return FALSE; + } + + client->cmd_context = NULL; + return TRUE; } - - client_send_tagline(client, !lsub ? - "OK List completed." : - "OK Lsub completed."); return TRUE; }
--- a/src/imap/commands-util.c Wed Aug 18 08:10:45 2004 +0300 +++ b/src/imap/commands-util.c Wed Aug 18 08:13:47 2004 +0300 @@ -218,8 +218,7 @@ size_t size, i; memset(flags, 0, sizeof(*flags)); - buffer = buffer_create_dynamic(pool_datastack_create(), - 256, (size_t)-1); + buffer = buffer_create_dynamic(client->cmd_pool, 256, (size_t)-1); while (args->type != IMAP_ARG_EOL) { if (args->type != IMAP_ARG_ATOM) {