index-mail-headers.c revision 645f258ea29afaf09b673fc65d1bd788dfec8db8
/* Copyright (C) 2003 Timo Sirainen */
/*
Headers are stored in 1-4 pieces. There's a list of header names that each
piece contains, so if piece doesn't actually contain some listed header,
it's known not to exist in the mail at all.
Header name lists are stored in sorted order, so we can use binary
searching.
We have to be able to do 3 things:
- Get value for one header
- Get a list of headers, possibly containing more than requested
- Save some of the uncached headers into cache
First is easy. Second means that we have to store the wanted headers in
a single string which we can directly return.
Third is a bit tricky if we want to avoid parsing and copying the data
uselessly. It's possible if we want to cache all requested uncached
headers. That should be the common case, so I'll optimize for that.
Another even more common case is that everything is already cached. So:
- If we request only cached headers, parse them and copy only wanted
headers to header_data.
- If we request a non-cached header, trash the header_data and all
pointers to it. Copy all cached headers to beginning if it and save
a marker where it ends.
- If we again request single cached header, we'll have to parse the
header_data up to the marker again.
- When saving the uncached headers, we know that they all come after the
marker. If we want to save them all, it's directly there in a string.
Otherwise we have to parse them and copy the wanted headers, but it's
still less work.
*/
#include "lib.h"
#include "istream.h"
#include "buffer.h"
#include "str.h"
#include "message-date.h"
#include "imap-envelope.h"
#include "imap-bodystructure.h"
#include "index-storage.h"
#include "index-mail.h"
#include <stdlib.h>
struct cached_header {
const char *name;
unsigned int parsing:1;
unsigned int fully_saved:1;
};
static struct cached_header *
unsigned int *idx_r)
{
struct cached_header **data;
int ret;
if (ret < 0)
else if (ret > 0)
else {
}
}
return NULL;
}
static struct cached_header *
{
struct cached_header *hdr;
unsigned int idx;
return hdr;
return hdr;
}
{
}
static const char *const *sort_array(const char *const *arr)
{
const char **data;
int i, already_sorted;
/* copy the wanted_headers array */
if (i > 0 && already_sorted &&
}
/* and sort it */
if (!already_sorted)
return data;
}
const char *const wanted_headers[])
{
return -1;
ret = -1;
for (i = MAIL_CACHE_HEADERS_COUNT-1; i >= 0; i--) {
continue;
if (cmp == 0) {
break;
} else {
if (cmp < 0)
break;
}
}
return ret;
/* find the minimum matching header number */
ret = i;
}
return ret;
}
const char *const wanted_headers[])
{
int idx;
if (idx < 0)
return -1;
mail_cache_header_fields[idx]) != 0)
return idx;
}
return -1;
}
{
const struct cached_header **data;
size /= sizeof(struct cached_header *);
for (i = 0; i < size; i++)
}
{
struct cached_header **data;
size /= sizeof(struct cached_header *);
for (i = 0; i < size; i++) {
}
}
}
const char *const headers[])
{
struct cached_header **data;
int cmp;
size /= sizeof(struct cached_header *);
/* parsing all headers */
for (i = 0; i < size; i++)
} else {
t_push();
if (cmp <= 0) {
if (cmp == 0)
headers++;
}
}
t_pop();
}
}
{
struct cached_header *cached_hdr;
return;
if (data->save_envelope) {
/* finalize the envelope */
}
}
/* end of headers */
if (data->save_sent_date) {
/* not found */
}
}
return;
}
else {
/* 0 == parse error */
}
}
}
}
if (cached_hdr->value_idx == 0) {
}
if (!hdr->no_newline)
} else {
/* it's already in header_data. */
if (cached_hdr->value_idx == 0) {
}
}
}
}
{
return FALSE; /* all headers used */
/* FIXME: add some smart checks here. we don't necessarily want to
cache everything.. */
return FALSE;
return TRUE;
}
{
struct cached_header **data;
size /= sizeof(struct cached_header *);
for (i = 0; i < size; i++) {
}
}
{
const char *str, *const *idx_headers;
t_push();
/* it's already in header_data. */
/* we might be parsing a bit more.. */
} else {
/* broken - we expected the header to exist */
t_pop();
return FALSE;
}
}
idx);
t_pop();
return TRUE;
}
{
if (!index_mail_open_stream(mail, 0))
return FALSE;
/* can_cache_headers() locks the cache file. it must be done before
we can expect cached headers to stay the same. it's not a good idea
to cache some headers twice because of race conditions.. */
if (data->header_data_cached_partial) {
/* too difficult to handle efficiently, trash it */
}
/* add all cached headers to beginning of header_data */
continue;
}
/* make sure we cache everything */
break;
}
headers++;
}
}
if (max >= 0) {
/* now we'll have to set value_idx for all headers that
are already cached */
return FALSE;
}
}
} else {
}
if (data->bodystructure_header_want) {
}
if (get_parts) {
/* we know the NULs now, update them */
} else {
}
}
return TRUE;
}
{
struct cached_header *hdr;
const char *arr[2];
int idx;
if (!hdr->fully_saved) {
/* we need to parse header anyway */
idx = -1;
} else {
if (idx >= 0) {
return NULL;
}
}
if (idx < 0) {
/* might have been moved in memory, get it again */
}
}
}
const char *const minimum_fields[])
{
struct cached_header *hdr;
if (idx >= 0) {
/* copy from cache to header_data */
continue;
}
if (!data->header_data_cached_partial) {
}
} else {
/* it's not cached yet - see if we have them parsed */
if (!hdr->fully_saved)
}
if (!all_saved)
}
}
{
}
{
const char *const *tmp;
int idx;
const char *const *tmp;
}
if (idx != -1) {
/* see if it's cached */
}
}
/* See if we're going to have to parse the header */
if (idx != -2) {
if (idx >= 0) {
if ((data->cached_fields &
mail_cache_header_fields[idx]) != 0)
break;
}
}
}
}
{
int i;
for (i = 0; i < MAIL_CACHE_HEADERS_COUNT; i++) {
return i;
}
return -1;
}
{
int idx;
if (!data->header_save)
return;
accessing headers from same message. index_mails should probably be
shared.. */
if (idx >= 0) {
/* all headers found */
} else {
/* there's some new headers */
if (idx < 0)
return;
return;
}
}