Mercurial > dovecot > core-2.2
changeset 14228:d8a88e53f1e6
imap: Changed internal FETCH command handling API.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 01 Mar 2012 09:31:40 +0200 |
parents | df631445f150 |
children | 96e3b3ef59dc |
files | src/imap/cmd-fetch.c src/imap/cmd-select.c src/imap/imap-fetch-body.c src/imap/imap-fetch.c src/imap/imap-fetch.h |
diffstat | 5 files changed, 253 insertions(+), 237 deletions(-) [+] |
line wrap: on
line diff
--- a/src/imap/cmd-fetch.c Tue Feb 28 05:27:03 2012 +0200 +++ b/src/imap/cmd-fetch.c Thu Mar 01 09:31:40 2012 +0200 @@ -21,13 +21,14 @@ }; static bool -fetch_parse_args(struct imap_fetch_context *ctx, const struct imap_arg *arg, - const struct imap_arg **next_arg_r) +fetch_parse_args(struct imap_fetch_context *ctx, + struct client_command_context *cmd, + const struct imap_arg *arg, const struct imap_arg **next_arg_r) { const char *str, *const *macro; - if (ctx->cmd->uid) { - if (!imap_fetch_init_handler(ctx, "UID", &arg)) + if (cmd->uid) { + if (!imap_fetch_cmd_init_handler(ctx, cmd, "UID", &arg)) return FALSE; } if (imap_arg_get_atom(arg, &str)) { @@ -43,12 +44,12 @@ macro = full_macro; else { macro = NULL; - if (!imap_fetch_init_handler(ctx, str, &arg)) + if (!imap_fetch_cmd_init_handler(ctx, cmd, str, &arg)) return FALSE; } if (macro != NULL) { while (*macro != NULL) { - if (!imap_fetch_init_handler(ctx, *macro, &arg)) + if (!imap_fetch_cmd_init_handler(ctx, cmd, *macro, &arg)) return FALSE; macro++; } @@ -60,11 +61,11 @@ while (imap_arg_get_atom(arg, &str)) { str = t_str_ucase(str); arg++; - if (!imap_fetch_init_handler(ctx, str, &arg)) + if (!imap_fetch_cmd_init_handler(ctx, cmd, str, &arg)) return FALSE; } if (!IMAP_ARG_IS_EOL(arg)) { - client_send_command_error(ctx->cmd, + client_send_command_error(cmd, "FETCH list contains non-atoms."); return FALSE; } @@ -74,6 +75,7 @@ static bool fetch_parse_modifier(struct imap_fetch_context *ctx, + struct client_command_context *cmd, const char *name, const struct imap_arg **args) { const char *str; @@ -82,58 +84,59 @@ if (strcmp(name, "CHANGEDSINCE") == 0) { if (!imap_arg_get_atom(*args, &str) || str_to_uint64(str, &modseq) < 0) { - client_send_command_error(ctx->cmd, + client_send_command_error(cmd, "Invalid CHANGEDSINCE modseq."); return FALSE; } *args += 1; - return imap_fetch_add_changed_since(ctx, modseq); + imap_fetch_add_changed_since(ctx, modseq); + return TRUE; } - if (strcmp(name, "VANISHED") == 0 && ctx->cmd->uid) { + if (strcmp(name, "VANISHED") == 0 && cmd->uid) { if ((ctx->client->enabled_features & MAILBOX_FEATURE_QRESYNC) == 0) { - client_send_command_error(ctx->cmd, - "QRESYNC not enabled"); + client_send_command_error(cmd, "QRESYNC not enabled"); return FALSE; } ctx->send_vanished = TRUE; return TRUE; } - client_send_command_error(ctx->cmd, "Unknown FETCH modifier"); + client_send_command_error(cmd, "Unknown FETCH modifier"); return FALSE; } static bool fetch_parse_modifiers(struct imap_fetch_context *ctx, + struct client_command_context *cmd, const struct imap_arg *args) { const char *name; while (!IMAP_ARG_IS_EOL(args)) { if (!imap_arg_get_atom(args, &name)) { - client_send_command_error(ctx->cmd, + client_send_command_error(cmd, "FETCH modifiers contain non-atoms."); return FALSE; } args++; - if (!fetch_parse_modifier(ctx, t_str_ucase(name), &args)) + if (!fetch_parse_modifier(ctx, cmd, t_str_ucase(name), &args)) return FALSE; } if (ctx->send_vanished && (ctx->search_args->args->next == NULL || ctx->search_args->args->next->type != SEARCH_MODSEQ)) { - client_send_command_error(ctx->cmd, + client_send_command_error(cmd, "VANISHED used without CHANGEDSINCE"); return FALSE; } return TRUE; } -static bool cmd_fetch_finish(struct imap_fetch_context *ctx) +static bool cmd_fetch_finish(struct imap_fetch_context *ctx, + struct client_command_context *cmd) { static const char *ok_message = "OK Fetch completed."; - struct client_command_context *cmd = ctx->cmd; const char *tagged_reply = ok_message; if (ctx->partial_fetch) { @@ -170,11 +173,11 @@ { struct imap_fetch_context *ctx = cmd->context; - if (imap_fetch_more(ctx) == 0) { + if (imap_fetch_more(ctx, cmd) == 0) { /* unfinished */ return FALSE; } - return cmd_fetch_finish(ctx); + return cmd_fetch_finish(ctx, cmd); } bool cmd_fetch(struct client_command_context *cmd) @@ -213,15 +216,15 @@ } ctx->search_args = search_args; - if (!fetch_parse_args(ctx, &args[1], &next_arg) || + if (!fetch_parse_args(ctx, cmd, &args[1], &next_arg) || (imap_arg_get_list(next_arg, &list_arg) && - !fetch_parse_modifiers(ctx, list_arg))) { + !fetch_parse_modifiers(ctx, cmd, list_arg))) { imap_fetch_deinit(ctx); return TRUE; } if (imap_fetch_begin(ctx) == 0) { - if (imap_fetch_more(ctx) == 0) { + if (imap_fetch_more(ctx, cmd) == 0) { /* unfinished */ cmd->state = CLIENT_COMMAND_STATE_WAIT_OUTPUT; @@ -230,5 +233,5 @@ return FALSE; } } - return cmd_fetch_finish(ctx); + return cmd_fetch_finish(ctx, cmd); }
--- a/src/imap/cmd-select.c Tue Feb 28 05:27:03 2012 +0200 +++ b/src/imap/cmd-select.c Thu Mar 01 09:31:40 2012 +0200 @@ -214,7 +214,7 @@ struct imap_select_context *ctx = cmd->context; int ret; - if (imap_fetch_more(ctx->fetch_ctx) == 0) { + if (imap_fetch_more(ctx->fetch_ctx, cmd) == 0) { /* unfinished */ return FALSE; } @@ -247,16 +247,13 @@ fetch_ctx->qresync_sample_seqset = &ctx->qresync_sample_seqset; fetch_ctx->qresync_sample_uidset = &ctx->qresync_sample_uidset; - if (!imap_fetch_add_changed_since(fetch_ctx, ctx->qresync_modseq) || - !imap_fetch_init_handler(fetch_ctx, "UID", NULL) || - !imap_fetch_init_handler(fetch_ctx, "FLAGS", NULL) || - !imap_fetch_init_handler(fetch_ctx, "MODSEQ", NULL)) { - (void)imap_fetch_deinit(fetch_ctx); - return -1; - } + imap_fetch_add_changed_since(fetch_ctx, ctx->qresync_modseq); + imap_fetch_init_nofail_handler(fetch_ctx, imap_fetch_uid_init); + imap_fetch_init_nofail_handler(fetch_ctx, imap_fetch_flags_init); + imap_fetch_init_nofail_handler(fetch_ctx, imap_fetch_modseq_init); if (imap_fetch_begin(fetch_ctx) == 0) { - if (imap_fetch_more(fetch_ctx) == 0) { + if (imap_fetch_more(fetch_ctx, ctx->cmd) == 0) { /* unfinished */ ctx->fetch_ctx = fetch_ctx; ctx->cmd->state = CLIENT_COMMAND_STATE_WAIT_OUTPUT;
--- a/src/imap/imap-fetch-body.c Tue Feb 28 05:27:03 2012 +0200 +++ b/src/imap/imap-fetch-body.c Thu Mar 01 09:31:40 2012 +0200 @@ -305,7 +305,7 @@ { string_t *str; - ctx->cur_name = p_strconcat(ctx->cmd->pool, + ctx->cur_name = p_strconcat(ctx->pool, "[", body->section, "]", NULL); ctx->cur_size = get_send_size(body, size->virtual_size); @@ -607,63 +607,60 @@ return TRUE; } -static bool fetch_body_header_fields_init(struct imap_fetch_context *ctx, +static bool fetch_body_header_fields_init(struct imap_fetch_init_context *ctx, struct imap_fetch_body_data *body, const char *section) { - const char *const *arr, *name; + const char *const *arr; if (!fetch_body_header_fields_check(section)) return FALSE; - name = get_body_name(body); - if ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER | - MAIL_FETCH_STREAM_BODY)) != 0) { + if ((ctx->fetch_ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER | + 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, FALSE, FALSE, name, "NIL", + imap_fetch_add_handler(ctx, 0, "NIL", fetch_body_header_partial, body); return TRUE; } for (arr = body->fields; *arr != NULL; arr++) { - const char *hdr = p_strdup(ctx->cmd->pool, *arr); - array_append(&ctx->all_headers, &hdr, 1); + const char *hdr = p_strdup(ctx->fetch_ctx->pool, *arr); + array_append(&ctx->fetch_ctx->all_headers, &hdr, 1); } - body->header_ctx = mailbox_header_lookup_init(ctx->box, body->fields); - imap_fetch_add_handler(ctx, FALSE, TRUE, name, "NIL", + body->header_ctx = mailbox_header_lookup_init(ctx->fetch_ctx->box, + body->fields); + imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_WANT_DEINIT, "NIL", fetch_body_header_fields, body); return TRUE; } -static bool fetch_body_section_name_init(struct imap_fetch_context *ctx, - struct imap_fetch_body_data *body) +static bool +fetch_body_section_name_init(struct imap_fetch_init_context *ctx, + struct imap_fetch_body_data *body) { - const char *name, *section = body->section; + const char *section = body->section; - name = get_body_name(body); if (*section == '\0') { - ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER | + ctx->fetch_ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY; - imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL", - fetch_body, body); + imap_fetch_add_handler(ctx, 0, "NIL", fetch_body, body); return TRUE; } if (strcmp(section, "TEXT") == 0) { - ctx->fetch_data |= MAIL_FETCH_STREAM_BODY; - imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL", - fetch_body, body); + ctx->fetch_ctx->fetch_data |= MAIL_FETCH_STREAM_BODY; + imap_fetch_add_handler(ctx, 0, "NIL", fetch_body, body); return TRUE; } if (strncmp(section, "HEADER", 6) == 0) { /* exact header matches could be cached */ if (section[6] == '\0') { - ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER; - imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL", - fetch_body, body); + ctx->fetch_ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER; + imap_fetch_add_handler(ctx, 0, "NIL", fetch_body, body); return TRUE; } @@ -673,12 +670,12 @@ if (strncmp(section, "HEADER.FIELDS.NOT ", 18) == 0 && fetch_body_header_fields_check(section+18)) { - imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL", + imap_fetch_add_handler(ctx, 0, "NIL", fetch_body_header_partial, body); return TRUE; } } else if (*section >= '0' && *section <= '9') { - ctx->fetch_data |= MAIL_FETCH_STREAM_BODY | + ctx->fetch_ctx->fetch_data |= MAIL_FETCH_STREAM_BODY | MAIL_FETCH_MESSAGE_PARTS; while ((*section >= '0' && *section <= '9') || @@ -692,14 +689,13 @@ 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, FALSE, FALSE, name, "NIL", + imap_fetch_add_handler(ctx, 0, "NIL", fetch_body_mime, body); return TRUE; } } - client_send_command_error(ctx->cmd, - "Invalid BODY[..] parameter: Unknown or broken section"); + ctx->error = "Invalid BODY[..] parameter: Unknown or broken section"; return FALSE; } @@ -723,34 +719,32 @@ return TRUE; } -static bool body_section_build(struct imap_fetch_context *ctx, - struct imap_fetch_body_data *body, - const char *prefix, - const struct imap_arg *args, - unsigned int args_count) +static bool +body_section_build(struct imap_fetch_init_context *ctx, + struct imap_fetch_body_data *body, const char *prefix, + const struct imap_arg *args, unsigned int args_count) { string_t *str; const char **arr, *value; size_t i; - str = str_new(ctx->cmd->pool, 128); + str = str_new(ctx->fetch_ctx->pool, 128); str_append(str, prefix); str_append(str, " ("); /* @UNSAFE: NULL-terminated list of headers */ - arr = p_new(ctx->cmd->pool, const char *, args_count + 1); + arr = p_new(ctx->fetch_ctx->pool, const char *, args_count + 1); for (i = 0; i < args_count; i++) { if (!imap_arg_get_astring(&args[i], &value)) { - client_send_command_error(ctx->cmd, - "Invalid BODY[..] parameter: " - "Header list contains non-strings"); + ctx->error = "Invalid BODY[..] parameter: " + "Header list contains non-strings"; return FALSE; } if (i != 0) str_append_c(str, ' '); - arr[i] = p_strdup(ctx->cmd->pool, t_str_ucase(value)); + arr[i] = p_strdup(ctx->fetch_ctx->pool, t_str_ucase(value)); if (args[i].type == IMAP_ARG_ATOM) str_append(str, arr[i]); @@ -769,53 +763,51 @@ return TRUE; } -bool fetch_body_section_init(struct imap_fetch_context *ctx, const char *name, - const struct imap_arg **args) +bool imap_fetch_body_section_init(struct imap_fetch_init_context *ctx) { struct imap_fetch_body_data *body; const struct imap_arg *list_args; unsigned int list_count; - const char *partial, *str; - const char *p = name + 4; + const char *partial, *str, *p; - body = p_new(ctx->cmd->pool, struct imap_fetch_body_data, 1); + i_assert(strncmp(ctx->name, "BODY", 4) == 0); + p = ctx->name + 4; + + body = p_new(ctx->fetch_ctx->pool, struct imap_fetch_body_data, 1); body->max_size = (uoff_t)-1; if (strncmp(p, ".PEEK", 5) == 0) { body->peek = TRUE; p += 5; } else { - ctx->flags_update_seen = TRUE; + ctx->fetch_ctx->flags_update_seen = TRUE; } if (*p != '[') { - client_send_command_error(ctx->cmd, - "Invalid BODY[..] parameter: Missing '['"); + ctx->error = "Invalid BODY[..] parameter: Missing '['"; return FALSE; } - if (imap_arg_get_list_full(&(*args)[0], &list_args, &list_count)) { + if (imap_arg_get_list_full(&ctx->args[0], &list_args, &list_count)) { /* BODY[HEADER.FIELDS.. (headers list)] */ - if (!imap_arg_get_atom(&(*args)[1], &str) || + if (!imap_arg_get_atom(&ctx->args[1], &str) || str[0] != ']') { - client_send_command_error(ctx->cmd, - "Invalid BODY[..] parameter: Missing ']'"); + ctx->error = "Invalid BODY[..] parameter: Missing ']'"; return FALSE; } if (!body_section_build(ctx, body, p+1, list_args, list_count)) return FALSE; p = str; - *args += 2; + ctx->args += 2; } else { /* no headers list */ body->section = p+1; p = strchr(body->section, ']'); if (p == NULL) { - client_send_command_error(ctx->cmd, - "Invalid BODY[..] parameter: Missing ']'"); + ctx->error = "Invalid BODY[..] parameter: Missing ']'"; return FALSE; } - body->section = p_strdup_until(ctx->cmd->pool, + body->section = p_strdup_until(ctx->fetch_ctx->pool, body->section, p); } @@ -827,9 +819,8 @@ if (!read_uoff_t(&p, &body->skip) || body->skip > OFF_T_MAX) { /* wrapped */ - client_send_command_error(ctx->cmd, - "Invalid BODY[..] parameter: " - "Too big partial start"); + ctx->error = "Invalid BODY[..] parameter: " + "Too big partial start"; return FALSE; } @@ -838,22 +829,22 @@ if (!read_uoff_t(&p, &body->max_size) || body->max_size > OFF_T_MAX) { /* wrapped */ - client_send_command_error(ctx->cmd, - "Invalid BODY[..] parameter: " - "Too big partial end"); + ctx->error = "Invalid BODY[..] parameter: " + "Too big partial end"; return FALSE; } } if (*p != '>') { - client_send_command_error(ctx->cmd, - t_strdup_printf("Invalid BODY[..] parameter: " - "Missing '>' in '%s'", - partial)); + ctx->error = t_strdup_printf( + "Invalid BODY[..] parameter: " + "Missing '>' in '%s'", partial); return FALSE; } } + /* sanitize the name */ + ctx->name = get_body_name(body); return fetch_body_section_name_init(ctx, body); } @@ -954,39 +945,37 @@ return fetch_stream(ctx, &body_size); } -bool fetch_rfc822_init(struct imap_fetch_context *ctx, const char *name, - const struct imap_arg **args ATTR_UNUSED) +bool imap_fetch_rfc822_init(struct imap_fetch_init_context *ctx) { + const char *name = ctx->name; + if (name[6] == '\0') { - ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER | + ctx->fetch_ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY; - ctx->flags_update_seen = TRUE; - imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL", - fetch_rfc822, NULL); + ctx->fetch_ctx->flags_update_seen = TRUE; + imap_fetch_add_handler(ctx, 0, "NIL", fetch_rfc822, NULL); return TRUE; } if (strcmp(name+6, ".SIZE") == 0) { - ctx->fetch_data |= MAIL_FETCH_VIRTUAL_SIZE; - imap_fetch_add_handler(ctx, TRUE, FALSE, name, "0", - fetch_rfc822_size, NULL); + ctx->fetch_ctx->fetch_data |= MAIL_FETCH_VIRTUAL_SIZE; + imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED, + "0", fetch_rfc822_size, NULL); return TRUE; } if (strcmp(name+6, ".HEADER") == 0) { - ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER; - imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL", + ctx->fetch_ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER; + imap_fetch_add_handler(ctx, 0, "NIL", 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, FALSE, FALSE, name, "NIL", - fetch_rfc822_text, NULL); + ctx->fetch_ctx->fetch_data |= MAIL_FETCH_STREAM_BODY; + ctx->fetch_ctx->flags_update_seen = TRUE; + imap_fetch_add_handler(ctx, 0, "NIL", fetch_rfc822_text, NULL); return TRUE; } - client_send_command_error(ctx->cmd, t_strconcat( - "Unknown parameter ", name, NULL)); + ctx->error = t_strconcat("Unknown parameter ", name, NULL); return FALSE; }
--- a/src/imap/imap-fetch.c Tue Feb 28 05:27:03 2012 +0200 +++ b/src/imap/imap-fetch.c Thu Mar 01 09:31:40 2012 +0200 @@ -45,24 +45,53 @@ return strcmp(name, h->name); } -bool imap_fetch_init_handler(struct imap_fetch_context *ctx, const char *name, - const struct imap_arg **args) +bool imap_fetch_init_handler(struct imap_fetch_init_context *init_ctx) { const struct imap_fetch_handler *handler; const char *lookup_name, *p; - for (p = name; i_isalnum(*p) || *p == '-'; p++) ; - lookup_name = t_strdup_until(name, p); + for (p = init_ctx->name; i_isalnum(*p) || *p == '-'; p++) ; + lookup_name = t_strdup_until(init_ctx->name, p); handler = array_bsearch(&fetch_handlers, lookup_name, imap_fetch_handler_bsearch); if (handler == NULL) { - client_send_command_error(ctx->cmd, - t_strconcat("Unknown parameter ", name, NULL)); + init_ctx->error = t_strdup_printf("Unknown parameter: %s", + init_ctx->name); return FALSE; } + return handler->init(init_ctx); +} - return handler->init(ctx, name, args); +void imap_fetch_init_nofail_handler(struct imap_fetch_context *ctx, + bool (*init)(struct imap_fetch_init_context *)) +{ + struct imap_fetch_init_context init_ctx; + + memset(&init_ctx, 0, sizeof(init_ctx)); + init_ctx.fetch_ctx = ctx; + if (!init(&init_ctx)) + i_unreached(); +} + +bool imap_fetch_cmd_init_handler(struct imap_fetch_context *ctx, + struct client_command_context *cmd, + const char *name, const struct imap_arg **args) +{ + struct imap_fetch_init_context init_ctx; + + memset(&init_ctx, 0, sizeof(init_ctx)); + init_ctx.fetch_ctx = ctx; + init_ctx.name = name; + init_ctx.args = *args; + + if (!imap_fetch_init_handler(&init_ctx)) { + i_assert(init_ctx.error != NULL); + client_send_command_error(cmd, init_ctx.error); + return FALSE; + } + *args = init_ctx.args; + return TRUE; } struct imap_fetch_context * @@ -73,7 +102,7 @@ ctx = p_new(cmd->pool, struct imap_fetch_context, 1); ctx->client = client; - ctx->cmd = cmd; + ctx->pool = cmd->pool; ctx->box = box; ctx->cur_str = str_new(default_pool, 8192); @@ -85,7 +114,7 @@ return ctx; } -bool imap_fetch_add_changed_since(struct imap_fetch_context *ctx, +void imap_fetch_add_changed_since(struct imap_fetch_context *ctx, uint64_t modseq) { struct mail_search_arg *search_arg; @@ -93,26 +122,26 @@ search_arg = p_new(ctx->search_args->pool, struct mail_search_arg, 1); search_arg->type = SEARCH_MODSEQ; search_arg->value.modseq = - p_new(ctx->cmd->pool, struct mail_search_modseq, 1); + p_new(ctx->pool, struct mail_search_modseq, 1); search_arg->value.modseq->modseq = modseq + 1; search_arg->next = ctx->search_args->args->next; ctx->search_args->args->next = search_arg; - return imap_fetch_init_handler(ctx, "MODSEQ", NULL); + imap_fetch_init_nofail_handler(ctx, imap_fetch_modseq_init); } #undef imap_fetch_add_handler -void imap_fetch_add_handler(struct imap_fetch_context *ctx, - bool buffered, bool want_deinit, - const char *name, const char *nil_reply, +void imap_fetch_add_handler(struct imap_fetch_init_context *ctx, + enum imap_fetch_handler_flags flags, + const char *nil_reply, 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. + to write the output in fetch_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 @@ -123,7 +152,7 @@ if (context == NULL) { /* don't allow duplicate handlers */ - array_foreach(&ctx->handlers, ctx_handler) { + array_foreach(&ctx->fetch_ctx->handlers, ctx_handler) { if (ctx_handler->handler == handler && ctx_handler->context == NULL) return; @@ -133,17 +162,17 @@ memset(&h, 0, sizeof(h)); h.handler = handler; h.context = context; - h.buffered = buffered; - h.want_deinit = want_deinit; - h.name = p_strdup(ctx->cmd->pool, name); - h.nil_reply = p_strdup(ctx->cmd->pool, nil_reply); + h.buffered = (flags & IMAP_FETCH_HANDLER_FLAG_BUFFERED) != 0; + h.want_deinit = (flags & IMAP_FETCH_HANDLER_FLAG_WANT_DEINIT) != 0; + h.name = p_strdup(ctx->fetch_ctx->pool, ctx->name); + h.nil_reply = p_strdup(ctx->fetch_ctx->pool, nil_reply); - if (!buffered) - array_append(&ctx->handlers, &h, 1); + if (!h.buffered) + array_append(&ctx->fetch_ctx->handlers, &h, 1); else { - array_insert(&ctx->handlers, ctx->buffered_handlers_count, - &h, 1); - ctx->buffered_handlers_count++; + array_insert(&ctx->fetch_ctx->handlers, + ctx->fetch_ctx->buffered_handlers_count, &h, 1); + ctx->fetch_ctx->buffered_handlers_count++; } } @@ -312,7 +341,7 @@ ctx->flags_update_seen = FALSE; else if (!ctx->flags_have_handler) { ctx->flags_show_only_seen_changes = TRUE; - (void)imap_fetch_init_handler(ctx, "FLAGS", NULL); + imap_fetch_init_nofail_handler(ctx, imap_fetch_flags_init); } } @@ -337,7 +366,7 @@ /* Delayed uidset -> seqset conversion. VANISHED needs the uidset. */ mail_search_args_init(ctx->search_args, ctx->box, TRUE, - &ctx->cmd->client->search_saved_uidset); + &ctx->client->search_saved_uidset); ctx->search_ctx = mailbox_search_init(ctx->trans, ctx->search_args, NULL, ctx->fetch_data, ctx->all_headers_ctx); @@ -387,7 +416,8 @@ return 0; } -static int imap_fetch_more_int(struct imap_fetch_context *ctx) +static int imap_fetch_more_int(struct imap_fetch_context *ctx, + struct client_command_context *cmd) { struct client *client = ctx->client; const struct imap_fetch_context_handler *handlers; @@ -430,7 +460,7 @@ } if (ctx->cur_mail == NULL) { - if (ctx->cmd->cancel) + if (cmd->cancel) return 1; if (!mailbox_search_next(ctx->search_ctx, @@ -503,19 +533,20 @@ return 1; } -int imap_fetch_more(struct imap_fetch_context *ctx) +int imap_fetch_more(struct imap_fetch_context *ctx, + struct client_command_context *cmd) { int ret; i_assert(ctx->client->output_lock == NULL || - ctx->client->output_lock == ctx->cmd); + ctx->client->output_lock == cmd); - ret = imap_fetch_more_int(ctx); + ret = imap_fetch_more_int(ctx, cmd); if (ret < 0) ctx->failed = TRUE; if (ctx->line_partial) { /* nothing can be sent until FETCH is finished */ - ctx->client->output_lock = ctx->cmd; + ctx->client->output_lock = cmd; } return ret; } @@ -580,16 +611,15 @@ return 1; } -static bool fetch_body_init(struct imap_fetch_context *ctx, const char *name, - const struct imap_arg **args) +static bool fetch_body_init(struct imap_fetch_init_context *ctx) { - if (name[4] == '\0') { - ctx->fetch_data |= MAIL_FETCH_IMAP_BODY; - imap_fetch_add_handler(ctx, FALSE, FALSE, name, - "("BODY_NIL_REPLY")", fetch_body, NULL); + if (ctx->name[4] == '\0') { + ctx->fetch_ctx->fetch_data |= MAIL_FETCH_IMAP_BODY; + imap_fetch_add_handler(ctx, 0, "("BODY_NIL_REPLY")", + fetch_body, NULL); return TRUE; } - return fetch_body_section_init(ctx, name, args); + return imap_fetch_body_section_init(ctx); } static int fetch_bodystructure(struct imap_fetch_context *ctx, @@ -616,13 +646,10 @@ return 1; } -static bool -fetch_bodystructure_init(struct imap_fetch_context *ctx, const char *name, - const struct imap_arg **args ATTR_UNUSED) +static bool fetch_bodystructure_init(struct imap_fetch_init_context *ctx) { - ctx->fetch_data |= MAIL_FETCH_IMAP_BODYSTRUCTURE; - imap_fetch_add_handler(ctx, FALSE, FALSE, name, - "("BODY_NIL_REPLY" NIL NIL NIL NIL)", + ctx->fetch_ctx->fetch_data |= MAIL_FETCH_IMAP_BODYSTRUCTURE; + imap_fetch_add_handler(ctx, 0, "("BODY_NIL_REPLY" NIL NIL NIL NIL)", fetch_bodystructure, NULL); return TRUE; } @@ -649,12 +676,10 @@ return 1; } -static bool -fetch_envelope_init(struct imap_fetch_context *ctx, const char *name, - const struct imap_arg **args ATTR_UNUSED) +static bool fetch_envelope_init(struct imap_fetch_init_context *ctx) { - ctx->fetch_data |= MAIL_FETCH_IMAP_ENVELOPE; - imap_fetch_add_handler(ctx, FALSE, FALSE, name, ENVELOPE_NIL_REPLY, + ctx->fetch_ctx->fetch_data |= MAIL_FETCH_IMAP_ENVELOPE; + imap_fetch_add_handler(ctx, 0, ENVELOPE_NIL_REPLY, fetch_envelope, NULL); return TRUE; } @@ -684,13 +709,12 @@ return 1; } -static bool -fetch_flags_init(struct imap_fetch_context *ctx, const char *name, - const struct imap_arg **args ATTR_UNUSED) +bool imap_fetch_flags_init(struct imap_fetch_init_context *ctx) { - ctx->flags_have_handler = TRUE; - ctx->fetch_data |= MAIL_FETCH_FLAGS; - imap_fetch_add_handler(ctx, TRUE, FALSE, name, "()", fetch_flags, NULL); + ctx->fetch_ctx->flags_have_handler = TRUE; + ctx->fetch_ctx->fetch_data |= MAIL_FETCH_FLAGS; + imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED, + "()", fetch_flags, NULL); return TRUE; } @@ -707,12 +731,10 @@ return 1; } -static bool -fetch_internaldate_init(struct imap_fetch_context *ctx, const char *name, - const struct imap_arg **args ATTR_UNUSED) +static bool fetch_internaldate_init(struct imap_fetch_init_context *ctx) { - ctx->fetch_data |= MAIL_FETCH_RECEIVED_DATE; - imap_fetch_add_handler(ctx, TRUE, FALSE, name, + ctx->fetch_ctx->fetch_data |= MAIL_FETCH_RECEIVED_DATE; + imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED, "\"01-Jan-1970 00:00:00 +0000\"", fetch_internaldate, NULL); return TRUE; @@ -731,13 +753,11 @@ return 1; } -static bool -fetch_modseq_init(struct imap_fetch_context *ctx, const char *name, - const struct imap_arg **args ATTR_UNUSED) +bool imap_fetch_modseq_init(struct imap_fetch_init_context *ctx) { - (void)client_enable(ctx->client, MAILBOX_FEATURE_CONDSTORE); - imap_fetch_add_handler(ctx, TRUE, FALSE, name, NULL, - fetch_modseq, NULL); + (void)client_enable(ctx->fetch_ctx->client, MAILBOX_FEATURE_CONDSTORE); + imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED, + NULL, fetch_modseq, NULL); return TRUE; } @@ -748,11 +768,10 @@ return 1; } -static bool -fetch_uid_init(struct imap_fetch_context *ctx ATTR_UNUSED, const char *name, - const struct imap_arg **args ATTR_UNUSED) +bool imap_fetch_uid_init(struct imap_fetch_init_context *ctx) { - imap_fetch_add_handler(ctx, TRUE, FALSE, name, NULL, fetch_uid, NULL); + imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED, + NULL, fetch_uid, NULL); return TRUE; } @@ -770,12 +789,11 @@ return 1; } -static bool -fetch_guid_init(struct imap_fetch_context *ctx ATTR_UNUSED, const char *name, - const struct imap_arg **args ATTR_UNUSED) +static bool fetch_guid_init(struct imap_fetch_init_context *ctx) { - ctx->fetch_data |= MAIL_FETCH_GUID; - imap_fetch_add_handler(ctx, TRUE, FALSE, name, "", fetch_guid, NULL); + ctx->fetch_ctx->fetch_data |= MAIL_FETCH_GUID; + imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED, + "", fetch_guid, NULL); return TRUE; } @@ -798,13 +816,10 @@ return 1; } -static bool -fetch_x_mailbox_init(struct imap_fetch_context *ctx ATTR_UNUSED, - const char *name, - const struct imap_arg **args ATTR_UNUSED) +static bool fetch_x_mailbox_init(struct imap_fetch_init_context *ctx) { - imap_fetch_add_handler(ctx, TRUE, FALSE, name, NULL, - fetch_x_mailbox, NULL); + imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED, + NULL, fetch_x_mailbox, NULL); return TRUE; } @@ -816,13 +831,10 @@ return 1; } -static bool -fetch_x_real_uid_init(struct imap_fetch_context *ctx ATTR_UNUSED, - const char *name, - const struct imap_arg **args ATTR_UNUSED) +static bool fetch_x_real_uid_init(struct imap_fetch_init_context *ctx) { - imap_fetch_add_handler(ctx, TRUE, FALSE, name, NULL, - fetch_x_real_uid, NULL); + imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED, + NULL, fetch_x_real_uid, NULL); return TRUE; } @@ -839,12 +851,10 @@ return 1; } -static bool -fetch_x_savedate_init(struct imap_fetch_context *ctx, const char *name, - const struct imap_arg **args ATTR_UNUSED) +static bool fetch_x_savedate_init(struct imap_fetch_init_context *ctx) { - ctx->fetch_data |= MAIL_FETCH_SAVE_DATE; - imap_fetch_add_handler(ctx, TRUE, FALSE, name, + ctx->fetch_ctx->fetch_data |= MAIL_FETCH_SAVE_DATE; + imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED, "\"01-Jan-1970 00:00:00 +0000\"", fetch_x_savedate, NULL); return TRUE; @@ -855,11 +865,11 @@ { "BODY", fetch_body_init }, { "BODYSTRUCTURE", fetch_bodystructure_init }, { "ENVELOPE", fetch_envelope_init }, - { "FLAGS", fetch_flags_init }, + { "FLAGS", imap_fetch_flags_init }, { "INTERNALDATE", fetch_internaldate_init }, - { "MODSEQ", fetch_modseq_init }, - { "RFC822", fetch_rfc822_init }, - { "UID", fetch_uid_init }, + { "MODSEQ", imap_fetch_modseq_init }, + { "RFC822", imap_fetch_rfc822_init }, + { "UID", imap_fetch_uid_init }, { "X-GUID", fetch_guid_init }, { "X-MAILBOX", fetch_x_mailbox_init }, { "X-REAL-UID", fetch_x_real_uid_init },
--- a/src/imap/imap-fetch.h Tue Feb 28 05:27:03 2012 +0200 +++ b/src/imap/imap-fetch.h Thu Mar 01 09:31:40 2012 +0200 @@ -3,17 +3,29 @@ struct imap_fetch_context; +enum imap_fetch_handler_flags { + IMAP_FETCH_HANDLER_FLAG_BUFFERED = 0x01, + IMAP_FETCH_HANDLER_FLAG_WANT_DEINIT = 0x02 +}; + /* Returns 1 = ok, 0 = client output buffer full, call again, -1 = error. mail = NULL for deinit. */ typedef int imap_fetch_handler_t(struct imap_fetch_context *ctx, struct mail *mail, void *context); +struct imap_fetch_init_context { + struct imap_fetch_context *fetch_ctx; + const char *name; + const struct imap_arg *args; + + const char *error; +}; + struct imap_fetch_handler { const char *name; - /* Returns FALSE if arg is invalid. */ - bool (*init)(struct imap_fetch_context *ctx, const char *name, - const struct imap_arg **args); + /* Returns FALSE and sets ctx->error if arg is invalid */ + bool (*init)(struct imap_fetch_init_context *ctx); }; struct imap_fetch_context_handler { @@ -29,8 +41,8 @@ struct imap_fetch_context { struct client *client; - struct client_command_context *cmd; struct mailbox *box; + pool_t pool; struct mailbox_transaction_context *trans; struct mail_search_args *search_args; @@ -76,40 +88,45 @@ void imap_fetch_handlers_register(const struct imap_fetch_handler *handlers, size_t count); -void imap_fetch_add_handler(struct imap_fetch_context *ctx, - bool buffered, bool want_deinit, - const char *name, const char *nil_reply, +void imap_fetch_add_handler(struct imap_fetch_init_context *ctx, + enum imap_fetch_handler_flags flags, + const char *nil_reply, imap_fetch_handler_t *handler, void *context); #ifdef CONTEXT_TYPE_SAFETY -# define imap_fetch_add_handler(ctx, buffered, want_deinit, name, nil_reply, \ - handler, context) \ +# define imap_fetch_add_handler(ctx, flags, nil_reply, handler, context) \ ({(void)(1 ? 0 : handler((struct imap_fetch_context *)NULL, \ (struct mail *)NULL, context)); \ - imap_fetch_add_handler(ctx, buffered, want_deinit, name, nil_reply, \ + imap_fetch_add_handler(ctx, flags, nil_reply, \ (imap_fetch_handler_t *)handler, context); }) #else -# define imap_fetch_add_handler(ctx, buffered, want_deinit, name, nil_reply, \ - handler, context) \ - imap_fetch_add_handler(ctx, buffered, want_deinit, name, nil_reply, \ +# define imap_fetch_add_handler(ctx, flags, nil_reply, handler, context) \ + imap_fetch_add_handler(ctx, flags, nil_reply, \ (imap_fetch_handler_t *)handler, context) #endif struct imap_fetch_context * imap_fetch_init(struct client_command_context *cmd, struct mailbox *box); int imap_fetch_deinit(struct imap_fetch_context *ctx); -bool imap_fetch_init_handler(struct imap_fetch_context *ctx, const char *name, - const struct imap_arg **args); +bool imap_fetch_init_handler(struct imap_fetch_init_context *init_ctx); +void imap_fetch_init_nofail_handler(struct imap_fetch_context *ctx, + bool (*init)(struct imap_fetch_init_context *)); +bool imap_fetch_cmd_init_handler(struct imap_fetch_context *ctx, + struct client_command_context *cmd, + const char *name, const struct imap_arg **args); -bool imap_fetch_add_changed_since(struct imap_fetch_context *ctx, +void imap_fetch_add_changed_since(struct imap_fetch_context *ctx, uint64_t modseq); int imap_fetch_begin(struct imap_fetch_context *ctx); -int imap_fetch_more(struct imap_fetch_context *ctx); +int imap_fetch_more(struct imap_fetch_context *ctx, + struct client_command_context *cmd); -bool fetch_body_section_init(struct imap_fetch_context *ctx, const char *name, - const struct imap_arg **args); -bool fetch_rfc822_init(struct imap_fetch_context *ctx, const char *name, - const struct imap_arg **args); +bool imap_fetch_flags_init(struct imap_fetch_init_context *ctx); +bool imap_fetch_modseq_init(struct imap_fetch_init_context *ctx); +bool imap_fetch_uid_init(struct imap_fetch_init_context *ctx); + +bool imap_fetch_body_section_init(struct imap_fetch_init_context *ctx); +bool imap_fetch_rfc822_init(struct imap_fetch_init_context *ctx); void imap_fetch_handlers_init(void); void imap_fetch_handlers_deinit(void);