comparison src/lib-storage/index/index-sort.c @ 21599:a90f51ba2e9c

lib-storage: Fix error handling when sorting mails. All errors were treated the same as if message had been expunged. This caused potentially wrong results to be sent to the client without any indication that they're wrong.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Fri, 17 Feb 2017 18:19:46 +0200
parents 2e2563132d5f
children fb8ef6e2c2fe
comparison
equal deleted inserted replaced
21598:e76e742bfbab 21599:a90f51ba2e9c
29 }; 29 };
30 ARRAY_DEFINE_TYPE(mail_sort_node_float, struct mail_sort_node_float); 30 ARRAY_DEFINE_TYPE(mail_sort_node_float, struct mail_sort_node_float);
31 31
32 struct sort_cmp_context { 32 struct sort_cmp_context {
33 struct mail_search_sort_program *program; 33 struct mail_search_sort_program *program;
34 struct mail *mail;
35 bool reverse; 34 bool reverse;
36 }; 35 };
37 36
38 static struct sort_cmp_context static_node_cmp_context; 37 static struct sort_cmp_context static_node_cmp_context;
39 38
40 static void 39 static void
40 index_sort_program_set_mail_failed(struct mail_search_sort_program *program,
41 struct mail *mail)
42 {
43 if (mailbox_get_last_mail_error(mail->box) != MAIL_ERROR_EXPUNGED)
44 program->failed = TRUE;
45 }
46
47 static void
41 index_sort_list_add_arrival(struct mail_search_sort_program *program, 48 index_sort_list_add_arrival(struct mail_search_sort_program *program,
42 struct mail *mail) 49 struct mail *mail)
43 { 50 {
44 ARRAY_TYPE(mail_sort_node_date) *nodes = program->context; 51 ARRAY_TYPE(mail_sort_node_date) *nodes = program->context;
45 struct mail_sort_node_date *node; 52 struct mail_sort_node_date *node;
46 53
47 node = array_append_space(nodes); 54 node = array_append_space(nodes);
48 node->seq = mail->seq; 55 node->seq = mail->seq;
49 if (mail_get_received_date(mail, &node->date) < 0) 56 if (mail_get_received_date(mail, &node->date) < 0) {
57 index_sort_program_set_mail_failed(program, mail);
50 node->date = 0; 58 node->date = 0;
59 }
51 } 60 }
52 61
53 static void 62 static void
54 index_sort_list_add_date(struct mail_search_sort_program *program, 63 index_sort_list_add_date(struct mail_search_sort_program *program,
55 struct mail *mail) 64 struct mail *mail)
58 struct mail_sort_node_date *node; 67 struct mail_sort_node_date *node;
59 int tz; 68 int tz;
60 69
61 node = array_append_space(nodes); 70 node = array_append_space(nodes);
62 node->seq = mail->seq; 71 node->seq = mail->seq;
63 if (mail_get_date(mail, &node->date, &tz) < 0) 72 if (mail_get_date(mail, &node->date, &tz) < 0) {
73 index_sort_program_set_mail_failed(program, mail);
64 node->date = 0; 74 node->date = 0;
65 else if (node->date == 0) { 75 } else if (node->date == 0) {
66 if (mail_get_received_date(mail, &node->date) < 0) 76 if (mail_get_received_date(mail, &node->date) < 0) {
77 index_sort_program_set_mail_failed(program, mail);
67 node->date = 0; 78 node->date = 0;
79 }
68 } 80 }
69 } 81 }
70 82
71 static void 83 static void
72 index_sort_list_add_size(struct mail_search_sort_program *program, 84 index_sort_list_add_size(struct mail_search_sort_program *program,
75 ARRAY_TYPE(mail_sort_node_size) *nodes = program->context; 87 ARRAY_TYPE(mail_sort_node_size) *nodes = program->context;
76 struct mail_sort_node_size *node; 88 struct mail_sort_node_size *node;
77 89
78 node = array_append_space(nodes); 90 node = array_append_space(nodes);
79 node->seq = mail->seq; 91 node->seq = mail->seq;
80 if (mail_get_virtual_size(mail, &node->size) < 0) 92 if (mail_get_virtual_size(mail, &node->size) < 0) {
93 index_sort_program_set_mail_failed(program, mail);
81 node->size = 0; 94 node->size = 0;
82 } 95 }
83 96 }
84 static uoff_t index_sort_get_pop3_order(struct mail *mail) 97
98 static int index_sort_get_pop3_order(struct mail *mail, uoff_t *size_r)
85 { 99 {
86 const char *str; 100 const char *str;
87 uoff_t size; 101
88 102 if (mail_get_special(mail, MAIL_FETCH_POP3_ORDER, &str) < 0) {
89 if (mail_get_special(mail, MAIL_FETCH_POP3_ORDER, &str) < 0 || 103 *size_r = (uint32_t)-1;
90 str_to_uoff(str, &size) < 0) 104 return -1;
91 return (uint32_t)-1; 105 }
92 else 106
93 return size; 107 if (str_to_uoff(str, size_r) < 0)
108 *size_r = (uint32_t)-1;
109 return 0;
94 } 110 }
95 111
96 static void 112 static void
97 index_sort_list_add_pop3_order(struct mail_search_sort_program *program, 113 index_sort_list_add_pop3_order(struct mail_search_sort_program *program,
98 struct mail *mail) 114 struct mail *mail)
100 ARRAY_TYPE(mail_sort_node_size) *nodes = program->context; 116 ARRAY_TYPE(mail_sort_node_size) *nodes = program->context;
101 struct mail_sort_node_size *node; 117 struct mail_sort_node_size *node;
102 118
103 node = array_append_space(nodes); 119 node = array_append_space(nodes);
104 node->seq = mail->seq; 120 node->seq = mail->seq;
105 node->size = index_sort_get_pop3_order(mail); 121 (void)index_sort_get_pop3_order(mail, &node->size);
106 } 122 }
107 123
108 static float index_sort_get_relevancy(struct mail *mail) 124 static int index_sort_get_relevancy(struct mail *mail, float *result_r)
109 { 125 {
110 const char *str; 126 const char *str;
111 127
112 if (mail_get_special(mail, MAIL_FETCH_SEARCH_RELEVANCY, &str) < 0) 128 if (mail_get_special(mail, MAIL_FETCH_SEARCH_RELEVANCY, &str) < 0) {
113 return 0; 129 *result_r = 0;
114 else 130 return -1;
115 return strtod(str, NULL); 131 }
132 *result_r = strtod(str, NULL);
133 return 0;
116 } 134 }
117 135
118 static void 136 static void
119 index_sort_list_add_relevancy(struct mail_search_sort_program *program, 137 index_sort_list_add_relevancy(struct mail_search_sort_program *program,
120 struct mail *mail) 138 struct mail *mail)
122 ARRAY_TYPE(mail_sort_node_float) *nodes = program->context; 140 ARRAY_TYPE(mail_sort_node_float) *nodes = program->context;
123 struct mail_sort_node_float *node; 141 struct mail_sort_node_float *node;
124 142
125 node = array_append_space(nodes); 143 node = array_append_space(nodes);
126 node->seq = mail->seq; 144 node->seq = mail->seq;
127 node->num = index_sort_get_relevancy(mail); 145 (void)index_sort_get_relevancy(mail, &node->num);
128 } 146 }
129 147
130 void index_sort_list_add(struct mail_search_sort_program *program, 148 void index_sort_list_add(struct mail_search_sort_program *program,
131 struct mail *mail) 149 struct mail *mail)
132 { 150 {
145 if (n1->date < n2->date) 163 if (n1->date < n2->date)
146 return !ctx->reverse ? -1 : 1; 164 return !ctx->reverse ? -1 : 1;
147 if (n1->date > n2->date) 165 if (n1->date > n2->date)
148 return !ctx->reverse ? 1 : -1; 166 return !ctx->reverse ? 1 : -1;
149 167
150 return index_sort_node_cmp_type(ctx->mail, 168 return index_sort_node_cmp_type(ctx->program,
151 ctx->program->sort_program + 1, 169 ctx->program->sort_program + 1,
152 n1->seq, n2->seq); 170 n1->seq, n2->seq);
153 } 171 }
154 172
155 static void 173 static void
171 if (n1->size < n2->size) 189 if (n1->size < n2->size)
172 return !ctx->reverse ? -1 : 1; 190 return !ctx->reverse ? -1 : 1;
173 if (n1->size > n2->size) 191 if (n1->size > n2->size)
174 return !ctx->reverse ? 1 : -1; 192 return !ctx->reverse ? 1 : -1;
175 193
176 return index_sort_node_cmp_type(ctx->mail, 194 return index_sort_node_cmp_type(ctx->program,
177 ctx->program->sort_program + 1, 195 ctx->program->sort_program + 1,
178 n1->seq, n2->seq); 196 n1->seq, n2->seq);
179 } 197 }
180 198
181 static void 199 static void
197 if (n1->num < n2->num) 215 if (n1->num < n2->num)
198 return !ctx->reverse ? -1 : 1; 216 return !ctx->reverse ? -1 : 1;
199 if (n1->num > n2->num) 217 if (n1->num > n2->num)
200 return !ctx->reverse ? 1 : -1; 218 return !ctx->reverse ? 1 : -1;
201 219
202 return index_sort_node_cmp_type(ctx->mail, 220 return index_sort_node_cmp_type(ctx->program,
203 ctx->program->sort_program + 1, 221 ctx->program->sort_program + 1,
204 n1->seq, n2->seq); 222 n1->seq, n2->seq);
205 } 223 }
206 224
207 static void 225 static void
222 240
223 void index_sort_list_finish(struct mail_search_sort_program *program) 241 void index_sort_list_finish(struct mail_search_sort_program *program)
224 { 242 {
225 i_zero(&static_node_cmp_context); 243 i_zero(&static_node_cmp_context);
226 static_node_cmp_context.program = program; 244 static_node_cmp_context.program = program;
227 static_node_cmp_context.mail = program->temp_mail;
228 static_node_cmp_context.reverse = 245 static_node_cmp_context.reverse =
229 (program->sort_program[0] & MAIL_SORT_FLAG_REVERSE) != 0; 246 (program->sort_program[0] & MAIL_SORT_FLAG_REVERSE) != 0;
230 247
231 program->sort_list_finish(program); 248 program->sort_list_finish(program);
232 } 249 }
328 i_unreached(); 345 i_unreached();
329 } 346 }
330 return program; 347 return program;
331 } 348 }
332 349
333 void index_sort_program_deinit(struct mail_search_sort_program **_program) 350 int index_sort_program_deinit(struct mail_search_sort_program **_program)
334 { 351 {
335 struct mail_search_sort_program *program = *_program; 352 struct mail_search_sort_program *program = *_program;
336 353
337 *_program = NULL; 354 *_program = NULL;
338 355
339 if (program->context != NULL) 356 if (program->context != NULL)
340 index_sort_list_finish(program); 357 index_sort_list_finish(program);
341 mail_free(&program->temp_mail); 358 mail_free(&program->temp_mail);
342 array_free(&program->seqs); 359 array_free(&program->seqs);
360
361 int ret = program->failed ? -1 : 0;
343 i_free(program); 362 i_free(program);
363 return ret;
344 } 364 }
345 365
346 static int 366 static int
347 get_first_addr(struct mail *mail, const char *header, 367 get_first_addr(struct mail *mail, const char *header,
348 struct message_address **addr_r) 368 struct message_address **addr_r)
415 mail_set_seq(mail, seq); 435 mail_set_seq(mail, seq);
416 str_truncate(dest, 0); 436 str_truncate(dest, 0);
417 437
418 switch (sort_type & MAIL_SORT_MASK) { 438 switch (sort_type & MAIL_SORT_MASK) {
419 case MAIL_SORT_SUBJECT: 439 case MAIL_SORT_SUBJECT:
420 if ((ret = mail_get_first_header(mail, "Subject", &str)) <= 0) 440 ret = mail_get_first_header(mail, "Subject", &str);
421 return ret; 441 if (ret < 0)
442 break;
443 if (ret == 0) {
444 /* nonexistent header */
445 return 1;
446 }
422 str = imap_get_base_subject_cased(pool_datastack_create(), 447 str = imap_get_base_subject_cased(pool_datastack_create(),
423 str, &reply_or_fw); 448 str, &reply_or_fw);
424 str_append(dest, str); 449 str_append(dest, str);
425 return 0; 450 return 1;
426 case MAIL_SORT_CC: 451 case MAIL_SORT_CC:
427 ret = get_first_mailbox(mail, "Cc", &str); 452 ret = get_first_mailbox(mail, "Cc", &str);
428 break; 453 break;
429 case MAIL_SORT_FROM: 454 case MAIL_SORT_FROM:
430 ret = get_first_mailbox(mail, "From", &str); 455 ret = get_first_mailbox(mail, "From", &str);
439 ret = get_display_name(mail, "To", &str); 464 ret = get_display_name(mail, "To", &str);
440 break; 465 break;
441 default: 466 default:
442 i_unreached(); 467 i_unreached();
443 } 468 }
469 if (ret < 0) {
470 if (mailbox_get_last_mail_error(mail->box) == MAIL_ERROR_EXPUNGED)
471 return 0;
472 return -1;
473 }
444 474
445 (void)uni_utf8_to_decomposed_titlecase(str, strlen(str), dest); 475 (void)uni_utf8_to_decomposed_titlecase(str, strlen(str), dest);
446 return ret; 476 return 1;
447 } 477 }
448 478
449 int index_sort_node_cmp_type(struct mail *mail, 479 int index_sort_node_cmp_type(struct mail_search_sort_program *program,
450 const enum mail_sort_type *sort_program, 480 const enum mail_sort_type *sort_program,
451 uint32_t seq1, uint32_t seq2) 481 uint32_t seq1, uint32_t seq2)
452 { 482 {
483 struct mail *mail = program->temp_mail;
453 enum mail_sort_type sort_type; 484 enum mail_sort_type sort_type;
454 time_t time1, time2; 485 time_t time1, time2;
455 uoff_t size1, size2; 486 uoff_t size1, size2;
456 float float1, float2; 487 float float1, float2;
457 int tz, ret = 0; 488 int tz, ret = 0;
467 T_BEGIN { 498 T_BEGIN {
468 string_t *str1, *str2; 499 string_t *str1, *str2;
469 500
470 str1 = t_str_new(256); 501 str1 = t_str_new(256);
471 str2 = t_str_new(256); 502 str2 = t_str_new(256);
472 (void)index_sort_header_get(mail, seq1, sort_type, str1); 503 if (index_sort_header_get(mail, seq1, sort_type, str1) < 0)
473 (void)index_sort_header_get(mail, seq2, sort_type, str2); 504 index_sort_program_set_mail_failed(program, mail);
505 if (index_sort_header_get(mail, seq2, sort_type, str2) < 0)
506 index_sort_program_set_mail_failed(program, mail);
474 507
475 ret = strcmp(str_c(str1), str_c(str2)); 508 ret = strcmp(str_c(str1), str_c(str2));
476 } T_END; 509 } T_END;
477 break; 510 break;
478 case MAIL_SORT_ARRIVAL: 511 case MAIL_SORT_ARRIVAL:
479 mail_set_seq(mail, seq1); 512 mail_set_seq(mail, seq1);
480 if (mail_get_received_date(mail, &time1) < 0) 513 if (mail_get_received_date(mail, &time1) < 0) {
514 index_sort_program_set_mail_failed(program, mail);
481 time1 = 0; 515 time1 = 0;
516 }
482 517
483 mail_set_seq(mail, seq2); 518 mail_set_seq(mail, seq2);
484 if (mail_get_received_date(mail, &time2) < 0) 519 if (mail_get_received_date(mail, &time2) < 0) {
485 time1 = 0; 520 index_sort_program_set_mail_failed(program, mail);
521 time2 = 0;
522 }
486 523
487 ret = time1 < time2 ? -1 : 524 ret = time1 < time2 ? -1 :
488 (time1 > time2 ? 1 : 0); 525 (time1 > time2 ? 1 : 0);
489 break; 526 break;
490 case MAIL_SORT_DATE: 527 case MAIL_SORT_DATE:
491 mail_set_seq(mail, seq1); 528 mail_set_seq(mail, seq1);
492 if (mail_get_date(mail, &time1, &tz) < 0) 529 if (mail_get_date(mail, &time1, &tz) < 0) {
530 index_sort_program_set_mail_failed(program, mail);
493 time1 = 0; 531 time1 = 0;
494 else if (time1 == 0) { 532 } else if (time1 == 0) {
495 if (mail_get_received_date(mail, &time1) < 0) 533 if (mail_get_received_date(mail, &time1) < 0) {
534 index_sort_program_set_mail_failed(program, mail);
496 time1 = 0; 535 time1 = 0;
536 }
497 } 537 }
498 538
499 mail_set_seq(mail, seq2); 539 mail_set_seq(mail, seq2);
500 if (mail_get_date(mail, &time2, &tz) < 0) 540 if (mail_get_date(mail, &time2, &tz) < 0) {
541 index_sort_program_set_mail_failed(program, mail);
501 time2 = 0; 542 time2 = 0;
502 else if (time2 == 0) { 543 } else if (time2 == 0) {
503 if (mail_get_received_date(mail, &time2) < 0) 544 if (mail_get_received_date(mail, &time2) < 0) {
545 index_sort_program_set_mail_failed(program, mail);
504 time2 = 0; 546 time2 = 0;
547 }
505 } 548 }
506 549
507 ret = time1 < time2 ? -1 : 550 ret = time1 < time2 ? -1 :
508 (time1 > time2 ? 1 : 0); 551 (time1 > time2 ? 1 : 0);
509 break; 552 break;
510 case MAIL_SORT_SIZE: 553 case MAIL_SORT_SIZE:
511 mail_set_seq(mail, seq1); 554 mail_set_seq(mail, seq1);
512 if (mail_get_virtual_size(mail, &size1) < 0) 555 if (mail_get_virtual_size(mail, &size1) < 0) {
556 index_sort_program_set_mail_failed(program, mail);
513 size1 = 0; 557 size1 = 0;
558 }
514 559
515 mail_set_seq(mail, seq2); 560 mail_set_seq(mail, seq2);
516 if (mail_get_virtual_size(mail, &size2) < 0) 561 if (mail_get_virtual_size(mail, &size2) < 0) {
562 index_sort_program_set_mail_failed(program, mail);
517 size2 = 0; 563 size2 = 0;
564 }
518 565
519 ret = size1 < size2 ? -1 : 566 ret = size1 < size2 ? -1 :
520 (size1 > size2 ? 1 : 0); 567 (size1 > size2 ? 1 : 0);
521 break; 568 break;
522 case MAIL_SORT_RELEVANCY: 569 case MAIL_SORT_RELEVANCY:
523 mail_set_seq(mail, seq1); 570 mail_set_seq(mail, seq1);
524 float1 = index_sort_get_relevancy(mail); 571 if (index_sort_get_relevancy(mail, &float1) < 0)
572 index_sort_program_set_mail_failed(program, mail);
525 mail_set_seq(mail, seq2); 573 mail_set_seq(mail, seq2);
526 float2 = index_sort_get_relevancy(mail); 574 if (index_sort_get_relevancy(mail, &float2) < 0)
575 index_sort_program_set_mail_failed(program, mail);
527 576
528 /* NOTE: higher relevancy is returned first, unlike with all 577 /* NOTE: higher relevancy is returned first, unlike with all
529 other number based sort keys */ 578 other number based sort keys */
530 ret = float1 < float2 ? 1 : 579 ret = float1 < float2 ? 1 :
531 (float1 > float2 ? -1 : 0); 580 (float1 > float2 ? -1 : 0);
532 break; 581 break;
533 case MAIL_SORT_POP3_ORDER: 582 case MAIL_SORT_POP3_ORDER:
534 /* 32bit numbers would be enough, but since there is already 583 /* 32bit numbers would be enough, but since there is already
535 existing code for uoff_t in sizes, just use them. */ 584 existing code for uoff_t in sizes, just use them. */
536 mail_set_seq(mail, seq1); 585 mail_set_seq(mail, seq1);
537 size1 = index_sort_get_pop3_order(mail); 586 if (index_sort_get_pop3_order(mail, &size1) < 0)
587 index_sort_program_set_mail_failed(program, mail);
538 mail_set_seq(mail, seq2); 588 mail_set_seq(mail, seq2);
539 size2 = index_sort_get_pop3_order(mail); 589 if (index_sort_get_pop3_order(mail, &size2) < 0)
590 index_sort_program_set_mail_failed(program, mail);
540 591
541 ret = size1 < size2 ? -1 : 592 ret = size1 < size2 ? -1 :
542 (size1 > size2 ? 1 : 0); 593 (size1 > size2 ? 1 : 0);
543 break; 594 break;
544 case MAIL_SORT_END: 595 case MAIL_SORT_END:
548 case MAIL_SORT_FLAG_REVERSE: 599 case MAIL_SORT_FLAG_REVERSE:
549 i_unreached(); 600 i_unreached();
550 } 601 }
551 602
552 if (ret == 0) { 603 if (ret == 0) {
553 return index_sort_node_cmp_type(mail, sort_program+1, 604 return index_sort_node_cmp_type(program, sort_program+1,
554 seq1, seq2); 605 seq1, seq2);
555 } 606 }
556 607
557 if ((*sort_program & MAIL_SORT_FLAG_REVERSE) != 0) 608 if ((*sort_program & MAIL_SORT_FLAG_REVERSE) != 0)
558 ret = ret < 0 ? 1 : -1; 609 ret = ret < 0 ? 1 : -1;