pop3c-mail.c revision e130bb802c8bfb6c6cc44e5c8bc098b4fa5af789
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2011-2013 Dovecot authors, see the included COPYING file */
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen
46552a931924c2d743f045e95b08c3ce6beda91aTimo Sirainen#include "lib.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "ioloop.h"
d3d769026fae5d21c2d29614d3bc4579e8d79e81Timo Sirainen#include "istream.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "index-mail.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "pop3c-client.h"
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen#include "pop3c-sync.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "pop3c-storage.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainenstatic int pop3c_mail_get_received_date(struct mail *_mail, time_t *date_r)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen int tz;
92c49f3005f4dff1a6f576fffa8112ef6d1cae7fTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* FIXME: we could also parse the first Received: header and get
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen the date from there, but since this code is unlikely to be called
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen except during migration, I don't think it really matters. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return index_mail_get_date(_mail, date_r, &tz);
4ead43ecc06d10047998966c4dc0b142ecce4b66Timo Sirainen}
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen
1d4f710106fb498750456724628da6063e012e6dTimo Sirainenstatic int pop3c_mail_get_save_date(struct mail *_mail, time_t *date_r)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen{
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen struct index_mail_data *data = &mail->data;
ab0d9eecd85f74acae18fe88529302e0776cc500Timo Sirainen
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen if (data->save_date == (time_t)-1) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* FIXME: we could use a value stored in cache */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return pop3c_mail_get_received_date(_mail, date_r);
336b825e0321b798690351d9899b1b0cb99ec462Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen *date_r = data->save_date;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int pop3c_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct pop3c_mailbox *mbox = (struct pop3c_mailbox *)_mail->box;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct message_size hdr_size, body_size;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream *input;
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen if (mail->data.virtual_size != (uoff_t)-1) {
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen /* virtual size is already known. it's the same as our
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen (correct) physical size */
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen *size_r = mail->data.virtual_size;
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen return 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (index_mail_get_physical_size(_mail, size_r) == 0) {
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen *size_r = mail->data.physical_size;
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen return 0;
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen }
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (_mail->lookup_abort == MAIL_LOOKUP_ABORT_READ_MAIL &&
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen (_mail->box->flags & MAILBOX_FLAG_POP3_SESSION) != 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* kludge: we want output for POP3 LIST with
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen pop3_fast_size_lookups=yes. use the remote's LIST values
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen regardless of their correctness */
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen if (mbox->msg_sizes == NULL) {
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen if (pop3c_sync_get_sizes(mbox) < 0)
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen return -1;
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen }
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen i_assert(_mail->seq <= mbox->msg_count);
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen *size_r = mbox->msg_sizes[_mail->seq-1];
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen return 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* slow way: get the whole message body */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (mail_get_stream(_mail, &hdr_size, &body_size, &input) < 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(mail->data.physical_size != (uoff_t)-1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen *size_r = mail->data.physical_size;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void pop3c_mail_cache_size(struct index_mail *mail)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen struct mail *_mail = &mail->mail.mail;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen uoff_t size;
d3d769026fae5d21c2d29614d3bc4579e8d79e81Timo Sirainen unsigned int cache_idx;
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (i_stream_get_size(mail->data.stream, TRUE, &size) <= 0)
5a9e240ebf8d0daaf029973973b52e415148070bTimo Sirainen return;
5a9e240ebf8d0daaf029973973b52e415148070bTimo Sirainen mail->data.virtual_size = size;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen cache_idx = mail->ibox->cache_fields[MAIL_CACHE_VIRTUAL_FULL_SIZE].idx;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (mail_cache_field_exists(_mail->transaction->cache_view,
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen _mail->seq, cache_idx) == 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_cache_add_idx(mail, cache_idx, &size, sizeof(size));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* make sure it's not cached twice */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail->data.dont_cache_fetch_fields |=
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen MAIL_CACHE_VIRTUAL_FULL_SIZE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen}
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainenpop3c_mail_get_stream(struct mail *_mail, bool get_body,
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen struct message_size *hdr_size,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct message_size *body_size, struct istream **stream_r)
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct pop3c_mailbox *mbox = (struct pop3c_mailbox *)_mail->box;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen enum pop3c_capability capa;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *name, *cmd, *error;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream *input;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (get_body && mail->data.stream != NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen name = i_stream_get_name(mail->data.stream);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strncmp(name, "RETR", 4) == 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* we've fetched the body */
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen } else if (strncmp(name, "TOP", 3) == 0) {
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen /* we've fetched the header, but we need the body
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen now too */
d3d769026fae5d21c2d29614d3bc4579e8d79e81Timo Sirainen index_mail_close_streams(mail);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_panic("Unexpected POP3 stream name: %s", name);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (mail->data.stream == NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen capa = pop3c_client_get_capabilities(mbox->client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (get_body || (capa & POP3C_CAPABILITY_TOP) == 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen cmd = t_strdup_printf("RETR %u\r\n", _mail->seq);
c7fca6cbb32388556d9f6d8313486cc4e4a3c058Timo Sirainen get_body = TRUE;
c7fca6cbb32388556d9f6d8313486cc4e4a3c058Timo Sirainen } else {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen cmd = t_strdup_printf("TOP %u 0\r\n", _mail->seq);
c7fca6cbb32388556d9f6d8313486cc4e4a3c058Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (pop3c_client_cmd_stream(mbox->client, cmd,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen &input, &error) < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_storage_set_error(mbox->box.storage,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen !pop3c_client_is_connected(mbox->client) ?
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen MAIL_ERROR_TEMP : MAIL_ERROR_EXPUNGED, error);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail->data.stream = input;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (mail->mail.v.istream_opened != NULL) {
5a9e240ebf8d0daaf029973973b52e415148070bTimo Sirainen if (mail->mail.v.istream_opened(_mail,
5a9e240ebf8d0daaf029973973b52e415148070bTimo Sirainen &mail->data.stream) < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_close_streams(mail);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen }
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_stream_set_name(mail->data.stream, t_strcut(cmd, '\r'));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (get_body)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen pop3c_mail_cache_size(mail);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return index_mail_init_stream(mail, hdr_size, body_size, stream_r);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenpop3c_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char **value_r)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct pop3c_mailbox *mbox = (struct pop3c_mailbox *)_mail->box;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen switch (field) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case MAIL_FETCH_UIDL_BACKEND:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case MAIL_FETCH_GUID:
05e55893a799de645fc8cd2203d6013f0e0f1b79Timo Sirainen if (mbox->msg_uidls == NULL) {
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainen if (pop3c_sync_get_uidls(mbox) < 0)
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainen return -1;
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainen }
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainen i_assert(_mail->seq <= mbox->msg_count);
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainen *value_r = mbox->msg_uidls[_mail->seq-1];
5d2e7ec2ea725c8a6a63f56b771e746f93e782ecTimo Sirainen return 0;
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainen default:
5d2e7ec2ea725c8a6a63f56b771e746f93e782ecTimo Sirainen return index_mail_get_special(_mail, field, value_r);
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstruct mail_vfuncs pop3c_mail_vfuncs = {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_close,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_free,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_set_seq,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_set_uid,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_set_uid_cache_updates,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_prefetch,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_precache,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_add_temp_wanted_fields,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_get_flags,
bdb9f7f7fbf828fb85a393bd2803167b1bb8ff0dTimo Sirainen index_mail_get_keywords,
bdb9f7f7fbf828fb85a393bd2803167b1bb8ff0dTimo Sirainen index_mail_get_keyword_indexes,
bdb9f7f7fbf828fb85a393bd2803167b1bb8ff0dTimo Sirainen index_mail_get_modseq,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_get_pvt_modseq,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_get_parts,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_get_date,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen pop3c_mail_get_received_date,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen pop3c_mail_get_save_date,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_get_virtual_size,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen pop3c_mail_get_physical_size,
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen index_mail_get_first_header,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_get_headers,
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen index_mail_get_header_stream,
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen pop3c_mail_get_stream,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_get_binary_stream,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen pop3c_mail_get_special,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_get_real_mail,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_update_flags,
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen index_mail_update_keywords,
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen index_mail_update_modseq,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_update_pvt_modseq,
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen NULL,
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen index_mail_expunge,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_set_cache_corrupted,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen index_mail_opened
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen};
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen