imap-fetch-body.c revision 80bade1fe92cfb591a43da66e109a4cde2ec7d9b
/* Copyright (C) 2002-2004 Timo Sirainen */
#include "common.h"
#include "buffer.h"
#include "str.h"
#include "strescape.h"
#include "istream.h"
#include "ostream.h"
#include "istream-header-filter.h"
#include "message-parser.h"
#include "message-send.h"
#include "mail-storage.h"
#include "imap-parser.h"
#include "imap-fetch.h"
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
struct imap_fetch_body_data {
struct imap_fetch_body_data *next;
struct mailbox_header_lookup_ctx *header_ctx;
const char *section; /* NOTE: always uppercased */
set it to (uoff_t)-1 */
const char *const *fields;
unsigned int skip_set:1;
unsigned int peek:1;
};
struct partial_cache {
unsigned int select_counter;
unsigned int uid;
int cr_skipped;
struct message_size pos;
};
static struct partial_cache partial = { 0, 0, 0, 0, { 0, 0, 0 } };
{
int cr_skipped;
/* we can use the cache */
} else {
}
return cr_skipped;
}
{
return 0;
}
const struct imap_fetch_body_data *body,
{
else
else
return str;
}
int add_missing_eoh, int *last_cr)
{
const unsigned char *msg;
unsigned char add;
/* go through the message data and insert CRs where needed. */
while (vsize_left > 0 && !blocks &&
add = '\0';
for (i = 0; i < size && vsize_left > 0; i++) {
vsize_left--;
if (msg[i] == '\n') {
(i == 0 && !cr_skipped)) {
/* missing CR */
add = '\r';
break;
}
} else if (msg[i] == '\0') {
add = 128;
break;
}
}
return -1;
add = '\0';
}
if (ret > 0)
if (add != '\0') {
return -1;
if (ret == 0)
else {
sent++;
if (add == 128)
}
}
}
/* Netscape missing EOH workaround. */
return -1;
sent += 2;
}
/* Input stream gave less data then we expected. Two choices
here: either we fill the missing data with spaces or we
disconnect the client.
We shouldn't really ever get here. One reason is if mail
was deleted from NFS server while we were reading it.
Another is some temporary disk error.
If we filled the missing data the client could cache it,
and if it was just a temporary error the message would be
permanently left corrupted in client's local cache. So, we
disconnect the client and hope that next try works. */
return -1;
}
*last_cr = cr_skipped;
return sent;
}
{
if (ret < 0)
return -1;
if (ctx->update_partial) {
}
}
{
if (ret < 0)
return -1;
/* Netscape missing EOH workaround. */
return -1;
}
/* Input stream gave less data than expected */
return -1;
}
}
const struct message_size *size)
{
/* no need to kludge with CRs, we can use sendfile() */
} else {
}
}
const struct imap_fetch_body_data *body,
const struct message_size *size)
{
return -1;
if (!ctx->update_partial) {
} else {
}
}
void *context)
{
const struct message_size *fetch_size;
return -1;
case '\0':
/* BODY[] - fetch everything */
fetch_size = &body_size;
break;
case 'H':
/* BODY[HEADER] - fetch only header */
fetch_size = &hdr_size;
break;
case 'T':
/* BODY[TEXT] - skip header */
fetch_size = &body_size;
break;
default:
i_unreached();
}
}
{
}
{
return;
return;
}
}
const struct imap_fetch_body_data *body,
const char *header_section)
{
struct message_size msg_size;
/* MIME, HEADER.FIELDS (list), HEADER.FIELDS.NOT (list) */
/* Mime-Version + Content-* fields */
NULL, 0,
} else {
i_error("BUG: Accepted invalid section from user: '%s'",
return -1;
}
if (!ctx->cur_have_eoh &&
(client_workarounds & WORKAROUND_NETSCAPE_EOH) != 0) {
/* Netscape 4.x doesn't like if end of headers line is
missing. */
}
}
{
return -1;
}
{
struct message_size size;
return -1;
/* FIXME: We'll just always add the end of headers line now.
ideally mail-storage would have a way to tell us if it exists. */
}
/* Find message_part for section (eg. 1.3.4) */
{
const struct message_part *part;
const char *path;
unsigned int num;
return -1;
/* get part number */
num = 0;
return FALSE;
path++;
}
if (*path == '.')
path++;
/* find the part */
} else {
/* only 1 allowed with non-multipart messages */
if (num != 1)
}
/* if remainder of path is a number or "HEADER",
}
}
return 0;
}
void *context)
{
const struct message_part *part;
const char *section;
return -1;
/* part doesn't exist */
return -1;
return 1;
}
return -1;
}
/* all headers */
}
}
return 1;
}
static int fetch_body_header_fields_check(const char *section)
{
if (*section++ != '(')
return FALSE;
if (*section == '(')
return FALSE;
section++;
}
if (*section++ != ')')
return FALSE;
if (*section != '\0')
return FALSE;
return TRUE;
}
struct imap_fetch_body_data *body,
const char *section)
{
const char *const *arr;
return FALSE;
MAIL_FETCH_STREAM_BODY)) != 0) {
/* we'll need to open the file anyway, don't try to get the
headers from cache. */
return TRUE;
}
t_push();
}
t_pop();
return TRUE;
}
struct imap_fetch_body_data *body)
{
if (*section == '\0') {
return TRUE;
}
return TRUE;
}
/* exact header matches could be cached */
return TRUE;
}
return TRUE;
body);
return TRUE;
}
if (*section == '\0' ||
return TRUE;
}
}
"Invalid BODY[..] parameter: Unknown or broken section");
return FALSE;
}
/* Parse next digits in string into integer. Returns FALSE if the integer
becomes too big and wraps. */
{
*value = 0;
while (**p >= '0' && **p <= '9') {
return FALSE;
(*p)++;
}
return TRUE;
}
struct imap_fetch_body_data *body,
const char *prefix,
const struct imap_arg_list *list)
{
const char **arr;
size_t i;
/* @UNSAFE: NULL-terminated list of headers */
"Invalid BODY[..] parameter: "
"Header list contains non-strings");
return FALSE;
}
if (i != 0)
else {
}
}
return TRUE;
}
{
struct imap_fetch_body_data *body;
const char *partial;
const char *p = name + 4;
p += 5;
} else {
}
if (*p != '[') {
"Invalid BODY[..] parameter: Missing '['");
return FALSE;
}
/* BODY[HEADER.FIELDS.. (headers list)] */
"Invalid BODY[..] parameter: Missing ']'");
return FALSE;
}
IMAP_ARG_LIST(&(*args)[0])))
return FALSE;
*args += 2;
} else {
/* no headers list */
if (p == NULL) {
"Invalid BODY[..] parameter: Missing ']'");
return FALSE;
}
}
if (*++p == '<') {
/* <start.end> */
partial = p;
p++;
/* wrapped */
"Invalid BODY[..] parameter: "
"Too big partial start");
return FALSE;
}
if (*p == '.') {
p++;
if (*p == '-' && (client_workarounds &
WORKAROUND_TB_NEGATIVE_FETCH) != 0) {
/* Thunderbird messed up some calculations
and wants to read the message past it's
end. The fetch returns empty result anyway,
so just ignore '-'. */
p++;
}
/* wrapped */
"Invalid BODY[..] parameter: "
"Too big partial end");
return FALSE;
}
}
if (*p != '>') {
t_strdup_printf("Invalid BODY[..] parameter: "
"Missing '>' in '%s'",
partial));
return FALSE;
}
}
}
void *context __attr_unused__)
{
return -1;
return 1;
}
void *context __attr_unused__)
{
const char *str;
return -1;
if (ctx->cur_offset == 0) {
}
return -1;
}
}
{
struct message_size hdr_size;
const char *str;
return -1;
}
return -1;
}
void *context __attr_unused__)
{
const char *str;
return -1;
}
return -1;
}
{
return TRUE;
}
return TRUE;
}
return TRUE;
}
return TRUE;
}
return FALSE;
}