239
239
search_args = pop3_search_build(client, 0);
240
240
ctx = mailbox_search_init(client->trans, search_args,
241
pop3_sort_program, 0, NULL);
242
242
mail_search_args_unref(&search_args);
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) {
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;
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));
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,
508
search_args, NULL, 0, NULL);
511
509
mail_search_args_unref(&search_args);
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);
517
513
(void)mailbox_search_deinit(&search_ctx);
519
515
mailbox_transaction_commit(&client->trans);
557
static bool pop3_get_uid(struct client *client, struct cmd_uidl_context *ctx,
558
struct var_expand_table *tab, string_t *str)
554
pop3_get_uid(struct client *client, struct mail *mail, string_t *str,
555
bool *permanent_uidl_r)
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" },
565
struct var_expand_table *tab;
560
566
char uid_str[MAX_INT_STRLEN];
561
567
const char *uidl;
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 &&
565
571
str_append(str, uidl);
572
/* UIDL is already permanent */
573
*permanent_uidl_r = TRUE;
577
*permanent_uidl_r = FALSE;
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);
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);
575
589
if ((client->uidl_keymask & UIDL_UID) != 0) {
576
590
i_snprintf(uid_str, sizeof(uid_str), "%u",
578
592
tab[1].value = uid_str;
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') {
608
621
var_expand(str, client->mail_set->pop3_uidl_format, tab);
625
list_uidls_saved_iter(struct client *client, struct cmd_uidl_context *ctx)
630
while (ctx->msgnum < client->messages_count) {
631
uint32_t msgnum = ctx->msgnum++;
633
if (client->deleted) {
634
if (client->deleted_bitmask[msgnum / CHAR_BIT] &
635
(1 << (msgnum % CHAR_BIT)))
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)
646
/* output is being buffered, continue when there's
655
client_send_line(client, ".");
612
660
static bool list_uids_iter(struct client *client, struct cmd_uidl_context *ctx)
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" },
622
struct var_expand_table *tab;
625
unsigned int uidl_pos;
626
bool save_hashes, found = FALSE;
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);
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);
664
bool permanent_uidl, found = FALSE;
666
if (client->message_uidls != NULL)
667
return list_uidls_saved_iter(client, ctx);
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++;
642
673
if (client_verify_ordering(client, ctx->mail, msgnum) < 0)
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);
659
client->message_uidl_hashes[msgnum] =
660
crc32_str(str_c(str) + uidl_pos);
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));
687
ret = client_send_line(client,
688
ctx->list_all ? "%u %s" : "+OK %u %s",
689
msgnum+1, str_c(str));
666
692
if (ret == 0 && ctx->list_all) {
691
714
(void)list_uids_iter(client, ctx);
717
static void uidl_rename_duplicate(string_t *uidl, struct hash_table *prev_uidls)
720
unsigned int counter;
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 */
732
static void client_uidls_save(struct client *client)
734
struct mail_search_context *search_ctx;
735
struct mail_search_args *search_args;
737
struct hash_table *prev_uidls;
740
enum mail_fetch_field wanted_fields;
742
bool permanent_uidl, uidl_duplicates_rename;
744
i_assert(client->message_uidls == NULL);
746
search_args = pop3_search_build(client, 0);
748
if ((client->uidl_keymask & UIDL_MD5) != 0)
749
wanted_fields |= MAIL_FETCH_HEADER_MD5;
751
search_ctx = mailbox_search_init(client->trans, search_args,
753
wanted_fields, NULL);
754
mail_search_args_unref(&search_args);
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);
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");
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));
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));
781
(void)mailbox_search_deinit(&search_ctx);
782
hash_table_destroy(&prev_uidls);
694
785
static struct cmd_uidl_context *
695
786
cmd_uidl_init(struct client *client, uint32_t seq)
698
789
struct mail_search_args *search_args;
699
790
enum mail_fetch_field wanted_fields;
701
search_args = pop3_search_build(client, seq);
792
if (client->message_uidls_save && client->message_uidls == NULL)
793
client_uidls_save(client);
703
795
ctx = i_new(struct cmd_uidl_context, 1);
704
796
ctx->list_all = seq == 0;
707
if ((client->uidl_keymask & UIDL_MD5) != 0)
708
wanted_fields |= MAIL_FETCH_HEADER_MD5;
710
ctx->search_ctx = mailbox_search_init(client->trans, search_args,
712
mail_search_args_unref(&search_args);
714
ctx->mail = mail_alloc(client->trans, wanted_fields, NULL);
798
if (client->message_uidls == NULL) {
800
if ((client->uidl_keymask & UIDL_MD5) != 0)
801
wanted_fields |= MAIL_FETCH_HEADER_MD5;
803
search_args = pop3_search_build(client, seq);
804
ctx->search_ctx = mailbox_search_init(client->trans, search_args,
806
wanted_fields, NULL);
807
mail_search_args_unref(&search_args);
716
811
client->cmd = cmd_uidl_callback;
717
812
client->cmd_context = ctx;