imap-msgpart.c revision 27a44fcfd8d19bffe0f267f20a2b5d3fe7600fdd
/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "istream.h"
#include "istream-crlf.h"
#include "istream-nonuls.h"
#include "istream-base64.h"
#include "istream-header-filter.h"
#include "istream-qp.h"
#include "ostream.h"
#include "message-parser.h"
#include "message-decoder.h"
#include "mail-storage-private.h"
#include "mail-namespace.h"
#include "imap-parser.h"
#include "imap-msgpart.h"
enum fetch_type {
};
struct imap_msgpart {
/* "" for root, otherwise e.g. "1.2.3". the .MIME, .HEADER, etc.
suffix not included */
const char *section_number;
enum fetch_type fetch_type;
/* HEADER.FIELDS[.NOT] (list of headers) */
struct mailbox_header_lookup_ctx *header_ctx;
const char *const *headers;
/* which part of the message part to fetch (default: 0..(uoff_t)-1) */
unsigned int decode_cte_to_binary:1;
};
struct imap_msgpart_open_ctx {
/* from matching message_part, set after opening: */
struct message_size mime_hdr_size;
struct message_size mime_body_size;
};
{
struct imap_msgpart *msgpart;
return msgpart;
}
struct imap_msgpart *imap_msgpart_full(void)
{
return imap_msgpart_type(FETCH_FULL);
}
struct imap_msgpart *imap_msgpart_header(void)
{
return imap_msgpart_type(FETCH_HEADER);
}
struct imap_msgpart *imap_msgpart_body(void)
{
return imap_msgpart_type(FETCH_BODY);
}
static struct message_part *
{
const char *path;
unsigned int num;
/* get part number, we have already verified its validity */
num = 0;
path++;
}
if (*path == '.')
path++;
/* find the part */
} else {
/* only 1 allowed with non-multipart messages.
finished after this. */
if (num != 1)
else if (*path != '\0' &&
}
body part */
}
}
return part;
}
static int
{
struct imap_parser *parser;
unsigned int list_count;
unsigned int i;
int result = 0;
list_count > 0) {
const char *value;
for (i = 0; i < list_count; i++) {
result = -1;
break;
}
}
} else {
result = -1;
}
/* istream-header-filter requires headers to be sorted */
return result;
}
static int
const char *header_list)
{
/* HEADER.FIELDS (list), HEADER.FIELDS.NOT (list) */
&fields) < 0)
return -1;
return 0;
}
{
struct imap_msgpart *msgpart;
unsigned int i;
bool next_digit;
int ret;
/* get the section number */
next_digit = TRUE;
for (i = 0; section[i] != '\0'; i++) {
next_digit = FALSE;
next_digit = TRUE;
} else {
break;
}
}
if (i == 0) {
/* [], [HEADER], etc. */
} else if (section[i] == '\0') {
/* [1.2.3] */
pool_unref(&pool);
return -1;
}
section = "";
} else {
/* [1.2.3.MIME], [1.2.3.HEADER], etc */
pool_unref(&pool);
return -1;
}
section += i;
}
if (*section == '\0') {
/* BODY[] - header+body */
} else {
/* BODY[1] - body only */
}
return 0;
}
ret = 0;
section+14);
section+18);
} else {
ret = -1;
}
if (ret < 0) {
return -1;
}
/* we may be able to get this from cache, don't give a
wanted_fields hint */
else
} else {
i_unreached();
}
return 0;
}
{
}
{
}
{
}
{
return msgpart->partial_offset;
}
{
return msgpart->wanted_fields;
}
static int
const struct imap_msgpart *msgpart,
struct message_size *hdr_size_r,
struct imap_msgpart_open_result *result_r)
{
bool has_nuls;
(void *)NULL);
} else {
(void *)NULL);
}
return -1;
}
i_stream_seek(input, 0);
return 0;
}
static void
{
int ret;
if (ret < 0)
return;
break;
/* skip header */
/* skip body */
part->physical_pos +
} else {
/* maybe we have a child and can skip using it? */
}
}
}
static struct istream *
const struct imap_msgpart *msgpart)
{
struct istream *crlf_input;
const unsigned char *data;
if (virtual_skip == 0) {
/* no need to seek */
/* use cache */
} else {
/* can't use cache, but maybe we can skip faster using the
message parts. */
}
input = crlf_input;
if ((msgpart->partial_offset != 0 ||
/* update cache */
if (data[0] == '\n') {
/* the physical_pos points to virtual CRLF, but
virtual_pos already skipped CR. that can't work,
so seek back the virtual CR */
cache->virtual_pos--;
}
}
return input;
}
static void
bool convert_nuls, bool use_partial_cache,
const struct message_size *part_size,
struct imap_msgpart_open_result *result)
{
/* input is already seeked to the beginning of the wanted data */
/* can't seek past the MIME part */
return;
}
/* input has CRLF linefeeds, we can quickly seek to
wanted position */
} else {
/* input has LF linefeeds. it can be slow to seek to wanted
position, so try to do caching whenever possible */
msgpart);
}
/* limit output to specified number of bytes */
} else {
/* send all bytes */
}
/* IMAP literals must not contain NULs. change them to
0x80 characters. */
}
}
static int
struct message_part **part_r)
{
return 1;
}
return -1;
/* MIME part not found. */
return 0;
}
switch (msgpart->fetch_type) {
case FETCH_MIME:
return 0;
}
break;
case FETCH_FULL:
case FETCH_MIME_BODY:
break;
case FETCH_HEADER:
case FETCH_HEADER_FIELDS:
case FETCH_HEADER_FIELDS_NOT:
case FETCH_BODY:
return 0;
}
break;
}
return 1;
}
static int
const struct message_part *part,
struct message_size *part_size_r,
struct imap_msgpart_open_result *result_r)
{
/* find the MIME part */
return -1;
} else switch (msgpart->fetch_type) {
case FETCH_FULL:
/* fetch the whole message */
return -1;
break;
case FETCH_MIME:
case FETCH_MIME_BODY:
i_unreached();
case FETCH_HEADER:
case FETCH_HEADER_FIELDS_NOT:
/* fetch the message's header */
return -1;
break;
case FETCH_HEADER_FIELDS:
/* try to lookup the headers from cache */
}
&input) < 0)
return -1;
result_r->size_field = 0;
break;
case FETCH_BODY:
/* fetch the message's body */
return -1;
break;
}
/* return specific headers */
}
switch (msgpart->fetch_type) {
case FETCH_FULL:
/* fall through */
case FETCH_MIME:
case FETCH_HEADER:
break;
case FETCH_HEADER_FIELDS:
case FETCH_HEADER_FIELDS_NOT:
i_unreached();
case FETCH_BODY:
case FETCH_MIME_BODY:
break;
}
return 0;
}
struct imap_msgpart_open_result *result_r)
{
struct message_part *part;
struct message_size part_size;
int ret;
return -1;
if (ret == 0) {
/* MIME part not found. return an empty part. */
return 0;
}
if (msgpart->decode_cte_to_binary &&
/* binary fetch */
return -1;
}
return -1;
} else {
result_r) < 0)
return -1;
}
return 0;
}
{
struct imap_msgpart_open_result result;
struct message_part *part;
bool include_hdr;
int ret;
if (!msgpart->decode_cte_to_binary ||
/* generic implementation */
return -1;
return 0;
}
/* binary-optimized implementation: */
return -1;
if (ret == 0) {
/* MIME part not found. return an empty part. */
*size_r = 0;
return 0;
}
return -1;
}
}
{
}