pop3c-mail.c revision 0d6ae58916bee3452c91d9d81be72227761ec33d
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2011-2012 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen#include "istream.h"
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen#include "index-mail.h"
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen#include "pop3c-client.h"
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen#include "pop3c-sync.h"
105addcb709523868418cc3e3baad7ad3453a91eTimo Sirainen#include "pop3c-storage.h"
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen
105addcb709523868418cc3e3baad7ad3453a91eTimo Sirainenstatic int pop3c_mail_get_received_date(struct mail *_mail, time_t *date_r)
105addcb709523868418cc3e3baad7ad3453a91eTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_storage_set_error(_mail->box->storage, MAIL_ERROR_NOTPOSSIBLE,
105addcb709523868418cc3e3baad7ad3453a91eTimo Sirainen "POP3 has no received date");
105addcb709523868418cc3e3baad7ad3453a91eTimo Sirainen *date_r = (time_t)-1;
105addcb709523868418cc3e3baad7ad3453a91eTimo Sirainen return -1;
105addcb709523868418cc3e3baad7ad3453a91eTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int pop3c_mail_get_save_date(struct mail *_mail, time_t *date_r)
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen{
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen mail_storage_set_error(_mail->box->storage, MAIL_ERROR_NOTPOSSIBLE,
105addcb709523868418cc3e3baad7ad3453a91eTimo Sirainen "POP3 has no save date");
49d4afbb76f47c8904537d087bc81e43f1c0aa25Timo Sirainen *date_r = (time_t)-1;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen return -1;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen}
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen
b44faf865da16ac4d18eecd85a55b3fab6b9e63aTimo Sirainenstatic int pop3c_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct pop3c_mailbox *mbox = (struct pop3c_mailbox *)_mail->box;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen struct message_size hdr_size, body_size;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen struct istream *input;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen if (mail->data.virtual_size != 0) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen /* virtual size is already known. it's the same as our
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen (correct) physical size */
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen *size_r = mail->data.virtual_size;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen return 0;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen if (index_mail_get_physical_size(_mail, size_r) == 0) {
c5794838af9995f50bfecb06a3cd4f9a0ac77858Timo Sirainen *size_r = mail->data.physical_size;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen return 0;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen }
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen
651fc0f1e43fef3e02e0e7b5f498973b05f641d7Timo Sirainen if (_mail->lookup_abort == MAIL_LOOKUP_ABORT_READ_MAIL &&
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen (_mail->box->flags & MAILBOX_FLAG_POP3_SESSION) != 0) {
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen /* kludge: we want output for POP3 LIST with
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen pop3_fast_size_lookups=yes. use the remote's LIST values
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen regardless of their correctness */
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen if (mbox->msg_sizes == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (pop3c_sync_get_sizes(mbox) < 0)
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen return -1;
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen }
041d312b44f8d41f0c9a5762c23e4d146ef7302bTimo Sirainen i_assert(_mail->seq <= mbox->msg_count);
041d312b44f8d41f0c9a5762c23e4d146ef7302bTimo Sirainen *size_r = mbox->msg_sizes[_mail->seq-1];
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen /* slow way: get the whole message body */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_get_stream(_mail, &hdr_size, &body_size, &input) < 0)
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen i_assert(mail->data.physical_size != (uoff_t)-1);
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen *size_r = mail->data.physical_size;
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen return 0;
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen}
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void pop3c_mail_cache_size(struct index_mail *mail)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail *_mail = &mail->mail.mail;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int cache_idx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (i_stream_get_size(mail->data.stream, TRUE, &size) <= 0)
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen return;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen mail->data.virtual_size = size;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen cache_idx = mail->ibox->cache_fields[MAIL_CACHE_VIRTUAL_FULL_SIZE].idx;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen if (mail_cache_field_exists(_mail->transaction->cache_view,
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen _mail->seq, cache_idx) == 0) {
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen index_mail_cache_add_idx(mail, cache_idx, &size, sizeof(size));
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen /* make sure it's not cached twice */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail->data.dont_cache_fetch_fields |=
659fe5d24825b160cae512538088020d97a60239Timo Sirainen MAIL_CACHE_VIRTUAL_FULL_SIZE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen}
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainenstatic int
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainenpop3c_mail_get_stream(struct mail *_mail, bool get_body,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_size *hdr_size,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_size *body_size, struct istream **stream_r)
659fe5d24825b160cae512538088020d97a60239Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct pop3c_mailbox *mbox = (struct pop3c_mailbox *)_mail->box;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen enum pop3c_capability capa;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen const char *name, *cmd, *error;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct istream *input;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (get_body && mail->data.stream != NULL) {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen name = i_stream_get_name(mail->data.stream);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (strncmp(name, "RETR", 4) == 0) {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen /* we've fetched the body */
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen } else if (strncmp(name, "TOP", 3) == 0) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* we've fetched the header, but we need the body
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen now too */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index_mail_close_streams(mail);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen i_panic("Unexpected POP3 stream name: %s", name);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen }
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen }
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (mail->data.stream == NULL) {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen capa = pop3c_client_get_capabilities(mbox->client);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (get_body || (capa & POP3C_CAPABILITY_TOP) == 0) {
a928e7efabb1672b1476e597106d4b4b81ac6f3cTimo Sirainen cmd = t_strdup_printf("RETR %u\r\n", _mail->seq);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen get_body = TRUE;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen } else {
838f56174b963779a88083a0d0e85b30d2d846e7Timo Sirainen cmd = t_strdup_printf("TOP %u 0\r\n", _mail->seq);
894987bf45718f8849cc3898afdfb1ac3cfa2445Timo Sirainen }
894987bf45718f8849cc3898afdfb1ac3cfa2445Timo Sirainen if (pop3c_client_cmd_stream(mbox->client, cmd,
894987bf45718f8849cc3898afdfb1ac3cfa2445Timo Sirainen &input, &error) < 0) {
838f56174b963779a88083a0d0e85b30d2d846e7Timo Sirainen mail_storage_set_error(mbox->box.storage,
838f56174b963779a88083a0d0e85b30d2d846e7Timo Sirainen !pop3c_client_is_connected(mbox->client) ?
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen MAIL_ERROR_TEMP : MAIL_ERROR_EXPUNGED, error);
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen return -1;
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen }
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen mail->data.stream = input;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (mail->mail.v.istream_opened != NULL) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (mail->mail.v.istream_opened(_mail,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen &mail->data.stream) < 0) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen index_mail_close_streams(mail);
838f56174b963779a88083a0d0e85b30d2d846e7Timo Sirainen return -1;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen i_stream_set_name(mail->data.stream, t_strcut(cmd, '\r'));
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (get_body)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen pop3c_mail_cache_size(mail);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6e07b4251bf6a3cf34019c351a32a65c08392e58Timo Sirainen return index_mail_init_stream(mail, hdr_size, body_size, stream_r);
6e07b4251bf6a3cf34019c351a32a65c08392e58Timo Sirainen}
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenstatic int
d143077bd518de129b8d446fb58e003903e50867Timo Sirainenpop3c_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen const char **value_r)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen{
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen struct pop3c_mailbox *mbox = (struct pop3c_mailbox *)_mail->box;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen switch (field) {
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen case MAIL_FETCH_UIDL_BACKEND:
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen if (mbox->msg_uidls == NULL) {
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen if (pop3c_sync_get_uidls(mbox) < 0)
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen return -1;
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen }
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen i_assert(_mail->seq <= mbox->msg_count);
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen *value_r = mbox->msg_uidls[_mail->seq-1];
e76f5e07be5bec4e5ca99c3e093ff7f11edbe1b7Timo Sirainen return 0;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen default:
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen return index_mail_get_special(_mail, field, value_r);
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen }
a928e7efabb1672b1476e597106d4b4b81ac6f3cTimo Sirainen}
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen
c5794838af9995f50bfecb06a3cd4f9a0ac77858Timo Sirainenstruct mail_vfuncs pop3c_mail_vfuncs = {
c5794838af9995f50bfecb06a3cd4f9a0ac77858Timo Sirainen index_mail_close,
c5794838af9995f50bfecb06a3cd4f9a0ac77858Timo Sirainen index_mail_free,
c5794838af9995f50bfecb06a3cd4f9a0ac77858Timo Sirainen index_mail_set_seq,
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen index_mail_set_uid,
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen index_mail_set_uid_cache_updates,
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen index_mail_prefetch,
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen index_mail_precache,
e188bab0b830136d04a1dd8b55e9afefae20d930Timo Sirainen index_mail_add_temp_wanted_fields,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen index_mail_get_flags,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen index_mail_get_keywords,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen index_mail_get_keyword_indexes,
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen index_mail_get_modseq,
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen index_mail_get_parts,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen index_mail_get_date,
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen pop3c_mail_get_received_date,
bd503f12eb667df389a99162f567bd8785798f55Timo Sirainen pop3c_mail_get_save_date,
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen index_mail_get_virtual_size,
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen pop3c_mail_get_physical_size,
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen index_mail_get_first_header,
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen index_mail_get_headers,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen index_mail_get_header_stream,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen pop3c_mail_get_stream,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen pop3c_mail_get_special,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen index_mail_get_real_mail,
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen index_mail_update_flags,
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen index_mail_update_keywords,
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen index_mail_update_modseq,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen NULL,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen index_mail_expunge,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen index_mail_set_cache_corrupted,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen index_mail_opened
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen};
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen