[dovecot-cvs] dovecot/src/imap client.c, 1.38, 1.39 client.h, 1.20,
1.21 cmd-list.c, 1.39, 1.40 commands-util.c, 1.34, 1.35
cras at dovecot.org
cras at dovecot.org
Wed Aug 18 08:13:49 EEST 2004
Update of /home/cvs/dovecot/src/imap
In directory talvi:/tmp/cvs-serv26526
Modified Files:
client.c client.h cmd-list.c commands-util.c
Log Message:
LIST command interrupts itself when output buffer gets full and continues
again when there's space.
Index: client.c
===================================================================
RCS file: /home/cvs/dovecot/src/imap/client.c,v
retrieving revision 1.38
retrieving revision 1.39
diff -u -d -r1.38 -r1.39
--- client.c 15 Aug 2004 03:40:30 -0000 1.38
+++ client.c 18 Aug 2004 05:13:47 -0000 1.39
@@ -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)
Index: client.h
===================================================================
RCS file: /home/cvs/dovecot/src/imap/client.h,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- client.h 15 Aug 2004 03:40:30 -0000 1.20
+++ client.h 18 Aug 2004 05:13:47 -0000 1.21
@@ -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);
Index: cmd-list.c
===================================================================
RCS file: /home/cvs/dovecot/src/imap/cmd-list.c,v
retrieving revision 1.39
retrieving revision 1.40
diff -u -d -r1.39 -r1.40
--- cmd-list.c 26 Jul 2004 23:09:28 -0000 1.39
+++ cmd-list.c 18 Aug 2004 05:13:47 -0000 1.40
@@ -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;
- enum imap_match_result match;
+ struct namespace *ns = ctx->ns;
const char *cur_prefix, *cur_ref, *cur_mask;
+ enum imap_match_result match;
+ unsigned int count;
size_t len;
- int inbox, match_inbox;
- inbox = strncasecmp(ref, "INBOX", 5) == 0 ||
- (*ref == '\0' && strncasecmp(mask, "INBOX", 5) == 0);
+ cur_prefix = ns->prefix;
+ cur_ref = ctx->ref;
+ cur_mask = ctx->mask;
- 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 (*ctx->ref != '\0') {
+ skip_prefix(&cur_prefix, &cur_ref, ctx->inbox);
- if (*cur_ref != '\0' && *cur_prefix != '\0') {
- /* reference parameter didn't match with
- namespace prefix. skip this. */
- t_pop();
- continue;
- }
+ if (*cur_ref != '\0' && *cur_prefix != '\0') {
+ /* reference parameter didn't match with
+ namespace prefix. skip this. */
+ return;
}
+ }
- if (*cur_ref == '\0' && *cur_prefix != '\0') {
- skip_prefix(&cur_prefix, &cur_mask,
- inbox && cur_ref == ref);
- }
+ if (*cur_ref == '\0' && *cur_prefix != '\0') {
+ skip_prefix(&cur_prefix, &cur_mask,
+ ctx->inbox && cur_ref == ctx->ref);
+ }
- glob = imap_match_init(pool_datastack_create(), mask,
- inbox && cur_ref == ref, ns->sep);
- match_inbox = imap_match(glob, "INBOX") == IMAP_MATCH_YES;
+ ctx->glob = imap_match_init(client->cmd_pool, ctx->mask,
+ ctx->inbox && cur_ref == ctx->ref, ns->sep);
- 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')
+ 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 (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 (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));
}
+ }
- 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;
+ if (match < 0)
+ return;
- 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--;
+ 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--;
+ }
+ }
- if (*cur_mask != '*' || strcmp(mask, "*") == 0)
- glob = NULL;
+ ctx->match_inbox = imap_match(ctx->glob, "INBOX") == IMAP_MATCH_YES;
- cur_ref = namespace_fix_sep(ns, cur_ref);
- cur_mask = namespace_fix_sep(ns, cur_mask);
+ if (*cur_mask != '*' || strcmp(ctx->mask, "*") == 0) {
+ /* a) we don't have '*' in mask
+ b) we want to display everything
- 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;
- }
+ 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;
}
- t_pop();
+ if (ret == 0)
+ return FALSE;
}
- return 0;
+ 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_send_tagline(client, !lsub ?
- "OK List completed." :
- "OK Lsub completed.");
+ 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;
+ }
return TRUE;
}
Index: commands-util.c
===================================================================
RCS file: /home/cvs/dovecot/src/imap/commands-util.c,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -d -r1.34 -r1.35
--- commands-util.c 22 Jul 2004 21:20:00 -0000 1.34
+++ commands-util.c 18 Aug 2004 05:13:47 -0000 1.35
@@ -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) {
More information about the dovecot-cvs
mailing list