Mercurial > dovecot > core-2.2
view src/lib-storage/index/index-fetch.c @ 273:9be2c12d0983 HEAD
STORE needs to sync too, or maildir could see old filenames.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 19 Sep 2002 21:58:09 +0300 |
parents | 29cf23950452 |
children | b79b6da2f84a |
line wrap: on
line source
/* Copyright (C) 2002 Timo Sirainen */ #include "lib.h" #include "iobuffer.h" #include "temp-string.h" #include "mail-custom-flags.h" #include "index-storage.h" #include "index-fetch.h" #include "index-messageset.h" #include "message-send.h" #include "imap-date.h" #include "imap-util.h" #include "imap-message-cache.h" #include <unistd.h> static int index_fetch_body(MailIndexRecord *rec, FetchContext *ctx) { const char *body; body = imap_msgcache_get(ctx->cache, IMAP_CACHE_BODY); if (body != NULL) { t_string_printfa(ctx->str, "BODY %s ", body); return TRUE; } else { mail_storage_set_critical(ctx->storage, "Couldn't generate BODY for UID %u (index %s)", rec->uid, ctx->index->filepath); return FALSE; } } static int index_fetch_bodystructure(MailIndexRecord *rec, FetchContext *ctx) { const char *bodystructure; bodystructure = imap_msgcache_get(ctx->cache, IMAP_CACHE_BODYSTRUCTURE); if (bodystructure != NULL) { t_string_printfa(ctx->str, "BODYSTRUCTURE %s ", bodystructure); return TRUE; } else { mail_storage_set_critical(ctx->storage, "Couldn't generate BODYSTRUCTURE for UID %u (index %s)", rec->uid, ctx->index->filepath); return FALSE; } } static int index_fetch_envelope(MailIndexRecord *rec, FetchContext *ctx) { const char *envelope; envelope = imap_msgcache_get(ctx->cache, IMAP_CACHE_ENVELOPE); if (envelope != NULL) { t_string_printfa(ctx->str, "ENVELOPE (%s) ", envelope); return TRUE; } else { mail_storage_set_critical(ctx->storage, "Couldn't generate ENVELOPE for UID %u (index %s)", rec->uid, ctx->index->filepath); return FALSE; } } static int index_fetch_rfc822_size(MailIndexRecord *rec, FetchContext *ctx) { MessageSize hdr_size, body_size; if (!imap_msgcache_get_rfc822(ctx->cache, NULL, &hdr_size, &body_size)) { mail_storage_set_critical(ctx->storage, "Couldn't get RFC822.SIZE for UID %u (index %s)", rec->uid, ctx->index->filepath); return FALSE; } t_string_printfa(ctx->str, "RFC822.SIZE %"PRIuUOFF_T" ", hdr_size.virtual_size + body_size.virtual_size); return TRUE; } static void index_fetch_flags(MailIndexRecord *rec, FetchContext *ctx) { MailFlags flags; flags = rec->msg_flags; if (rec->uid >= ctx->index->first_recent_uid) flags |= MAIL_RECENT; if (ctx->update_seen) flags |= MAIL_SEEN; t_string_printfa(ctx->str, "FLAGS (%s) ", imap_write_flags(flags, ctx->custom_flags)); } static void index_fetch_internaldate(MailIndexRecord *rec, FetchContext *ctx) { t_string_printfa(ctx->str, "INTERNALDATE \"%s\" ", imap_to_datetime(rec->internal_date)); } static void index_fetch_uid(MailIndexRecord *rec, FetchContext *ctx) { t_string_printfa(ctx->str, "UID %u ", rec->uid); } static int index_fetch_send_rfc822(MailIndexRecord *rec, FetchContext *ctx) { MessageSize hdr_size, body_size; IOBuffer *inbuf; const char *str; if (!imap_msgcache_get_rfc822(ctx->cache, &inbuf, &hdr_size, &body_size)) { mail_storage_set_critical(ctx->storage, "Couldn't get RFC822 for UID %u (index %s)", rec->uid, ctx->index->filepath); return FALSE; } str = t_strdup_printf(" RFC822 {%"PRIuUOFF_T"}\r\n", hdr_size.virtual_size + body_size.virtual_size); if (ctx->first) { str++; ctx->first = FALSE; } if (io_buffer_send(ctx->outbuf, str, strlen(str)) < 0) return FALSE; body_size.physical_size += hdr_size.physical_size; body_size.virtual_size += hdr_size.virtual_size; return message_send(ctx->outbuf, inbuf, &body_size, 0, (uoff_t)-1); } static int index_fetch_send_rfc822_header(MailIndexRecord *rec, FetchContext *ctx) { MessageSize hdr_size; IOBuffer *inbuf; const char *str; if (!imap_msgcache_get_rfc822(ctx->cache, &inbuf, &hdr_size, NULL)) { mail_storage_set_critical(ctx->storage, "Couldn't get RFC822.HEADER for UID %u (index %s)", rec->uid, ctx->index->filepath); return FALSE; } str = t_strdup_printf(" RFC822.HEADER {%"PRIuUOFF_T"}\r\n", hdr_size.virtual_size); if (ctx->first) { str++; ctx->first = FALSE; } if (io_buffer_send(ctx->outbuf, str, strlen(str)) < 0) return FALSE; return message_send(ctx->outbuf, inbuf, &hdr_size, 0, (uoff_t)-1); } static int index_fetch_send_rfc822_text(MailIndexRecord *rec, FetchContext *ctx) { MessageSize body_size; IOBuffer *inbuf; const char *str; if (!imap_msgcache_get_rfc822(ctx->cache, &inbuf, NULL, &body_size)) { mail_storage_set_critical(ctx->storage, "Couldn't get RFC822.TEXT for UID %u (index %s)", rec->uid, ctx->index->filepath); return FALSE; } str = t_strdup_printf(" RFC822.TEXT {%"PRIuUOFF_T"}\r\n", body_size.virtual_size); if (ctx->first) { str++; ctx->first = FALSE; } if (io_buffer_send(ctx->outbuf, str, strlen(str)) < 0) return FALSE; return message_send(ctx->outbuf, inbuf, &body_size, 0, (uoff_t)-1); } static ImapCacheField index_get_cache(MailFetchData *fetch_data) { MailFetchBodyData *sect; ImapCacheField field; field = 0; if (fetch_data->body) field |= IMAP_CACHE_BODY; if (fetch_data->bodystructure) field |= IMAP_CACHE_BODYSTRUCTURE; if (fetch_data->envelope) field |= IMAP_CACHE_ENVELOPE; if (fetch_data->rfc822_size) { field |= IMAP_CACHE_MESSAGE_HDR_SIZE | IMAP_CACHE_MESSAGE_BODY_SIZE; } if (fetch_data->rfc822) { field |= IMAP_CACHE_MESSAGE_OPEN | IMAP_CACHE_MESSAGE_HDR_SIZE | IMAP_CACHE_MESSAGE_BODY_SIZE; } if (fetch_data->rfc822_header) field |= IMAP_CACHE_MESSAGE_OPEN | IMAP_CACHE_MESSAGE_HDR_SIZE; if (fetch_data->rfc822_text) field |= IMAP_CACHE_MESSAGE_OPEN | IMAP_CACHE_MESSAGE_BODY_SIZE; /* check what body[] sections want */ sect = fetch_data->body_sections; for (; sect != NULL; sect = sect->next) field |= index_fetch_body_get_cache(sect->section); return field; } static void index_msgcache_open(FetchContext *ctx, MailIndexRecord *rec) { ImapCacheField fields; uoff_t virtual_header_size, virtual_body_size; void *mail_cache_context; fields = index_get_cache(ctx->fetch_data); if (fields == 0) return; mail_cache_context = index_msgcache_get_context(ctx->index, rec); virtual_header_size = (rec->index_flags & INDEX_MAIL_FLAG_BINARY_HEADER) ? rec->header_size : 0; virtual_body_size = (rec->index_flags & INDEX_MAIL_FLAG_BINARY_BODY) ? rec->body_size : 0; imap_msgcache_open(ctx->cache, rec->uid, fields, virtual_header_size, virtual_body_size, mail_cache_context); } static int index_fetch_mail(MailIndex *index __attr_unused__, MailIndexRecord *rec, unsigned int seq, void *context) { FetchContext *ctx = context; MailFetchBodyData *sect; unsigned int orig_len; int failed, data_written; ctx->str = t_string_new(2048); t_string_printfa(ctx->str, "* %u FETCH (", seq); orig_len = ctx->str->len; /* first see what we need to do. this way we don't first do some light parsing and later notice that we need to do heavier parsing anyway */ index_msgcache_open(ctx, rec); failed = TRUE; data_written = FALSE; do { /* these can't fail */ if (ctx->fetch_data->uid) index_fetch_uid(rec, ctx); if (ctx->fetch_data->flags) index_fetch_flags(rec, ctx); if (ctx->fetch_data->internaldate) index_fetch_internaldate(rec, ctx); /* rest can */ if (ctx->fetch_data->body) if (!index_fetch_body(rec, ctx)) break; if (ctx->fetch_data->bodystructure) if (!index_fetch_bodystructure(rec, ctx)) break; if (ctx->fetch_data->envelope) if (!index_fetch_envelope(rec, ctx)) break; if (ctx->fetch_data->rfc822_size) if (!index_fetch_rfc822_size(rec, ctx)) break; /* send the data written into temp string, not including the trailing zero */ ctx->first = ctx->str->len == orig_len; if (ctx->str->len > 0) { if (!ctx->first) ctx->str->len--; if (io_buffer_send(ctx->outbuf, ctx->str->str, ctx->str->len) < 0) break; } data_written = TRUE; /* large data */ if (ctx->fetch_data->rfc822) if (!index_fetch_send_rfc822(rec, ctx)) break; if (ctx->fetch_data->rfc822_text) if (!index_fetch_send_rfc822_text(rec, ctx)) break; if (ctx->fetch_data->rfc822_header) if (!index_fetch_send_rfc822_header(rec, ctx)) break; sect = ctx->fetch_data->body_sections; for (; sect != NULL; sect = sect->next) { if (!index_fetch_body_section(rec, seq, sect, ctx)) break; } failed = FALSE; } while (0); if (data_written) { if (io_buffer_send(ctx->outbuf, ")\r\n", 3) < 0) failed = TRUE; } imap_msgcache_close(ctx->cache); return !failed; } int index_storage_fetch(Mailbox *box, MailFetchData *fetch_data, IOBuffer *outbuf, int *all_found) { IndexMailbox *ibox = (IndexMailbox *) box; FetchContext ctx; MailFetchBodyData *sect; int ret; if (!index_storage_sync_if_possible(ibox)) return FALSE; if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_SHARED)) return mail_storage_set_index_error(ibox); memset(&ctx, 0, sizeof(ctx)); ctx.box = box; ctx.storage = box->storage; ctx.cache = ibox->cache; ctx.index = ibox->index; ctx.custom_flags = mail_custom_flags_list_get(ibox->index->custom_flags); ctx.fetch_data = fetch_data; ctx.outbuf = outbuf; /* If we have any BODY[..] sections, \Seen flag is added for all messages */ sect = ctx.fetch_data->body_sections; for (; sect != NULL; sect = sect->next) { if (!sect->peek) { ctx.update_seen = TRUE; break; } } ret = index_messageset_foreach(ibox, fetch_data->messageset, fetch_data->uidset, index_fetch_mail, &ctx); mail_custom_flags_list_unref(ibox->index->custom_flags); if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_UNLOCK)) return mail_storage_set_index_error(ibox); if (all_found != NULL) *all_found = ret == 1; if (ret >= 1 && ctx.update_seen && !box->readonly) { /* BODY[..] was fetched, set \Seen flag for all messages. This needs to be done separately because we need exclusive lock for it */ if (!index_storage_update_flags(box, fetch_data->messageset, fetch_data->uidset, MAIL_SEEN, NULL, MODIFY_ADD, NULL, NULL, NULL)) return FALSE; } return ret > 0; }