imap-fetch.c revision 79fcd3f95a6266cc62ceaa753e56dd4456ab7c4b
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (C) 2002-2004 Timo Sirainen */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenconst struct imap_fetch_handler default_handlers[7];
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic int imap_fetch_handler_cmp(const void *p1, const void *p2)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen const struct imap_fetch_handler *h1 = p1, *h2 = p2;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenvoid imap_fetch_handlers_register(const struct imap_fetch_handler *handlers,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen fetch_handlers = buffer_create_dynamic(default_pool, 128);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen buffer_append(fetch_handlers, handlers, sizeof(*handlers) * count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data = buffer_get_modifyable_data(fetch_handlers, &size);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen qsort(data, size / sizeof(*handlers), sizeof(*handlers),
3e564425db51f3921ce4de11859777135fdedd15Timo Sirainenstatic int imap_fetch_handler_bsearch(const void *name_p, const void *handler_p)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen const struct imap_fetch_handler *h = handler_p;
4ba9a1d3facc515b3feb5238a16bcf91f76fac61Timo Sirainen return name[i] < 'A' || name[i] >= 'Z' ? 0 : -1;
dfaefeabae939803ceb8c503101e86b5496541d1Timo Sirainenbool imap_fetch_init_handler(struct imap_fetch_context *ctx, const char *name,
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainenstruct imap_fetch_context *imap_fetch_init(struct client_command_context *cmd)
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen imap_fetch_handlers_register(default_handlers,
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen ctx = p_new(cmd->pool, struct imap_fetch_context, 1);
c5ab90cfad9cc3e33bcb1baeb30ffc82a7b7053aTimo Sirainen ctx->all_headers_buf = buffer_create_dynamic(cmd->pool, 128);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenvoid imap_fetch_add_handler(struct imap_fetch_context *ctx,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen /* partially because of broken clients, but also partially because
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen it potentially can make client implementations faster, we have a
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen buffered parameter which basically means that the handler promises
cff1f182205e674285cf3ff446a0dcf7afea277dTimo Sirainen to write the output in ctx->cur_str. The cur_str is then sent to
cff1f182205e674285cf3ff446a0dcf7afea277dTimo Sirainen client before calling any non-buffered handlers.
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen We try to keep the handler registration order the same as the
e03d986a74128f5ba30fcfda9f6e36578f5d8decTimo Sirainen client requested them. This is especially useful to get UID
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen returned first, which some clients rely on..
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen const struct imap_fetch_context_handler *handlers;
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen unsigned int i, size;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen /* don't allow duplicate handlers */
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen for (i = 0; i < size; i++) {
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen memset(&h, 0, sizeof(h));
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen array_insert(&ctx->handlers, ctx->buffered_handlers_count,
4b41116563110d00330896a568eff1078c382827Timo Sirainenvoid imap_fetch_begin(struct imap_fetch_context *ctx,
b2c1349cf07410aefab0f5b17153af9e5cfcf48fTimo Sirainen (void)imap_fetch_init_handler(ctx, "FLAGS", NULL);
8a13b020f90e080570658b18c042e7e352c8b14fTimo Sirainen if (buffer_get_used_size(ctx->all_headers_buf) != 0 &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER |
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen buffer_append(ctx->all_headers_buf, &null, sizeof(null));
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen data = buffer_get_data(ctx->all_headers_buf, NULL);
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen ctx->trans = mailbox_transaction_begin(ctx->box,
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen ctx->select_counter = ctx->client->select_counter;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->mail = mail_alloc(ctx->trans, ctx->fetch_data,
a3ee5ce6ecc8e228ee69300fdd562d7ac8be89a7Timo Sirainen mailbox_search_init(ctx->trans, NULL, search_arg, NULL);
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainenstatic int imap_fetch_flush_buffer(struct imap_fetch_context *ctx)
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen const unsigned char *data;
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen /* there's an extra space at the end if we added any fetch items
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (o_stream_send(ctx->client->output, data, len) < 0)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen const struct imap_fetch_context_handler *handlers;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen unsigned int size;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* not an error, just lost it. */
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen if (o_stream_get_buffer_used_size(ctx->client->output) >=
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen for (; ctx->cur_handler < size; ctx->cur_handler++) {
4bbd396aa6198c84f3f7763b6e8a63a26e97e141Timo Sirainen /* first non-buffered handler.
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen flush the buffer. */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* not an error, just lost it. */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* no non-buffered handlers */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenint imap_fetch_deinit(struct imap_fetch_context *ctx)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen const struct imap_fetch_context_handler *handlers;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen unsigned int i, count;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen for (i = 0; i < count; i++) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen handlers[i].handler(ctx, NULL, handlers[i].context);
c7e14824e4e1ca9dc5d48d1eddc4a38d3041218fTimo Sirainen if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (mailbox_search_deinit(&ctx->search_ctx) < 0)
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainen mailbox_header_lookup_deinit(&ctx->all_headers_ctx);
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen if (mailbox_transaction_commit(&ctx->trans, 0) < 0)
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainenstatic int fetch_body(struct imap_fetch_context *ctx, struct mail *mail,
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen body = mail_get_special(mail, MAIL_FETCH_IMAP_BODY);
defb12ecd360df672ffb2f4dbf4d1218a0a9549cTimo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (o_stream_send(ctx->client->output, "BODY (", 6) < 0 ||
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen o_stream_send_str(ctx->client->output, body) < 0 ||
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainenstatic bool fetch_body_init(struct imap_fetch_context *ctx, const char *name,
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, fetch_body, NULL);
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen return fetch_body_section_init(ctx, name, args);
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainenstatic int fetch_bodystructure(struct imap_fetch_context *ctx,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct mail *mail, void *context __attr_unused__)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen bodystructure = mail_get_special(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (o_stream_send(ctx->client->output, "BODYSTRUCTURE (", 15) < 0 ||
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen o_stream_send_str(ctx->client->output, bodystructure) < 0 ||
e63bdfedcf61e1a9ee21990140cbd0d0638da7e1Timo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainenstatic bool fetch_bodystructure_init(struct imap_fetch_context *ctx,
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen ctx->fetch_data |= MAIL_FETCH_IMAP_BODYSTRUCTURE;
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, fetch_bodystructure, NULL);
d54ab8987e482a8df250615b44f41fa040c38741Timo Sirainenstatic int fetch_envelope(struct imap_fetch_context *ctx, struct mail *mail,
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen envelope = mail_get_special(mail, MAIL_FETCH_IMAP_ENVELOPE);
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
e050e5c9b1688765f1fdfce9b7141f7b614383fdTimo Sirainen if (o_stream_send(ctx->client->output, "ENVELOPE (", 10) < 0 ||
4d527c363482be2b65dd0573d878ecda86cbb0bbTimo Sirainen o_stream_send_str(ctx->client->output, envelope) < 0 ||
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
b62140c5849297a800fee942026d9c3cb8c60206Timo Sirainenstatic bool fetch_envelope_init(struct imap_fetch_context *ctx,
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, fetch_envelope, NULL);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainenstatic int fetch_flags(struct imap_fetch_context *ctx, struct mail *mail,
de58be41126e5d68008d2ea706d62ccdc1f29337Timo Sirainen const char *const *keywords;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (ctx->flags_update_seen && (flags & MAIL_SEEN) == 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* Add \Seen flag */
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if (mail_update_flags(mail, MODIFY_ADD, MAIL_SEEN) < 0)
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen } else if (ctx->flags_show_only_seen_changes) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen imap_write_flags(ctx->cur_str, flags, keywords);
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainenstatic bool fetch_flags_init(struct imap_fetch_context *ctx,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen imap_fetch_add_handler(ctx, TRUE, FALSE, fetch_flags, NULL);
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainenstatic int fetch_internaldate(struct imap_fetch_context *ctx, struct mail *mail,
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen str_printfa(ctx->cur_str, "INTERNALDATE \"%s\" ",
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainenstatic bool fetch_internaldate_init(struct imap_fetch_context *ctx,
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen imap_fetch_add_handler(ctx, TRUE, FALSE, fetch_internaldate, NULL);
b3b4f3875850099c9292ad74d08bb385c3988f8fTimo Sirainenstatic int fetch_uid(struct imap_fetch_context *ctx, struct mail *mail,
return TRUE;