imap-fetch.c revision dbcc1233028625274a8224b3efeca01d73dbbb4c
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen/* Copyright (C) 2002-2004 Timo Sirainen */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenconst struct imap_fetch_handler default_handlers[8];
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainenstatic int imap_fetch_handler_cmp(const void *p1, const void *p2)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen const struct imap_fetch_handler *h1 = p1, *h2 = p2;
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainenvoid imap_fetch_handlers_register(const struct imap_fetch_handler *handlers,
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen fetch_handlers = buffer_create_dynamic(default_pool, 128);
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen buffer_append(fetch_handlers, handlers, sizeof(*handlers) * count);
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen data = buffer_get_modifiable_data(fetch_handlers, &size);
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen qsort(data, size / sizeof(*handlers), sizeof(*handlers),
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainenstatic int imap_fetch_handler_bsearch(const void *name_p, const void *handler_p)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen const struct imap_fetch_handler *h = handler_p;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen return name[i] < 'A' || name[i] >= 'Z' ? 0 : -1;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainenbool imap_fetch_init_handler(struct imap_fetch_context *ctx, const char *name,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct imap_fetch_context *imap_fetch_init(struct client_command_context *cmd)
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen imap_fetch_handlers_register(default_handlers,
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen ctx = p_new(cmd->pool, struct imap_fetch_context, 1);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen ctx->all_headers_buf = buffer_create_dynamic(cmd->pool, 128);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenvoid imap_fetch_add_handler(struct imap_fetch_context *ctx,
6237f743bbaf74de5a2d2051672baed87023657bTimo Sirainen /* partially because of broken clients, but also partially because
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen it potentially can make client implementations faster, we have a
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen buffered parameter which basically means that the handler promises
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen to write the output in ctx->cur_str. The cur_str is then sent to
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen client before calling any non-buffered handlers.
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen We try to keep the handler registration order the same as the
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen client requested them. This is especially useful to get UID
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen returned first, which some clients rely on..
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen const struct imap_fetch_context_handler *handlers;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen unsigned int i, size;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen /* don't allow duplicate handlers */
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen for (i = 0; i < size; i++) {
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen memset(&h, 0, sizeof(h));
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen array_insert(&ctx->handlers, ctx->buffered_handlers_count,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid imap_fetch_begin(struct imap_fetch_context *ctx,
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen (void)imap_fetch_init_handler(ctx, "FLAGS", NULL);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen if (buffer_get_used_size(ctx->all_headers_buf) != 0 &&
325d4ad220bd13f6d176391d962a0e33c856a7f6Timo Sirainen ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER |
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen buffer_append(ctx->all_headers_buf, &null, sizeof(null));
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen data = buffer_get_data(ctx->all_headers_buf, NULL);
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen ctx->trans = mailbox_transaction_begin(ctx->box,
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen ctx->select_counter = ctx->client->select_counter;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen ctx->mail = mail_alloc(ctx->trans, ctx->fetch_data,
93fa87cf1a96c4f279ec4f5c311820313ba12c34Timo Sirainen mailbox_search_init(ctx->trans, NULL, search_arg, NULL);
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainenstatic int imap_fetch_flush_buffer(struct imap_fetch_context *ctx)
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen const unsigned char *data;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* there's an extra space at the end if we added any fetch items
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen if (o_stream_send(ctx->client->output, data, len) < 0)
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen const struct imap_fetch_context_handler *handlers;
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen unsigned int size;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen /* not an error, just lost it. */
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen if (o_stream_get_buffer_used_size(ctx->client->output) >=
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen for (; ctx->cur_handler < size; ctx->cur_handler++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* first non-buffered handler.
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen flush the buffer. */
369a1084c500a9df7448ffa9409ce32e42060bc2Timo Sirainen /* not an error, just lost it. */
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen /* no non-buffered handlers */
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0)
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainenint imap_fetch_deinit(struct imap_fetch_context *ctx)
c18e2301f4c81f2819711661890db7796d4450c3Timo Sirainen const struct imap_fetch_context_handler *handlers;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen unsigned int i, count;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen for (i = 0; i < count; i++) {
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen handlers[i].handler(ctx, NULL, handlers[i].context);
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mailbox_search_deinit(&ctx->search_ctx) < 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mailbox_header_lookup_deinit(&ctx->all_headers_ctx);
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen if (mailbox_transaction_commit(&ctx->trans, 0) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int fetch_body(struct imap_fetch_context *ctx, struct mail *mail,
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen body = mail_get_special(mail, MAIL_FETCH_IMAP_BODY);
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen if (o_stream_send(ctx->client->output, "BODY (", 6) < 0 ||
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen o_stream_send_str(ctx->client->output, body) < 0 ||
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainenstatic bool fetch_body_init(struct imap_fetch_context *ctx, const char *name,
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, fetch_body, NULL);
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen return fetch_body_section_init(ctx, name, args);
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainenstatic int fetch_bodystructure(struct imap_fetch_context *ctx,
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen struct mail *mail, void *context __attr_unused__)
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen bodystructure = mail_get_special(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE);
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen if (o_stream_send(ctx->client->output, "BODYSTRUCTURE (", 15) < 0 ||
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen o_stream_send_str(ctx->client->output, bodystructure) < 0 ||
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainenstatic bool fetch_bodystructure_init(struct imap_fetch_context *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->fetch_data |= MAIL_FETCH_IMAP_BODYSTRUCTURE;
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, fetch_bodystructure, NULL);
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainenstatic int fetch_envelope(struct imap_fetch_context *ctx, struct mail *mail,
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen envelope = mail_get_special(mail, MAIL_FETCH_IMAP_ENVELOPE);
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
365435901c22df7e5838f574c950b0e32e77f78aTimo Sirainen if (o_stream_send(ctx->client->output, "ENVELOPE (", 10) < 0 ||
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen o_stream_send_str(ctx->client->output, envelope) < 0 ||
365435901c22df7e5838f574c950b0e32e77f78aTimo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainenstatic bool fetch_envelope_init(struct imap_fetch_context *ctx,
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, fetch_envelope, NULL);
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenstatic int fetch_flags(struct imap_fetch_context *ctx, struct mail *mail,
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen const char *const *keywords;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen if (ctx->flags_update_seen && (flags & MAIL_SEEN) == 0) {
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen /* Add \Seen flag */
return TRUE;
return TRUE;
return TRUE;
return size;
return TRUE;