mail.c revision ad48319996942463675b53877092ab7e13a7a75a
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
49e358eebea107aad9919dcc4bd88cee8519ba2eTimo Sirainen#include "ioloop.h"
49e358eebea107aad9919dcc4bd88cee8519ba2eTimo Sirainen#include "buffer.h"
49e358eebea107aad9919dcc4bd88cee8519ba2eTimo Sirainen#include "hex-binary.h"
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen#include "crc32.h"
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include "sha1.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "hostpid.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "mail-storage-private.h"
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen#include <time.h>
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
da2aa032ccfa8e7e4a4380ef738014549f4d2c2dTimo Sirainenstruct mail *mail_alloc(struct mailbox_transaction_context *t,
da2aa032ccfa8e7e4a4380ef738014549f4d2c2dTimo Sirainen enum mail_fetch_field wanted_fields,
411d6baa37f31d90730e90c4a28c43e1974bbe58Timo Sirainen struct mailbox_header_lookup_ctx *wanted_headers)
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen{
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen return t->box->v.mail_alloc(t, wanted_fields, wanted_headers);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenvoid mail_free(struct mail **mail)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen struct mail_private *p = (struct mail_private *)*mail;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen p->v.free(*mail);
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen *mail = NULL;
43834f87bf431198f986e86052a4f6e558fdb07dTimo Sirainen}
43834f87bf431198f986e86052a4f6e558fdb07dTimo Sirainen
09801f106cd531a28b4e03ec665e44c421264560Timo Sirainenvoid mail_set_seq(struct mail *mail, uint32_t seq)
09801f106cd531a28b4e03ec665e44c421264560Timo Sirainen{
09801f106cd531a28b4e03ec665e44c421264560Timo Sirainen struct mail_private *p = (struct mail_private *)mail;
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen p->v.set_seq(mail, seq);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen}
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen
212a34c06ff45952c008ae9eec387ced783de6cfPhil Carmodybool mail_set_uid(struct mail *mail, uint32_t uid)
212a34c06ff45952c008ae9eec387ced783de6cfPhil Carmody{
212a34c06ff45952c008ae9eec387ced783de6cfPhil Carmody struct mail_private *p = (struct mail_private *)mail;
212a34c06ff45952c008ae9eec387ced783de6cfPhil Carmody
10c96a244935de4add8213ba0b894178dfb889a5Timo Sirainen return p->v.set_uid(mail, uid);
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen}
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainenenum mail_flags mail_get_flags(struct mail *mail)
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen{
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen struct mail_private *p = (struct mail_private *)mail;
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return p->v.get_flags(mail);
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen}
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenuint64_t mail_get_modseq(struct mail *mail)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen{
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen struct mail_private *p = (struct mail_private *)mail;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen return p->v.get_modseq(mail);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen}
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainenconst char *const *mail_get_keywords(struct mail *mail)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_private *p = (struct mail_private *)mail;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen return p->v.get_keywords(mail);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen}
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainenconst ARRAY_TYPE(keyword_indexes) *mail_get_keyword_indexes(struct mail *mail)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen{
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen struct mail_private *p = (struct mail_private *)mail;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen return p->v.get_keyword_indexes(mail);
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen}
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainenint mail_get_parts(struct mail *mail, const struct message_part **parts_r)
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen{
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen struct mail_private *p = (struct mail_private *)mail;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return p->v.get_parts(mail, parts_r);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen}
46ce4d9273e6df12ef1912bbdb1c8b84b104f394Timo Sirainen
46ce4d9273e6df12ef1912bbdb1c8b84b104f394Timo Sirainenint mail_get_date(struct mail *mail, time_t *date_r, int *timezone_r)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_private *p = (struct mail_private *)mail;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen int tz;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (timezone_r == NULL)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen timezone_r = &tz;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen return p->v.get_date(mail, date_r, timezone_r);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainenint mail_get_received_date(struct mail *mail, time_t *date_r)
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen{
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen struct mail_private *p = (struct mail_private *)mail;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return p->v.get_received_date(mail, date_r);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen}
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainenint mail_get_save_date(struct mail *mail, time_t *date_r)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen{
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen struct mail_private *p = (struct mail_private *)mail;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return p->v.get_save_date(mail, date_r);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenint mail_get_virtual_size(struct mail *mail, uoff_t *size_r)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_private *p = (struct mail_private *)mail;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return p->v.get_virtual_size(mail, size_r);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainenint mail_get_physical_size(struct mail *mail, uoff_t *size_r)
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen{
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen struct mail_private *p = (struct mail_private *)mail;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen return p->v.get_physical_size(mail, size_r);
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen}
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainenint mail_get_first_header(struct mail *mail, const char *field,
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen const char **value_r)
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen{
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen struct mail_private *p = (struct mail_private *)mail;
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return p->v.get_first_header(mail, field, FALSE, value_r);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen}
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainenint mail_get_first_header_utf8(struct mail *mail, const char *field,
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen const char **value_r)
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen{
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen struct mail_private *p = (struct mail_private *)mail;
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen return p->v.get_first_header(mail, field, TRUE, value_r);
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen}
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainenint mail_get_headers(struct mail *mail, const char *field,
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen const char *const **value_r)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen{
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen struct mail_private *p = (struct mail_private *)mail;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen return p->v.get_headers(mail, field, FALSE, value_r);
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen}
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainenint mail_get_headers_utf8(struct mail *mail, const char *field,
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen const char *const **value_r)
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen{
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen struct mail_private *p = (struct mail_private *)mail;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return p->v.get_headers(mail, field, TRUE, value_r);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainenint mail_get_header_stream(struct mail *mail,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mailbox_header_lookup_ctx *headers,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct istream **stream_r)
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen{
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen struct mail_private *p = (struct mail_private *)mail;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
699fdc186f982f70d990820796eaa0f12133e27cTimo Sirainen return p->v.get_header_stream(mail, headers, stream_r);
699fdc186f982f70d990820796eaa0f12133e27cTimo Sirainen}
699fdc186f982f70d990820796eaa0f12133e27cTimo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainenint mail_set_aborted(struct mail *mail)
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_storage_set_error(mail->box->storage, MAIL_ERROR_NOTPOSSIBLE,
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen "Mail field not cached");
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen return -1;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen}
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainenint mail_get_stream(struct mail *mail, struct message_size *hdr_size,
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen struct message_size *body_size, struct istream **stream_r)
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen{
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen struct mail_private *p = (struct mail_private *)mail;
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen if (mail->lookup_abort != MAIL_LOOKUP_ABORT_NEVER)
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen return mail_set_aborted(mail);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return p->v.get_stream(mail, hdr_size, body_size, stream_r);
}
int mail_get_special(struct mail *mail, enum mail_fetch_field field,
const char **value_r)
{
struct mail_private *p = (struct mail_private *)mail;
return p->v.get_special(mail, field, value_r);
}
void mail_update_flags(struct mail *mail, enum modify_type modify_type,
enum mail_flags flags)
{
struct mail_private *p = (struct mail_private *)mail;
p->v.update_flags(mail, modify_type, flags);
}
void mail_update_keywords(struct mail *mail, enum modify_type modify_type,
struct mail_keywords *keywords)
{
struct mail_private *p = (struct mail_private *)mail;
p->v.update_keywords(mail, modify_type, keywords);
}
void mail_update_modseq(struct mail *mail, uint64_t min_modseq)
{
struct mail_private *p = (struct mail_private *)mail;
p->v.update_modseq(mail, min_modseq);
}
void mail_update_uid(struct mail *mail, uint32_t new_uid)
{
struct mail_private *p = (struct mail_private *)mail;
p->v.update_uid(mail, new_uid);
}
void mail_expunge(struct mail *mail)
{
struct mail_private *p = (struct mail_private *)mail;
p->v.expunge(mail);
}
void mail_set_expunged(struct mail *mail)
{
mail_storage_set_error(mail->box->storage, MAIL_ERROR_EXPUNGED,
"Message was expunged");
mail->expunged = TRUE;
}
void mail_set_cache_corrupted(struct mail *mail, enum mail_fetch_field field)
{
struct mail_private *p = (struct mail_private *)mail;
p->v.set_cache_corrupted(mail, field);
}
const char *mail_generate_guid_string(void)
{
static struct timespec ts = { 0, 0 };
static unsigned int pid = 0;
/* we'll use the current time in nanoseconds as the initial 64bit
counter. */
if (ts.tv_sec == 0) {
if (clock_gettime(CLOCK_REALTIME, &ts) < 0)
i_fatal("clock_gettime() failed: %m");
pid = getpid();
} else if ((uint32_t)ts.tv_nsec < (uint32_t)-1) {
ts.tv_nsec++;
} else {
ts.tv_sec++;
ts.tv_nsec = 0;
}
return t_strdup_printf("%04x%04lx%04x%s",
(unsigned int)ts.tv_nsec,
(unsigned long)ts.tv_sec,
pid, my_hostname);
}
void mail_generate_guid_128(uint8_t guid[MAIL_GUID_128_SIZE])
{
static struct timespec ts = { 0, 0 };
static uint8_t guid_static[8];
uint32_t pid, host_crc;
/* we'll use the current time in nanoseconds as the initial 64bit
counter. */
if (ts.tv_sec == 0) {
if (clock_gettime(CLOCK_REALTIME, &ts) < 0)
i_fatal("clock_gettime() failed: %m");
pid = getpid();
host_crc = crc32_str(my_hostname);
guid_static[0] = (pid & 0x000000ff);
guid_static[1] = (pid & 0x0000ff00) >> 8;
guid_static[2] = (pid & 0x00ff0000) >> 16;
guid_static[3] = (pid & 0xff000000) >> 24;
guid_static[4] = (host_crc & 0x000000ff);
guid_static[5] = (host_crc & 0x0000ff00) >> 8;
guid_static[6] = (host_crc & 0x00ff0000) >> 16;
guid_static[7] = (host_crc & 0xff000000) >> 24;
} else if ((uint32_t)ts.tv_nsec < (uint32_t)-1) {
ts.tv_nsec++;
} else {
ts.tv_sec++;
ts.tv_nsec = 0;
}
guid[0] = (ts.tv_nsec & 0x000000ff);
guid[1] = (ts.tv_nsec & 0x0000ff00) >> 8;
guid[2] = (ts.tv_nsec & 0x00ff0000) >> 16;
guid[3] = (ts.tv_nsec & 0xff000000) >> 24;
guid[4] = (ts.tv_sec & 0x000000ff);
guid[5] = (ts.tv_sec & 0x0000ff00) >> 8;
guid[6] = (ts.tv_sec & 0x00ff0000) >> 16;
guid[7] = (ts.tv_sec & 0xff000000) >> 24;
memcpy(guid + 8, guid_static, 8);
}
void mail_generate_guid_128_hash(const char *guid,
uint8_t guid_128[MAIL_GUID_128_SIZE])
{
unsigned char sha1_sum[SHA1_RESULTLEN];
buffer_t buf;
buffer_create_data(&buf, guid_128, MAIL_GUID_128_SIZE);
if (strlen(guid) != MAIL_GUID_128_SIZE*2 ||
hex_to_binary(guid, &buf) < 0 ||
buf.used != MAIL_GUID_128_SIZE) {
/* not 128bit hex. use a hash of it instead. */
buffer_set_used_size(&buf, 0);
sha1_get_digest(guid, strlen(guid), sha1_sum);
#if SHA1_RESULTLEN < DBOX_GUID_BIN_LEN
# error not possible
#endif
buffer_append(&buf,
sha1_sum + SHA1_RESULTLEN - MAIL_GUID_128_SIZE,
MAIL_GUID_128_SIZE);
}
}
bool mail_guid_128_is_empty(const uint8_t guid_128[MAIL_GUID_128_SIZE])
{
unsigned int i;
for (i = 0; i < MAILBOX_GUID_SIZE; i++) {
if (guid_128[i] != 0)
return FALSE;
}
return TRUE;
}