~james-page/ubuntu/raring/dovecot/autopkgtest

« back to all changes in this revision

Viewing changes to src/pop3/pop3-commands.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2012-06-11 11:11:54 UTC
  • mfrom: (1.15.2) (4.1.27 sid)
  • Revision ID: package-import@ubuntu.com-20120611111154-678cwbdj6ktgsv1h
Tags: 1:2.1.7-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/{control,rules}: enable PIE hardening.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + d/control: Added Pre-Depends: dpkg (>= 1.15.6) to dovecot-dbg to support
    xz compression in Ubuntu.
  + d/control: Demote dovecot-common Recommends: to Suggests: to prevent
    install of extra packages on upgrade.
  + d/patches/dovecot-drac.patch: Updated with version for dovecot >= 2.0.0.
  + d/control: Drop B-D on systemd.
* Dropped changes:
  + d/patches/fix-racey-restart.patch: part of 2.1.x, no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2002-2012 Dovecot authors, see the included COPYING file */
2
2
 
3
3
#include "pop3-common.h"
4
4
#include "array.h"
5
5
#include "istream.h"
6
6
#include "ostream.h"
 
7
#include "hash.h"
7
8
#include "str.h"
8
 
#include "crc32.h"
9
9
#include "var-expand.h"
10
10
#include "message-size.h"
11
11
#include "mail-storage.h"
238
238
 
239
239
        search_args = pop3_search_build(client, 0);
240
240
        ctx = mailbox_search_init(client->trans, search_args,
241
 
                                  pop3_sort_program);
 
241
                                  pop3_sort_program, 0, NULL);
242
242
        mail_search_args_unref(&search_args);
243
243
 
244
244
        msgnum = 0;
245
 
        mail = mail_alloc(client->trans, 0, NULL);
246
 
        while (mailbox_search_next(ctx, mail)) {
 
245
        while (mailbox_search_next(ctx, &mail)) {
247
246
                if (client_verify_ordering(client, mail, msgnum) < 0) {
248
247
                        ret = FALSE;
249
248
                        break;
260
259
                }
261
260
                msgnum++;
262
261
        }
263
 
        mail_free(&mail);
264
262
 
265
263
        client->seen_change_count = 0;
266
264
        if (mailbox_search_deinit(&ctx) < 0)
432
430
        ctx = i_new(struct fetch_context, 1);
433
431
        ctx->byte_counter = byte_counter;
434
432
        ctx->byte_counter_offset = client->output->offset;
435
 
 
436
 
        ctx->mail = mail_alloc(client->trans, MAIL_FETCH_STREAM_HEADER |
 
433
        ctx->mail = mail_alloc(client->trans,
 
434
                               MAIL_FETCH_STREAM_HEADER |
437
435
                               MAIL_FETCH_STREAM_BODY, NULL);
438
436
        mail_set_seq(ctx->mail, msgnum_to_seq(client, msgnum));
439
437
 
507
505
                /* remove all \Seen flags (as specified by RFC 1460) */
508
506
                search_args = pop3_search_build(client, 0);
509
507
                search_ctx = mailbox_search_init(client->trans,
510
 
                                                 search_args, NULL);
 
508
                                                 search_args, NULL, 0, NULL);
511
509
                mail_search_args_unref(&search_args);
512
510
 
513
 
                mail = mail_alloc(client->trans, 0, NULL);
514
 
                while (mailbox_search_next(search_ctx, mail))
 
511
                while (mailbox_search_next(search_ctx, &mail))
515
512
                        mail_update_flags(mail, MODIFY_REMOVE, MAIL_SEEN);
516
 
                mail_free(&mail);
517
513
                (void)mailbox_search_deinit(&search_ctx);
518
514
 
519
515
                mailbox_transaction_commit(&client->trans);
554
550
        bool list_all;
555
551
};
556
552
 
557
 
static bool pop3_get_uid(struct client *client, struct cmd_uidl_context *ctx,
558
 
                         struct var_expand_table *tab, string_t *str)
 
553
static void
 
554
pop3_get_uid(struct client *client, struct mail *mail, string_t *str,
 
555
             bool *permanent_uidl_r)
559
556
{
 
557
        static struct var_expand_table static_tab[] = {
 
558
                { 'v', NULL, "uidvalidity" },
 
559
                { 'u', NULL, "uid" },
 
560
                { 'm', NULL, "md5" },
 
561
                { 'f', NULL, "filename" },
 
562
                { 'g', NULL, "guid" },
 
563
                { '\0', NULL, NULL }
 
564
        };
 
565
        struct var_expand_table *tab;
560
566
        char uid_str[MAX_INT_STRLEN];
561
567
        const char *uidl;
562
568
 
563
 
        if (mail_get_special(ctx->mail, MAIL_FETCH_UIDL_BACKEND, &uidl) == 0 &&
 
569
        if (mail_get_special(mail, MAIL_FETCH_UIDL_BACKEND, &uidl) == 0 &&
564
570
            *uidl != '\0') {
565
571
                str_append(str, uidl);
566
 
                return TRUE;
 
572
                /* UIDL is already permanent */
 
573
                *permanent_uidl_r = TRUE;
 
574
                return;
567
575
        }
568
576
 
 
577
        *permanent_uidl_r = FALSE;
 
578
 
569
579
        if (client->set->pop3_reuse_xuidl &&
570
 
            mail_get_first_header(ctx->mail, "X-UIDL", &uidl) > 0) {
 
580
            mail_get_first_header(mail, "X-UIDL", &uidl) > 0) {
571
581
                str_append(str, uidl);
572
 
                return FALSE;
 
582
                return;
573
583
        }
574
584
 
 
585
        tab = t_malloc(sizeof(static_tab));
 
586
        memcpy(tab, static_tab, sizeof(static_tab));
 
587
        tab[0].value = t_strdup_printf("%u", client->uid_validity);
 
588
 
575
589
        if ((client->uidl_keymask & UIDL_UID) != 0) {
576
590
                i_snprintf(uid_str, sizeof(uid_str), "%u",
577
 
                           ctx->mail->uid);
 
591
                           mail->uid);
578
592
                tab[1].value = uid_str;
579
593
        }
580
594
        if ((client->uidl_keymask & UIDL_MD5) != 0) {
581
 
                if (mail_get_special(ctx->mail, MAIL_FETCH_HEADER_MD5,
 
595
                if (mail_get_special(mail, MAIL_FETCH_HEADER_MD5,
582
596
                                     &tab[2].value) < 0 ||
583
597
                    *tab[2].value == '\0') {
584
598
                        /* broken */
587
601
                }
588
602
        }
589
603
        if ((client->uidl_keymask & UIDL_FILE_NAME) != 0) {
590
 
                if (mail_get_special(ctx->mail,
591
 
                                     MAIL_FETCH_UIDL_FILE_NAME,
 
604
                if (mail_get_special(mail, MAIL_FETCH_UIDL_FILE_NAME,
592
605
                                     &tab[3].value) < 0 ||
593
606
                    *tab[3].value == '\0') {
594
607
                        /* broken */
597
610
                }
598
611
        }
599
612
        if ((client->uidl_keymask & UIDL_GUID) != 0) {
600
 
                if (mail_get_special(ctx->mail, MAIL_FETCH_GUID,
 
613
                if (mail_get_special(mail, MAIL_FETCH_GUID,
601
614
                                     &tab[4].value) < 0 ||
602
615
                    *tab[4].value == '\0') {
603
616
                        /* broken */
606
619
                }
607
620
        }
608
621
        var_expand(str, client->mail_set->pop3_uidl_format, tab);
609
 
        return FALSE;
 
622
}
 
623
 
 
624
static bool
 
625
list_uidls_saved_iter(struct client *client, struct cmd_uidl_context *ctx)
 
626
{
 
627
        bool found = FALSE;
 
628
        int ret;
 
629
 
 
630
        while (ctx->msgnum < client->messages_count) {
 
631
                uint32_t msgnum = ctx->msgnum++;
 
632
 
 
633
                if (client->deleted) {
 
634
                        if (client->deleted_bitmask[msgnum / CHAR_BIT] &
 
635
                            (1 << (msgnum % CHAR_BIT)))
 
636
                                continue;
 
637
                }
 
638
                found = TRUE;
 
639
 
 
640
                ret = client_send_line(client,
 
641
                                       ctx->list_all ? "%u %s" : "+OK %u %s",
 
642
                                       msgnum+1, client->message_uidls[msgnum]);
 
643
                if (ret < 0 || !ctx->list_all)
 
644
                        break;
 
645
                if (ret == 0) {
 
646
                        /* output is being buffered, continue when there's
 
647
                           more space */
 
648
                        return FALSE;
 
649
                }
 
650
        }
 
651
        /* finished */
 
652
        client->cmd = NULL;
 
653
 
 
654
        if (ctx->list_all)
 
655
                client_send_line(client, ".");
 
656
        i_free(ctx);
 
657
        return found;
610
658
}
611
659
 
612
660
static bool list_uids_iter(struct client *client, struct cmd_uidl_context *ctx)
613
661
{
614
 
        static struct var_expand_table static_tab[] = {
615
 
                { 'v', NULL, "uidvalidity" },
616
 
                { 'u', NULL, "uid" },
617
 
                { 'm', NULL, "md5" },
618
 
                { 'f', NULL, "filename" },
619
 
                { 'g', NULL, "guid" },
620
 
                { '\0', NULL, NULL }
621
 
        };
622
 
        struct var_expand_table *tab;
623
662
        string_t *str;
624
663
        int ret;
625
 
        unsigned int uidl_pos;
626
 
        bool save_hashes, found = FALSE;
627
 
 
628
 
        tab = t_malloc(sizeof(static_tab));
629
 
        memcpy(tab, static_tab, sizeof(static_tab));
630
 
        tab[0].value = t_strdup_printf("%u", client->uid_validity);
631
 
 
632
 
        save_hashes = client->message_uidl_hashes_save && ctx->list_all;
633
 
        if (save_hashes && client->message_uidl_hashes == NULL) {
634
 
                client->message_uidl_hashes =
635
 
                        i_new(uint32_t, client->messages_count);
636
 
        }
 
664
        bool permanent_uidl, found = FALSE;
 
665
 
 
666
        if (client->message_uidls != NULL)
 
667
                return list_uidls_saved_iter(client, ctx);
637
668
 
638
669
        str = t_str_new(128);
639
 
        while (mailbox_search_next(ctx->search_ctx, ctx->mail)) {
 
670
        while (mailbox_search_next(ctx->search_ctx, &ctx->mail)) {
640
671
                uint32_t msgnum = ctx->msgnum++;
641
672
 
642
673
                if (client_verify_ordering(client, ctx->mail, msgnum) < 0)
649
680
                found = TRUE;
650
681
 
651
682
                str_truncate(str, 0);
652
 
                str_printfa(str, ctx->list_all ? "%u " : "+OK %u ", msgnum+1);
653
 
                uidl_pos = str_len(str);
654
 
                if (!pop3_get_uid(client, ctx, tab, str) &&
655
 
                    client->set->pop3_save_uidl)
656
 
                        mail_update_pop3_uidl(ctx->mail, str_c(str) + uidl_pos);
657
 
 
658
 
                if (save_hashes) {
659
 
                        client->message_uidl_hashes[msgnum] =
660
 
                                crc32_str(str_c(str) + uidl_pos);
661
 
                }
662
 
 
663
 
                ret = client_send_line(client, "%s", str_c(str));
 
683
                pop3_get_uid(client, ctx->mail, str, &permanent_uidl);
 
684
                if (client->set->pop3_save_uidl && !permanent_uidl)
 
685
                        mail_update_pop3_uidl(ctx->mail, str_c(str));
 
686
 
 
687
                ret = client_send_line(client,
 
688
                                       ctx->list_all ? "%u %s" : "+OK %u %s",
 
689
                                       msgnum+1, str_c(str));
664
690
                if (ret < 0)
665
691
                        break;
666
692
                if (ret == 0 && ctx->list_all) {
671
697
        }
672
698
 
673
699
        /* finished */
674
 
        mail_free(&ctx->mail);
675
700
        (void)mailbox_search_deinit(&ctx->search_ctx);
676
701
 
677
702
        client->cmd = NULL;
678
703
 
679
 
        if (save_hashes)
680
 
                client->message_uidl_hashes_save = FALSE;
681
704
        if (ctx->list_all)
682
705
                client_send_line(client, ".");
683
706
        i_free(ctx);
691
714
        (void)list_uids_iter(client, ctx);
692
715
}
693
716
 
 
717
static void uidl_rename_duplicate(string_t *uidl, struct hash_table *prev_uidls)
 
718
{
 
719
        void *key, *value;
 
720
        unsigned int counter;
 
721
 
 
722
        while (hash_table_lookup_full(prev_uidls, str_c(uidl), &key, &value)) {
 
723
                /* duplicate. the value contains the number of duplicates. */
 
724
                counter = POINTER_CAST_TO(value, unsigned int) + 1;
 
725
                hash_table_update(prev_uidls, key, POINTER_CAST(counter));
 
726
                str_printfa(uidl, "-%u", counter);
 
727
                /* the second lookup really should return NULL, but just in
 
728
                   case of some weird UIDLs do this as many times as needed */
 
729
        }
 
730
}
 
731
 
 
732
static void client_uidls_save(struct client *client)
 
733
{
 
734
        struct mail_search_context *search_ctx;
 
735
        struct mail_search_args *search_args;
 
736
        struct mail *mail;
 
737
        struct hash_table *prev_uidls;
 
738
        string_t *str;
 
739
        char *uidl;
 
740
        enum mail_fetch_field wanted_fields;
 
741
        uint32_t msgnum;
 
742
        bool permanent_uidl, uidl_duplicates_rename;
 
743
 
 
744
        i_assert(client->message_uidls == NULL);
 
745
 
 
746
        search_args = pop3_search_build(client, 0);
 
747
        wanted_fields = 0;
 
748
        if ((client->uidl_keymask & UIDL_MD5) != 0)
 
749
                wanted_fields |= MAIL_FETCH_HEADER_MD5;
 
750
 
 
751
        search_ctx = mailbox_search_init(client->trans, search_args,
 
752
                                         pop3_sort_program,
 
753
                                         wanted_fields, NULL);
 
754
        mail_search_args_unref(&search_args);
 
755
 
 
756
        uidl_duplicates_rename =
 
757
                strcmp(client->set->pop3_uidl_duplicates, "rename") == 0;
 
758
        prev_uidls = hash_table_create(default_pool, default_pool, 0,
 
759
                                      str_hash, (hash_cmp_callback_t *)strcmp);
 
760
        client->uidl_pool = pool_alloconly_create("message uidls", 1024);
 
761
        client->message_uidls = p_new(client->uidl_pool, const char *,
 
762
                                      client->messages_count);
 
763
 
 
764
        str = t_str_new(128); msgnum = 0;
 
765
        while (mailbox_search_next(search_ctx, &mail)) {
 
766
                if (client_verify_ordering(client, mail, msgnum) < 0)
 
767
                        i_fatal("Can't finish POP3 UIDL command");
 
768
 
 
769
                str_truncate(str, 0);
 
770
                pop3_get_uid(client, mail, str, &permanent_uidl);
 
771
                if (client->set->pop3_save_uidl && !permanent_uidl)
 
772
                        mail_update_pop3_uidl(mail, str_c(str));
 
773
 
 
774
                if (uidl_duplicates_rename)
 
775
                        uidl_rename_duplicate(str, prev_uidls);
 
776
                uidl = p_strdup(client->uidl_pool, str_c(str));
 
777
                client->message_uidls[msgnum] = uidl;
 
778
                hash_table_insert(prev_uidls, uidl, POINTER_CAST(1));
 
779
                msgnum++;
 
780
        }
 
781
        (void)mailbox_search_deinit(&search_ctx);
 
782
        hash_table_destroy(&prev_uidls);
 
783
}
 
784
 
694
785
static struct cmd_uidl_context *
695
786
cmd_uidl_init(struct client *client, uint32_t seq)
696
787
{
698
789
        struct mail_search_args *search_args;
699
790
        enum mail_fetch_field wanted_fields;
700
791
 
701
 
        search_args = pop3_search_build(client, seq);
 
792
        if (client->message_uidls_save && client->message_uidls == NULL)
 
793
                client_uidls_save(client);
702
794
 
703
795
        ctx = i_new(struct cmd_uidl_context, 1);
704
796
        ctx->list_all = seq == 0;
705
797
 
706
 
        wanted_fields = 0;
707
 
        if ((client->uidl_keymask & UIDL_MD5) != 0)
708
 
                wanted_fields |= MAIL_FETCH_HEADER_MD5;
709
 
 
710
 
        ctx->search_ctx = mailbox_search_init(client->trans, search_args,
711
 
                                              pop3_sort_program);
712
 
        mail_search_args_unref(&search_args);
713
 
 
714
 
        ctx->mail = mail_alloc(client->trans, wanted_fields, NULL);
 
798
        if (client->message_uidls == NULL) {
 
799
                wanted_fields = 0;
 
800
                if ((client->uidl_keymask & UIDL_MD5) != 0)
 
801
                        wanted_fields |= MAIL_FETCH_HEADER_MD5;
 
802
 
 
803
                search_args = pop3_search_build(client, seq);
 
804
                ctx->search_ctx = mailbox_search_init(client->trans, search_args,
 
805
                                                      pop3_sort_program,
 
806
                                                      wanted_fields, NULL);
 
807
                mail_search_args_unref(&search_args);
 
808
        }
 
809
 
715
810
        if (seq == 0) {
716
811
                client->cmd = cmd_uidl_callback;
717
812
                client->cmd_context = ctx;