~ubuntu-branches/ubuntu/wily/dovecot/wily

« back to all changes in this revision

Viewing changes to src/lib-storage/index/imapc/imapc-mail-fetch.c

  • Committer: Package Import Robot
  • Author(s): Jelmer Vernooij
  • Date: 2015-05-24 15:01:19 UTC
  • mto: (4.1.53 sid)
  • mto: This revision was merged to the branch mainline in revision 102.
  • Revision ID: package-import@ubuntu.com-20150524150119-hsh6cbr1fqseapga
Tags: upstream-2.2.18
ImportĀ upstreamĀ versionĀ 2.2.18

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
#include "str.h"
5
5
#include "ioloop.h"
6
6
#include "istream.h"
 
7
#include "istream-concat.h"
7
8
#include "istream-header-filter.h"
8
9
#include "message-header-parser.h"
9
10
#include "imap-arg.h"
211
212
        str_printfa(str, "UID FETCH %u (", _mail->uid);
212
213
        if ((fields & MAIL_FETCH_RECEIVED_DATE) != 0)
213
214
                str_append(str, "INTERNALDATE ");
214
 
        if ((fields & MAIL_FETCH_PHYSICAL_SIZE) != 0)
 
215
        if ((fields & (MAIL_FETCH_PHYSICAL_SIZE | MAIL_FETCH_VIRTUAL_SIZE)) != 0)
215
216
                str_append(str, "RFC822.SIZE ");
216
217
        if ((fields & MAIL_FETCH_GUID) != 0) {
217
218
                str_append(str, mbox->guid_fetch_field_name);
218
219
                str_append_c(str, ' ');
219
220
        }
220
221
 
221
 
        if ((fields & MAIL_FETCH_STREAM_BODY) != 0)
222
 
                str_append(str, "BODY.PEEK[] ");
223
 
        else if ((fields & MAIL_FETCH_STREAM_HEADER) != 0)
 
222
        if ((fields & MAIL_FETCH_STREAM_BODY) != 0) {
 
223
                if (!IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_ZIMBRA_WORKAROUNDS))
 
224
                        str_append(str, "BODY.PEEK[] ");
 
225
                else {
 
226
                        /* BODY.PEEK[] can return different headers than
 
227
                           BODY.PEEK[HEADER] (e.g. invalid 8bit chars replaced
 
228
                           with '?' in HEADER) - this violates IMAP protocol
 
229
                           and messes up dsync since it sometimes fetches the
 
230
                           full body and sometimes only the headers. */
 
231
                        str_append(str, "BODY.PEEK[HEADER] BODY.PEEK[TEXT] ");
 
232
                }
 
233
        } else if ((fields & MAIL_FETCH_STREAM_HEADER) != 0)
224
234
                str_append(str, "BODY.PEEK[HEADER] ");
225
235
        else if (headers != NULL) {
226
236
                mail->fetching_headers =
267
277
        } else {
268
278
                return;
269
279
        }
 
280
        mail->header_fetched = TRUE;
270
281
        mail->body_fetched = TRUE;
271
 
        imapc_mail_init_stream(mail, TRUE);
 
282
        imapc_mail_init_stream(mail);
272
283
}
273
284
 
274
285
static enum mail_fetch_field
285
296
        if ((data->wanted_fields & MAIL_FETCH_SAVE_DATE) != 0 &&
286
297
            data->save_date == (time_t)-1 && data->received_date == (time_t)-1)
287
298
                fields |= MAIL_FETCH_RECEIVED_DATE;
288
 
        if ((data->wanted_fields & MAIL_FETCH_PHYSICAL_SIZE) != 0 &&
 
299
        if ((data->wanted_fields & (MAIL_FETCH_PHYSICAL_SIZE |
 
300
                                    MAIL_FETCH_VIRTUAL_SIZE)) != 0 &&
289
301
            data->physical_size == (uoff_t)-1 &&
290
302
            IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_RFC822_SIZE))
291
 
                fields |= MAIL_FETCH_PHYSICAL_SIZE;
 
303
                fields |= MAIL_FETCH_PHYSICAL_SIZE | MAIL_FETCH_VIRTUAL_SIZE;
292
304
        if ((data->wanted_fields & MAIL_FETCH_GUID) != 0 &&
293
305
            data->guid == NULL && mbox->guid_fetch_field_name != NULL)
294
306
                fields |= MAIL_FETCH_GUID;
332
344
                        return FALSE;
333
345
                fields &= ~MAIL_FETCH_RECEIVED_DATE;
334
346
        }
335
 
        if ((fields & MAIL_FETCH_PHYSICAL_SIZE) != 0) {
 
347
        if ((fields & (MAIL_FETCH_PHYSICAL_SIZE | MAIL_FETCH_VIRTUAL_SIZE)) != 0) {
336
348
                if (imail->imail.data.physical_size == (uoff_t)-1)
337
349
                        return FALSE;
338
 
                fields &= ~MAIL_FETCH_PHYSICAL_SIZE;
 
350
                fields &= ~(MAIL_FETCH_PHYSICAL_SIZE | MAIL_FETCH_VIRTUAL_SIZE);
339
351
        }
340
352
        if ((fields & MAIL_FETCH_GUID) != 0) {
341
353
                if (imail->imail.data.guid == NULL)
450
462
        *input = filter_input;
451
463
}
452
464
 
453
 
void imapc_mail_init_stream(struct imapc_mail *mail, bool have_body)
 
465
void imapc_mail_init_stream(struct imapc_mail *mail)
454
466
{
455
467
        struct index_mail *imail = &mail->imail;
456
468
        struct mail *_mail = &imail->mail.mail;
469
481
                        index_mail_close_streams(imail);
470
482
                        return;
471
483
                }
472
 
        } else if (have_body) {
 
484
        } else if (mail->body_fetched) {
473
485
                ret = i_stream_get_size(imail->data.stream, TRUE, &size);
474
486
                if (ret < 0) {
475
487
                        index_mail_close_streams(imail);
482
494
                imail->data.virtual_size = size;
483
495
        }
484
496
 
485
 
        imail->data.stream_has_only_header = !have_body;
 
497
        imail->data.stream_has_only_header = !mail->body_fetched;
486
498
        if (index_mail_init_stream(imail, NULL, NULL, &input) < 0)
487
499
                index_mail_close_streams(imail);
488
500
}
490
502
static void
491
503
imapc_fetch_stream(struct imapc_mail *mail,
492
504
                   const struct imapc_untagged_reply *reply,
493
 
                   const struct imap_arg *arg, bool body)
 
505
                   const struct imap_arg *arg,
 
506
                   bool have_header, bool have_body)
494
507
{
495
508
        struct index_mail *imail = &mail->imail;
 
509
        struct istream *hdr_stream = NULL;
496
510
        const char *value;
497
511
        int fd;
498
512
 
499
513
        if (imail->data.stream != NULL) {
500
 
                if (!body)
 
514
                i_assert(mail->header_fetched);
 
515
                if (mail->body_fetched || !have_body)
501
516
                        return;
502
 
                /* maybe the existing stream has no body. replace it. */
 
517
                if (have_header) {
 
518
                        /* replace the existing stream */
 
519
                } else if (mail->fd == -1) {
 
520
                        /* append this body stream to the existing
 
521
                           header stream */
 
522
                        hdr_stream = imail->data.stream;
 
523
                        i_stream_ref(hdr_stream);
 
524
                } else {
 
525
                        /* append this body stream to the existing
 
526
                           header stream. we'll need to recreate the stream
 
527
                           with autoclosed fd. */
 
528
                        if (lseek(mail->fd, 0, SEEK_SET) < 0)
 
529
                                i_error("lseek(imapc) failed: %m");
 
530
                        hdr_stream = i_stream_create_fd_autoclose(&mail->fd, 0);
 
531
                }
503
532
                index_mail_close_streams(imail);
504
533
                if (mail->fd != -1) {
505
534
                        if (close(mail->fd) < 0)
506
535
                                i_error("close(imapc mail) failed: %m");
507
536
                        mail->fd = -1;
508
537
                }
 
538
        } else {
 
539
                if (!have_header) {
 
540
                        /* BODY.PEEK[TEXT] received - we can't currently handle
 
541
                           this before receiving BODY.PEEK[HEADER] reply */
 
542
                        return;
 
543
                }
509
544
        }
510
545
 
511
546
        if (arg->type == IMAP_ARG_LITERAL_SIZE) {
512
 
                if (!imapc_find_lfile_arg(reply, arg, &fd))
 
547
                if (!imapc_find_lfile_arg(reply, arg, &fd)) {
 
548
                        if (hdr_stream != NULL)
 
549
                                i_stream_unref(&hdr_stream);
513
550
                        return;
 
551
                }
514
552
                if ((fd = dup(fd)) == -1) {
515
553
                        i_error("dup() failed: %m");
 
554
                        if (hdr_stream != NULL)
 
555
                                i_stream_unref(&hdr_stream);
516
556
                        return;
517
557
                }
518
558
                mail->fd = fd;
519
559
                imail->data.stream = i_stream_create_fd(fd, 0, FALSE);
520
560
        } else {
521
561
                if (!imap_arg_get_nstring(arg, &value))
522
 
                        return;
 
562
                        value = NULL;
523
563
                if (value == NULL) {
524
564
                        mail_set_expunged(&imail->mail.mail);
 
565
                        if (hdr_stream != NULL)
 
566
                                i_stream_unref(&hdr_stream);
525
567
                        return;
526
568
                }
527
569
                if (mail->body == NULL) {
528
570
                        mail->body = buffer_create_dynamic(default_pool,
529
571
                                                           arg->str_len + 1);
 
572
                } else if (!have_header && hdr_stream != NULL) {
 
573
                        /* header is already in the buffer - add body now
 
574
                           without destroying the existing header data */
 
575
                        i_stream_unref(&hdr_stream);
 
576
                } else {
 
577
                        buffer_set_used_size(mail->body, 0);
530
578
                }
531
 
                buffer_set_used_size(mail->body, 0);
532
579
                buffer_append(mail->body, value, arg->str_len);
533
580
                imail->data.stream = i_stream_create_from_data(mail->body->data,
534
581
                                                               mail->body->used);
535
582
        }
536
 
        mail->body_fetched = body;
537
 
 
538
 
        imapc_mail_init_stream(mail, body);
 
583
        if (have_header)
 
584
                mail->header_fetched = TRUE;
 
585
        mail->body_fetched = have_body;
 
586
 
 
587
        if (hdr_stream != NULL) {
 
588
                struct istream *inputs[3];
 
589
 
 
590
                inputs[0] = hdr_stream;
 
591
                inputs[1] = imail->data.stream;
 
592
                inputs[2] = NULL;
 
593
                imail->data.stream = i_stream_create_concat(inputs);
 
594
                i_stream_unref(&inputs[0]);
 
595
                i_stream_unref(&inputs[1]);
 
596
        }
 
597
 
 
598
        imapc_mail_init_stream(mail);
539
599
}
540
600
 
541
601
static void
623
683
                        break;
624
684
 
625
685
                if (strcasecmp(key, "BODY[]") == 0) {
626
 
                        imapc_fetch_stream(mail, reply, &args[i+1], TRUE);
 
686
                        imapc_fetch_stream(mail, reply, &args[i+1], TRUE, TRUE);
627
687
                        match = TRUE;
628
688
                } else if (strcasecmp(key, "BODY[HEADER]") == 0) {
629
 
                        imapc_fetch_stream(mail, reply, &args[i+1], FALSE);
 
689
                        imapc_fetch_stream(mail, reply, &args[i+1], TRUE, FALSE);
 
690
                        match = TRUE;
 
691
                } else if (strcasecmp(key, "BODY[TEXT]") == 0) {
 
692
                        imapc_fetch_stream(mail, reply, &args[i+1], FALSE, TRUE);
630
693
                        match = TRUE;
631
694
                } else if (strcasecmp(key, "BODY[HEADER.FIELDS") == 0) {
632
695
                        imapc_fetch_header_stream(mail, reply, &args[i+1]);