imap-fetch-body.c revision 0d82d7744160c598ecfe73ec25598ad43596d10c
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
12d38e76ba7f70d6219c89ec7416fea0d5de7e02Timo Sirainen const char *section; /* NOTE: always uppercased */
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen uoff_t skip, max_size; /* if you don't want max_size,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen set it to (uoff_t)-1 */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *const *fields;
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainenstatic void fetch_read_error(struct imap_fetch_context *ctx)
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen "read(%s) failed: %m (FETCH for mailbox %s UID %u)",
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mailbox_get_vname(ctx->cur_mail->box), ctx->cur_mail->uid);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainenstatic int seek_partial(unsigned int select_counter, unsigned int uid,
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainen if (select_counter == partial->select_counter && uid == partial->uid &&
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen stream->v_offset == partial->physical_start &&
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* we can use the cache */
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen memset(&partial->pos, 0, sizeof(partial->pos));
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen i_stream_seek(stream, partial->physical_start +
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen if (message_skip_virtual(stream, virtual_skip, &partial->pos,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic uoff_t get_send_size(const struct imap_fetch_body_data *body,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return size <= body->max_size ? size : body->max_size;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic const char *get_body_name(const struct imap_fetch_body_data *body)
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen str_printfa(str, "<%"PRIuUOFF_T">", body->skip);
83d2e37f065eabe38dc92db485c5ca39ee43ce05Timo Sirainenstatic string_t *get_prefix(struct imap_fetch_context *ctx,
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen str_printfa(str, " {%"PRIuUOFF_T"}\r\n", size);
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainenstatic off_t imap_fetch_send(struct imap_fetch_context *ctx,
3a7113e3e2dac0e333e1a3f62af7d682896f59c6Timo Sirainen struct ostream *output, struct istream *input,
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen const unsigned char *msg;
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen unsigned char add;
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen /* go through the message data and insert CRs where needed. */
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen i_stream_read_data(input, &msg, &size, 0) > 0) {
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen for (i = 0; i < size && vsize_left > 0; i++) {
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen (i == 0 && !cr_skipped)) {
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen /* missing CR */
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen if ((ret = o_stream_send(output, msg, i)) < 0)
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if ((ret = o_stream_send(output, &add, 1)) < 0)
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen if (add_missing_eoh && sent + 2 == virtual_size) {
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen /* Netscape missing EOH workaround. */
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen o_stream_set_max_buffer_size(output, (size_t)-1);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if ((uoff_t)sent != virtual_size && !blocks) {
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen /* Input stream gave less data than we expected. Two choices
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen here: either we fill the missing data with spaces or we
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen disconnect the client.
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen We shouldn't really ever get here. One reason is if mail
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen was deleted from NFS server while we were reading it.
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen Another is some temporary disk error.
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen If we filled the missing data the client could cache it,
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen and if it was just a temporary error the message would be
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen permanently left corrupted in client's local cache. So, we
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen disconnect the client and hope that next try works. */
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_error("FETCH %s for mailbox %s UID %u got too little data: "
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen "%"PRIuUOFF_T" vs %"PRIuUOFF_T, ctx->cur_name,
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen ctx->cur_mail->uid, (uoff_t)sent, virtual_size);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mail_set_cache_corrupted(ctx->cur_mail, ctx->cur_size_field);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client_disconnect(ctx->client, "FETCH failed");
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainenstatic int fetch_stream_send(struct imap_fetch_context *ctx)
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen o_stream_set_max_buffer_size(ctx->client->output, 4096);
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen ret = imap_fetch_send(ctx, ctx->client->output, ctx->cur_input,
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen ctx->skip_cr, ctx->cur_size - ctx->cur_offset,
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen o_stream_set_max_buffer_size(ctx->client->output, (size_t)-1);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen struct partial_fetch_cache *p = &ctx->client->last_partial;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic int fetch_stream_send_direct(struct imap_fetch_context *ctx)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen o_stream_set_max_buffer_size(ctx->client->output, 0);
31633d676642b83305b8d46da495d9bb4e2d1ff8Timo Sirainen ret = o_stream_send_istream(ctx->client->output, ctx->cur_input);
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen o_stream_set_max_buffer_size(ctx->client->output, (size_t)-1);
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen if (ctx->cur_append_eoh && ctx->cur_offset + 2 == ctx->cur_size) {
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi /* Netscape missing EOH workaround. */
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi if (o_stream_send(ctx->client->output, "\r\n", 2) < 0)
3db05c8c00faca6ab9ac8391e1d6977365f4d1b3Timo Sirainen /* unfinished */
f0ecd925c7feb815c4b9acf84772fcd56c02319bTimo Sirainen if (!i_stream_have_bytes_left(ctx->cur_input)) {
f0ecd925c7feb815c4b9acf84772fcd56c02319bTimo Sirainen /* Input stream gave less data than expected */
f0ecd925c7feb815c4b9acf84772fcd56c02319bTimo Sirainen "got too little data (copying): "
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->cur_name, mailbox_get_vname(ctx->cur_mail->box),
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->cur_mail->uid, ctx->cur_offset, ctx->cur_size);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen client_disconnect(ctx->client, "FETCH failed");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen o_stream_set_flush_pending(ctx->client->output, TRUE);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic int fetch_stream(struct imap_fetch_context *ctx,
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (size->physical_size == size->virtual_size &&
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen /* no need to kludge with CRs, we can use sendfile() */
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen input = i_stream_create_limit(ctx->cur_input, ctx->cur_size);
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainenstatic int fetch_data(struct imap_fetch_context *ctx,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen ctx->cur_size = get_send_size(body, size->virtual_size);
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainen if (message_skip_virtual(ctx->cur_input, body->skip, NULL,
484e12acec34f16e5a8adc001e23ae48f1dda8c7Timo Sirainen if (seek_partial(ctx->select_counter, ctx->cur_mail->uid,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenstatic int fetch_body(struct imap_fetch_context *ctx, struct mail *mail,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (mail_get_stream(mail, NULL, NULL, &input) < 0 ||
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen mail_get_virtual_size(mail, &body_size.virtual_size) < 0 ||
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen mail_get_physical_size(mail, &body_size.physical_size) < 0)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen /* BODY[] - fetch everything */
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen ctx->cur_size_field = MAIL_FETCH_VIRTUAL_SIZE;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen /* BODY[HEADER] - fetch only header */
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen ctx->cur_size_field = MAIL_FETCH_MESSAGE_PARTS;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen /* BODY[TEXT] - skip header */
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen i_stream_skip(ctx->cur_input, hdr_size.physical_size);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen ctx->cur_size_field = MAIL_FETCH_VIRTUAL_SIZE;
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainenstatic void header_filter_eoh(struct message_header_line *hdr,
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainenstatic int fetch_header_partial_from(struct imap_fetch_context *ctx,
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen /* MIME, HEADER.FIELDS (list), HEADER.FIELDS.NOT (list) */
88e9835c4d8973c62cd4db1ec7324ff46dd3ff15Timo Sirainen if (strncmp(header_section, "HEADER.FIELDS ", 14) == 0) {
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen input = i_stream_create_header_filter(ctx->cur_input,
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen } else if (strncmp(header_section, "HEADER.FIELDS.NOT ", 18) == 0) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen input = i_stream_create_header_filter(ctx->cur_input,
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen i_error("BUG: Accepted invalid section from user: '%s'",
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen if (message_get_header_size(ctx->cur_input, &msg_size, NULL) < 0) {
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainenfetch_body_header_partial(struct imap_fetch_context *ctx, struct mail *mail,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (mail_get_stream(mail, NULL, NULL, &ctx->cur_input) < 0)
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return fetch_header_partial_from(ctx, body, body->section);
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainenfetch_body_header_fields(struct imap_fetch_context *ctx, struct mail *mail,
3bfdab77880db25dbdc8bf48c2cfc2d50b98e426Aki Tuomi /* deinit */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (mail_get_header_stream(mail, body->header_ctx, &ctx->cur_input) < 0)
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen if (message_get_body_size(ctx->cur_input, &size, NULL) < 0) {
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen /* FIXME: We'll just always add the end of headers line now.
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen ideally mail-storage would have a way to tell us if it exists. */
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen/* Find message_part for section (eg. 1.3.4) */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic int part_find(struct mail *mail, const struct imap_fetch_body_data *body,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen const struct message_part **part_r, const char **section_r)
7cba14a4c3beb026a2862ee50d24c554fa713329Timo Sirainen unsigned int num;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen while (*path >= '0' && *path <= '9' && part != NULL) {
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen /* get part number, we have already verified its validity */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (part->flags & MESSAGE_PART_FLAG_MULTIPART) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* find the part */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* only 1 allowed with non-multipart messages */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen (part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) &&
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* if we continue inside the message/rfc822, skip this
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic int fetch_body_mime(struct imap_fetch_context *ctx, struct mail *mail,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (part_find(mail, body, &part, §ion) < 0)
3340fc9aeaa655dc3bb8f329ebdfcb38a5121949Timo Sirainen /* part doesn't exist */
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen string_t *str = get_prefix(ctx, body, (uoff_t)-1);
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen if (mail_get_stream(mail, NULL, NULL, &ctx->cur_input) < 0)
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen ctx->cur_size_field = MAIL_FETCH_MESSAGE_PARTS;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* fetch the whole section */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos +
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return fetch_data(ctx, body, &part->body_size);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* fetch section's MIME header */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos);
3340fc9aeaa655dc3bb8f329ebdfcb38a5121949Timo Sirainen return fetch_data(ctx, body, &part->header_size);
3340fc9aeaa655dc3bb8f329ebdfcb38a5121949Timo Sirainen /* TEXT and HEADER are only for message/rfc822 parts */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if ((part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) == 0) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen i_assert(part->children != NULL && part->children->next == NULL);
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos +
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen return fetch_data(ctx, body, &part->body_size);
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen /* all headers */
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return fetch_data(ctx, body, &part->header_size);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen return fetch_header_partial_from(ctx, body, section);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen i_error("BUG: Accepted invalid section from user: '%s'", body->section);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainenstatic bool fetch_body_header_fields_check(const char *section)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return FALSE; /* has to be at least one field */
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainenstatic bool fetch_body_header_fields_init(struct imap_fetch_context *ctx,
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen if ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER |
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen /* we'll need to open the file anyway, don't try to get the
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen headers from cache. */
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL",
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen for (arr = body->fields; *arr != NULL; arr++) {
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen const char *hdr = p_strdup(ctx->cmd->pool, *arr);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen body->header_ctx = mailbox_header_lookup_init(ctx->box, body->fields);
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen imap_fetch_add_handler(ctx, FALSE, TRUE, name, "NIL",
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainenstatic bool fetch_body_section_name_init(struct imap_fetch_context *ctx,
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL",
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL",
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* exact header matches could be cached */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL",
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (strncmp(section, "HEADER.FIELDS ", 14) == 0 &&
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen fetch_body_header_fields_init(ctx, body, section+14))
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (strncmp(section, "HEADER.FIELDS.NOT ", 18) == 0 &&
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL",
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen } else if (*section >= '0' && *section <= '9') {
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen while ((*section >= '0' && *section <= '9') ||
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen (strncmp(section, "HEADER.FIELDS ", 14) == 0 &&
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen fetch_body_header_fields_check(section+14)) ||
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen (strncmp(section, "HEADER.FIELDS.NOT ", 18) == 0 &&
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen fetch_body_header_fields_check(section+18))) {
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen imap_fetch_add_handler(ctx, FALSE, FALSE, name, "NIL",
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen "Invalid BODY[..] parameter: Unknown or broken section");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen/* Parse next digits in string into integer. Returns FALSE if the integer
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen becomes too big and wraps. */
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainenstatic bool read_uoff_t(const char **p, uoff_t *value)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenstatic bool body_section_build(struct imap_fetch_context *ctx,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* @UNSAFE: NULL-terminated list of headers */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen arr = p_new(ctx->cmd->pool, const char *, args_count + 1);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen for (i = 0; i < args_count; i++) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (!imap_arg_get_astring(&args[i], &value)) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen "Invalid BODY[..] parameter: "
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen "Header list contains non-strings");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen arr[i] = p_strdup(ctx->cmd->pool, t_str_ucase(value));
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen qsort(arr, args_count, sizeof(*arr), i_strcasecmp_p);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenbool fetch_body_section_init(struct imap_fetch_context *ctx, const char *name,
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainen body = p_new(ctx->cmd->pool, struct imap_fetch_body_data, 1);
4e65040b019c061d242c8bc19bf76009679b8a15Timo Sirainen if (*p != '[') {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen "Invalid BODY[..] parameter: Missing '['");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (imap_arg_get_list_full(&(*args)[0], &list_args, &list_count)) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* BODY[HEADER.FIELDS.. (headers list)] */
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen "Invalid BODY[..] parameter: Missing ']'");
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (!body_section_build(ctx, body, p+1, list_args, list_count))
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen /* no headers list */
a355fad576bc0c95b11161cf48b48d343229a2b3Timo Sirainen "Invalid BODY[..] parameter: Missing ']'");
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen body->section = p_strdup_until(ctx->cmd->pool,
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen if (*++p == '<') {
3a7113e3e2dac0e333e1a3f62af7d682896f59c6Timo Sirainen /* <start.end> */
12d38e76ba7f70d6219c89ec7416fea0d5de7e02Timo Sirainen if (!read_uoff_t(&p, &body->skip) || body->skip > OFF_T_MAX) {
3a7113e3e2dac0e333e1a3f62af7d682896f59c6Timo Sirainen /* wrapped */
return FALSE;
return FALSE;
partial));
return FALSE;
const char *str;
const char *str;
const char *str;
return TRUE;
return TRUE;
return TRUE;
return TRUE;
return FALSE;