imap-thread.c (75154B)
1 /* 2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client 3 * Copyright (C) 2005-2022 the Claws Mail team and DINH Viet Hoa 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include <glib.h> 20 #include <glib/gi18n.h> 21 #include "imap-thread.h" 22 #include <imap.h> 23 #include <sys/types.h> 24 #include <sys/stat.h> 25 #include <fcntl.h> 26 #include <sys/socket.h> 27 #include <sys/mman.h> 28 #include <sys/wait.h> 29 #include <gtk/gtk.h> 30 #include <log.h> 31 #include "etpan-thread-manager.h" 32 #include "etpan-ssl.h" 33 #include "utils.h" 34 #include "mainwindow.h" 35 #include "file-utils.h" 36 #include "ssl.h" 37 #include "ssl_certificate.h" 38 #include "socket.h" 39 #include "remotefolder.h" 40 #include "tags.h" 41 42 #define DISABLE_LOG_DURING_LOGIN 43 44 static struct etpan_thread_manager * thread_manager = NULL; 45 static chash * courier_workaround_hash = NULL; 46 static chash * imap_hash = NULL; 47 static chash * session_hash = NULL; 48 static guint thread_manager_signal = 0; 49 static GIOChannel * io_channel = NULL; 50 51 static gboolean thread_manager_event(GIOChannel * source, 52 GIOCondition condition, 53 gpointer data) 54 { 55 etpan_thread_manager_loop(thread_manager); 56 return TRUE; 57 } 58 59 static void imap_logger_noop(int direction, const char * str, size_t size) 60 { 61 /* inhibit logging */ 62 } 63 64 static void imap_logger_cmd(int direction, const char * str, size_t size) 65 { 66 gchar *buf; 67 gchar **lines; 68 int i = 0; 69 70 if (size > 8192) { 71 log_print(LOG_PROTOCOL, "IMAP%c [CMD data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size); 72 return; 73 } 74 buf = malloc(size+1); 75 memset(buf, 0, size+1); 76 strncpy(buf, str, size); 77 buf[size] = '\0'; 78 79 if (!strncmp(buf, "<<<<<<<", 7) 80 || !strncmp(buf, ">>>>>>>", 7)) { 81 free(buf); 82 return; 83 } 84 while (strstr(buf, "\r")) 85 *strstr(buf, "\r") = ' '; 86 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n') 87 buf[strlen(buf)-1] = '\0'; 88 89 lines = g_strsplit(buf, "\n", -1); 90 91 while (lines[i] && *lines[i]) { 92 log_print(LOG_PROTOCOL, "IMAP%c %s\n", direction?'>':'<', lines[i]); 93 i++; 94 } 95 g_strfreev(lines); 96 free(buf); 97 } 98 99 static void imap_logger_fetch(int direction, const char * str, size_t size) 100 { 101 gchar *buf; 102 gchar **lines; 103 int i = 0; 104 105 if (size > 128 && !direction) { 106 log_print(LOG_PROTOCOL, "IMAP%c [FETCH data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size); 107 return; 108 } 109 110 buf = malloc(size+1); 111 memset(buf, 0, size+1); 112 strncpy(buf, str, size); 113 buf[size] = '\0'; 114 if (!strncmp(buf, "<<<<<<<", 7) 115 || !strncmp(buf, ">>>>>>>", 7)) { 116 free(buf); 117 return; 118 } 119 while (strstr(buf, "\r")) 120 *strstr(buf, "\r") = ' '; 121 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n') 122 buf[strlen(buf)-1] = '\0'; 123 124 lines = g_strsplit(buf, "\n", -1); 125 126 if (direction != 0 || (buf[0] == '*' && buf[1] == ' ') || size < 32) { 127 while (lines[i] && *lines[i]) { 128 log_print(LOG_PROTOCOL, "IMAP%c %s\n", direction?'>':'<', lines[i]); 129 i++; 130 } 131 } else { 132 log_print(LOG_PROTOCOL, "IMAP%c [data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size); 133 } 134 g_strfreev(lines); 135 free(buf); 136 } 137 138 static void imap_logger_uid(int direction, const char * str, size_t size) 139 { 140 gchar *buf; 141 gchar **lines; 142 int i = 0; 143 144 if (size > 8192) { 145 log_print(LOG_PROTOCOL, "IMAP%c [UID data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size); 146 return; 147 } 148 buf = malloc(size+1); 149 memset(buf, 0, size+1); 150 strncpy(buf, str, size); 151 buf[size] = '\0'; 152 if (!strncmp(buf, "<<<<<<<", 7) 153 || !strncmp(buf, ">>>>>>>", 7)) { 154 free(buf); 155 return; 156 } 157 while (strstr(buf, "\r")) 158 *strstr(buf, "\r") = ' '; 159 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n') 160 buf[strlen(buf)-1] = '\0'; 161 162 lines = g_strsplit(buf, "\n", -1); 163 164 while (lines[i] && *lines[i]) { 165 int llen = strlen(lines[i]); 166 if (llen < 64) 167 log_print(LOG_PROTOCOL, "IMAP%c %s\n", direction?'>':'<', lines[i]); 168 else { 169 gchar tmp[64]; 170 strncpy2(tmp, lines[i], 63); 171 log_print(LOG_PROTOCOL, "IMAP%c %s[... - %d bytes more]\n", direction?'>':'<', tmp, 172 llen-64); 173 } 174 i++; 175 } 176 g_strfreev(lines); 177 free(buf); 178 } 179 180 static void imap_logger_append(int direction, const char * str, size_t size) 181 { 182 gchar *buf; 183 gchar **lines; 184 int i = 0; 185 186 if (size > 8192) { 187 log_print(LOG_PROTOCOL, "IMAP%c [APPEND data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size); 188 return; 189 } else if (direction == 0 && size > 64) { 190 log_print(LOG_PROTOCOL, "IMAP%c [APPEND data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size); 191 return; 192 } 193 buf = malloc(size+1); 194 memset(buf, 0, size+1); 195 strncpy(buf, str, size); 196 buf[size] = '\0'; 197 if (!strncmp(buf, "<<<<<<<", 7) 198 || !strncmp(buf, ">>>>>>>", 7)) { 199 free(buf); 200 return; 201 } 202 while (strstr(buf, "\r")) 203 *strstr(buf, "\r") = ' '; 204 while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n') 205 buf[strlen(buf)-1] = '\0'; 206 207 lines = g_strsplit(buf, "\n", -1); 208 209 if (direction == 0 || (buf[0] == '*' && buf[1] == ' ') || size < 64) { 210 while (lines[i] && *lines[i]) { 211 log_print(LOG_PROTOCOL, "IMAP%c %s\n", direction?'>':'<', lines[i]); 212 i++; 213 } 214 } else { 215 log_print(LOG_PROTOCOL, "IMAP%c [data - %"G_GSIZE_FORMAT" bytes]\n", direction?'>':'<', size); 216 } 217 g_strfreev(lines); 218 free(buf); 219 } 220 221 #define ETPAN_DEFAULT_NETWORK_TIMEOUT 60 222 gboolean etpan_skip_ssl_cert_check = FALSE; 223 extern void mailsasl_ref(void); 224 225 void imap_main_init(gboolean skip_ssl_cert_check) 226 { 227 int fd_thread_manager; 228 229 etpan_skip_ssl_cert_check = skip_ssl_cert_check; 230 mailstream_network_delay.tv_sec = ETPAN_DEFAULT_NETWORK_TIMEOUT; 231 mailstream_network_delay.tv_usec = 0; 232 233 mailstream_debug = 1; 234 mailstream_logger = imap_logger_cmd; 235 mailsasl_ref(); 236 237 imap_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE); 238 session_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE); 239 courier_workaround_hash = chash_new(CHASH_COPYKEY, CHASH_DEFAULTSIZE); 240 241 thread_manager = etpan_thread_manager_new(); 242 243 fd_thread_manager = etpan_thread_manager_get_fd(thread_manager); 244 245 io_channel = g_io_channel_unix_new(fd_thread_manager); 246 thread_manager_signal = g_io_add_watch_full(io_channel, 0, G_IO_IN, 247 thread_manager_event, 248 (gpointer) NULL, 249 NULL); 250 } 251 252 void imap_main_set_timeout(int sec) 253 { 254 mailstream_network_delay.tv_sec = sec; 255 mailstream_network_delay.tv_usec = 0; 256 } 257 258 void imap_main_done(gboolean have_connectivity) 259 { 260 imap_disconnect_all(have_connectivity); 261 etpan_thread_manager_stop(thread_manager); 262 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) 263 return; 264 #endif 265 etpan_thread_manager_join(thread_manager); 266 267 g_source_remove(thread_manager_signal); 268 g_io_channel_unref(io_channel); 269 270 etpan_thread_manager_free(thread_manager); 271 272 chash_free(courier_workaround_hash); 273 chash_free(session_hash); 274 chash_free(imap_hash); 275 } 276 277 void imap_init(Folder * folder) 278 { 279 struct etpan_thread * thread; 280 chashdatum key; 281 chashdatum value; 282 283 thread = etpan_thread_manager_get_thread(thread_manager); 284 285 key.data = &folder; 286 key.len = sizeof(folder); 287 value.data = thread; 288 value.len = 0; 289 290 chash_set(imap_hash, &key, &value, NULL); 291 } 292 293 void imap_done(Folder * folder) 294 { 295 struct etpan_thread * thread; 296 chashdatum key; 297 chashdatum value; 298 int r; 299 300 key.data = &folder; 301 key.len = sizeof(folder); 302 303 r = chash_get(imap_hash, &key, &value); 304 if (r < 0) 305 return; 306 307 thread = value.data; 308 309 etpan_thread_unbind(thread); 310 311 chash_delete(imap_hash, &key, NULL); 312 313 debug_print("remove thread\n"); 314 } 315 316 static struct etpan_thread * get_thread(Folder * folder) 317 { 318 struct etpan_thread * thread; 319 chashdatum key; 320 chashdatum value; 321 int r; 322 323 key.data = &folder; 324 key.len = sizeof(folder); 325 326 r = chash_get(imap_hash, &key, &value); 327 if (r < 0) 328 return NULL; 329 330 thread = value.data; 331 332 return thread; 333 } 334 335 static mailimap * get_imap(Folder * folder) 336 { 337 mailimap * imap; 338 chashdatum key; 339 chashdatum value; 340 int r; 341 342 key.data = &folder; 343 key.len = sizeof(folder); 344 345 r = chash_get(session_hash, &key, &value); 346 if (r < 0) 347 return NULL; 348 349 imap = value.data; 350 debug_print("found imap %p\n", imap); 351 return imap; 352 } 353 354 static gboolean cb_show_error(gpointer data) 355 { 356 mainwindow_show_error(); 357 return FALSE; 358 } 359 360 static void generic_cb(int cancelled, void * result, void * callback_data) 361 { 362 struct etpan_thread_op * op; 363 364 op = (struct etpan_thread_op *) callback_data; 365 366 debug_print("generic_cb\n"); 367 if (op->imap && op->imap->imap_response_info && 368 op->imap->imap_response_info->rsp_alert) { 369 log_error(LOG_PROTOCOL, "IMAP< Alert: %s\n", 370 op->imap->imap_response_info->rsp_alert); 371 g_timeout_add(10, cb_show_error, NULL); 372 } 373 op->finished = 1; 374 } 375 376 /* Please do *not* blindly use imap pointers after this function returns, 377 * someone may have deleted it while this function was waiting for completion. 378 * Check return value to see if imap is still valid. 379 * Run get_imap(folder) again to get a fresh and valid pointer. 380 */ 381 static int threaded_run(Folder * folder, void * param, void * result, 382 void (* func)(struct etpan_thread_op * )) 383 { 384 struct etpan_thread_op * op; 385 struct etpan_thread * thread; 386 struct mailimap * imap = get_imap(folder); 387 388 imap_folder_ref(folder); 389 390 op = etpan_thread_op_new(); 391 392 op->imap = imap; 393 op->param = param; 394 op->result = result; 395 396 op->run = func; 397 op->callback = generic_cb; 398 op->callback_data = op; 399 400 thread = get_thread(folder); 401 etpan_thread_op_schedule(thread, op); 402 403 while (!op->finished) { 404 gtk_main_iteration(); 405 } 406 407 etpan_thread_op_free(op); 408 409 imap_folder_unref(folder); 410 411 if (imap != get_imap(folder)) { 412 g_warning("returning from operation on a stale imap %p", imap); 413 return 1; 414 } 415 416 return 0; 417 } 418 419 420 /* connect */ 421 422 struct connect_param { 423 mailimap * imap; 424 PrefsAccount *account; 425 const char * server; 426 int port; 427 }; 428 429 struct connect_result { 430 int error; 431 }; 432 433 #define CHECK_IMAP() { \ 434 if (!param->imap) { \ 435 result->error = MAILIMAP_ERROR_BAD_STATE; \ 436 return; \ 437 } \ 438 } 439 440 441 static void delete_imap_run(struct etpan_thread_op * op) 442 { 443 mailimap * imap = op->imap; 444 445 /* we don't want libetpan to logout */ 446 if (imap->imap_stream) { 447 mailstream_close(imap->imap_stream); 448 imap->imap_stream = NULL; 449 } 450 451 mailimap_free(imap); 452 } 453 454 static void threaded_delete_imap(Folder *folder, mailimap *imap) 455 { 456 struct etpan_thread_op * op; 457 458 /* No need to wait for completion, threaded_run() won't work here. */ 459 op = etpan_thread_op_new(); 460 op->imap = imap; 461 op->run = delete_imap_run; 462 op->cleanup = etpan_thread_op_free; 463 464 etpan_thread_op_schedule(get_thread(folder), op); 465 466 debug_print("threaded delete imap posted\n"); 467 } 468 469 static void delete_imap(Folder *folder, mailimap *imap) 470 { 471 chashdatum key; 472 473 key.data = &folder; 474 key.len = sizeof(folder); 475 chash_delete(session_hash, &key, NULL); 476 477 if (!imap) 478 return; 479 key.data = &imap; 480 key.len = sizeof(imap); 481 chash_delete(courier_workaround_hash, &key, NULL); 482 /* We can't just free imap here as there may be ops on it pending 483 * in the thread. Posting freeing as an op will synchronize against 484 * existing jobs and as imap is already removed from session_hash 485 * we are sure no new ops can be posted. */ 486 threaded_delete_imap(folder, imap); 487 } 488 489 static void connect_run(struct etpan_thread_op * op) 490 { 491 int r; 492 struct connect_param * param; 493 struct connect_result * result; 494 495 param = op->param; 496 result = op->result; 497 498 CHECK_IMAP(); 499 500 r = mailimap_socket_connect(param->imap, param->server, param->port); 501 502 result->error = r; 503 } 504 505 506 int imap_threaded_connect(Folder * folder, const char * server, int port) 507 { 508 struct connect_param param; 509 struct connect_result result; 510 chashdatum key; 511 chashdatum value; 512 mailimap * imap, * oldimap; 513 514 oldimap = get_imap(folder); 515 516 imap = mailimap_new(0, NULL); 517 518 if (oldimap) { 519 debug_print("deleting old imap %p\n", oldimap); 520 delete_imap(folder, oldimap); 521 } 522 523 key.data = &folder; 524 key.len = sizeof(folder); 525 value.data = imap; 526 value.len = 0; 527 chash_set(session_hash, &key, &value, NULL); 528 529 param.imap = imap; 530 param.server = server; 531 param.port = port; 532 533 threaded_run(folder, ¶m, &result, connect_run); 534 535 debug_print("connect ok %i with imap %p\n", result.error, imap); 536 537 return result.error; 538 } 539 540 static void connect_ssl_run(struct etpan_thread_op * op) 541 { 542 int r; 543 struct connect_param * param; 544 struct connect_result * result; 545 546 param = op->param; 547 result = op->result; 548 549 CHECK_IMAP(); 550 551 r = mailimap_ssl_connect_with_callback(param->imap, param->server, param->port, etpan_connect_ssl_context_cb, param->account); 552 result->error = r; 553 } 554 555 int imap_threaded_connect_ssl(Folder * folder, const char * server, int port) 556 { 557 struct connect_param param; 558 struct connect_result result; 559 chashdatum key; 560 chashdatum value; 561 mailimap * imap, * oldimap; 562 gboolean accept_if_valid = FALSE; 563 564 oldimap = get_imap(folder); 565 566 imap = mailimap_new(0, NULL); 567 568 if (oldimap) { 569 debug_print("deleting old imap %p\n", oldimap); 570 delete_imap(folder, oldimap); 571 } 572 573 key.data = &folder; 574 key.len = sizeof(folder); 575 value.data = imap; 576 value.len = 0; 577 chash_set(session_hash, &key, &value, NULL); 578 579 param.imap = imap; 580 param.server = server; 581 param.port = port; 582 param.account = folder->account; 583 584 if (folder->account) 585 accept_if_valid = TRUE; 586 587 if (threaded_run(folder, ¶m, &result, connect_ssl_run)) 588 return MAILIMAP_ERROR_INVAL; 589 590 if ((result.error == MAILIMAP_NO_ERROR_AUTHENTICATED || 591 result.error == MAILIMAP_NO_ERROR_NON_AUTHENTICATED) && !etpan_skip_ssl_cert_check) { 592 if (etpan_certificate_check(imap->imap_stream, server, port, 593 accept_if_valid) != TRUE) 594 result.error = MAILIMAP_ERROR_SSL; 595 } 596 debug_print("connect %d with imap %p\n", result.error, imap); 597 598 return result.error; 599 } 600 601 struct capa_param { 602 mailimap * imap; 603 }; 604 605 struct capa_result { 606 int error; 607 struct mailimap_capability_data *caps; 608 }; 609 610 static void capability_run(struct etpan_thread_op * op) 611 { 612 int r; 613 struct capa_param * param; 614 struct capa_result * result; 615 struct mailimap_capability_data *caps; 616 617 param = op->param; 618 result = op->result; 619 620 CHECK_IMAP(); 621 622 r = mailimap_capability(param->imap, &caps); 623 624 result->error = r; 625 result->caps = (r == 0 ? caps : NULL); 626 } 627 628 629 int imap_threaded_capability(Folder *folder, struct mailimap_capability_data ** caps) 630 { 631 struct capa_param param; 632 struct capa_result result; 633 mailimap *imap; 634 635 imap = get_imap(folder); 636 637 param.imap = imap; 638 639 threaded_run(folder, ¶m, &result, capability_run); 640 641 debug_print("capa %d\n", result.error); 642 643 if (result.error == MAILIMAP_NO_ERROR) 644 *caps = result.caps; 645 646 return result.error; 647 648 } 649 650 struct disconnect_param { 651 mailimap * imap; 652 }; 653 654 struct disconnect_result { 655 int error; 656 }; 657 658 static void disconnect_run(struct etpan_thread_op * op) 659 { 660 int r; 661 struct disconnect_param * param; 662 struct disconnect_result * result; 663 664 param = op->param; 665 result = op->result; 666 667 CHECK_IMAP(); 668 669 r = mailimap_logout(param->imap); 670 671 result->error = r; 672 } 673 674 void imap_threaded_disconnect(Folder * folder) 675 { 676 struct connect_param param; 677 struct connect_result result; 678 mailimap * imap; 679 680 imap = get_imap(folder); 681 if (imap == NULL) { 682 debug_print("was disconnected\n"); 683 return; 684 } 685 686 param.imap = imap; 687 688 if (threaded_run(folder, ¶m, &result, disconnect_run)) { 689 debug_print("imap already deleted %p\n", imap); 690 } else { 691 debug_print("deleting old imap %p\n", imap); 692 delete_imap(folder, imap); 693 } 694 695 debug_print("disconnect ok\n"); 696 } 697 698 699 struct list_param { 700 mailimap * imap; 701 const char * base; 702 const char * wildcard; 703 gboolean sub_only; 704 }; 705 706 struct list_result { 707 int error; 708 clist * list; 709 }; 710 711 static void list_run(struct etpan_thread_op * op) 712 { 713 struct list_param * param; 714 struct list_result * result; 715 int r; 716 clist * list; 717 718 param = op->param; 719 result = op->result; 720 721 CHECK_IMAP(); 722 723 list = NULL; 724 725 if (param->base == NULL || param->wildcard == NULL) { 726 result->list = list; 727 result->error = -1; 728 debug_print("no base or wildcard (%p %p)\n", param->base, param->wildcard); 729 return; 730 } 731 if (param->sub_only) 732 r = mailimap_lsub(param->imap, param->base, 733 param->wildcard, &list); 734 else 735 r = mailimap_list(param->imap, param->base, 736 param->wildcard, &list); 737 result->error = r; 738 result->list = list; 739 debug_print("imap list run - end\n"); 740 } 741 742 int imap_threaded_list(Folder * folder, const char * base, 743 const char * wildcard, 744 clist ** p_result) 745 { 746 struct list_param param; 747 struct list_result result; 748 749 debug_print("imap list - begin\n"); 750 751 param.imap = get_imap(folder); 752 param.base = base; 753 param.wildcard = wildcard; 754 param.sub_only = FALSE; 755 756 threaded_run(folder, ¶m, &result, list_run); 757 758 * p_result = result.list; 759 760 debug_print("imap list - end %p\n", result.list); 761 762 return result.error; 763 } 764 765 int imap_threaded_lsub(Folder * folder, const char * base, 766 const char * wildcard, 767 clist ** p_result) 768 { 769 struct list_param param; 770 struct list_result result; 771 772 debug_print("imap lsub - begin\n"); 773 774 param.imap = get_imap(folder); 775 param.base = base; 776 param.wildcard = wildcard; 777 param.sub_only = TRUE; 778 779 threaded_run(folder, ¶m, &result, list_run); 780 781 * p_result = result.list; 782 783 debug_print("imap lsub - end %p\n", result.list); 784 785 return result.error; 786 } 787 788 struct subscribe_param { 789 mailimap * imap; 790 const char * mb; 791 gboolean subscribe; 792 }; 793 794 struct subscribe_result { 795 int error; 796 }; 797 798 static void subscribe_run(struct etpan_thread_op * op) 799 { 800 struct subscribe_param * param; 801 struct subscribe_result * result; 802 int r; 803 804 param = op->param; 805 result = op->result; 806 807 CHECK_IMAP(); 808 809 if (param->mb == NULL) { 810 result->error = -1; 811 debug_print("no mb\n"); 812 return; 813 } 814 if (param->subscribe) 815 r = mailimap_subscribe(param->imap, param->mb); 816 else 817 r = mailimap_unsubscribe(param->imap, param->mb); 818 result->error = r; 819 debug_print("imap %ssubscribe run - end %d\n", param->subscribe?"":"un", r); 820 } 821 822 int imap_threaded_subscribe(Folder * folder, const char * mb, 823 gboolean subscribe) 824 { 825 struct subscribe_param param; 826 struct subscribe_result result; 827 828 debug_print("imap list - begin\n"); 829 830 param.imap = get_imap(folder); 831 param.mb = mb; 832 param.subscribe = subscribe; 833 834 threaded_run(folder, ¶m, &result, subscribe_run); 835 836 return result.error; 837 } 838 839 struct login_param { 840 mailimap * imap; 841 const char * login; 842 const char * password; 843 const char * type; 844 const char * server; 845 }; 846 847 struct login_result { 848 int error; 849 }; 850 851 static void login_run(struct etpan_thread_op * op) 852 { 853 struct login_param * param; 854 struct login_result * result; 855 int r; 856 #ifdef DISABLE_LOG_DURING_LOGIN 857 int old_debug; 858 #endif 859 860 param = op->param; 861 result = op->result; 862 863 CHECK_IMAP(); 864 865 #ifdef DISABLE_LOG_DURING_LOGIN 866 old_debug = mailstream_debug; 867 mailstream_debug = 0; 868 #endif 869 if (!strcmp(param->type, "plaintext")) 870 r = mailimap_login(param->imap, 871 param->login, param->password); 872 else if (!strcmp(param->type, "GSSAPI")) 873 r = mailimap_authenticate(param->imap, 874 param->type, param->server, NULL, NULL, 875 param->login, param->login, 876 param->password, NULL); 877 else if (!strncmp(param->type, "SCRAM-SHA-", 10)) 878 /* 7th argument has to be NULL here, to stop libetpan sending the 879 * a= attribute in its initial SCRAM-SHA-1 message to server. At least 880 * Dovecot 2.2 doesn't seem to like that, and will not authenticate 881 * successfully. */ 882 r = mailimap_authenticate(param->imap, 883 param->type, NULL, NULL, NULL, 884 NULL, param->login, 885 param->password, NULL); 886 else if (!strcmp(param->type, "XOAUTH2")) 887 r = mailimap_oauth2_authenticate(param->imap, param->login, param->password); 888 else 889 r = mailimap_authenticate(param->imap, 890 param->type, NULL, NULL, NULL, 891 param->login, param->login, 892 param->password, NULL); 893 #ifdef DISABLE_LOG_DURING_LOGIN 894 mailstream_debug = old_debug; 895 #endif 896 897 result->error = r; 898 if (param->imap->imap_response) 899 imap_logger_cmd(0, param->imap->imap_response, strlen(param->imap->imap_response)); 900 debug_print("imap login run - end %i\n", r); 901 } 902 903 int imap_threaded_login(Folder * folder, 904 const char * login, const char * password, 905 const char * type) 906 { 907 struct login_param param; 908 struct login_result result; 909 910 debug_print("imap login - begin\n"); 911 912 if (!folder) 913 return MAILIMAP_ERROR_INVAL; 914 915 param.imap = get_imap(folder); 916 param.login = login; 917 param.password = password; 918 param.type = type; 919 if (folder && folder->account) 920 param.server = folder->account->recv_server; 921 else 922 param.server = NULL; 923 924 threaded_run(folder, ¶m, &result, login_run); 925 926 debug_print("imap login - end\n"); 927 928 return result.error; 929 } 930 931 932 struct status_param { 933 mailimap * imap; 934 const char * mb; 935 struct mailimap_status_att_list * status_att_list; 936 }; 937 938 struct status_result { 939 int error; 940 struct mailimap_mailbox_data_status * data_status; 941 }; 942 943 static void status_run(struct etpan_thread_op * op) 944 { 945 struct status_param * param; 946 struct status_result * result; 947 int r; 948 949 param = op->param; 950 result = op->result; 951 952 CHECK_IMAP(); 953 954 r = mailimap_status(param->imap, param->mb, 955 param->status_att_list, 956 &result->data_status); 957 958 result->error = r; 959 debug_print("imap status run - end %i\n", r); 960 } 961 962 int imap_threaded_status(Folder * folder, const char * mb, 963 struct mailimap_mailbox_data_status ** data_status, 964 guint mask) 965 { 966 struct status_param param; 967 struct status_result result; 968 struct mailimap_status_att_list * status_att_list; 969 970 debug_print("imap status - begin\n"); 971 972 status_att_list = mailimap_status_att_list_new_empty(); 973 if (mask & 1 << 0) { 974 mailimap_status_att_list_add(status_att_list, 975 MAILIMAP_STATUS_ATT_MESSAGES); 976 } 977 if (mask & 1 << 1) { 978 mailimap_status_att_list_add(status_att_list, 979 MAILIMAP_STATUS_ATT_RECENT); 980 } 981 if (mask & 1 << 2) { 982 mailimap_status_att_list_add(status_att_list, 983 MAILIMAP_STATUS_ATT_UIDNEXT); 984 } 985 if (mask & 1 << 3) { 986 mailimap_status_att_list_add(status_att_list, 987 MAILIMAP_STATUS_ATT_UIDVALIDITY); 988 } 989 if (mask & 1 << 4) { 990 mailimap_status_att_list_add(status_att_list, 991 MAILIMAP_STATUS_ATT_UNSEEN); 992 } 993 param.imap = get_imap(folder); 994 param.mb = mb; 995 param.status_att_list = status_att_list; 996 997 threaded_run(folder, ¶m, &result, status_run); 998 999 debug_print("imap status - end\n"); 1000 1001 * data_status = result.data_status; 1002 1003 mailimap_status_att_list_free(status_att_list); 1004 1005 return result.error; 1006 } 1007 1008 1009 1010 struct noop_param { 1011 mailimap * imap; 1012 }; 1013 1014 struct noop_result { 1015 int error; 1016 }; 1017 1018 static void noop_run(struct etpan_thread_op * op) 1019 { 1020 struct noop_param * param; 1021 struct noop_result * result; 1022 int r; 1023 1024 param = op->param; 1025 result = op->result; 1026 1027 CHECK_IMAP(); 1028 1029 r = mailimap_noop(param->imap); 1030 1031 result->error = r; 1032 debug_print("imap noop run - end %i\n", r); 1033 } 1034 1035 int imap_threaded_noop(Folder * folder, unsigned int * p_exists, 1036 unsigned int *p_recent, 1037 unsigned int *p_expunge, 1038 unsigned int *p_unseen, 1039 unsigned int *p_uidnext, 1040 unsigned int *p_uidval) 1041 { 1042 struct noop_param param; 1043 struct noop_result result; 1044 mailimap * imap; 1045 1046 debug_print("imap noop - begin\n"); 1047 1048 imap = get_imap(folder); 1049 param.imap = imap; 1050 1051 if (threaded_run(folder, ¶m, &result, noop_run)) 1052 return MAILIMAP_ERROR_INVAL; 1053 1054 if (result.error == 0 && imap && imap->imap_selection_info != NULL) { 1055 * p_exists = imap->imap_selection_info->sel_exists; 1056 * p_recent = imap->imap_selection_info->sel_recent; 1057 * p_unseen = imap->imap_selection_info->sel_unseen; 1058 * p_uidnext = imap->imap_selection_info->sel_uidnext; 1059 * p_uidval = imap->imap_selection_info->sel_uidvalidity; 1060 } else { 1061 * p_exists = 0; 1062 * p_recent = 0; 1063 * p_unseen = 0; 1064 * p_uidnext = 0; 1065 * p_uidval = 0; 1066 } 1067 if (result.error == 0 && imap && imap->imap_response_info != NULL && 1068 imap->imap_response_info->rsp_expunged != NULL) { 1069 * p_expunge = clist_count(imap->imap_response_info->rsp_expunged); 1070 } else { 1071 * p_expunge = 0; 1072 } 1073 debug_print("imap noop - end [EXISTS %d RECENT %d EXPUNGE %d UNSEEN %d UIDNEXT %d UIDVAL %d]\n", 1074 *p_exists, *p_recent, *p_expunge, *p_unseen, 1075 *p_uidnext, *p_uidval); 1076 1077 return result.error; 1078 } 1079 1080 struct starttls_result { 1081 int error; 1082 }; 1083 1084 static void starttls_run(struct etpan_thread_op * op) 1085 { 1086 struct connect_param * param; 1087 struct starttls_result * result; 1088 int r; 1089 1090 param = op->param; 1091 result = op->result; 1092 1093 CHECK_IMAP(); 1094 1095 r = mailimap_starttls(param->imap); 1096 1097 result->error = r; 1098 debug_print("imap STARTTLS run - end %i\n", r); 1099 1100 if (r == 0) { 1101 mailimap *imap = param->imap; 1102 mailstream_low *plain_low = NULL; 1103 mailstream_low *tls_low = NULL; 1104 int fd = -1; 1105 1106 plain_low = mailstream_get_low(imap->imap_stream); 1107 fd = mailstream_low_get_fd(plain_low); 1108 if (fd == -1) { 1109 debug_print("imap STARTTLS run - can't get fd\n"); 1110 result->error = MAILIMAP_ERROR_STREAM; 1111 return; 1112 } 1113 1114 tls_low = mailstream_low_tls_open_with_callback(fd, etpan_connect_ssl_context_cb, param->account); 1115 if (tls_low == NULL) { 1116 debug_print("imap STARTTLS run - can't tls_open\n"); 1117 result->error = MAILIMAP_ERROR_STREAM; 1118 return; 1119 } 1120 mailstream_low_free(plain_low); 1121 mailstream_set_low(imap->imap_stream, tls_low); 1122 } 1123 } 1124 1125 int imap_threaded_starttls(Folder * folder, const gchar *host, int port) 1126 { 1127 struct connect_param param; 1128 struct starttls_result result; 1129 gboolean accept_if_valid = FALSE; 1130 1131 debug_print("imap STARTTLS - begin\n"); 1132 1133 param.imap = get_imap(folder); 1134 param.server = host; 1135 param.port = port; 1136 param.account = folder->account; 1137 1138 if (folder->account) 1139 accept_if_valid = TRUE; 1140 1141 if (threaded_run(folder, ¶m, &result, starttls_run)) 1142 return MAILIMAP_ERROR_INVAL; 1143 1144 debug_print("imap STARTTLS - end\n"); 1145 1146 if (result.error == 0 && param.imap && !etpan_skip_ssl_cert_check) { 1147 if (etpan_certificate_check(param.imap->imap_stream, host, port, 1148 accept_if_valid) != TRUE) 1149 return MAILIMAP_ERROR_SSL; 1150 } 1151 return result.error; 1152 } 1153 1154 struct create_param { 1155 mailimap * imap; 1156 const char * mb; 1157 }; 1158 1159 struct create_result { 1160 int error; 1161 }; 1162 1163 static void create_run(struct etpan_thread_op * op) 1164 { 1165 struct create_param * param; 1166 struct create_result * result; 1167 int r; 1168 1169 param = op->param; 1170 result = op->result; 1171 1172 CHECK_IMAP(); 1173 1174 r = mailimap_create(param->imap, param->mb); 1175 1176 result->error = r; 1177 debug_print("imap create run - end %i\n", r); 1178 } 1179 1180 int imap_threaded_create(Folder * folder, const char * mb) 1181 { 1182 struct create_param param; 1183 struct create_result result; 1184 1185 debug_print("imap create - begin\n"); 1186 1187 param.imap = get_imap(folder); 1188 param.mb = mb; 1189 1190 threaded_run(folder, ¶m, &result, create_run); 1191 1192 debug_print("imap create - end\n"); 1193 1194 return result.error; 1195 } 1196 1197 1198 1199 1200 struct rename_param { 1201 mailimap * imap; 1202 const char * mb; 1203 const char * new_name; 1204 }; 1205 1206 struct rename_result { 1207 int error; 1208 }; 1209 1210 static void rename_run(struct etpan_thread_op * op) 1211 { 1212 struct rename_param * param; 1213 struct rename_result * result; 1214 int r; 1215 1216 param = op->param; 1217 result = op->result; 1218 1219 CHECK_IMAP(); 1220 1221 r = mailimap_rename(param->imap, param->mb, param->new_name); 1222 1223 result->error = r; 1224 debug_print("imap rename run - end %i\n", r); 1225 } 1226 1227 int imap_threaded_rename(Folder * folder, 1228 const char * mb, const char * new_name) 1229 { 1230 struct rename_param param; 1231 struct rename_result result; 1232 1233 debug_print("imap rename - begin\n"); 1234 1235 param.imap = get_imap(folder); 1236 param.mb = mb; 1237 param.new_name = new_name; 1238 1239 threaded_run(folder, ¶m, &result, rename_run); 1240 1241 debug_print("imap rename - end\n"); 1242 1243 return result.error; 1244 } 1245 1246 1247 1248 1249 struct delete_param { 1250 mailimap * imap; 1251 const char * mb; 1252 }; 1253 1254 struct delete_result { 1255 int error; 1256 }; 1257 1258 static void delete_run(struct etpan_thread_op * op) 1259 { 1260 struct delete_param * param; 1261 struct delete_result * result; 1262 int r; 1263 1264 param = op->param; 1265 result = op->result; 1266 1267 CHECK_IMAP(); 1268 1269 r = mailimap_delete(param->imap, param->mb); 1270 1271 result->error = r; 1272 debug_print("imap delete run - end %i\n", r); 1273 } 1274 1275 int imap_threaded_delete(Folder * folder, const char * mb) 1276 { 1277 struct delete_param param; 1278 struct delete_result result; 1279 1280 debug_print("imap delete - begin\n"); 1281 1282 param.imap = get_imap(folder); 1283 param.mb = mb; 1284 1285 threaded_run(folder, ¶m, &result, delete_run); 1286 1287 debug_print("imap delete - end\n"); 1288 1289 return result.error; 1290 } 1291 1292 1293 1294 struct select_param { 1295 mailimap * imap; 1296 const char * mb; 1297 }; 1298 1299 struct select_result { 1300 int error; 1301 }; 1302 1303 static void select_run(struct etpan_thread_op * op) 1304 { 1305 struct select_param * param; 1306 struct select_result * result; 1307 int r; 1308 1309 param = op->param; 1310 result = op->result; 1311 1312 CHECK_IMAP(); 1313 1314 r = mailimap_select(param->imap, param->mb); 1315 1316 result->error = r; 1317 debug_print("imap select run - end %i\n", r); 1318 } 1319 1320 int imap_threaded_select(Folder * folder, const char * mb, 1321 gint * exists, gint * recent, gint * unseen, 1322 guint32 * uid_validity,gint *can_create_flags, 1323 GSList **ok_flags) 1324 { 1325 struct select_param param; 1326 struct select_result result; 1327 mailimap * imap; 1328 1329 debug_print("imap select - begin\n"); 1330 1331 imap = get_imap(folder); 1332 param.imap = imap; 1333 param.mb = mb; 1334 1335 if (threaded_run(folder, ¶m, &result, select_run)) 1336 return MAILIMAP_ERROR_INVAL; 1337 1338 if (result.error != MAILIMAP_NO_ERROR) 1339 return result.error; 1340 1341 if (!imap || imap->imap_selection_info == NULL) 1342 return MAILIMAP_ERROR_PARSE; 1343 1344 * exists = imap->imap_selection_info->sel_exists; 1345 * recent = imap->imap_selection_info->sel_recent; 1346 * unseen = imap->imap_selection_info->sel_unseen; 1347 * uid_validity = imap->imap_selection_info->sel_uidvalidity; 1348 * can_create_flags = FALSE; 1349 1350 if (imap->imap_selection_info->sel_perm_flags) { 1351 GSList *t_flags = NULL; 1352 clistiter *cur = NULL; 1353 if (imap->imap_selection_info->sel_perm_flags) 1354 cur = clist_begin(imap->imap_selection_info->sel_perm_flags); 1355 1356 for (; cur; cur = clist_next(cur)) { 1357 struct mailimap_flag_perm *flag = (struct mailimap_flag_perm *)clist_content(cur); 1358 if (flag->fl_type == MAILIMAP_FLAG_PERM_ALL) 1359 *can_create_flags = TRUE; 1360 else if (flag->fl_flag && 1361 flag->fl_flag->fl_type == 6 && 1362 !strcmp(flag->fl_flag->fl_data.fl_extension, "*")) 1363 *can_create_flags = TRUE; 1364 if (flag->fl_flag && ok_flags) { 1365 MsgPermFlags c_flag = 0; 1366 switch (flag->fl_flag->fl_type) { 1367 case MAILIMAP_FLAG_ANSWERED: 1368 c_flag = IMAP_FLAG_ANSWERED; 1369 break; 1370 case MAILIMAP_FLAG_FLAGGED: 1371 c_flag = IMAP_FLAG_FLAGGED; 1372 break; 1373 case MAILIMAP_FLAG_DELETED: 1374 c_flag = IMAP_FLAG_DELETED; 1375 break; 1376 case MAILIMAP_FLAG_DRAFT: 1377 c_flag = IMAP_FLAG_DRAFT; 1378 break; 1379 case MAILIMAP_FLAG_SEEN: 1380 c_flag = IMAP_FLAG_SEEN; 1381 break; 1382 case MAILIMAP_FLAG_KEYWORD: 1383 if (!strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_FORWARDED)) 1384 c_flag = IMAP_FLAG_FORWARDED; 1385 if (!strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_JUNK)) 1386 c_flag = IMAP_FLAG_SPAM; 1387 if (!strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_NON_JUNK) || 1388 !strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_NO_JUNK) || 1389 !strcasecmp(flag->fl_flag->fl_data.fl_keyword, RTAG_NOT_JUNK)) 1390 c_flag = IMAP_FLAG_HAM; 1391 break; 1392 default: 1393 break; 1394 } 1395 if (c_flag != 0) { 1396 t_flags = g_slist_prepend(t_flags, 1397 GUINT_TO_POINTER(c_flag)); 1398 } 1399 } 1400 } 1401 if (ok_flags) 1402 *ok_flags = t_flags; 1403 } 1404 debug_print("imap select - end\n"); 1405 1406 return result.error; 1407 } 1408 1409 static void close_run(struct etpan_thread_op * op) 1410 { 1411 struct select_param * param; 1412 struct select_result * result; 1413 int r; 1414 1415 param = op->param; 1416 result = op->result; 1417 1418 CHECK_IMAP(); 1419 1420 r = mailimap_close(param->imap); 1421 1422 result->error = r; 1423 debug_print("imap close run - end %i\n", r); 1424 } 1425 1426 int imap_threaded_close(Folder * folder) 1427 { 1428 struct select_param param; 1429 struct select_result result; 1430 mailimap * imap; 1431 1432 debug_print("imap close - begin\n"); 1433 1434 imap = get_imap(folder); 1435 param.imap = imap; 1436 1437 threaded_run(folder, ¶m, &result, close_run); 1438 1439 if (result.error != MAILIMAP_NO_ERROR) 1440 return result.error; 1441 1442 debug_print("imap close - end\n"); 1443 1444 return result.error; 1445 } 1446 1447 struct examine_param { 1448 mailimap * imap; 1449 const char * mb; 1450 }; 1451 1452 struct examine_result { 1453 int error; 1454 }; 1455 1456 static void examine_run(struct etpan_thread_op * op) 1457 { 1458 struct examine_param * param; 1459 struct examine_result * result; 1460 int r; 1461 1462 param = op->param; 1463 result = op->result; 1464 1465 CHECK_IMAP(); 1466 1467 r = mailimap_examine(param->imap, param->mb); 1468 1469 result->error = r; 1470 debug_print("imap examine run - end %i\n", r); 1471 } 1472 1473 int imap_threaded_examine(Folder * folder, const char * mb, 1474 gint * exists, gint * recent, gint * unseen, 1475 guint32 * uid_validity) 1476 { 1477 struct examine_param param; 1478 struct examine_result result; 1479 mailimap * imap; 1480 1481 debug_print("imap examine - begin\n"); 1482 1483 imap = get_imap(folder); 1484 param.imap = imap; 1485 param.mb = mb; 1486 1487 if (threaded_run(folder, ¶m, &result, examine_run)) 1488 return MAILIMAP_ERROR_INVAL; 1489 1490 if (result.error != MAILIMAP_NO_ERROR) 1491 return result.error; 1492 1493 if (!imap || imap->imap_selection_info == NULL) 1494 return MAILIMAP_ERROR_PARSE; 1495 1496 * exists = imap->imap_selection_info->sel_exists; 1497 * recent = imap->imap_selection_info->sel_recent; 1498 * unseen = imap->imap_selection_info->sel_unseen; 1499 * uid_validity = imap->imap_selection_info->sel_uidvalidity; 1500 1501 debug_print("imap examine - end\n"); 1502 1503 return result.error; 1504 } 1505 1506 1507 1508 1509 struct search_param { 1510 mailimap * imap; 1511 int type; 1512 const char *charset; 1513 struct mailimap_set * set; 1514 IMAPSearchKey* key; 1515 }; 1516 1517 struct search_result { 1518 int error; 1519 clist * search_result; 1520 }; 1521 1522 static struct mailimap_set_item *sc_mailimap_set_item_copy(struct mailimap_set_item *orig) 1523 { 1524 return mailimap_set_item_new(orig->set_first, orig->set_last); 1525 } 1526 1527 static struct mailimap_set *sc_mailimap_set_copy(struct mailimap_set *orig) 1528 { 1529 clist *list = orig ? orig->set_list : NULL; 1530 clist *newlist; 1531 clistiter *cur; 1532 1533 if (!orig) 1534 return NULL; 1535 1536 newlist = clist_new(); 1537 if (!newlist) 1538 return NULL; 1539 1540 for (cur = clist_begin(list); cur; cur = clist_next(cur)) { 1541 if (clist_append(newlist, 1542 sc_mailimap_set_item_copy( 1543 (struct mailimap_set_item *)clist_content(cur))) != 0) { 1544 clist_free(newlist); 1545 return NULL; 1546 } 1547 } 1548 return mailimap_set_new(newlist); 1549 } 1550 1551 static void search_run(struct etpan_thread_op * op) 1552 { 1553 struct search_param * param; 1554 struct search_result * result; 1555 int r; 1556 struct mailimap_search_key * key = NULL; 1557 struct mailimap_search_key * uid_key = NULL; 1558 struct mailimap_search_key * search_type_key = NULL; 1559 clist * search_result; 1560 1561 param = op->param; 1562 result = op->result; 1563 1564 CHECK_IMAP(); 1565 1566 /* we copy the mailimap_set because freeing the key is recursive */ 1567 if (param->set != NULL) { 1568 uid_key = mailimap_search_key_new_uid(sc_mailimap_set_copy(param->set)); 1569 } else if (param->type == IMAP_SEARCH_TYPE_SIMPLE) { 1570 uid_key = mailimap_search_key_new_all(); 1571 } 1572 switch (param->type) { 1573 case IMAP_SEARCH_TYPE_SIMPLE: 1574 search_type_key = NULL; 1575 break; 1576 case IMAP_SEARCH_TYPE_SEEN: 1577 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_READ, NULL, NULL, 0); 1578 break; 1579 case IMAP_SEARCH_TYPE_UNSEEN: 1580 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_UNREAD, NULL, NULL, 0); 1581 break; 1582 case IMAP_SEARCH_TYPE_ANSWERED: 1583 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_REPLIED, NULL, NULL, 0); 1584 break; 1585 case IMAP_SEARCH_TYPE_FLAGGED: 1586 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_MARKED, NULL, NULL, 0); 1587 break; 1588 case IMAP_SEARCH_TYPE_DELETED: 1589 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_DELETED, NULL, NULL, 0); 1590 break; 1591 case IMAP_SEARCH_TYPE_FORWARDED: 1592 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_TAG, NULL, RTAG_FORWARDED, 0); 1593 break; 1594 case IMAP_SEARCH_TYPE_SPAM: 1595 search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_TAG, NULL, RTAG_JUNK, 0); 1596 break; 1597 case IMAP_SEARCH_TYPE_KEYED: 1598 search_type_key = param->key; 1599 break; 1600 } 1601 1602 if (search_type_key != NULL) { 1603 if (param->set != NULL) { 1604 key = mailimap_search_key_new_multiple_empty(); 1605 mailimap_search_key_multiple_add(key, search_type_key); 1606 mailimap_search_key_multiple_add(key, uid_key); 1607 } else { 1608 key = search_type_key; 1609 } 1610 } else if (uid_key != NULL) { 1611 key = uid_key; 1612 } 1613 1614 if (key == NULL) { 1615 g_warning("no key!"); 1616 result = op->result; 1617 result->error = -1; 1618 result->search_result = NULL; 1619 } else { 1620 mailstream_logger = imap_logger_uid; 1621 1622 r = mailimap_uid_search(param->imap, param->charset, key, &search_result); 1623 1624 mailstream_logger = imap_logger_cmd; 1625 1626 /* free the key (with the imapset) */ 1627 mailimap_search_key_free(key); 1628 1629 result->error = r; 1630 result->search_result = search_result; 1631 } 1632 debug_print("imap search run - end %i\n", result->error); 1633 } 1634 1635 int imap_threaded_search(Folder * folder, int search_type, IMAPSearchKey* key, 1636 const char *charset, struct mailimap_set * set, 1637 clist ** search_result) 1638 { 1639 struct search_param param; 1640 struct search_result result; 1641 mailimap * imap; 1642 1643 debug_print("imap search - begin\n"); 1644 1645 imap = get_imap(folder); 1646 param.imap = imap; 1647 param.set = set; 1648 param.charset = charset; 1649 param.type = search_type; 1650 param.key = key; 1651 1652 threaded_run(folder, ¶m, &result, search_run); 1653 1654 if (result.error != MAILIMAP_NO_ERROR) 1655 return result.error; 1656 1657 debug_print("imap search - end\n"); 1658 1659 * search_result = result.search_result; 1660 1661 return result.error; 1662 } 1663 1664 1665 struct _IMAPSearchKey { 1666 struct mailimap_search_key* key; 1667 }; 1668 1669 IMAPSearchKey* imap_search_new(gint criteria, 1670 const gchar *header, 1671 const gchar *expr, 1672 int value) 1673 { 1674 char* sk_bcc = NULL; 1675 struct mailimap_date* sk_before = NULL; 1676 char* sk_body = NULL; 1677 char* sk_cc = NULL; 1678 char* sk_from = NULL; 1679 char* sk_keyword = NULL; 1680 struct mailimap_date* sk_on = NULL; 1681 struct mailimap_date* sk_since = NULL; 1682 char* sk_subject = NULL; 1683 char* sk_text = NULL; 1684 char* sk_to = NULL; 1685 char* sk_unkeyword = NULL; 1686 char* sk_header_name = NULL; 1687 char* sk_header_value = NULL; 1688 uint32_t sk_larger = 0; 1689 struct mailimap_search_key* sk_not = NULL; 1690 struct mailimap_search_key* sk_or1 = NULL; 1691 struct mailimap_search_key* sk_or2 = NULL; 1692 struct mailimap_date* sk_sentbefore = NULL; 1693 struct mailimap_date* sk_senton = NULL; 1694 struct mailimap_date* sk_sentsince = NULL; 1695 uint32_t sk_smaller = 0; 1696 struct mailimap_set* sk_uid = NULL; 1697 struct mailimap_set* sk_set = NULL; 1698 clist* sk_multiple = NULL; 1699 int etpan_matcher_type; 1700 1701 switch (criteria) { 1702 case IMAP_SEARCH_CRITERIA_ALL: etpan_matcher_type = MAILIMAP_SEARCH_KEY_ALL; break; 1703 case IMAP_SEARCH_CRITERIA_READ: etpan_matcher_type = MAILIMAP_SEARCH_KEY_SEEN; break; 1704 case IMAP_SEARCH_CRITERIA_UNREAD: etpan_matcher_type = MAILIMAP_SEARCH_KEY_UNSEEN; break; 1705 case IMAP_SEARCH_CRITERIA_NEW: etpan_matcher_type = MAILIMAP_SEARCH_KEY_NEW; break; 1706 case IMAP_SEARCH_CRITERIA_MARKED: etpan_matcher_type = MAILIMAP_SEARCH_KEY_FLAGGED; break; 1707 case IMAP_SEARCH_CRITERIA_REPLIED: etpan_matcher_type = MAILIMAP_SEARCH_KEY_ANSWERED; break; 1708 case IMAP_SEARCH_CRITERIA_DELETED: etpan_matcher_type = MAILIMAP_SEARCH_KEY_DELETED; break; 1709 1710 case IMAP_SEARCH_CRITERIA_TAG: 1711 sk_keyword = strdup(expr); 1712 etpan_matcher_type = MAILIMAP_SEARCH_KEY_KEYWORD; 1713 break; 1714 1715 case IMAP_SEARCH_CRITERIA_SUBJECT: 1716 etpan_matcher_type = MAILIMAP_SEARCH_KEY_SUBJECT; 1717 sk_subject = strdup(expr); 1718 break; 1719 1720 case IMAP_SEARCH_CRITERIA_TO: 1721 etpan_matcher_type = MAILIMAP_SEARCH_KEY_TO; 1722 sk_to = strdup(expr); 1723 break; 1724 1725 case IMAP_SEARCH_CRITERIA_CC: 1726 etpan_matcher_type = MAILIMAP_SEARCH_KEY_CC; 1727 sk_cc = strdup(expr); 1728 break; 1729 1730 case IMAP_SEARCH_CRITERIA_AGE_GREATER: 1731 case IMAP_SEARCH_CRITERIA_AGE_LOWER: 1732 { 1733 struct tm tm; 1734 time_t limit = time(NULL) - 60 * 60 * 24 * value; 1735 1736 tzset(); 1737 localtime_r(&limit, &tm); 1738 if (criteria == IMAP_SEARCH_CRITERIA_AGE_GREATER) { 1739 etpan_matcher_type = MAILIMAP_SEARCH_KEY_SENTBEFORE; 1740 sk_sentbefore = mailimap_date_new(tm.tm_mday, tm.tm_mon, tm.tm_year + 1900); 1741 } else { 1742 etpan_matcher_type = MAILIMAP_SEARCH_KEY_SENTSINCE; 1743 sk_sentsince = mailimap_date_new(tm.tm_mday, tm.tm_mon, tm.tm_year + 1900); 1744 } 1745 break; 1746 } 1747 1748 case IMAP_SEARCH_CRITERIA_BODY: 1749 etpan_matcher_type = MAILIMAP_SEARCH_KEY_BODY; 1750 sk_body = strdup(expr); 1751 break; 1752 1753 case IMAP_SEARCH_CRITERIA_MESSAGE: 1754 etpan_matcher_type = MAILIMAP_SEARCH_KEY_TEXT; 1755 sk_text = strdup(expr); 1756 break; 1757 1758 case IMAP_SEARCH_CRITERIA_HEADER: 1759 etpan_matcher_type = MAILIMAP_SEARCH_KEY_HEADER; 1760 sk_header_name = strdup(header); 1761 sk_header_value = strdup(expr); 1762 break; 1763 1764 case IMAP_SEARCH_CRITERIA_FROM: 1765 etpan_matcher_type = MAILIMAP_SEARCH_KEY_FROM; 1766 sk_from = strdup(expr); 1767 break; 1768 1769 case IMAP_SEARCH_CRITERIA_SIZE_GREATER: 1770 etpan_matcher_type = MAILIMAP_SEARCH_KEY_LARGER; 1771 sk_larger = value; 1772 break; 1773 1774 case IMAP_SEARCH_CRITERIA_SIZE_SMALLER: 1775 etpan_matcher_type = MAILIMAP_SEARCH_KEY_SMALLER; 1776 sk_smaller = value; 1777 break; 1778 1779 default: 1780 return NULL; 1781 } 1782 1783 return mailimap_search_key_new(etpan_matcher_type, 1784 sk_bcc, sk_before, sk_body, sk_cc, sk_from, sk_keyword, 1785 sk_on, sk_since, sk_subject, sk_text, sk_to, 1786 sk_unkeyword, sk_header_name,sk_header_value, sk_larger, 1787 sk_not, sk_or1, sk_or2, sk_sentbefore, sk_senton, 1788 sk_sentsince, sk_smaller, sk_uid, sk_set, sk_multiple); 1789 } 1790 1791 IMAPSearchKey* imap_search_not(IMAPSearchKey* key) 1792 { 1793 return mailimap_search_key_new_not(key); 1794 } 1795 1796 IMAPSearchKey* imap_search_or(IMAPSearchKey* l, IMAPSearchKey* r) 1797 { 1798 return mailimap_search_key_new_or(l, r); 1799 } 1800 1801 IMAPSearchKey* imap_search_and(IMAPSearchKey* l, IMAPSearchKey* r) 1802 { 1803 IMAPSearchKey* result = mailimap_search_key_new_multiple_empty(); 1804 mailimap_search_key_multiple_add(result, l); 1805 mailimap_search_key_multiple_add(result, r); 1806 1807 return result; 1808 } 1809 1810 void imap_search_free(IMAPSearchKey* key) 1811 { 1812 if (!key) 1813 return; 1814 1815 mailimap_search_key_free(key); 1816 } 1817 1818 1819 1820 static int imap_get_msg_att_info(struct mailimap_msg_att * msg_att, 1821 uint32_t * puid, 1822 char ** pheaders, 1823 size_t * pref_size, 1824 struct mailimap_msg_att_dynamic ** patt_dyn); 1825 1826 static int 1827 result_to_uid_list(clist * fetch_result, carray ** result) 1828 { 1829 clistiter * cur = NULL; 1830 int r; 1831 int res; 1832 carray * tab; 1833 1834 tab = carray_new(128); 1835 if (tab == NULL) { 1836 res = MAILIMAP_ERROR_MEMORY; 1837 goto err; 1838 } 1839 1840 if (fetch_result) 1841 cur = clist_begin(fetch_result); 1842 1843 for(; cur != NULL ; cur = clist_next(cur)) { 1844 struct mailimap_msg_att * msg_att; 1845 uint32_t uid; 1846 uint32_t * puid; 1847 1848 msg_att = clist_content(cur); 1849 1850 uid = 0; 1851 imap_get_msg_att_info(msg_att, &uid, NULL, NULL, NULL); 1852 1853 puid = malloc(sizeof(* puid)); 1854 if (puid == NULL) { 1855 res = MAILIMAP_ERROR_MEMORY; 1856 goto free_list; 1857 } 1858 * puid = uid; 1859 1860 r = carray_add(tab, puid, NULL); 1861 if (r < 0) { 1862 free(puid); 1863 res = MAILIMAP_ERROR_MEMORY; 1864 goto free_list; 1865 } 1866 } 1867 1868 * result = tab; 1869 1870 return MAILIMAP_NO_ERROR; 1871 1872 free_list: 1873 imap_fetch_uid_list_free(tab); 1874 err: 1875 return res; 1876 } 1877 1878 static int imap_get_messages_list(mailimap * imap, 1879 uint32_t first_index, 1880 carray ** result) 1881 { 1882 carray * env_list; 1883 int r; 1884 struct mailimap_fetch_att * fetch_att; 1885 struct mailimap_fetch_type * fetch_type; 1886 struct mailimap_set * set; 1887 clist * fetch_result; 1888 int res; 1889 1890 set = mailimap_set_new_interval(first_index, 0); 1891 if (set == NULL) { 1892 res = MAILIMAP_ERROR_MEMORY; 1893 goto err; 1894 } 1895 1896 fetch_type = mailimap_fetch_type_new_fetch_att_list_empty(); 1897 if (fetch_type == NULL) { 1898 res = MAILIMAP_ERROR_MEMORY; 1899 goto free_set; 1900 } 1901 1902 fetch_att = mailimap_fetch_att_new_uid(); 1903 if (fetch_att == NULL) { 1904 res = MAILIMAP_ERROR_MEMORY; 1905 goto free_fetch_type; 1906 } 1907 1908 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); 1909 if (r != MAILIMAP_NO_ERROR) { 1910 mailimap_fetch_att_free(fetch_att); 1911 res = MAILIMAP_ERROR_MEMORY; 1912 goto free_fetch_type; 1913 } 1914 1915 mailstream_logger = imap_logger_fetch; 1916 1917 r = mailimap_uid_fetch(imap, set, 1918 fetch_type, &fetch_result); 1919 1920 mailstream_logger = imap_logger_cmd; 1921 mailimap_fetch_type_free(fetch_type); 1922 mailimap_set_free(set); 1923 1924 if (r != MAILIMAP_NO_ERROR) { 1925 res = r; 1926 goto err; 1927 } 1928 1929 env_list = NULL; 1930 r = result_to_uid_list(fetch_result, &env_list); 1931 mailimap_fetch_list_free(fetch_result); 1932 1933 * result = env_list; 1934 1935 return MAILIMAP_NO_ERROR; 1936 1937 free_fetch_type: 1938 mailimap_fetch_type_free(fetch_type); 1939 free_set: 1940 mailimap_set_free(set); 1941 err: 1942 return res; 1943 } 1944 1945 1946 1947 1948 struct fetch_uid_param { 1949 mailimap * imap; 1950 uint32_t first_index; 1951 }; 1952 1953 struct fetch_uid_result { 1954 int error; 1955 carray * fetch_result; 1956 }; 1957 1958 static void fetch_uid_run(struct etpan_thread_op * op) 1959 { 1960 struct fetch_uid_param * param; 1961 struct fetch_uid_result * result; 1962 carray * fetch_result; 1963 int r; 1964 1965 param = op->param; 1966 result = op->result; 1967 1968 CHECK_IMAP(); 1969 1970 fetch_result = NULL; 1971 mailstream_logger = imap_logger_noop; 1972 log_print(LOG_PROTOCOL, "IMAP- [fetching UIDs...]\n"); 1973 1974 r = imap_get_messages_list(param->imap, param->first_index, 1975 &fetch_result); 1976 1977 mailstream_logger = imap_logger_cmd; 1978 1979 result->error = r; 1980 result->fetch_result = fetch_result; 1981 debug_print("imap fetch_uid run - end %i\n", r); 1982 } 1983 1984 int imap_threaded_fetch_uid(Folder * folder, uint32_t first_index, 1985 carray ** fetch_result) 1986 { 1987 struct fetch_uid_param param; 1988 struct fetch_uid_result result; 1989 mailimap * imap; 1990 1991 debug_print("imap fetch_uid - begin\n"); 1992 1993 imap = get_imap(folder); 1994 param.imap = imap; 1995 param.first_index = first_index; 1996 1997 threaded_run(folder, ¶m, &result, fetch_uid_run); 1998 1999 if (result.error != MAILIMAP_NO_ERROR) 2000 return result.error; 2001 2002 debug_print("imap fetch_uid - end\n"); 2003 2004 * fetch_result = result.fetch_result; 2005 2006 return result.error; 2007 } 2008 2009 2010 void imap_fetch_uid_list_free(carray * uid_list) 2011 { 2012 unsigned int i; 2013 2014 for(i = 0 ; i < carray_count(uid_list) ; i ++) { 2015 uint32_t * puid; 2016 2017 puid = carray_get(uid_list, i); 2018 free(puid); 2019 } 2020 carray_free(uid_list); 2021 } 2022 2023 2024 2025 2026 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn, GSList **tags); 2027 2028 static int 2029 result_to_uid_flags_list(clist * fetch_result, carray ** result) 2030 { 2031 clistiter * cur = NULL; 2032 int r; 2033 int res; 2034 carray * tab; 2035 GSList *tags = NULL; 2036 2037 tab = carray_new(128); 2038 if (tab == NULL) { 2039 res = MAILIMAP_ERROR_MEMORY; 2040 goto err; 2041 } 2042 2043 if (fetch_result) 2044 cur = clist_begin(fetch_result); 2045 2046 for(; cur != NULL ; cur = clist_next(cur)) { 2047 struct mailimap_msg_att * msg_att; 2048 uint32_t uid; 2049 uint32_t * puid; 2050 struct mailimap_msg_att_dynamic * att_dyn; 2051 int flags; 2052 int * pflags; 2053 2054 tags = NULL; 2055 2056 msg_att = clist_content(cur); 2057 2058 uid = 0; 2059 att_dyn = NULL; 2060 imap_get_msg_att_info(msg_att, &uid, NULL, NULL, &att_dyn); 2061 if (uid == 0) 2062 continue; 2063 if (att_dyn == NULL) 2064 continue; 2065 2066 flags = imap_flags_to_flags(att_dyn, &tags); 2067 2068 puid = malloc(sizeof(* puid)); 2069 if (puid == NULL) { 2070 res = MAILIMAP_ERROR_MEMORY; 2071 goto free_list; 2072 } 2073 * puid = uid; 2074 2075 r = carray_add(tab, puid, NULL); 2076 if (r < 0) { 2077 free(puid); 2078 res = MAILIMAP_ERROR_MEMORY; 2079 goto free_list; 2080 } 2081 pflags = malloc(sizeof(* pflags)); 2082 if (pflags == NULL) { 2083 res = MAILIMAP_ERROR_MEMORY; 2084 goto free_list; 2085 } 2086 * pflags = flags; 2087 r = carray_add(tab, pflags, NULL); 2088 if (r < 0) { 2089 free(pflags); 2090 res = MAILIMAP_ERROR_MEMORY; 2091 goto free_list; 2092 } 2093 r = carray_add(tab, tags, NULL); 2094 if (r < 0) { 2095 free(pflags); 2096 res = MAILIMAP_ERROR_MEMORY; 2097 goto free_list; 2098 } 2099 } 2100 2101 * result = tab; 2102 2103 return MAILIMAP_NO_ERROR; 2104 2105 free_list: 2106 imap_fetch_uid_flags_list_free(tab); 2107 slist_free_strings_full(tags); 2108 err: 2109 return res; 2110 } 2111 2112 static int imap_get_messages_flags_list(mailimap * imap, 2113 uint32_t first_index, 2114 carray ** result) 2115 { 2116 carray * env_list; 2117 int r; 2118 struct mailimap_fetch_att * fetch_att; 2119 struct mailimap_fetch_type * fetch_type; 2120 struct mailimap_set * set; 2121 clist * fetch_result; 2122 int res; 2123 2124 set = mailimap_set_new_interval(first_index, 0); 2125 if (set == NULL) { 2126 res = MAILIMAP_ERROR_MEMORY; 2127 goto err; 2128 } 2129 2130 fetch_type = mailimap_fetch_type_new_fetch_att_list_empty(); 2131 if (fetch_type == NULL) { 2132 res = MAILIMAP_ERROR_MEMORY; 2133 goto free_set; 2134 } 2135 2136 fetch_att = mailimap_fetch_att_new_flags(); 2137 if (fetch_att == NULL) { 2138 res = MAILIMAP_ERROR_MEMORY; 2139 goto free_fetch_type; 2140 } 2141 2142 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); 2143 if (r != MAILIMAP_NO_ERROR) { 2144 mailimap_fetch_att_free(fetch_att); 2145 res = MAILIMAP_ERROR_MEMORY; 2146 goto free_fetch_type; 2147 } 2148 2149 fetch_att = mailimap_fetch_att_new_uid(); 2150 if (fetch_att == NULL) { 2151 res = MAILIMAP_ERROR_MEMORY; 2152 goto free_fetch_type; 2153 } 2154 2155 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); 2156 if (r != MAILIMAP_NO_ERROR) { 2157 mailimap_fetch_att_free(fetch_att); 2158 res = MAILIMAP_ERROR_MEMORY; 2159 goto free_fetch_type; 2160 } 2161 2162 mailstream_logger = imap_logger_fetch; 2163 2164 r = mailimap_uid_fetch(imap, set, 2165 fetch_type, &fetch_result); 2166 2167 mailstream_logger = imap_logger_cmd; 2168 mailimap_fetch_type_free(fetch_type); 2169 mailimap_set_free(set); 2170 2171 if (r != MAILIMAP_NO_ERROR) { 2172 res = r; 2173 goto err; 2174 } 2175 2176 env_list = NULL; 2177 r = result_to_uid_flags_list(fetch_result, &env_list); 2178 mailimap_fetch_list_free(fetch_result); 2179 2180 * result = env_list; 2181 2182 return MAILIMAP_NO_ERROR; 2183 2184 free_fetch_type: 2185 mailimap_fetch_type_free(fetch_type); 2186 free_set: 2187 mailimap_set_free(set); 2188 err: 2189 return res; 2190 } 2191 2192 2193 2194 static void fetch_uid_flags_run(struct etpan_thread_op * op) 2195 { 2196 struct fetch_uid_param * param; 2197 struct fetch_uid_result * result; 2198 carray * fetch_result; 2199 int r; 2200 2201 param = op->param; 2202 result = op->result; 2203 2204 CHECK_IMAP(); 2205 2206 fetch_result = NULL; 2207 r = imap_get_messages_flags_list(param->imap, param->first_index, 2208 &fetch_result); 2209 2210 result->error = r; 2211 result->fetch_result = fetch_result; 2212 debug_print("imap fetch_uid run - end %i\n", r); 2213 } 2214 2215 int imap_threaded_fetch_uid_flags(Folder * folder, uint32_t first_index, 2216 carray ** fetch_result) 2217 { 2218 struct fetch_uid_param param; 2219 struct fetch_uid_result result; 2220 mailimap * imap; 2221 2222 debug_print("imap fetch_uid - begin\n"); 2223 2224 imap = get_imap(folder); 2225 param.imap = imap; 2226 param.first_index = first_index; 2227 2228 mailstream_logger = imap_logger_noop; 2229 log_print(LOG_PROTOCOL, "IMAP- [fetching flags...]\n"); 2230 2231 threaded_run(folder, ¶m, &result, fetch_uid_flags_run); 2232 2233 mailstream_logger = imap_logger_cmd; 2234 2235 2236 if (result.error != MAILIMAP_NO_ERROR) 2237 return result.error; 2238 2239 debug_print("imap fetch_uid - end\n"); 2240 2241 * fetch_result = result.fetch_result; 2242 2243 return result.error; 2244 } 2245 2246 2247 void imap_fetch_uid_flags_list_free(carray * uid_flags_list) 2248 { 2249 unsigned int i; 2250 2251 for(i = 0 ; i < carray_count(uid_flags_list) ; i += 3) { 2252 void * data; 2253 2254 data = carray_get(uid_flags_list, i); 2255 free(data); 2256 data = carray_get(uid_flags_list, i + 1); 2257 free(data); 2258 } 2259 carray_free(uid_flags_list); 2260 } 2261 2262 2263 2264 static int imap_fetch(mailimap * imap, 2265 uint32_t msg_index, 2266 char ** result, 2267 size_t * result_len) 2268 { 2269 int r; 2270 struct mailimap_set * set; 2271 struct mailimap_fetch_att * fetch_att; 2272 struct mailimap_fetch_type * fetch_type; 2273 clist * fetch_result; 2274 struct mailimap_msg_att * msg_att; 2275 struct mailimap_msg_att_item * msg_att_item; 2276 char * text; 2277 size_t text_length; 2278 int res; 2279 clistiter * cur; 2280 struct mailimap_section * section; 2281 2282 set = mailimap_set_new_single(msg_index); 2283 if (set == NULL) { 2284 res = MAILIMAP_ERROR_MEMORY; 2285 goto err; 2286 } 2287 2288 section = mailimap_section_new(NULL); 2289 if (section == NULL) { 2290 res = MAILIMAP_ERROR_MEMORY; 2291 goto free_set; 2292 } 2293 2294 fetch_att = mailimap_fetch_att_new_body_peek_section(section); 2295 if (fetch_att == NULL) { 2296 mailimap_section_free(section); 2297 res = MAILIMAP_ERROR_MEMORY; 2298 goto free_set; 2299 } 2300 2301 fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); 2302 if (fetch_type == NULL) { 2303 res = MAILIMAP_ERROR_MEMORY; 2304 goto free_fetch_att; 2305 } 2306 2307 mailstream_logger = imap_logger_fetch; 2308 2309 r = mailimap_uid_fetch(imap, set, 2310 fetch_type, &fetch_result); 2311 2312 mailstream_logger = imap_logger_cmd; 2313 2314 mailimap_fetch_type_free(fetch_type); 2315 mailimap_set_free(set); 2316 2317 switch (r) { 2318 case MAILIMAP_NO_ERROR: 2319 break; 2320 default: 2321 return r; 2322 } 2323 2324 if (fetch_result == NULL || clist_begin(fetch_result) == NULL) { 2325 mailimap_fetch_list_free(fetch_result); 2326 return MAILIMAP_ERROR_FETCH; 2327 } 2328 2329 msg_att = clist_begin(fetch_result)->data; 2330 2331 text = NULL; 2332 text_length = 0; 2333 2334 if (msg_att->att_list) 2335 cur = clist_begin(msg_att->att_list); 2336 else 2337 cur = NULL; 2338 2339 for(; cur != NULL ; cur = clist_next(cur)) { 2340 msg_att_item = clist_content(cur); 2341 2342 if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) { 2343 if (msg_att_item->att_data.att_static->att_type == 2344 MAILIMAP_MSG_ATT_BODY_SECTION) { 2345 text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part; 2346 /* detach */ 2347 msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL; 2348 text_length = 2349 msg_att_item->att_data.att_static->att_data.att_body_section->sec_length; 2350 } 2351 } 2352 } 2353 2354 mailimap_fetch_list_free(fetch_result); 2355 2356 if (text == NULL) 2357 return MAILIMAP_ERROR_FETCH; 2358 2359 * result = text; 2360 * result_len = text_length; 2361 2362 return MAILIMAP_NO_ERROR; 2363 2364 free_fetch_att: 2365 mailimap_fetch_att_free(fetch_att); 2366 free_set: 2367 mailimap_set_free(set); 2368 err: 2369 return res; 2370 } 2371 2372 static int imap_fetch_header(mailimap * imap, 2373 uint32_t msg_index, 2374 char ** result, 2375 size_t * result_len) 2376 { 2377 int r; 2378 struct mailimap_set * set; 2379 struct mailimap_fetch_att * fetch_att; 2380 struct mailimap_fetch_type * fetch_type; 2381 clist * fetch_result; 2382 struct mailimap_msg_att * msg_att; 2383 struct mailimap_msg_att_item * msg_att_item; 2384 char * text; 2385 size_t text_length; 2386 int res; 2387 clistiter * cur; 2388 struct mailimap_section * section; 2389 2390 set = mailimap_set_new_single(msg_index); 2391 if (set == NULL) { 2392 res = MAILIMAP_ERROR_MEMORY; 2393 goto err; 2394 } 2395 2396 section = mailimap_section_new_header(); 2397 if (section == NULL) { 2398 res = MAILIMAP_ERROR_MEMORY; 2399 goto free_set; 2400 } 2401 2402 fetch_att = mailimap_fetch_att_new_body_peek_section(section); 2403 if (fetch_att == NULL) { 2404 mailimap_section_free(section); 2405 res = MAILIMAP_ERROR_MEMORY; 2406 goto free_set; 2407 } 2408 2409 fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); 2410 if (fetch_type == NULL) { 2411 res = MAILIMAP_ERROR_MEMORY; 2412 goto free_fetch_att; 2413 } 2414 2415 mailstream_logger = imap_logger_fetch; 2416 2417 r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result); 2418 2419 mailstream_logger = imap_logger_cmd; 2420 mailimap_fetch_type_free(fetch_type); 2421 mailimap_set_free(set); 2422 2423 switch (r) { 2424 case MAILIMAP_NO_ERROR: 2425 break; 2426 default: 2427 return r; 2428 } 2429 2430 if (fetch_result == NULL || clist_begin(fetch_result) == NULL) { 2431 mailimap_fetch_list_free(fetch_result); 2432 return MAILIMAP_ERROR_FETCH; 2433 } 2434 2435 msg_att = clist_begin(fetch_result)->data; 2436 2437 text = NULL; 2438 text_length = 0; 2439 2440 if (msg_att->att_list) 2441 cur = clist_begin(msg_att->att_list); 2442 else 2443 cur = NULL; 2444 2445 for(; cur != NULL ; cur = clist_next(cur)) { 2446 msg_att_item = clist_content(cur); 2447 2448 if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) { 2449 if (msg_att_item->att_data.att_static->att_type == 2450 MAILIMAP_MSG_ATT_BODY_SECTION) { 2451 text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part; 2452 msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL; 2453 text_length = 2454 msg_att_item->att_data.att_static->att_data.att_body_section->sec_length; 2455 } 2456 } 2457 } 2458 2459 mailimap_fetch_list_free(fetch_result); 2460 2461 if (text == NULL) 2462 return MAILIMAP_ERROR_FETCH; 2463 2464 * result = text; 2465 * result_len = text_length; 2466 2467 return MAILIMAP_NO_ERROR; 2468 2469 free_fetch_att: 2470 mailimap_fetch_att_free(fetch_att); 2471 free_set: 2472 mailimap_set_free(set); 2473 err: 2474 return res; 2475 } 2476 2477 2478 2479 struct fetch_content_param { 2480 mailimap * imap; 2481 uint32_t msg_index; 2482 const char * filename; 2483 int with_body; 2484 }; 2485 2486 struct fetch_content_result { 2487 int error; 2488 }; 2489 2490 static void fetch_content_run(struct etpan_thread_op * op) 2491 { 2492 struct fetch_content_param * param; 2493 struct fetch_content_result * result; 2494 char * content; 2495 size_t content_size; 2496 int r; 2497 int fd; 2498 FILE * f; 2499 2500 param = op->param; 2501 result = op->result; 2502 2503 CHECK_IMAP(); 2504 2505 content = NULL; 2506 content_size = 0; 2507 if (param->with_body) 2508 r = imap_fetch(param->imap, param->msg_index, 2509 &content, &content_size); 2510 else 2511 r = imap_fetch_header(param->imap, param->msg_index, 2512 &content, &content_size); 2513 2514 result->error = r; 2515 2516 if (r == MAILIMAP_NO_ERROR) { 2517 fd = g_open(param->filename, O_RDWR | O_CREAT, 0600); 2518 if (fd < 0) { 2519 result->error = MAILIMAP_ERROR_FETCH; 2520 goto free; 2521 } 2522 2523 f = fdopen(fd, "wb"); 2524 if (f == NULL) { 2525 result->error = MAILIMAP_ERROR_FETCH; 2526 goto close; 2527 } 2528 2529 r = fwrite(content, 1, content_size, f); 2530 if (r < content_size) { 2531 result->error = MAILIMAP_ERROR_FETCH; 2532 goto do_fclose; 2533 } 2534 2535 if (fclose(f) == EOF) { 2536 result->error = MAILIMAP_ERROR_FETCH; 2537 goto unlink; 2538 } 2539 goto free; 2540 2541 do_fclose: 2542 fclose(f); 2543 goto unlink; 2544 close: 2545 close(fd); 2546 unlink: 2547 if (unlink(param->filename) < 0) 2548 FILE_OP_ERROR(param->filename, "unlink"); 2549 2550 free: 2551 /* mmap_string_unref is a simple free in libetpan 2552 * when it has MMAP_UNAVAILABLE defined */ 2553 if (mmap_string_unref(content) != 0) 2554 free(content); 2555 } 2556 2557 debug_print("imap fetch_content run - end %i\n", result->error); 2558 } 2559 2560 int imap_threaded_fetch_content(Folder * folder, uint32_t msg_index, 2561 int with_body, 2562 const char * filename) 2563 { 2564 struct fetch_content_param param; 2565 struct fetch_content_result result; 2566 mailimap * imap; 2567 2568 debug_print("imap fetch_content - begin\n"); 2569 2570 imap = get_imap(folder); 2571 param.imap = imap; 2572 param.msg_index = msg_index; 2573 param.filename = filename; 2574 param.with_body = with_body; 2575 2576 threaded_run(folder, ¶m, &result, fetch_content_run); 2577 2578 if (result.error != MAILIMAP_NO_ERROR) 2579 return result.error; 2580 2581 debug_print("imap fetch_content - end\n"); 2582 2583 return result.error; 2584 } 2585 2586 2587 2588 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn, GSList **s_tags) 2589 { 2590 int flags; 2591 clist * flag_list; 2592 clistiter * cur; 2593 GSList *tags = NULL; 2594 2595 flags = MSG_UNREAD; 2596 2597 flag_list = att_dyn->att_list; 2598 if (flag_list == NULL) 2599 return flags; 2600 2601 for(cur = clist_begin(flag_list) ; cur != NULL ; 2602 cur = clist_next(cur)) { 2603 struct mailimap_flag_fetch * flag_fetch; 2604 2605 flag_fetch = clist_content(cur); 2606 if (flag_fetch->fl_type == MAILIMAP_FLAG_FETCH_RECENT) 2607 flags |= MSG_NEW; 2608 else { 2609 switch (flag_fetch->fl_flag->fl_type) { 2610 case MAILIMAP_FLAG_ANSWERED: 2611 flags |= MSG_REPLIED; 2612 break; 2613 case MAILIMAP_FLAG_FLAGGED: 2614 flags |= MSG_MARKED; 2615 break; 2616 case MAILIMAP_FLAG_DELETED: 2617 flags |= MSG_DELETED; 2618 break; 2619 case MAILIMAP_FLAG_SEEN: 2620 flags &= ~MSG_UNREAD; 2621 flags &= ~MSG_NEW; 2622 break; 2623 case MAILIMAP_FLAG_KEYWORD: 2624 if (!strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_FORWARDED)) 2625 flags |= MSG_FORWARDED; 2626 else if (!strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_JUNK)) 2627 flags |= MSG_SPAM; 2628 else if (!strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_NON_JUNK) || 2629 !strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_NO_JUNK) || 2630 !strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, RTAG_NOT_JUNK)) 2631 flags &= ~MSG_SPAM; 2632 else if (s_tags) 2633 tags = g_slist_prepend(tags, g_strdup(flag_fetch->fl_flag->fl_data.fl_keyword)); 2634 break; 2635 } 2636 } 2637 } 2638 if (s_tags) 2639 *s_tags = tags; 2640 return flags; 2641 } 2642 2643 static int imap_get_msg_att_info(struct mailimap_msg_att * msg_att, 2644 uint32_t * puid, 2645 char ** pheaders, 2646 size_t * pref_size, 2647 struct mailimap_msg_att_dynamic ** patt_dyn) 2648 { 2649 clistiter * item_cur; 2650 uint32_t uid; 2651 char * headers; 2652 size_t ref_size; 2653 struct mailimap_msg_att_dynamic * att_dyn; 2654 2655 uid = 0; 2656 headers = NULL; 2657 ref_size = 0; 2658 att_dyn = NULL; 2659 2660 if (msg_att->att_list) 2661 item_cur = clist_begin(msg_att->att_list); 2662 else 2663 item_cur = NULL; 2664 for(; item_cur != NULL ; item_cur = clist_next(item_cur)) { 2665 struct mailimap_msg_att_item * item; 2666 2667 item = clist_content(item_cur); 2668 2669 switch (item->att_type) { 2670 case MAILIMAP_MSG_ATT_ITEM_STATIC: 2671 switch (item->att_data.att_static->att_type) { 2672 case MAILIMAP_MSG_ATT_UID: 2673 uid = item->att_data.att_static->att_data.att_uid; 2674 break; 2675 2676 case MAILIMAP_MSG_ATT_BODY_SECTION: 2677 if (headers == NULL) { 2678 headers = item->att_data.att_static->att_data.att_body_section->sec_body_part; 2679 } 2680 break; 2681 case MAILIMAP_MSG_ATT_RFC822_SIZE: 2682 ref_size = item->att_data.att_static->att_data.att_rfc822_size; 2683 break; 2684 } 2685 break; 2686 2687 case MAILIMAP_MSG_ATT_ITEM_DYNAMIC: 2688 if (att_dyn == NULL) { 2689 att_dyn = item->att_data.att_dyn; 2690 } 2691 break; 2692 } 2693 } 2694 2695 if (puid != NULL) 2696 * puid = uid; 2697 if (pheaders != NULL) 2698 * pheaders = headers; 2699 if (pref_size != NULL) 2700 * pref_size = ref_size; 2701 if (patt_dyn != NULL) 2702 * patt_dyn = att_dyn; 2703 2704 return MAIL_NO_ERROR; 2705 } 2706 2707 static struct imap_fetch_env_info * 2708 fetch_to_env_info(struct mailimap_msg_att * msg_att, GSList **tags) 2709 { 2710 struct imap_fetch_env_info * info; 2711 uint32_t uid; 2712 char * headers; 2713 size_t size; 2714 struct mailimap_msg_att_dynamic * att_dyn; 2715 2716 imap_get_msg_att_info(msg_att, &uid, &headers, &size, 2717 &att_dyn); 2718 2719 if (!headers) 2720 return NULL; 2721 info = malloc(sizeof(* info)); 2722 info->uid = uid; 2723 info->headers = strdup(headers); 2724 info->size = size; 2725 info->flags = imap_flags_to_flags(att_dyn, tags); 2726 2727 return info; 2728 } 2729 2730 static int 2731 imap_fetch_result_to_envelop_list(clist * fetch_result, 2732 carray ** p_env_list) 2733 { 2734 clistiter * cur; 2735 2736 if (fetch_result) { 2737 carray * env_list; 2738 env_list = carray_new(16); 2739 2740 for(cur = clist_begin(fetch_result) ; cur != NULL ; 2741 cur = clist_next(cur)) { 2742 struct mailimap_msg_att * msg_att; 2743 struct imap_fetch_env_info * env_info; 2744 GSList *tags = NULL; 2745 2746 msg_att = clist_content(cur); 2747 2748 env_info = fetch_to_env_info(msg_att, &tags); 2749 if (!env_info 2750 || carray_add(env_list, env_info, NULL) != 0 2751 || carray_add(env_list, tags, NULL) != 0) { 2752 carray_free(env_list); 2753 return MAILIMAP_ERROR_MEMORY; 2754 } 2755 } 2756 * p_env_list = env_list; 2757 } else { 2758 * p_env_list = NULL; 2759 } 2760 2761 return MAIL_NO_ERROR; 2762 } 2763 2764 static int imap_add_envelope_fetch_att(struct mailimap_fetch_type * fetch_type) 2765 { 2766 struct mailimap_fetch_att * fetch_att; 2767 int i; 2768 char * header; 2769 clist * hdrlist; 2770 struct mailimap_header_list * imap_hdrlist; 2771 struct mailimap_section * section; 2772 char *headers[] = { 2773 "Date", "From", "To", "Cc", "Subject", "Message-ID", 2774 "References", "In-Reply-To", NULL 2775 }; 2776 2777 hdrlist = clist_new(); 2778 if (!hdrlist) 2779 return MAIL_ERROR_MEMORY; 2780 i = 0; 2781 while (headers[i] != NULL) { 2782 header = strdup(headers[i]); 2783 if (header == NULL || clist_append(hdrlist, header) != 0) { 2784 clist_free(hdrlist); 2785 return MAIL_ERROR_MEMORY; 2786 } 2787 ++i; 2788 } 2789 2790 imap_hdrlist = mailimap_header_list_new(hdrlist); 2791 section = mailimap_section_new_header_fields(imap_hdrlist); 2792 fetch_att = mailimap_fetch_att_new_body_peek_section(section); 2793 mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); 2794 2795 return MAIL_NO_ERROR; 2796 } 2797 2798 static int imap_add_header_fetch_att(struct mailimap_fetch_type * fetch_type) 2799 { 2800 struct mailimap_fetch_att * fetch_att; 2801 struct mailimap_section * section; 2802 2803 section = mailimap_section_new_header(); 2804 fetch_att = mailimap_fetch_att_new_body_peek_section(section); 2805 mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); 2806 2807 return MAIL_NO_ERROR; 2808 } 2809 2810 static int 2811 imap_get_envelopes_list(mailimap * imap, struct mailimap_set * set, 2812 carray ** p_env_list) 2813 { 2814 struct mailimap_fetch_att * fetch_att; 2815 struct mailimap_fetch_type * fetch_type; 2816 int res; 2817 clist * fetch_result; 2818 int r; 2819 carray * env_list = NULL; 2820 chashdatum key; 2821 chashdatum value; 2822 2823 fetch_type = mailimap_fetch_type_new_fetch_att_list_empty(); 2824 2825 /* uid */ 2826 fetch_att = mailimap_fetch_att_new_uid(); 2827 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); 2828 2829 /* flags */ 2830 fetch_att = mailimap_fetch_att_new_flags(); 2831 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); 2832 2833 /* rfc822 size */ 2834 fetch_att = mailimap_fetch_att_new_rfc822_size(); 2835 r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); 2836 2837 /* headers */ 2838 key.data = &imap; 2839 key.len = sizeof(imap); 2840 r = chash_get(courier_workaround_hash, &key, &value); 2841 if (r < 0) 2842 r = imap_add_envelope_fetch_att(fetch_type); 2843 else 2844 r = imap_add_header_fetch_att(fetch_type); 2845 2846 if (r != MAILIMAP_NO_ERROR) { 2847 debug_print("add fetch attr: %d\n", r); 2848 return r; 2849 } 2850 2851 mailstream_logger = imap_logger_fetch; 2852 2853 r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result); 2854 2855 mailstream_logger = imap_logger_cmd; 2856 switch (r) { 2857 case MAILIMAP_NO_ERROR: 2858 break; 2859 default: 2860 mailimap_fetch_type_free(fetch_type); 2861 debug_print("uid_fetch: %d\n", r); 2862 return r; 2863 } 2864 2865 if (fetch_result == NULL || clist_begin(fetch_result) == NULL) { 2866 res = MAILIMAP_ERROR_FETCH; 2867 debug_print("clist_begin = NULL\n"); 2868 goto err; 2869 } 2870 2871 r = imap_fetch_result_to_envelop_list(fetch_result, &env_list); 2872 mailimap_fetch_list_free(fetch_result); 2873 2874 if (r != MAILIMAP_NO_ERROR) { 2875 mailimap_fetch_type_free(fetch_type); 2876 res = MAILIMAP_ERROR_MEMORY; 2877 debug_print("fetch_result_to_envelop_list: %d\n", res); 2878 goto err; 2879 } 2880 2881 mailimap_fetch_type_free(fetch_type); 2882 2883 * p_env_list = env_list; 2884 2885 return MAILIMAP_NO_ERROR; 2886 2887 err: 2888 return res; 2889 } 2890 2891 struct fetch_env_param { 2892 mailimap * imap; 2893 struct mailimap_set * set; 2894 }; 2895 2896 struct fetch_env_result { 2897 carray * fetch_env_result; 2898 int error; 2899 }; 2900 2901 static void fetch_env_run(struct etpan_thread_op * op) 2902 { 2903 struct fetch_env_param * param; 2904 struct fetch_env_result * result; 2905 carray * env_list; 2906 int r; 2907 2908 param = op->param; 2909 result = op->result; 2910 2911 CHECK_IMAP(); 2912 2913 env_list = NULL; 2914 r = imap_get_envelopes_list(param->imap, param->set, 2915 &env_list); 2916 2917 result->error = r; 2918 result->fetch_env_result = env_list; 2919 2920 debug_print("imap fetch_env run - end %i\n", r); 2921 } 2922 2923 int imap_threaded_fetch_env(Folder * folder, struct mailimap_set * set, 2924 carray ** p_env_list) 2925 { 2926 struct fetch_env_param param; 2927 struct fetch_env_result result; 2928 mailimap * imap; 2929 2930 debug_print("imap fetch_env - begin\n"); 2931 2932 imap = get_imap(folder); 2933 param.imap = imap; 2934 param.set = set; 2935 2936 if (threaded_run(folder, ¶m, &result, fetch_env_run)) 2937 return MAILIMAP_ERROR_INVAL; 2938 2939 if (result.error != MAILIMAP_NO_ERROR) { 2940 chashdatum key; 2941 chashdatum value; 2942 int r; 2943 2944 key.data = &imap; 2945 key.len = sizeof(imap); 2946 r = chash_get(courier_workaround_hash, &key, &value); 2947 if (r < 0) { 2948 value.data = NULL; 2949 value.len = 0; 2950 chash_set(courier_workaround_hash, &key, &value, NULL); 2951 2952 threaded_run(folder, ¶m, &result, fetch_env_run); 2953 } 2954 } 2955 2956 if (result.error != MAILIMAP_NO_ERROR) 2957 return result.error; 2958 2959 debug_print("imap fetch_env - end\n"); 2960 2961 * p_env_list = result.fetch_env_result; 2962 2963 return result.error; 2964 } 2965 2966 void imap_fetch_env_free(carray * env_list) 2967 { 2968 unsigned int i; 2969 2970 for(i = 0 ; i < carray_count(env_list) ; i += 2) { 2971 struct imap_fetch_env_info * env_info; 2972 2973 env_info = carray_get(env_list, i); 2974 free(env_info->headers); 2975 free(env_info); 2976 } 2977 carray_free(env_list); 2978 } 2979 2980 2981 2982 2983 2984 struct append_param { 2985 mailimap * imap; 2986 const char * mailbox; 2987 const char * filename; 2988 struct mailimap_flag_list * flag_list; 2989 }; 2990 2991 struct append_result { 2992 int error; 2993 int uid; 2994 }; 2995 2996 static void append_run(struct etpan_thread_op * op) 2997 { 2998 struct append_param * param; 2999 struct append_result * result; 3000 int r; 3001 char * data; 3002 size_t size; 3003 struct stat stat_buf; 3004 int fd; 3005 guint32 uid = 0, val = 0; 3006 3007 param = op->param; 3008 result = op->result; 3009 3010 CHECK_IMAP(); 3011 3012 r = stat(param->filename, &stat_buf); 3013 if (r < 0) { 3014 result->error = MAILIMAP_ERROR_APPEND; 3015 return; 3016 } 3017 size = stat_buf.st_size; 3018 3019 fd = g_open(param->filename, O_RDONLY, 0); 3020 if (fd < 0) { 3021 result->error = MAILIMAP_ERROR_APPEND; 3022 return; 3023 } 3024 3025 data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); 3026 if (data == (void *) MAP_FAILED) { 3027 close(fd); 3028 result->error = MAILIMAP_ERROR_APPEND; 3029 return; 3030 } 3031 3032 mailstream_logger = imap_logger_append; 3033 3034 r = mailimap_uidplus_append(param->imap, param->mailbox, 3035 param->flag_list, NULL, 3036 data, size, &val, &uid); 3037 3038 mailstream_logger = imap_logger_cmd; 3039 3040 munmap(data, size); 3041 close(fd); 3042 3043 result->error = r; 3044 result->uid = uid; 3045 debug_print("imap append run - end %i uid %d\n", r, uid); 3046 } 3047 3048 int imap_threaded_append(Folder * folder, const char * mailbox, 3049 const char * filename, 3050 struct mailimap_flag_list * flag_list, 3051 int *uid) 3052 { 3053 struct append_param param; 3054 struct append_result result; 3055 mailimap * imap; 3056 3057 debug_print("imap append - begin\n"); 3058 3059 imap = get_imap(folder); 3060 param.imap = imap; 3061 param.mailbox = mailbox; 3062 param.filename = filename; 3063 param.flag_list = flag_list; 3064 3065 threaded_run(folder, ¶m, &result, append_run); 3066 3067 if (result.error != MAILIMAP_NO_ERROR) 3068 return result.error; 3069 3070 debug_print("imap append - end\n"); 3071 if (uid != NULL) 3072 *uid = result.uid; 3073 3074 return result.error; 3075 } 3076 3077 3078 3079 3080 struct expunge_param { 3081 mailimap * imap; 3082 }; 3083 3084 struct expunge_result { 3085 int error; 3086 }; 3087 3088 static void expunge_run(struct etpan_thread_op * op) 3089 { 3090 struct expunge_param * param; 3091 struct expunge_result * result; 3092 int r; 3093 3094 param = op->param; 3095 result = op->result; 3096 3097 CHECK_IMAP(); 3098 3099 r = mailimap_expunge(param->imap); 3100 3101 result->error = r; 3102 debug_print("imap expunge run - end %i\n", r); 3103 } 3104 3105 int imap_threaded_expunge(Folder * folder) 3106 { 3107 struct expunge_param param; 3108 struct expunge_result result; 3109 3110 debug_print("imap expunge - begin\n"); 3111 3112 param.imap = get_imap(folder); 3113 3114 threaded_run(folder, ¶m, &result, expunge_run); 3115 3116 debug_print("imap expunge - end\n"); 3117 3118 return result.error; 3119 } 3120 3121 3122 struct copy_param { 3123 mailimap * imap; 3124 struct mailimap_set * set; 3125 const char * mb; 3126 }; 3127 3128 struct copy_result { 3129 int error; 3130 struct mailimap_set *source; 3131 struct mailimap_set *dest; 3132 }; 3133 3134 static void copy_run(struct etpan_thread_op * op) 3135 { 3136 struct copy_param * param; 3137 struct copy_result * result; 3138 int r; 3139 guint32 val; 3140 struct mailimap_set *source = NULL, *dest = NULL; 3141 3142 param = op->param; 3143 result = op->result; 3144 3145 CHECK_IMAP(); 3146 3147 r = mailimap_uidplus_uid_copy(param->imap, param->set, param->mb, 3148 &val, &source, &dest); 3149 3150 result->error = r; 3151 if (r == 0) { 3152 result->source = source; 3153 result->dest = dest; 3154 } else { 3155 result->source = NULL; 3156 result->dest = NULL; 3157 } 3158 debug_print("imap copy run - end %i\n", r); 3159 } 3160 3161 int imap_threaded_copy(Folder * folder, struct mailimap_set * set, 3162 const char * mb, struct mailimap_set **source, 3163 struct mailimap_set **dest) 3164 { 3165 struct copy_param param; 3166 struct copy_result result; 3167 mailimap * imap; 3168 3169 debug_print("imap copy - begin\n"); 3170 3171 imap = get_imap(folder); 3172 param.imap = imap; 3173 param.set = set; 3174 param.mb = mb; 3175 3176 threaded_run(folder, ¶m, &result, copy_run); 3177 *source = NULL; 3178 *dest = NULL; 3179 3180 if (result.error != MAILIMAP_NO_ERROR) 3181 return result.error; 3182 3183 *source = result.source; 3184 *dest = result.dest; 3185 3186 debug_print("imap copy - end\n"); 3187 3188 return result.error; 3189 } 3190 3191 3192 3193 struct store_param { 3194 mailimap * imap; 3195 struct mailimap_set * set; 3196 struct mailimap_store_att_flags * store_att_flags; 3197 }; 3198 3199 struct store_result { 3200 int error; 3201 }; 3202 3203 static void store_run(struct etpan_thread_op * op) 3204 { 3205 struct store_param * param; 3206 struct store_result * result; 3207 int r; 3208 3209 param = op->param; 3210 result = op->result; 3211 3212 CHECK_IMAP(); 3213 3214 r = mailimap_uid_store(param->imap, param->set, 3215 param->store_att_flags); 3216 3217 result->error = r; 3218 3219 debug_print("imap store run - end %i\n", r); 3220 } 3221 3222 int imap_threaded_store(Folder * folder, struct mailimap_set * set, 3223 struct mailimap_store_att_flags * store_att_flags) 3224 { 3225 struct store_param param; 3226 struct store_result result; 3227 mailimap * imap; 3228 3229 debug_print("imap store - begin\n"); 3230 3231 imap = get_imap(folder); 3232 param.imap = imap; 3233 param.set = set; 3234 param.store_att_flags = store_att_flags; 3235 3236 threaded_run(folder, ¶m, &result, store_run); 3237 3238 if (result.error != MAILIMAP_NO_ERROR) 3239 return result.error; 3240 3241 debug_print("imap store - end\n"); 3242 3243 return result.error; 3244 } 3245 3246 static void do_exec_command(int fd, const char * command, 3247 const char * servername, uint16_t port) 3248 { 3249 int i, maxopen; 3250 3251 if (fork() > 0) { 3252 /* Fork again to become a child of init rather than 3253 the etpan client. */ 3254 exit(0); 3255 } 3256 3257 if (servername) 3258 g_setenv("ETPANSERVER", servername, TRUE); 3259 else 3260 g_unsetenv("ETPANSERVER"); 3261 3262 if (port) { 3263 char porttext[20]; 3264 3265 snprintf(porttext, sizeof(porttext), "%d", port); 3266 g_setenv("ETPANPORT", porttext, TRUE); 3267 } 3268 else { 3269 g_unsetenv("ETPANPORT"); 3270 } 3271 3272 /* Not a lot we can do if there's an error other than bail. */ 3273 if (dup2(fd, 0) == -1) 3274 exit(1); 3275 if (dup2(fd, 1) == -1) 3276 exit(1); 3277 3278 /* Should we close stderr and reopen /dev/null? */ 3279 3280 maxopen = sysconf(_SC_OPEN_MAX); 3281 for (i=3; i < maxopen; i++) 3282 close(i); 3283 3284 #ifdef TIOCNOTTY 3285 /* Detach from the controlling tty if we have one. Otherwise, 3286 SSH might do something stupid like trying to use it instead 3287 of running $SSH_ASKPASS. Doh. */ 3288 fd = g_open("/dev/tty", O_RDONLY, 0); 3289 if (fd != -1) { 3290 ioctl(fd, TIOCNOTTY, NULL); 3291 close(fd); 3292 } 3293 #endif /* TIOCNOTTY */ 3294 3295 execl("/bin/sh", "/bin/sh", "-c", command, NULL); 3296 3297 /* Eep. Shouldn't reach this */ 3298 exit(1); 3299 } 3300 3301 static int subcommand_connect(const char *command, 3302 const char *servername, uint16_t port) 3303 { 3304 /* SEB unsupported on Windows */ 3305 int sockfds[2]; 3306 pid_t childpid; 3307 3308 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) 3309 return -1; 3310 3311 childpid = fork(); 3312 if (!childpid) { 3313 do_exec_command(sockfds[1], command, servername, port); 3314 } 3315 else if (childpid == -1) { 3316 close(sockfds[0]); 3317 close(sockfds[1]); 3318 return -1; 3319 } 3320 3321 close(sockfds[1]); 3322 3323 /* Reap child, leaving grandchild process to run */ 3324 waitpid(childpid, NULL, 0); 3325 3326 return sockfds[0]; 3327 } 3328 3329 static int socket_connect_cmd(mailimap * imap, const char * command, 3330 const char * server, int port) 3331 { 3332 int fd; 3333 mailstream * s; 3334 int r; 3335 3336 fd = subcommand_connect(command, server, port); 3337 if (fd < 0) 3338 return MAILIMAP_ERROR_STREAM; 3339 3340 s = mailstream_socket_open(fd); 3341 if (s == NULL) { 3342 close(fd); 3343 return MAILIMAP_ERROR_STREAM; 3344 } 3345 3346 r = mailimap_connect(imap, s); 3347 if (r != MAILIMAP_NO_ERROR_AUTHENTICATED 3348 && r != MAILIMAP_NO_ERROR_NON_AUTHENTICATED) { 3349 mailstream_close(s); 3350 if (imap) 3351 imap->imap_stream = NULL; 3352 return r; 3353 } 3354 3355 return r; 3356 } 3357 3358 /* connect cmd */ 3359 3360 struct connect_cmd_param { 3361 mailimap * imap; 3362 const char * command; 3363 const char * server; 3364 int port; 3365 }; 3366 3367 struct connect_cmd_result { 3368 int error; 3369 }; 3370 3371 static void connect_cmd_run(struct etpan_thread_op * op) 3372 { 3373 int r; 3374 struct connect_cmd_param * param; 3375 struct connect_cmd_result * result; 3376 3377 param = op->param; 3378 result = op->result; 3379 3380 CHECK_IMAP(); 3381 3382 r = socket_connect_cmd(param->imap, param->command, 3383 param->server, param->port); 3384 3385 result->error = r; 3386 } 3387 3388 3389 int imap_threaded_connect_cmd(Folder * folder, const char * command, 3390 const char * server, int port) 3391 { 3392 struct connect_cmd_param param; 3393 struct connect_cmd_result result; 3394 chashdatum key; 3395 chashdatum value; 3396 mailimap * imap, * oldimap; 3397 3398 oldimap = get_imap(folder); 3399 3400 imap = mailimap_new(0, NULL); 3401 3402 if (oldimap) { 3403 debug_print("deleting old imap %p\n", oldimap); 3404 delete_imap(folder, oldimap); 3405 } 3406 3407 key.data = &folder; 3408 key.len = sizeof(folder); 3409 value.data = imap; 3410 value.len = 0; 3411 chash_set(session_hash, &key, &value, NULL); 3412 3413 param.imap = imap; 3414 param.command = command; 3415 param.server = server; 3416 param.port = port; 3417 3418 threaded_run(folder, ¶m, &result, connect_cmd_run); 3419 3420 debug_print("connect_cmd ok %i with imap %p\n", result.error, imap); 3421 3422 return result.error; 3423 } 3424 3425 void imap_threaded_cancel(Folder * folder) 3426 { 3427 mailimap * imap; 3428 3429 imap = get_imap(folder); 3430 if (imap && imap->imap_stream != NULL) 3431 mailstream_cancel(imap->imap_stream); 3432 }