imap-fetch-body.c revision 768a07208b89e58308a965494090b658a577bc56
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (C) 2002-2004 Timo Sirainen */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *section; /* NOTE: always uppercased */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen uoff_t skip, max_size; /* if you don't want max_size,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen set it to (uoff_t)-1 */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *const *fields;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen unsigned int uid;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic struct partial_cache partial = { 0, 0, 0, 0, { 0, 0, 0 } };
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int seek_partial(unsigned int select_counter, unsigned int uid,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct partial_cache *partial, struct istream *stream,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (select_counter == partial->select_counter && uid == partial->uid &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen stream->v_offset == partial->physical_start &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* we can use the cache */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen memset(&partial->pos, 0, sizeof(partial->pos));
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_stream_seek(stream, partial->physical_start +
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen message_skip_virtual(stream, virtual_skip, &partial->pos,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic uoff_t get_send_size(const struct imap_fetch_body_data *body,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return size <= body->max_size ? size : body->max_size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic string_t *get_prefix(struct imap_fetch_context *ctx,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str_printfa(str, "<%"PRIuUOFF_T">", body->skip);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_printfa(str, " {%"PRIuUOFF_T"}\r\n", size);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic off_t imap_fetch_send(struct ostream *output, struct istream *input,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const unsigned char *msg;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen unsigned char add;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* go through the message data and insert CRs where needed. */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_stream_read_data(input, &msg, &size, 0) > 0) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen for (i = 0; i < size && vsize_left > 0; i++) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen (i == 0 && !cr_skipped)) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* missing CR */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if ((ret = o_stream_send(output, msg, i)) < 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if ((ret = o_stream_send(output, &add, 1)) < 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (add_missing_eoh && sent + 2 == virtual_size) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* Netscape missing EOH workaround. */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen o_stream_set_max_buffer_size(output, (size_t)-1);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if ((uoff_t)sent != virtual_size && !blocks) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* Input stream gave less data than we expected. Two choices
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen here: either we fill the missing data with spaces or we
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen disconnect the client.
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen We shouldn't really ever get here. One reason is if mail
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen was deleted from NFS server while we were reading it.
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen Another is some temporary disk error.
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen If we filled the missing data the client could cache it,
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen and if it was just a temporary error the message would be
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen permanently left corrupted in client's local cache. So, we
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen disconnect the client and hope that next try works. */
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainenstatic int fetch_stream_send(struct imap_fetch_context *ctx)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen o_stream_set_max_buffer_size(ctx->client->output, 4096);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ret = imap_fetch_send(ctx->client->output, ctx->cur_input,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->skip_cr, ctx->cur_size - ctx->cur_offset,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen o_stream_set_max_buffer_size(ctx->client->output, (size_t)-1);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->cur_input->v_offset - partial.physical_start;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic int fetch_stream_send_direct(struct imap_fetch_context *ctx)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen o_stream_set_max_buffer_size(ctx->client->output, 0);
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen ret = o_stream_send_istream(ctx->client->output, ctx->cur_input);
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen o_stream_set_max_buffer_size(ctx->client->output, (size_t)-1);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (ctx->cur_append_eoh && ctx->cur_offset + 2 == ctx->cur_size) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* Netscape missing EOH workaround. */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (o_stream_send(ctx->client->output, "\r\n", 2) < 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* Input stream gave less data than expected */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic int fetch_stream(struct imap_fetch_context *ctx,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (size->physical_size == size->virtual_size &&
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* no need to kludge with CRs, we can use sendfile() */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen input = i_stream_create_limit(default_pool, ctx->cur_input,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic int fetch_data(struct imap_fetch_context *ctx,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->cur_size = get_send_size(body, size->virtual_size);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen message_skip_virtual(ctx->cur_input, body->skip, NULL, FALSE,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen seek_partial(ctx->select_counter, ctx->cur_mail->uid,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic int fetch_body(struct imap_fetch_context *ctx, struct mail *mail,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const struct imap_fetch_body_data *body = context;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* BODY[] - fetch everything */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* BODY[HEADER] - fetch only header */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* BODY[TEXT] - skip header */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_stream_skip(ctx->cur_input, hdr_size.physical_size);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic void header_filter_eoh(struct message_header_line *hdr,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int fetch_header_partial_from(struct imap_fetch_context *ctx,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* MIME, HEADER.FIELDS (list), HEADER.FIELDS.NOT (list) */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (strncmp(header_section, "HEADER.FIELDS ", 14) == 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen input = i_stream_create_header_filter(ctx->cur_input,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else if (strncmp(header_section, "HEADER.FIELDS.NOT ", 18) == 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen input = i_stream_create_header_filter(ctx->cur_input,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_error("BUG: Accepted invalid section from user: '%s'",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen message_get_header_size(ctx->cur_input, &msg_size, NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen (client_workarounds & WORKAROUND_NETSCAPE_EOH) != 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* Netscape 4.x doesn't like if end of headers line is
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int fetch_body_header_partial(struct imap_fetch_context *ctx,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct imap_fetch_body_data *body = context;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->cur_input = mail_get_stream(mail, NULL, NULL);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return fetch_header_partial_from(ctx, body, body->section);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic int fetch_body_header_fields(struct imap_fetch_context *ctx,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const struct imap_fetch_body_data *body = context;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->cur_input = mail_get_header_stream(mail, body->header_ctx);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen message_get_body_size(ctx->cur_input, &size, NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* FIXME: We'll just always add the end of headers line now.
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ideally mail-storage would have a way to tell us if it exists. */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen/* Find message_part for section (eg. 1.3.4) */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic int part_find(struct mail *mail, const struct imap_fetch_body_data *body,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct message_part **part_r, const char **section_r)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int num;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen while (*path >= '0' && *path <= '9' && part != NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* get part number, we have already verified its validity */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (part->flags & MESSAGE_PART_FLAG_MULTIPART) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* find the part */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* only 1 allowed with non-multipart messages */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen (part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* if we continue inside the message/rfc822, skip this
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic int fetch_body_mime(struct imap_fetch_context *ctx, struct mail *mail,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const struct imap_fetch_body_data *body = context;
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen if (part_find(mail, body, &part, §ion) < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* part doesn't exist */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen string_t *str = get_prefix(ctx, body, (uoff_t)-1);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->cur_input = mail_get_stream(mail, NULL, NULL);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* fetch the whole section */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos +
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return fetch_data(ctx, body, &part->body_size);
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen /* fetch section's MIME header */
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return fetch_data(ctx, body, &part->header_size);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* TEXT and HEADER are only for message/rfc822 parts */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if ((part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) == 0) {
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen i_assert(part->children != NULL && part->children->next == NULL);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos +
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen return fetch_data(ctx, body, &part->body_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* all headers */
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return fetch_data(ctx, body, &part->header_size);
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen i_stream_seek(ctx->cur_input, part->physical_pos);
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen return fetch_header_partial_from(ctx, body, section);
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen i_error("BUG: Accepted invalid section from user: '%s'", body->section);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic int fetch_body_header_fields_check(const char *section)
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen return FALSE; /* has to be at least one field */
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainenstatic int fetch_body_header_fields_init(struct imap_fetch_context *ctx,
d516e6848ecfbc7381abe9414fd8011fdf9d8c95Timo Sirainen const char *const *arr;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER |
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* we'll need to open the file anyway, don't try to get the
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen headers from cache. */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen for (arr = body->fields; *arr != NULL; arr++) {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen buffer_append(ctx->all_headers_buf, &hdr, sizeof(hdr));
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen body->header_ctx = mailbox_header_lookup_init(ctx->box, body->fields);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen imap_fetch_add_handler(ctx, FALSE, fetch_body_header_fields, body);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainenstatic int fetch_body_section_name_init(struct imap_fetch_context *ctx,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen imap_fetch_add_handler(ctx, FALSE, fetch_body, body);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen imap_fetch_add_handler(ctx, FALSE, fetch_body, body);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* exact header matches could be cached */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen imap_fetch_add_handler(ctx, FALSE, fetch_body, body);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (strncmp(section, "HEADER.FIELDS ", 14) == 0 &&
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen fetch_body_header_fields_init(ctx, body, section+14))
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen if (strncmp(section, "HEADER.FIELDS.NOT ", 18) == 0 &&
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen } else if (*section >= '0' && *section <= '9') {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen while ((*section >= '0' && *section <= '9') ||
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen (strncmp(section, "HEADER.FIELDS ", 14) == 0 &&
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen fetch_body_header_fields_check(section+14)) ||
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen (strncmp(section, "HEADER.FIELDS.NOT ", 18) == 0 &&
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen fetch_body_header_fields_check(section+18))) {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen "Invalid BODY[..] parameter: Unknown or broken section");
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen/* Parse next digits in string into integer. Returns FALSE if the integer
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen becomes too big and wraps. */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenstatic int read_uoff_t(const char **p, uoff_t *value)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenstatic int body_section_build(struct imap_fetch_context *ctx,
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen const char **arr;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* @UNSAFE: NULL-terminated list of headers */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen arr = p_new(ctx->cmd->pool, const char *, list->size + 1);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen "Invalid BODY[..] parameter: "
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen "Header list contains non-strings");
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen arr[i] = str_ucase(IMAP_ARG_STR(&list->args[i]));
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen qsort(arr, list->size, sizeof(*arr), strcasecmp_p);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainenint fetch_body_section_init(struct imap_fetch_context *ctx, const char *name,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen body = p_new(ctx->cmd->pool, struct imap_fetch_body_data, 1);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (*p != '[') {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen "Invalid BODY[..] parameter: Missing '['");
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen /* BODY[HEADER.FIELDS.. (headers list)] */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen "Invalid BODY[..] parameter: Missing ']'");
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* no headers list */
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen "Invalid BODY[..] parameter: Missing ']'");
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen body->section = p_strdup_until(ctx->cmd->pool,
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen if (*++p == '<') {
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainen /* <start.end> */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (!read_uoff_t(&p, &body->skip) || body->skip > OFF_T_MAX) {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* wrapped */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen "Invalid BODY[..] parameter: "
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen "Too big partial start");
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (*p == '.') {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* wrapped */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen "Invalid BODY[..] parameter: "
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen "Too big partial end");
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen if (*p != '>') {
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen t_strdup_printf("Invalid BODY[..] parameter: "
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen "Missing '>' in '%s'",
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return fetch_body_section_name_init(ctx, body);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic int fetch_rfc822_size(struct imap_fetch_context *ctx, struct mail *mail,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str_printfa(ctx->cur_str, "RFC822.SIZE %"PRIuUOFF_T" ", size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic int fetch_rfc822(struct imap_fetch_context *ctx, struct mail *mail,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const char *str;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->cur_input = mail_get_stream(mail, &hdr_size, &body_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str = t_strdup_printf(" RFC822 {%"PRIuUOFF_T"}\r\n",
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (o_stream_send_str(ctx->client->output, str) < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic int fetch_rfc822_header(struct imap_fetch_context *ctx,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen struct mail *mail, void *context __attr_unused__)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const char *str;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->cur_input = mail_get_stream(mail, &hdr_size, NULL);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str = t_strdup_printf(" RFC822.HEADER {%"PRIuUOFF_T"}\r\n",
41955c400476941fa274f18b106a5922866fd780Timo Sirainen if (o_stream_send_str(ctx->client->output, str) < 0)
41955c400476941fa274f18b106a5922866fd780Timo Sirainenstatic int fetch_rfc822_text(struct imap_fetch_context *ctx, struct mail *mail,
41955c400476941fa274f18b106a5922866fd780Timo Sirainen const char *str;
41955c400476941fa274f18b106a5922866fd780Timo Sirainen ctx->cur_input = mail_get_stream(mail, &hdr_size, &body_size);
41955c400476941fa274f18b106a5922866fd780Timo Sirainen str = t_strdup_printf(" RFC822.TEXT {%"PRIuUOFF_T"}\r\n",
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (o_stream_send_str(ctx->client->output, str) < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_stream_seek(ctx->cur_input, hdr_size.physical_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenint fetch_rfc822_init(struct imap_fetch_context *ctx, const char *name,
41955c400476941fa274f18b106a5922866fd780Timo Sirainen imap_fetch_add_handler(ctx, FALSE, fetch_rfc822, NULL);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen imap_fetch_add_handler(ctx, TRUE, fetch_rfc822_size, NULL);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen imap_fetch_add_handler(ctx, FALSE, fetch_rfc822_header, NULL);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen imap_fetch_add_handler(ctx, FALSE, fetch_rfc822_text, NULL);