imap-fetch.c revision f32c6ed9db6f4c535f97a2020401572efc8abf86
/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file */
#include "imap-common.h"
#include "array.h"
#include "buffer.h"
#include "istream.h"
#include "ostream.h"
#include "str.h"
#include "message-size.h"
#include "imap-date.h"
#include "imap-utf7.h"
#include "mail-search-build.h"
#include "imap-commands.h"
#include "imap-quote.h"
#include "imap-fetch.h"
#include "imap-util.h"
#include <ctype.h>
#define BODY_NIL_REPLY \
"\"text\" \"plain\" NIL NIL NIL \"7bit\" 0 0"
#define ENVELOPE_NIL_REPLY \
"(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)"
const struct imap_fetch_handler *h2)
{
}
{
}
void imap_fetch_handler_unregister(const char *name)
{
}
static int
{
}
{
}
{
const struct imap_fetch_handler *handler;
const char *lookup_name, *p;
return FALSE;
}
return FALSE;
}
return TRUE;
}
bool (*init)(struct imap_fetch_init_context *))
{
struct imap_fetch_init_context init_ctx;
i_unreached();
}
struct imap_fetch_context **fetch_ctx_r,
const char **error_r)
{
struct imap_fetch_init_context init_ctx;
const char *str;
if (!imap_fetch_init_handler(&init_ctx)) {
return -1;
}
}
*error_r = "fetch-att list contains non-atoms.";
return -1;
}
return 0;
}
struct imap_fetch_context *
{
struct imap_fetch_context *ctx;
return ctx;
}
const char *nil_reply,
{
/* partially because of broken clients, but also partially because
it potentially can make client implementations faster, we have a
buffered parameter which basically means that the handler promises
to write the output in fetch_ctx->state.cur_str. The cur_str is then
sent to client before calling any non-buffered handlers.
We try to keep the handler registration order the same as the
client requested them. This is especially useful to get UID
returned first, which some clients rely on..
*/
const struct imap_fetch_context_handler *ctx_handler;
struct imap_fetch_context_handler h;
/* don't allow duplicate handlers */
return;
}
}
i_zero(&h);
if (!h.buffered)
else {
}
}
static void
const struct imap_fetch_qresync_args *qresync_args,
struct mailbox_transaction_context *trans,
{
struct mailbox_status status;
unsigned int i, count;
/* FIXME: we could do removals from the middle as well */
break;
}
if (i > 0)
}
static int
const struct imap_fetch_qresync_args *qresync_args,
{
struct mailbox_transaction_context *trans;
struct mail_search_args *search_args;
struct mail_search_context *search_ctx;
const struct seq_range *uid_filter;
struct mailbox_status status;
unsigned int i, count;
int ret = 0;
i = 0;
/* search UIDs only in given range */
next_uid++;
else if (++i < count)
else
break;
} else {
/* next_uid .. mail->uid-1 are expunged */
uid_filter[i].seq2);
i++;
}
}
else if (++i < count)
else
break;
}
}
if (i < count) {
uid_filter[i].seq2);
i++;
}
for (; i < count; i++) {
uid_filter[i].seq2);
}
(uint32_t)-1);
if (mailbox_search_deinit(&search_ctx) < 0)
ret = -1;
(void)mailbox_transaction_commit(&trans);
return ret;
}
const struct mail_search_args *search_args,
const struct imap_fetch_qresync_args *qresync_args)
{
int ret = 0;
/* return all expunged UIDs */
&expunged_uids_range) < 0) {
ret = -1;
}
}
if (array_count(&expunged_uids_range) > 0) {
}
return ret;
}
{
if (ctx->initialized)
return;
}
if ((ctx->fetch_data &
(MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY)) != 0)
}
struct mail_search_args *search_args)
{
const char *const *headers;
MAIL_FETCH_STREAM_BODY)) == 0)) {
}
if (ctx->flags_update_seen) {
/* Hide the implicit \Seen flag addition. Otherwise a separate
untagged FETCH FLAGS (\Seen) would be sent on top of the
one FLAGS (\Seen) already added in the main FETCH reply.
We don't set this always, because some plugins might want
to do their own flag changes which we don't want hidden.
(Of course this isn't perfect since if implicit \Seen flags
are added, other flag changes are also hidden.) */
}
if (wanted_headers != NULL)
}
{
const unsigned char *data;
if (len == 0)
return 0;
/* there's an extra space at the end if we added any fetch items
to buffer */
len--;
}
return -1;
return 0;
}
{
const struct imap_fetch_context_handler *handler;
if (imap_fetch_flush_buffer(ctx) < 0)
return -1;
}
return 0;
}
{
/* we've flushed an empty "FETCH (" reply so
far. we can't take it back, but RFC 3501
doesn't allow returning empty "FETCH ()"
either, so just add the current message's
UID there. */
}
}
{
return FALSE;
/* preserve the first error, since it may change in storage. */
}
return TRUE;
}
{
const struct imap_fetch_context_handler *handlers;
unsigned int count;
int ret;
if (ret == 0)
return 0;
if (ret < 0) {
return -1;
/* not an error, just lost it. */
if (imap_fetch_send_nil_reply(ctx) < 0)
return -1;
} else {
if (!imap_fetch_cur_failed(ctx))
return -1;
}
}
state->cur_handler++;
}
for (;;) {
if (ret <= 0)
return ret;
}
if (cancel)
return 1;
break;
}
/* first non-buffered handler.
flush the buffer. */
if (imap_fetch_flush_buffer(ctx) < 0)
return -1;
}
T_BEGIN {
const struct imap_fetch_context_handler *h =
h->context);
} T_END;
if (ret == 0)
return 0;
if (ret < 0) {
/* not an error, just lost it. */
if (imap_fetch_send_nil_reply(ctx) < 0)
return -1;
} else {
if (!imap_fetch_cur_failed(ctx))
return -1;
}
}
}
(state->line_partial ||
/* no non-buffered handlers */
if (imap_fetch_flush_buffer(ctx) < 0)
return -1;
}
if (state->line_partial)
state->cur_handler = 0;
}
}
struct client_command_context *cmd)
{
int ret;
if (ret < 0)
/* nothing can be sent until FETCH is finished */
}
/* canceling didn't really work. we must not output
anything anymore. */
}
return ret;
}
{
int ret;
if (ret < 0) {
/* we can't send any more replies to client, because
the FETCH reply wasn't fully sent. */
"NOTIFY failed in the middle of FETCH reply");
}
}
return ret;
}
{
if (state->line_partial) {
if (imap_fetch_flush_buffer(ctx) < 0)
}
}
}
/* even if something failed, we want to commit changes to
cache, as well as possible \Seen flag changes for FETCH
replies we returned so far. */
}
}
{
const struct imap_fetch_context_handler *handler;
(void)imap_fetch_end(ctx);
if (handler->want_deinit)
}
}
void *context ATTR_UNUSED)
{
const char *body;
return -1;
else {
return -1;
}
return -1;
return 1;
}
{
fetch_body, NULL);
return TRUE;
}
return imap_fetch_body_section_init(ctx);
}
{
const char *bodystructure;
&bodystructure) < 0)
return -1;
else {
return -1;
}
return -1;
return 1;
}
{
return TRUE;
}
void *context ATTR_UNUSED)
{
const char *envelope;
return -1;
else {
return -1;
}
return -1;
return 1;
}
{
return TRUE;
}
void *context ATTR_UNUSED)
{
enum mail_flags flags;
const char *const *keywords;
/* Add \Seen flag */
} else if (ctx->flags_show_only_seen_changes) {
return 1;
}
return 1;
}
{
return TRUE;
}
void *context ATTR_UNUSED)
{
return -1;
return 1;
}
{
"\"01-Jan-1970 00:00:00 +0000\"",
return TRUE;
}
void *context ATTR_UNUSED)
{
(unsigned long long)modseq);
return 1;
}
{
return FALSE;
}
return TRUE;
}
void *context ATTR_UNUSED)
{
return 1;
}
{
return TRUE;
}
void *context ATTR_UNUSED)
{
const char *value;
return -1;
return 1;
}
{
return TRUE;
}
void *context ATTR_UNUSED)
{
const char *name;
/* This can happen with virtual mailbox if the backend mail
is expunged. */
return -1;
}
return 1;
}
{
return TRUE;
}
void *context ATTR_UNUSED)
{
return -1;
return 1;
}
{
return TRUE;
}
void *context ATTR_UNUSED)
{
return -1;
return 1;
}
{
"\"01-Jan-1970 00:00:00 +0000\"",
return TRUE;
}
static const struct imap_fetch_handler
{ "BINARY", imap_fetch_binary_init },
{ "BODY", fetch_body_init },
{ "BODYSTRUCTURE", fetch_bodystructure_init },
{ "ENVELOPE", fetch_envelope_init },
{ "FLAGS", imap_fetch_flags_init },
{ "INTERNALDATE", fetch_internaldate_init },
{ "MODSEQ", imap_fetch_modseq_init },
{ "RFC822", imap_fetch_rfc822_init },
{ "UID", imap_fetch_uid_init },
{ "X-GUID", fetch_guid_init },
{ "X-MAILBOX", fetch_x_mailbox_init },
{ "X-REAL-UID", fetch_x_real_uid_init },
{ "X-SAVEDATE", fetch_x_savedate_init }
};
void imap_fetch_handlers_init(void)
{
}
void imap_fetch_handlers_deinit(void)
{
}