# HG changeset patch # User Timo Sirainen # Date 1111171793 -7200 # Node ID 8632ec8486c6d2c8668670893af172df8d8acaee # Parent 92909176842612a80ee8fea50eee25fa9e9abdbc Send buffered fetch items to client first. Fixes kmail and Thunderbird issues.. diff -r 929091768426 -r 8632ec8486c6 src/imap/imap-fetch-body.c --- a/src/imap/imap-fetch-body.c Fri Mar 18 19:34:11 2005 +0200 +++ b/src/imap/imap-fetch-body.c Fri Mar 18 20:49:53 2005 +0200 @@ -587,7 +587,8 @@ MAIL_FETCH_STREAM_BODY)) != 0) { /* we'll need to open the file anyway, don't try to get the headers from cache. */ - imap_fetch_add_handler(ctx, fetch_body_header_partial, body); + imap_fetch_add_handler(ctx, FALSE, + fetch_body_header_partial, body); return TRUE; } @@ -599,7 +600,7 @@ } body->header_ctx = mailbox_header_lookup_init(ctx->box, body->fields); - imap_fetch_add_handler(ctx, fetch_body_header_fields, body); + imap_fetch_add_handler(ctx, FALSE, fetch_body_header_fields, body); t_pop(); return TRUE; } @@ -612,13 +613,13 @@ if (*section == '\0') { ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY; - imap_fetch_add_handler(ctx, fetch_body, body); + imap_fetch_add_handler(ctx, FALSE, fetch_body, body); return TRUE; } if (strcmp(section, "TEXT") == 0) { ctx->fetch_data |= MAIL_FETCH_STREAM_BODY; - imap_fetch_add_handler(ctx, fetch_body, body); + imap_fetch_add_handler(ctx, FALSE, fetch_body, body); return TRUE; } @@ -626,7 +627,7 @@ /* exact header matches could be cached */ if (section[6] == '\0') { ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER; - imap_fetch_add_handler(ctx, fetch_body, body); + imap_fetch_add_handler(ctx, FALSE, fetch_body, body); return TRUE; } @@ -636,8 +637,8 @@ if (strncmp(section, "HEADER.FIELDS.NOT ", 18) == 0 && fetch_body_header_fields_check(section+18)) { - imap_fetch_add_handler(ctx, fetch_body_header_partial, - body); + imap_fetch_add_handler(ctx, FALSE, + fetch_body_header_partial, body); return TRUE; } } else if (*section >= '0' && *section <= '9') { @@ -655,7 +656,8 @@ fetch_body_header_fields_check(section+14)) || (strncmp(section, "HEADER.FIELDS.NOT ", 18) == 0 && fetch_body_header_fields_check(section+18))) { - imap_fetch_add_handler(ctx, fetch_body_mime, body); + imap_fetch_add_handler(ctx, FALSE, + fetch_body_mime, body); return TRUE; } } @@ -926,24 +928,24 @@ ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY; ctx->flags_update_seen = TRUE; - imap_fetch_add_handler(ctx, fetch_rfc822, NULL); + imap_fetch_add_handler(ctx, FALSE, fetch_rfc822, NULL); return TRUE; } if (strcmp(name+6, ".SIZE") == 0) { ctx->fetch_data |= MAIL_FETCH_VIRTUAL_SIZE; - imap_fetch_add_handler(ctx, fetch_rfc822_size, NULL); + imap_fetch_add_handler(ctx, TRUE, fetch_rfc822_size, NULL); return TRUE; } if (strcmp(name+6, ".HEADER") == 0) { ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER; - imap_fetch_add_handler(ctx, fetch_rfc822_header, NULL); + imap_fetch_add_handler(ctx, FALSE, fetch_rfc822_header, NULL); return TRUE; } if (strcmp(name+6, ".TEXT") == 0) { ctx->fetch_data |= MAIL_FETCH_STREAM_BODY; ctx->flags_update_seen = TRUE; - imap_fetch_add_handler(ctx, fetch_rfc822_text, NULL); + imap_fetch_add_handler(ctx, FALSE, fetch_rfc822_text, NULL); return TRUE; } diff -r 929091768426 -r 8632ec8486c6 src/imap/imap-fetch.c --- a/src/imap/imap-fetch.c Fri Mar 18 19:34:11 2005 +0200 +++ b/src/imap/imap-fetch.c Fri Mar 18 20:49:53 2005 +0200 @@ -93,22 +93,32 @@ ctx->cur_str = str_new(default_pool, 8192); ctx->all_headers_buf = buffer_create_dynamic(cmd->pool, 128); - ctx->handlers = buffer_create_dynamic(cmd->pool, 128); + ARRAY_CREATE(&ctx->handlers, cmd->pool, + struct imap_fetch_context_handler, 16); ctx->line_finished = TRUE; return ctx; } -void imap_fetch_add_handler(struct imap_fetch_context *ctx, +void imap_fetch_add_handler(struct imap_fetch_context *ctx, int buffered, imap_fetch_handler_t *handler, void *context) { + /* partially because of broken clients, but also partially because + it potentially can make client implementations faster, we have a + buffered parameter which basically means that the handler promises + to write the output in ctx->cur_str. The cur_str is then sent to + client before calling any non-buffered handlers. + + We try to keep the handler registration order the same as the + client requested them. This is especially useful to get UID + returned first, which some clients rely on.. + */ const struct imap_fetch_context_handler *handlers; struct imap_fetch_context_handler h; - size_t i, size; + unsigned int i, size; if (context == NULL) { /* don't allow duplicate handlers */ - handlers = buffer_get_data(ctx->handlers, &size); - size /= sizeof(*handlers); + handlers = array_get(&ctx->handlers, &size); for (i = 0; i < size; i++) { if (handlers[i].handler == handler && @@ -120,8 +130,15 @@ memset(&h, 0, sizeof(h)); h.handler = handler; h.context = context; + h.buffered = buffered; - buffer_append(ctx->handlers, &h, sizeof(h)); + if (!buffered) + array_append(&ctx->handlers, &h, 1); + else { + array_insert(&ctx->handlers, ctx->buffered_handlers_count, + &h, 1); + ctx->buffered_handlers_count++; + } } void imap_fetch_begin(struct imap_fetch_context *ctx, @@ -158,10 +175,34 @@ mailbox_search_init(ctx->trans, NULL, search_arg, NULL); } +static int imap_fetch_flush_buffer(struct imap_fetch_context *ctx) +{ + const unsigned char *data; + size_t len; + + i_assert(ctx->first); + + data = str_data(ctx->cur_str); + len = str_len(ctx->cur_str); + + /* there's an extra space at the end if we added any fetch items + to buffer */ + if (data[len-1] == ' ') { + len--; + ctx->first = FALSE; + } + + if (o_stream_send(ctx->client->output, data, len) < 0) + return -1; + + str_truncate(ctx->cur_str, 0); + return 0; +} + int imap_fetch(struct imap_fetch_context *ctx) { const struct imap_fetch_context_handler *handlers; - size_t size; + unsigned int size; int ret; if (ctx->cont_handler != NULL) { @@ -184,9 +225,7 @@ ctx->cur_handler++; } - handlers = buffer_get_data(ctx->handlers, &size); - size /= sizeof(*handlers); - + handlers = array_get(&ctx->handlers, &size); for (;;) { if (o_stream_get_buffer_used_size(ctx->client->output) >= CLIENT_OUTPUT_OPTIMAL_SIZE) { @@ -208,18 +247,19 @@ str_printfa(ctx->cur_str, "* %u FETCH (", ctx->cur_mail->seq); - if (o_stream_send(ctx->client->output, - str_data(ctx->cur_str), - str_len(ctx->cur_str)) < 0) - return -1; - - str_truncate(ctx->cur_str, 0); - str_append_c(ctx->cur_str, ' '); ctx->first = TRUE; ctx->line_finished = FALSE; } for (; ctx->cur_handler < size; ctx->cur_handler++) { + if (str_len(ctx->cur_str) > 0 && + !handlers[ctx->cur_handler].buffered) { + /* first non-buffered handler. + flush the buffer. */ + if (imap_fetch_flush_buffer(ctx) < 0) + return -1; + } + t_push(); ret = handlers[ctx->cur_handler]. handler(ctx, ctx->cur_mail, @@ -244,14 +284,11 @@ ctx->cur_offset = 0; } - if (str_len(ctx->cur_str) > 1) { - if (o_stream_send(ctx->client->output, - str_data(ctx->cur_str) + ctx->first, - str_len(ctx->cur_str) - 1 - - ctx->first) < 0) + if (str_len(ctx->cur_str) > 0) { + /* no non-buffered handlers */ + if (imap_fetch_flush_buffer(ctx) < 0) return -1; } - str_truncate(ctx->cur_str, 0); ctx->line_finished = TRUE; if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0) @@ -327,7 +364,7 @@ { if (name[4] == '\0') { ctx->fetch_data |= MAIL_FETCH_IMAP_BODY; - imap_fetch_add_handler(ctx, fetch_body, NULL); + imap_fetch_add_handler(ctx, FALSE, fetch_body, NULL); return TRUE; } return fetch_body_section_init(ctx, name, args); @@ -362,7 +399,7 @@ struct imap_arg **args __attr_unused__) { ctx->fetch_data |= MAIL_FETCH_IMAP_BODYSTRUCTURE; - imap_fetch_add_handler(ctx, fetch_bodystructure, NULL); + imap_fetch_add_handler(ctx, FALSE, fetch_bodystructure, NULL); return TRUE; } @@ -394,7 +431,7 @@ struct imap_arg **args __attr_unused__) { ctx->fetch_data |= MAIL_FETCH_IMAP_ENVELOPE; - imap_fetch_add_handler(ctx, fetch_envelope, NULL); + imap_fetch_add_handler(ctx, FALSE, fetch_envelope, NULL); return TRUE; } @@ -428,7 +465,7 @@ { ctx->flags_have_handler = TRUE; ctx->fetch_data |= MAIL_FETCH_FLAGS; - imap_fetch_add_handler(ctx, fetch_flags, NULL); + imap_fetch_add_handler(ctx, TRUE, fetch_flags, NULL); return TRUE; } @@ -452,7 +489,7 @@ struct imap_arg **args __attr_unused__) { ctx->fetch_data |= MAIL_FETCH_RECEIVED_DATE; - imap_fetch_add_handler(ctx, fetch_internaldate, NULL); + imap_fetch_add_handler(ctx, TRUE, fetch_internaldate, NULL); return TRUE; } @@ -467,7 +504,7 @@ const char *name __attr_unused__, struct imap_arg **args __attr_unused__) { - imap_fetch_add_handler(ctx, fetch_uid, NULL); + imap_fetch_add_handler(ctx, TRUE, fetch_uid, NULL); return TRUE; } diff -r 929091768426 -r 8632ec8486c6 src/imap/imap-fetch.h --- a/src/imap/imap-fetch.h Fri Mar 18 19:34:11 2005 +0200 +++ b/src/imap/imap-fetch.h Fri Mar 18 20:49:53 2005 +0200 @@ -19,6 +19,7 @@ struct imap_fetch_context_handler { imap_fetch_handler_t *handler; void *context; + int buffered; }; struct imap_fetch_context { @@ -34,7 +35,8 @@ buffer_t *all_headers_buf; struct mailbox_header_lookup_ctx *all_headers_ctx; - buffer_t *handlers; + array_t ARRAY_DEFINE(handlers, struct imap_fetch_context_handler); + unsigned int buffered_handlers_count; struct mail *cur_mail; unsigned int cur_handler; @@ -61,7 +63,7 @@ void imap_fetch_handlers_register(const struct imap_fetch_handler *handlers, size_t count); -void imap_fetch_add_handler(struct imap_fetch_context *ctx, +void imap_fetch_add_handler(struct imap_fetch_context *ctx, int buffered, imap_fetch_handler_t *handler, void *context); struct imap_fetch_context *imap_fetch_init(struct client_command_context *cmd);