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
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.
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.
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/>.
21 #include "claws-features.h"
27 #include <glib/gi18n.h>
28 #include "imap-thread.h"
30 #include <sys/types.h>
32 #if (defined(__DragonFly__) || defined (__NetBSD__) || defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__CYGWIN__))
33 #include <sys/socket.h>
42 #include "etpan-thread-manager.h"
43 #include "etpan-ssl.h"
45 #include "mainwindow.h"
47 #include "file-utils.h"
49 #include "ssl_certificate.h"
51 #include "remotefolder.h"
54 #define DISABLE_LOG_DURING_LOGIN
56 static struct etpan_thread_manager
* thread_manager
= NULL
;
57 static chash
* courier_workaround_hash
= NULL
;
58 static chash
* imap_hash
= NULL
;
59 static chash
* session_hash
= NULL
;
60 static guint thread_manager_signal
= 0;
61 static GIOChannel
* io_channel
= NULL
;
63 static int do_mailimap_socket_connect(mailimap
* imap
, const char * server
,
64 gushort port
, ProxyInfo
* proxy_info
)
70 return mailimap_socket_connect(imap
, server
, port
);
75 sock
= sock_connect(proxy_info
->proxy_host
, proxy_info
->proxy_port
);
78 return MAILIMAP_ERROR_CONNECTION_REFUSED
;
80 if (proxy_connect(sock
, server
, port
, proxy_info
) < 0) {
81 sock_close(sock
, TRUE
);
82 return MAILIMAP_ERROR_CONNECTION_REFUSED
;
85 stream
= mailstream_socket_open_timeout(sock
->sock
,
88 sock_close(sock
, TRUE
);
89 return MAILIMAP_ERROR_MEMORY
;
92 /* Libetpan now has the socket fd, and we're not interested in
93 * rest of the SockInfo struct. Let's free it, while not touching
94 * the socket itself. */
95 sock_close(sock
, FALSE
);
97 return mailimap_connect(imap
, stream
);
101 static int do_mailimap_ssl_connect_with_callback(mailimap
* imap
, const char * server
,
103 void (* callback
)(struct mailstream_ssl_context
* ssl_context
, void * data
),
105 ProxyInfo
*proxy_info
)
111 return mailimap_ssl_connect_with_callback(imap
, server
,
112 port
, callback
, data
);
117 sock
= sock_connect(proxy_info
->proxy_host
, proxy_info
->proxy_port
);
120 debug_print("Can not connect to proxy %s:%d\n",
121 proxy_info
->proxy_host
, proxy_info
->proxy_port
);
122 return MAILIMAP_ERROR_CONNECTION_REFUSED
;
125 if (proxy_connect(sock
, server
, port
, proxy_info
) < 0) {
126 debug_print("Can not make proxy connection via %s:%d\n",
127 proxy_info
->proxy_host
, proxy_info
->proxy_port
);
128 sock_close(sock
, TRUE
);
129 return MAILIMAP_ERROR_CONNECTION_REFUSED
;
132 stream
= mailstream_ssl_open_with_callback_timeout(sock
->sock
,
133 imap
->imap_timeout
, callback
, data
);
134 if (stream
== NULL
) {
135 sock_close(sock
, TRUE
);
136 return MAILIMAP_ERROR_SSL
;
139 /* Libetpan now has the socket fd, and we're not interested in
140 * rest of the SockInfo struct. Let's free it, while not touching
141 * the socket itself. */
142 sock_close(sock
, FALSE
);
144 return mailimap_connect(imap
, stream
);
148 static gboolean
thread_manager_event(GIOChannel
* source
,
149 GIOCondition condition
,
156 if (condition
& G_IO_IN
)
157 g_io_channel_read_chars(source
, &ch
, 1, &bytes_read
, NULL
);
159 etpan_thread_manager_loop(thread_manager
);
164 static void imap_logger_noop(int direction
, const char * str
, size_t size
)
166 /* inhibit logging */
169 static void imap_logger_cmd(int direction
, const char * str
, size_t size
)
176 log_print(LOG_PROTOCOL
, "IMAP%c [CMD data - %"G_GSIZE_FORMAT
" bytes]\n", direction
?'>':'<', size
);
179 buf
= malloc(size
+1);
180 memset(buf
, 0, size
+1);
181 strncpy(buf
, str
, size
);
184 if (!strncmp(buf
, "<<<<<<<", 7)
185 || !strncmp(buf
, ">>>>>>>", 7)) {
189 while (strstr(buf
, "\r"))
190 *strstr(buf
, "\r") = ' ';
191 while (strlen(buf
) > 0 && buf
[strlen(buf
)-1] == '\n')
192 buf
[strlen(buf
)-1] = '\0';
194 lines
= g_strsplit(buf
, "\n", -1);
196 while (lines
[i
] && *lines
[i
]) {
197 log_print(LOG_PROTOCOL
, "IMAP%c %s\n", direction
?'>':'<', lines
[i
]);
204 static void imap_logger_fetch(int direction
, const char * str
, size_t size
)
210 if (size
> 128 && !direction
) {
211 log_print(LOG_PROTOCOL
, "IMAP%c [FETCH data - %"G_GSIZE_FORMAT
" bytes]\n", direction
?'>':'<', size
);
215 buf
= malloc(size
+1);
216 memset(buf
, 0, size
+1);
217 strncpy(buf
, str
, size
);
219 if (!strncmp(buf
, "<<<<<<<", 7)
220 || !strncmp(buf
, ">>>>>>>", 7)) {
224 while (strstr(buf
, "\r"))
225 *strstr(buf
, "\r") = ' ';
226 while (strlen(buf
) > 0 && buf
[strlen(buf
)-1] == '\n')
227 buf
[strlen(buf
)-1] = '\0';
229 lines
= g_strsplit(buf
, "\n", -1);
231 if (direction
!= 0 || (buf
[0] == '*' && buf
[1] == ' ') || size
< 32) {
232 while (lines
[i
] && *lines
[i
]) {
233 log_print(LOG_PROTOCOL
, "IMAP%c %s\n", direction
?'>':'<', lines
[i
]);
237 log_print(LOG_PROTOCOL
, "IMAP%c [data - %"G_GSIZE_FORMAT
" bytes]\n", direction
?'>':'<', size
);
243 static void imap_logger_uid(int direction
, const char * str
, size_t size
)
250 log_print(LOG_PROTOCOL
, "IMAP%c [UID data - %"G_GSIZE_FORMAT
" bytes]\n", direction
?'>':'<', size
);
253 buf
= malloc(size
+1);
254 memset(buf
, 0, size
+1);
255 strncpy(buf
, str
, size
);
257 if (!strncmp(buf
, "<<<<<<<", 7)
258 || !strncmp(buf
, ">>>>>>>", 7)) {
262 while (strstr(buf
, "\r"))
263 *strstr(buf
, "\r") = ' ';
264 while (strlen(buf
) > 0 && buf
[strlen(buf
)-1] == '\n')
265 buf
[strlen(buf
)-1] = '\0';
267 lines
= g_strsplit(buf
, "\n", -1);
269 while (lines
[i
] && *lines
[i
]) {
270 int llen
= strlen(lines
[i
]);
272 log_print(LOG_PROTOCOL
, "IMAP%c %s\n", direction
?'>':'<', lines
[i
]);
275 strncpy2(tmp
, lines
[i
], 63);
276 log_print(LOG_PROTOCOL
, "IMAP%c %s[... - %d bytes more]\n", direction
?'>':'<', tmp
,
285 static void imap_logger_append(int direction
, const char * str
, size_t size
)
292 log_print(LOG_PROTOCOL
, "IMAP%c [APPEND data - %"G_GSIZE_FORMAT
" bytes]\n", direction
?'>':'<', size
);
294 } else if (direction
== 0 && size
> 64) {
295 log_print(LOG_PROTOCOL
, "IMAP%c [APPEND data - %"G_GSIZE_FORMAT
" bytes]\n", direction
?'>':'<', size
);
298 buf
= malloc(size
+1);
299 memset(buf
, 0, size
+1);
300 strncpy(buf
, str
, size
);
302 if (!strncmp(buf
, "<<<<<<<", 7)
303 || !strncmp(buf
, ">>>>>>>", 7)) {
307 while (strstr(buf
, "\r"))
308 *strstr(buf
, "\r") = ' ';
309 while (strlen(buf
) > 0 && buf
[strlen(buf
)-1] == '\n')
310 buf
[strlen(buf
)-1] = '\0';
312 lines
= g_strsplit(buf
, "\n", -1);
314 if (direction
== 0 || (buf
[0] == '*' && buf
[1] == ' ') || size
< 64) {
315 while (lines
[i
] && *lines
[i
]) {
316 log_print(LOG_PROTOCOL
, "IMAP%c %s\n", direction
?'>':'<', lines
[i
]);
320 log_print(LOG_PROTOCOL
, "IMAP%c [data - %"G_GSIZE_FORMAT
" bytes]\n", direction
?'>':'<', size
);
326 #define ETPAN_DEFAULT_NETWORK_TIMEOUT 60
327 gboolean etpan_skip_ssl_cert_check
= FALSE
;
328 extern void mailsasl_ref(void);
330 void imap_main_init(gboolean skip_ssl_cert_check
)
332 int fd_thread_manager
;
334 etpan_skip_ssl_cert_check
= skip_ssl_cert_check
;
335 mailstream_network_delay
.tv_sec
= ETPAN_DEFAULT_NETWORK_TIMEOUT
;
336 mailstream_network_delay
.tv_usec
= 0;
338 mailstream_debug
= 1;
339 mailstream_logger
= imap_logger_cmd
;
342 imap_hash
= chash_new(CHASH_COPYKEY
, CHASH_DEFAULTSIZE
);
343 session_hash
= chash_new(CHASH_COPYKEY
, CHASH_DEFAULTSIZE
);
344 courier_workaround_hash
= chash_new(CHASH_COPYKEY
, CHASH_DEFAULTSIZE
);
346 thread_manager
= etpan_thread_manager_new();
348 fd_thread_manager
= etpan_thread_manager_get_fd(thread_manager
);
351 io_channel
= g_io_channel_unix_new(fd_thread_manager
);
353 io_channel
= g_io_channel_win32_new_fd(fd_thread_manager
);
355 thread_manager_signal
= g_io_add_watch_full(io_channel
, 0, G_IO_IN
,
356 thread_manager_event
,
361 void imap_main_set_timeout(int sec
)
363 mailstream_network_delay
.tv_sec
= sec
;
364 mailstream_network_delay
.tv_usec
= 0;
367 void imap_main_done(gboolean have_connectivity
)
369 imap_disconnect_all(have_connectivity
);
370 etpan_thread_manager_stop(thread_manager
);
371 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
374 etpan_thread_manager_join(thread_manager
);
376 g_source_remove(thread_manager_signal
);
377 g_io_channel_unref(io_channel
);
379 etpan_thread_manager_free(thread_manager
);
381 chash_free(courier_workaround_hash
);
382 chash_free(session_hash
);
383 chash_free(imap_hash
);
386 void imap_init(Folder
* folder
)
388 struct etpan_thread
* thread
;
392 thread
= etpan_thread_manager_get_thread(thread_manager
);
395 key
.len
= sizeof(folder
);
399 chash_set(imap_hash
, &key
, &value
, NULL
);
402 void imap_done(Folder
* folder
)
404 struct etpan_thread
* thread
;
410 key
.len
= sizeof(folder
);
412 r
= chash_get(imap_hash
, &key
, &value
);
418 etpan_thread_unbind(thread
);
420 chash_delete(imap_hash
, &key
, NULL
);
422 debug_print("remove thread\n");
425 static struct etpan_thread
* get_thread(Folder
* folder
)
427 struct etpan_thread
* thread
;
433 key
.len
= sizeof(folder
);
435 r
= chash_get(imap_hash
, &key
, &value
);
444 static mailimap
* get_imap(Folder
* folder
)
452 key
.len
= sizeof(folder
);
454 r
= chash_get(session_hash
, &key
, &value
);
459 debug_print("found imap %p\n", imap
);
463 static gboolean
cb_show_error(gpointer data
)
465 mainwindow_show_error();
469 static void generic_cb(int cancelled
, void * result
, void * callback_data
)
471 struct etpan_thread_op
* op
;
473 op
= (struct etpan_thread_op
*) callback_data
;
475 debug_print("generic_cb\n");
476 if (op
->imap
&& op
->imap
->imap_response_info
&&
477 op
->imap
->imap_response_info
->rsp_alert
) {
478 log_error(LOG_PROTOCOL
, "IMAP< Alert: %s\n",
479 op
->imap
->imap_response_info
->rsp_alert
);
480 g_timeout_add(10, cb_show_error
, NULL
);
485 /* Please do *not* blindly use imap pointers after this function returns,
486 * someone may have deleted it while this function was waiting for completion.
487 * Check return value to see if imap is still valid.
488 * Run get_imap(folder) again to get a fresh and valid pointer.
490 static int threaded_run(Folder
* folder
, void * param
, void * result
,
491 void (* func
)(struct etpan_thread_op
* ))
493 struct etpan_thread_op
* op
;
494 struct etpan_thread
* thread
;
495 struct mailimap
* imap
= get_imap(folder
);
497 imap_folder_ref(folder
);
499 op
= etpan_thread_op_new();
506 op
->callback
= generic_cb
;
507 op
->callback_data
= op
;
509 thread
= get_thread(folder
);
510 etpan_thread_op_schedule(thread
, op
);
512 while (!op
->finished
) {
513 gtk_main_iteration();
516 etpan_thread_op_free(op
);
518 imap_folder_unref(folder
);
520 if (imap
!= get_imap(folder
)) {
521 g_warning("returning from operation on a stale imap %p", imap
);
531 struct connect_param
{
533 PrefsAccount
*account
;
536 ProxyInfo
* proxy_info
;
539 struct connect_result
{
543 #define CHECK_IMAP() { \
544 if (!param->imap) { \
545 result->error = MAILIMAP_ERROR_BAD_STATE; \
551 static void delete_imap_run(struct etpan_thread_op
* op
)
553 mailimap
* imap
= op
->imap
;
555 /* we don't want libetpan to logout */
556 if (imap
->imap_stream
) {
557 mailstream_close(imap
->imap_stream
);
558 imap
->imap_stream
= NULL
;
564 static void threaded_delete_imap(Folder
*folder
, mailimap
*imap
)
566 struct etpan_thread_op
* op
;
568 /* No need to wait for completion, threaded_run() won't work here. */
569 op
= etpan_thread_op_new();
571 op
->run
= delete_imap_run
;
572 op
->cleanup
= etpan_thread_op_free
;
574 etpan_thread_op_schedule(get_thread(folder
), op
);
576 debug_print("threaded delete imap posted\n");
579 static void delete_imap(Folder
*folder
, mailimap
*imap
)
584 key
.len
= sizeof(folder
);
585 chash_delete(session_hash
, &key
, NULL
);
590 key
.len
= sizeof(imap
);
591 chash_delete(courier_workaround_hash
, &key
, NULL
);
592 /* We can't just free imap here as there may be ops on it pending
593 * in the thread. Posting freeing as an op will synchronize against
594 * existing jobs and as imap is already removed from session_hash
595 * we are sure no new ops can be posted. */
596 threaded_delete_imap(folder
, imap
);
599 static void connect_run(struct etpan_thread_op
* op
)
602 struct connect_param
* param
;
603 struct connect_result
* result
;
610 r
= do_mailimap_socket_connect(param
->imap
,
611 param
->server
, param
->port
, param
->proxy_info
);
617 int imap_threaded_connect(Folder
* folder
, const char * server
, int port
, ProxyInfo
*proxy_info
)
619 struct connect_param param
;
620 struct connect_result result
;
623 mailimap
* imap
, * oldimap
;
625 oldimap
= get_imap(folder
);
627 imap
= mailimap_new(0, NULL
);
630 debug_print("deleting old imap %p\n", oldimap
);
631 delete_imap(folder
, oldimap
);
635 key
.len
= sizeof(folder
);
638 chash_set(session_hash
, &key
, &value
, NULL
);
641 param
.server
= server
;
643 param
.proxy_info
= proxy_info
;
646 threaded_run(folder
, ¶m
, &result
, connect_run
);
648 debug_print("connect ok %i with imap %p\n", result
.error
, imap
);
653 static void connect_ssl_run(struct etpan_thread_op
* op
)
656 struct connect_param
* param
;
657 struct connect_result
* result
;
664 r
= do_mailimap_ssl_connect_with_callback(param
->imap
,
665 param
->server
, param
->port
,
666 etpan_connect_ssl_context_cb
, param
->account
,
671 int imap_threaded_connect_ssl(Folder
* folder
, const char * server
, int port
, ProxyInfo
*proxy_info
)
673 struct connect_param param
;
674 struct connect_result result
;
677 mailimap
* imap
, * oldimap
;
678 gboolean accept_if_valid
= FALSE
;
680 oldimap
= get_imap(folder
);
682 imap
= mailimap_new(0, NULL
);
685 debug_print("deleting old imap %p\n", oldimap
);
686 delete_imap(folder
, oldimap
);
690 key
.len
= sizeof(folder
);
693 chash_set(session_hash
, &key
, &value
, NULL
);
696 param
.server
= server
;
698 param
.account
= folder
->account
;
699 param
.proxy_info
= proxy_info
;
702 accept_if_valid
= folder
->account
->ssl_certs_auto_accept
;
705 if (threaded_run(folder
, ¶m
, &result
, connect_ssl_run
))
706 return MAILIMAP_ERROR_INVAL
;
708 if ((result
.error
== MAILIMAP_NO_ERROR_AUTHENTICATED
||
709 result
.error
== MAILIMAP_NO_ERROR_NON_AUTHENTICATED
) && !etpan_skip_ssl_cert_check
) {
710 if (etpan_certificate_check(imap
->imap_stream
, server
, port
,
711 accept_if_valid
) != TRUE
)
712 result
.error
= MAILIMAP_ERROR_SSL
;
714 debug_print("connect %d with imap %p\n", result
.error
, imap
);
725 struct mailimap_capability_data
*caps
;
728 static void capability_run(struct etpan_thread_op
* op
)
731 struct capa_param
* param
;
732 struct capa_result
* result
;
733 struct mailimap_capability_data
*caps
;
740 r
= mailimap_capability(param
->imap
, &caps
);
743 result
->caps
= (r
== 0 ? caps
: NULL
);
747 int imap_threaded_capability(Folder
*folder
, struct mailimap_capability_data
** caps
)
749 struct capa_param param
;
750 struct capa_result result
;
753 imap
= get_imap(folder
);
757 threaded_run(folder
, ¶m
, &result
, capability_run
);
759 debug_print("capa %d\n", result
.error
);
761 if (result
.error
== MAILIMAP_NO_ERROR
)
768 struct disconnect_param
{
772 struct disconnect_result
{
776 static void disconnect_run(struct etpan_thread_op
* op
)
779 struct disconnect_param
* param
;
780 struct disconnect_result
* result
;
787 r
= mailimap_logout(param
->imap
);
792 void imap_threaded_disconnect(Folder
* folder
)
794 struct connect_param param
;
795 struct connect_result result
;
798 imap
= get_imap(folder
);
800 debug_print("was disconnected\n");
806 if (threaded_run(folder
, ¶m
, &result
, disconnect_run
)) {
807 debug_print("imap already deleted %p\n", imap
);
809 debug_print("deleting old imap %p\n", imap
);
810 delete_imap(folder
, imap
);
813 debug_print("disconnect ok\n");
820 const char * wildcard
;
829 static void list_run(struct etpan_thread_op
* op
)
831 struct list_param
* param
;
832 struct list_result
* result
;
843 if (param
->base
== NULL
|| param
->wildcard
== NULL
) {
846 debug_print("no base or wildcard (%p %p)\n", param
->base
, param
->wildcard
);
850 r
= mailimap_lsub(param
->imap
, param
->base
,
851 param
->wildcard
, &list
);
853 r
= mailimap_list(param
->imap
, param
->base
,
854 param
->wildcard
, &list
);
857 debug_print("imap list run - end\n");
860 int imap_threaded_list(Folder
* folder
, const char * base
,
861 const char * wildcard
,
864 struct list_param param
;
865 struct list_result result
;
867 debug_print("imap list - begin\n");
869 param
.imap
= get_imap(folder
);
871 param
.wildcard
= wildcard
;
872 param
.sub_only
= FALSE
;
874 threaded_run(folder
, ¶m
, &result
, list_run
);
876 * p_result
= result
.list
;
878 debug_print("imap list - end %p\n", result
.list
);
883 int imap_threaded_lsub(Folder
* folder
, const char * base
,
884 const char * wildcard
,
887 struct list_param param
;
888 struct list_result result
;
890 debug_print("imap lsub - begin\n");
892 param
.imap
= get_imap(folder
);
894 param
.wildcard
= wildcard
;
895 param
.sub_only
= TRUE
;
897 threaded_run(folder
, ¶m
, &result
, list_run
);
899 * p_result
= result
.list
;
901 debug_print("imap lsub - end %p\n", result
.list
);
906 struct subscribe_param
{
912 struct subscribe_result
{
916 static void subscribe_run(struct etpan_thread_op
* op
)
918 struct subscribe_param
* param
;
919 struct subscribe_result
* result
;
927 if (param
->mb
== NULL
) {
929 debug_print("no mb\n");
932 if (param
->subscribe
)
933 r
= mailimap_subscribe(param
->imap
, param
->mb
);
935 r
= mailimap_unsubscribe(param
->imap
, param
->mb
);
937 debug_print("imap %ssubscribe run - end %d\n", param
->subscribe
?"":"un", r
);
940 int imap_threaded_subscribe(Folder
* folder
, const char * mb
,
943 struct subscribe_param param
;
944 struct subscribe_result result
;
946 debug_print("imap list - begin\n");
948 param
.imap
= get_imap(folder
);
950 param
.subscribe
= subscribe
;
952 threaded_run(folder
, ¶m
, &result
, subscribe_run
);
960 const char * password
;
965 struct login_result
{
969 static void login_run(struct etpan_thread_op
* op
)
971 struct login_param
* param
;
972 struct login_result
* result
;
974 #ifdef DISABLE_LOG_DURING_LOGIN
983 #ifdef DISABLE_LOG_DURING_LOGIN
984 old_debug
= mailstream_debug
;
985 mailstream_debug
= 0;
987 if (!strcmp(param
->type
, "plaintext"))
988 r
= mailimap_login(param
->imap
,
989 param
->login
, param
->password
);
990 else if (!strcmp(param
->type
, "GSSAPI"))
991 r
= mailimap_authenticate(param
->imap
,
992 param
->type
, param
->server
, NULL
, NULL
,
993 param
->login
, param
->login
,
994 param
->password
, NULL
);
995 else if (!strncmp(param
->type
, "SCRAM-SHA-", 10))
996 /* 7th argument has to be NULL here, to stop libetpan sending the
997 * a= attribute in its initial SCRAM-SHA-1 message to server. At least
998 * Dovecot 2.2 doesn't seem to like that, and will not authenticate
1000 r
= mailimap_authenticate(param
->imap
,
1001 param
->type
, NULL
, NULL
, NULL
,
1003 param
->password
, NULL
);
1005 else if (!strcmp(param
->type
, "XOAUTH2"))
1006 r
= mailimap_oauth2_authenticate(param
->imap
, param
->login
, param
->password
);
1009 r
= mailimap_authenticate(param
->imap
,
1010 param
->type
, NULL
, NULL
, NULL
,
1011 param
->login
, param
->login
,
1012 param
->password
, NULL
);
1013 #ifdef DISABLE_LOG_DURING_LOGIN
1014 mailstream_debug
= old_debug
;
1018 if (param
->imap
->imap_response
)
1019 imap_logger_cmd(0, param
->imap
->imap_response
, strlen(param
->imap
->imap_response
));
1020 debug_print("imap login run - end %i\n", r
);
1023 int imap_threaded_login(Folder
* folder
,
1024 const char * login
, const char * password
,
1027 struct login_param param
;
1028 struct login_result result
;
1030 debug_print("imap login - begin\n");
1033 return MAILIMAP_ERROR_INVAL
;
1035 param
.imap
= get_imap(folder
);
1036 param
.login
= login
;
1037 param
.password
= password
;
1039 if (folder
&& folder
->account
)
1040 param
.server
= folder
->account
->recv_server
;
1042 param
.server
= NULL
;
1044 threaded_run(folder
, ¶m
, &result
, login_run
);
1046 debug_print("imap login - end\n");
1048 return result
.error
;
1052 struct status_param
{
1055 struct mailimap_status_att_list
* status_att_list
;
1058 struct status_result
{
1060 struct mailimap_mailbox_data_status
* data_status
;
1063 static void status_run(struct etpan_thread_op
* op
)
1065 struct status_param
* param
;
1066 struct status_result
* result
;
1070 result
= op
->result
;
1074 r
= mailimap_status(param
->imap
, param
->mb
,
1075 param
->status_att_list
,
1076 &result
->data_status
);
1079 debug_print("imap status run - end %i\n", r
);
1082 int imap_threaded_status(Folder
* folder
, const char * mb
,
1083 struct mailimap_mailbox_data_status
** data_status
,
1086 struct status_param param
;
1087 struct status_result result
;
1088 struct mailimap_status_att_list
* status_att_list
;
1090 debug_print("imap status - begin\n");
1092 status_att_list
= mailimap_status_att_list_new_empty();
1093 if (mask
& 1 << 0) {
1094 mailimap_status_att_list_add(status_att_list
,
1095 MAILIMAP_STATUS_ATT_MESSAGES
);
1097 if (mask
& 1 << 1) {
1098 mailimap_status_att_list_add(status_att_list
,
1099 MAILIMAP_STATUS_ATT_RECENT
);
1101 if (mask
& 1 << 2) {
1102 mailimap_status_att_list_add(status_att_list
,
1103 MAILIMAP_STATUS_ATT_UIDNEXT
);
1105 if (mask
& 1 << 3) {
1106 mailimap_status_att_list_add(status_att_list
,
1107 MAILIMAP_STATUS_ATT_UIDVALIDITY
);
1109 if (mask
& 1 << 4) {
1110 mailimap_status_att_list_add(status_att_list
,
1111 MAILIMAP_STATUS_ATT_UNSEEN
);
1113 param
.imap
= get_imap(folder
);
1115 param
.status_att_list
= status_att_list
;
1117 threaded_run(folder
, ¶m
, &result
, status_run
);
1119 debug_print("imap status - end\n");
1121 * data_status
= result
.data_status
;
1123 mailimap_status_att_list_free(status_att_list
);
1125 return result
.error
;
1134 struct noop_result
{
1138 static void noop_run(struct etpan_thread_op
* op
)
1140 struct noop_param
* param
;
1141 struct noop_result
* result
;
1145 result
= op
->result
;
1149 r
= mailimap_noop(param
->imap
);
1152 debug_print("imap noop run - end %i\n", r
);
1155 int imap_threaded_noop(Folder
* folder
, unsigned int * p_exists
,
1156 unsigned int *p_recent
,
1157 unsigned int *p_expunge
,
1158 unsigned int *p_unseen
,
1159 unsigned int *p_uidnext
,
1160 unsigned int *p_uidval
)
1162 struct noop_param param
;
1163 struct noop_result result
;
1166 debug_print("imap noop - begin\n");
1168 imap
= get_imap(folder
);
1171 if (threaded_run(folder
, ¶m
, &result
, noop_run
))
1172 return MAILIMAP_ERROR_INVAL
;
1174 if (result
.error
== 0 && imap
&& imap
->imap_selection_info
!= NULL
) {
1175 * p_exists
= imap
->imap_selection_info
->sel_exists
;
1176 * p_recent
= imap
->imap_selection_info
->sel_recent
;
1177 * p_unseen
= imap
->imap_selection_info
->sel_unseen
;
1178 * p_uidnext
= imap
->imap_selection_info
->sel_uidnext
;
1179 * p_uidval
= imap
->imap_selection_info
->sel_uidvalidity
;
1187 if (result
.error
== 0 && imap
&& imap
->imap_response_info
!= NULL
&&
1188 imap
->imap_response_info
->rsp_expunged
!= NULL
) {
1189 * p_expunge
= clist_count(imap
->imap_response_info
->rsp_expunged
);
1193 debug_print("imap noop - end [EXISTS %d RECENT %d EXPUNGE %d UNSEEN %d UIDNEXT %d UIDVAL %d]\n",
1194 *p_exists
, *p_recent
, *p_expunge
, *p_unseen
,
1195 *p_uidnext
, *p_uidval
);
1197 return result
.error
;
1201 struct starttls_result
{
1205 static void starttls_run(struct etpan_thread_op
* op
)
1207 struct connect_param
* param
;
1208 struct starttls_result
* result
;
1212 result
= op
->result
;
1216 r
= mailimap_starttls(param
->imap
);
1219 debug_print("imap STARTTLS run - end %i\n", r
);
1222 mailimap
*imap
= param
->imap
;
1223 mailstream_low
*plain_low
= NULL
;
1224 mailstream_low
*tls_low
= NULL
;
1227 plain_low
= mailstream_get_low(imap
->imap_stream
);
1228 fd
= mailstream_low_get_fd(plain_low
);
1230 debug_print("imap STARTTLS run - can't get fd\n");
1231 result
->error
= MAILIMAP_ERROR_STREAM
;
1235 tls_low
= mailstream_low_tls_open_with_callback(fd
, etpan_connect_ssl_context_cb
, param
->account
);
1236 if (tls_low
== NULL
) {
1237 debug_print("imap STARTTLS run - can't tls_open\n");
1238 result
->error
= MAILIMAP_ERROR_STREAM
;
1241 mailstream_low_free(plain_low
);
1242 mailstream_set_low(imap
->imap_stream
, tls_low
);
1246 int imap_threaded_starttls(Folder
* folder
, const gchar
*host
, int port
)
1248 struct connect_param param
;
1249 struct starttls_result result
;
1250 gboolean accept_if_valid
= FALSE
;
1252 debug_print("imap STARTTLS - begin\n");
1254 param
.imap
= get_imap(folder
);
1255 param
.server
= host
;
1257 param
.account
= folder
->account
;
1259 if (folder
->account
)
1260 accept_if_valid
= folder
->account
->ssl_certs_auto_accept
;
1262 if (threaded_run(folder
, ¶m
, &result
, starttls_run
))
1263 return MAILIMAP_ERROR_INVAL
;
1265 debug_print("imap STARTTLS - end\n");
1267 if (result
.error
== 0 && param
.imap
&& !etpan_skip_ssl_cert_check
) {
1268 if (etpan_certificate_check(param
.imap
->imap_stream
, host
, port
,
1269 accept_if_valid
) != TRUE
)
1270 return MAILIMAP_ERROR_SSL
;
1272 return result
.error
;
1276 struct create_param
{
1281 struct create_result
{
1285 static void create_run(struct etpan_thread_op
* op
)
1287 struct create_param
* param
;
1288 struct create_result
* result
;
1292 result
= op
->result
;
1296 r
= mailimap_create(param
->imap
, param
->mb
);
1299 debug_print("imap create run - end %i\n", r
);
1302 int imap_threaded_create(Folder
* folder
, const char * mb
)
1304 struct create_param param
;
1305 struct create_result result
;
1307 debug_print("imap create - begin\n");
1309 param
.imap
= get_imap(folder
);
1312 threaded_run(folder
, ¶m
, &result
, create_run
);
1314 debug_print("imap create - end\n");
1316 return result
.error
;
1322 struct rename_param
{
1325 const char * new_name
;
1328 struct rename_result
{
1332 static void rename_run(struct etpan_thread_op
* op
)
1334 struct rename_param
* param
;
1335 struct rename_result
* result
;
1339 result
= op
->result
;
1343 r
= mailimap_rename(param
->imap
, param
->mb
, param
->new_name
);
1346 debug_print("imap rename run - end %i\n", r
);
1349 int imap_threaded_rename(Folder
* folder
,
1350 const char * mb
, const char * new_name
)
1352 struct rename_param param
;
1353 struct rename_result result
;
1355 debug_print("imap rename - begin\n");
1357 param
.imap
= get_imap(folder
);
1359 param
.new_name
= new_name
;
1361 threaded_run(folder
, ¶m
, &result
, rename_run
);
1363 debug_print("imap rename - end\n");
1365 return result
.error
;
1371 struct delete_param
{
1376 struct delete_result
{
1380 static void delete_run(struct etpan_thread_op
* op
)
1382 struct delete_param
* param
;
1383 struct delete_result
* result
;
1387 result
= op
->result
;
1391 r
= mailimap_delete(param
->imap
, param
->mb
);
1394 debug_print("imap delete run - end %i\n", r
);
1397 int imap_threaded_delete(Folder
* folder
, const char * mb
)
1399 struct delete_param param
;
1400 struct delete_result result
;
1402 debug_print("imap delete - begin\n");
1404 param
.imap
= get_imap(folder
);
1407 threaded_run(folder
, ¶m
, &result
, delete_run
);
1409 debug_print("imap delete - end\n");
1411 return result
.error
;
1416 struct select_param
{
1421 struct select_result
{
1425 static void select_run(struct etpan_thread_op
* op
)
1427 struct select_param
* param
;
1428 struct select_result
* result
;
1432 result
= op
->result
;
1436 r
= mailimap_select(param
->imap
, param
->mb
);
1439 debug_print("imap select run - end %i\n", r
);
1442 int imap_threaded_select(Folder
* folder
, const char * mb
,
1443 gint
* exists
, gint
* recent
, gint
* unseen
,
1444 guint32
* uid_validity
,gint
*can_create_flags
,
1447 struct select_param param
;
1448 struct select_result result
;
1451 debug_print("imap select - begin\n");
1453 imap
= get_imap(folder
);
1457 if (threaded_run(folder
, ¶m
, &result
, select_run
))
1458 return MAILIMAP_ERROR_INVAL
;
1460 if (result
.error
!= MAILIMAP_NO_ERROR
)
1461 return result
.error
;
1463 if (!imap
|| imap
->imap_selection_info
== NULL
)
1464 return MAILIMAP_ERROR_PARSE
;
1466 * exists
= imap
->imap_selection_info
->sel_exists
;
1467 * recent
= imap
->imap_selection_info
->sel_recent
;
1468 * unseen
= imap
->imap_selection_info
->sel_unseen
;
1469 * uid_validity
= imap
->imap_selection_info
->sel_uidvalidity
;
1470 * can_create_flags
= FALSE
;
1472 if (imap
->imap_selection_info
->sel_perm_flags
) {
1473 GSList
*t_flags
= NULL
;
1474 clistiter
*cur
= NULL
;
1475 if (imap
->imap_selection_info
->sel_perm_flags
)
1476 cur
= clist_begin(imap
->imap_selection_info
->sel_perm_flags
);
1478 for (; cur
; cur
= clist_next(cur
)) {
1479 struct mailimap_flag_perm
*flag
= (struct mailimap_flag_perm
*)clist_content(cur
);
1480 if (flag
->fl_type
== MAILIMAP_FLAG_PERM_ALL
)
1481 *can_create_flags
= TRUE
;
1482 else if (flag
->fl_flag
&&
1483 flag
->fl_flag
->fl_type
== 6 &&
1484 !strcmp(flag
->fl_flag
->fl_data
.fl_extension
, "*"))
1485 *can_create_flags
= TRUE
;
1486 if (flag
->fl_flag
&& ok_flags
) {
1487 MsgPermFlags c_flag
= 0;
1488 switch (flag
->fl_flag
->fl_type
) {
1489 case MAILIMAP_FLAG_ANSWERED
:
1490 c_flag
= IMAP_FLAG_ANSWERED
;
1492 case MAILIMAP_FLAG_FLAGGED
:
1493 c_flag
= IMAP_FLAG_FLAGGED
;
1495 case MAILIMAP_FLAG_DELETED
:
1496 c_flag
= IMAP_FLAG_DELETED
;
1498 case MAILIMAP_FLAG_DRAFT
:
1499 c_flag
= IMAP_FLAG_DRAFT
;
1501 case MAILIMAP_FLAG_SEEN
:
1502 c_flag
= IMAP_FLAG_SEEN
;
1504 case MAILIMAP_FLAG_KEYWORD
:
1505 if (!strcasecmp(flag
->fl_flag
->fl_data
.fl_keyword
, RTAG_FORWARDED
))
1506 c_flag
= IMAP_FLAG_FORWARDED
;
1507 if (!strcasecmp(flag
->fl_flag
->fl_data
.fl_keyword
, RTAG_JUNK
))
1508 c_flag
= IMAP_FLAG_SPAM
;
1509 if (!strcasecmp(flag
->fl_flag
->fl_data
.fl_keyword
, RTAG_NON_JUNK
) ||
1510 !strcasecmp(flag
->fl_flag
->fl_data
.fl_keyword
, RTAG_NO_JUNK
) ||
1511 !strcasecmp(flag
->fl_flag
->fl_data
.fl_keyword
, RTAG_NOT_JUNK
))
1512 c_flag
= IMAP_FLAG_HAM
;
1518 t_flags
= g_slist_prepend(t_flags
,
1519 GUINT_TO_POINTER(c_flag
));
1524 *ok_flags
= t_flags
;
1526 debug_print("imap select - end\n");
1528 return result
.error
;
1531 static void close_run(struct etpan_thread_op
* op
)
1533 struct select_param
* param
;
1534 struct select_result
* result
;
1538 result
= op
->result
;
1542 r
= mailimap_close(param
->imap
);
1545 debug_print("imap close run - end %i\n", r
);
1548 int imap_threaded_close(Folder
* folder
)
1550 struct select_param param
;
1551 struct select_result result
;
1554 debug_print("imap close - begin\n");
1556 imap
= get_imap(folder
);
1559 threaded_run(folder
, ¶m
, &result
, close_run
);
1561 if (result
.error
!= MAILIMAP_NO_ERROR
)
1562 return result
.error
;
1564 debug_print("imap close - end\n");
1566 return result
.error
;
1569 struct examine_param
{
1574 struct examine_result
{
1578 static void examine_run(struct etpan_thread_op
* op
)
1580 struct examine_param
* param
;
1581 struct examine_result
* result
;
1585 result
= op
->result
;
1589 r
= mailimap_examine(param
->imap
, param
->mb
);
1592 debug_print("imap examine run - end %i\n", r
);
1595 int imap_threaded_examine(Folder
* folder
, const char * mb
,
1596 gint
* exists
, gint
* recent
, gint
* unseen
,
1597 guint32
* uid_validity
)
1599 struct examine_param param
;
1600 struct examine_result result
;
1603 debug_print("imap examine - begin\n");
1605 imap
= get_imap(folder
);
1609 if (threaded_run(folder
, ¶m
, &result
, examine_run
))
1610 return MAILIMAP_ERROR_INVAL
;
1612 if (result
.error
!= MAILIMAP_NO_ERROR
)
1613 return result
.error
;
1615 if (!imap
|| imap
->imap_selection_info
== NULL
)
1616 return MAILIMAP_ERROR_PARSE
;
1618 * exists
= imap
->imap_selection_info
->sel_exists
;
1619 * recent
= imap
->imap_selection_info
->sel_recent
;
1620 * unseen
= imap
->imap_selection_info
->sel_unseen
;
1621 * uid_validity
= imap
->imap_selection_info
->sel_uidvalidity
;
1623 debug_print("imap examine - end\n");
1625 return result
.error
;
1631 struct search_param
{
1634 const char *charset
;
1635 struct mailimap_set
* set
;
1639 struct search_result
{
1641 clist
* search_result
;
1644 static struct mailimap_set_item
*sc_mailimap_set_item_copy(struct mailimap_set_item
*orig
)
1646 return mailimap_set_item_new(orig
->set_first
, orig
->set_last
);
1649 static struct mailimap_set
*sc_mailimap_set_copy(struct mailimap_set
*orig
)
1651 clist
*list
= orig
? orig
->set_list
: NULL
;
1658 newlist
= clist_new();
1662 for (cur
= clist_begin(list
); cur
; cur
= clist_next(cur
)) {
1663 if (clist_append(newlist
,
1664 sc_mailimap_set_item_copy(
1665 (struct mailimap_set_item
*)clist_content(cur
))) != 0) {
1666 clist_free(newlist
);
1670 return mailimap_set_new(newlist
);
1673 static void search_run(struct etpan_thread_op
* op
)
1675 struct search_param
* param
;
1676 struct search_result
* result
;
1678 struct mailimap_search_key
* key
= NULL
;
1679 struct mailimap_search_key
* uid_key
= NULL
;
1680 struct mailimap_search_key
* search_type_key
= NULL
;
1681 clist
* search_result
;
1684 result
= op
->result
;
1688 /* we copy the mailimap_set because freeing the key is recursive */
1689 if (param
->set
!= NULL
) {
1690 uid_key
= mailimap_search_key_new_uid(sc_mailimap_set_copy(param
->set
));
1691 } else if (param
->type
== IMAP_SEARCH_TYPE_SIMPLE
) {
1692 uid_key
= mailimap_search_key_new_all();
1694 switch (param
->type
) {
1695 case IMAP_SEARCH_TYPE_SIMPLE
:
1696 search_type_key
= NULL
;
1698 case IMAP_SEARCH_TYPE_SEEN
:
1699 search_type_key
= imap_search_new(IMAP_SEARCH_CRITERIA_READ
, NULL
, NULL
, 0);
1701 case IMAP_SEARCH_TYPE_UNSEEN
:
1702 search_type_key
= imap_search_new(IMAP_SEARCH_CRITERIA_UNREAD
, NULL
, NULL
, 0);
1704 case IMAP_SEARCH_TYPE_ANSWERED
:
1705 search_type_key
= imap_search_new(IMAP_SEARCH_CRITERIA_REPLIED
, NULL
, NULL
, 0);
1707 case IMAP_SEARCH_TYPE_FLAGGED
:
1708 search_type_key
= imap_search_new(IMAP_SEARCH_CRITERIA_MARKED
, NULL
, NULL
, 0);
1710 case IMAP_SEARCH_TYPE_DELETED
:
1711 search_type_key
= imap_search_new(IMAP_SEARCH_CRITERIA_DELETED
, NULL
, NULL
, 0);
1713 case IMAP_SEARCH_TYPE_FORWARDED
:
1714 search_type_key
= imap_search_new(IMAP_SEARCH_CRITERIA_TAG
, NULL
, RTAG_FORWARDED
, 0);
1716 case IMAP_SEARCH_TYPE_SPAM
:
1717 search_type_key
= imap_search_new(IMAP_SEARCH_CRITERIA_TAG
, NULL
, RTAG_JUNK
, 0);
1719 case IMAP_SEARCH_TYPE_KEYED
:
1720 search_type_key
= param
->key
;
1724 if (search_type_key
!= NULL
) {
1725 if (param
->set
!= NULL
) {
1726 key
= mailimap_search_key_new_multiple_empty();
1727 mailimap_search_key_multiple_add(key
, search_type_key
);
1728 mailimap_search_key_multiple_add(key
, uid_key
);
1730 key
= search_type_key
;
1732 } else if (uid_key
!= NULL
) {
1737 g_warning("no key!");
1738 result
= op
->result
;
1740 result
->search_result
= NULL
;
1742 mailstream_logger
= imap_logger_uid
;
1744 r
= mailimap_uid_search(param
->imap
, param
->charset
, key
, &search_result
);
1746 mailstream_logger
= imap_logger_cmd
;
1748 /* free the key (with the imapset) */
1749 mailimap_search_key_free(key
);
1752 result
->search_result
= search_result
;
1754 debug_print("imap search run - end %i\n", result
->error
);
1757 int imap_threaded_search(Folder
* folder
, int search_type
, IMAPSearchKey
* key
,
1758 const char *charset
, struct mailimap_set
* set
,
1759 clist
** search_result
)
1761 struct search_param param
;
1762 struct search_result result
;
1765 debug_print("imap search - begin\n");
1767 imap
= get_imap(folder
);
1770 param
.charset
= charset
;
1771 param
.type
= search_type
;
1774 threaded_run(folder
, ¶m
, &result
, search_run
);
1776 if (result
.error
!= MAILIMAP_NO_ERROR
)
1777 return result
.error
;
1779 debug_print("imap search - end\n");
1781 * search_result
= result
.search_result
;
1783 return result
.error
;
1787 struct _IMAPSearchKey
{
1788 struct mailimap_search_key
* key
;
1791 IMAPSearchKey
* imap_search_new(gint criteria
,
1792 const gchar
*header
,
1796 char* sk_bcc
= NULL
;
1797 struct mailimap_date
* sk_before
= NULL
;
1798 char* sk_body
= NULL
;
1800 char* sk_from
= NULL
;
1801 char* sk_keyword
= NULL
;
1802 struct mailimap_date
* sk_on
= NULL
;
1803 struct mailimap_date
* sk_since
= NULL
;
1804 char* sk_subject
= NULL
;
1805 char* sk_text
= NULL
;
1807 char* sk_unkeyword
= NULL
;
1808 char* sk_header_name
= NULL
;
1809 char* sk_header_value
= NULL
;
1810 uint32_t sk_larger
= 0;
1811 struct mailimap_search_key
* sk_not
= NULL
;
1812 struct mailimap_search_key
* sk_or1
= NULL
;
1813 struct mailimap_search_key
* sk_or2
= NULL
;
1814 struct mailimap_date
* sk_sentbefore
= NULL
;
1815 struct mailimap_date
* sk_senton
= NULL
;
1816 struct mailimap_date
* sk_sentsince
= NULL
;
1817 uint32_t sk_smaller
= 0;
1818 struct mailimap_set
* sk_uid
= NULL
;
1819 struct mailimap_set
* sk_set
= NULL
;
1820 clist
* sk_multiple
= NULL
;
1821 int etpan_matcher_type
;
1824 case IMAP_SEARCH_CRITERIA_ALL
: etpan_matcher_type
= MAILIMAP_SEARCH_KEY_ALL
; break;
1825 case IMAP_SEARCH_CRITERIA_READ
: etpan_matcher_type
= MAILIMAP_SEARCH_KEY_SEEN
; break;
1826 case IMAP_SEARCH_CRITERIA_UNREAD
: etpan_matcher_type
= MAILIMAP_SEARCH_KEY_UNSEEN
; break;
1827 case IMAP_SEARCH_CRITERIA_NEW
: etpan_matcher_type
= MAILIMAP_SEARCH_KEY_NEW
; break;
1828 case IMAP_SEARCH_CRITERIA_MARKED
: etpan_matcher_type
= MAILIMAP_SEARCH_KEY_FLAGGED
; break;
1829 case IMAP_SEARCH_CRITERIA_REPLIED
: etpan_matcher_type
= MAILIMAP_SEARCH_KEY_ANSWERED
; break;
1830 case IMAP_SEARCH_CRITERIA_DELETED
: etpan_matcher_type
= MAILIMAP_SEARCH_KEY_DELETED
; break;
1832 case IMAP_SEARCH_CRITERIA_TAG
:
1833 sk_keyword
= strdup(expr
);
1834 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_KEYWORD
;
1837 case IMAP_SEARCH_CRITERIA_SUBJECT
:
1838 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_SUBJECT
;
1839 sk_subject
= strdup(expr
);
1842 case IMAP_SEARCH_CRITERIA_TO
:
1843 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_TO
;
1844 sk_to
= strdup(expr
);
1847 case IMAP_SEARCH_CRITERIA_CC
:
1848 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_CC
;
1849 sk_cc
= strdup(expr
);
1852 case IMAP_SEARCH_CRITERIA_AGE_GREATER
:
1853 case IMAP_SEARCH_CRITERIA_AGE_LOWER
:
1856 time_t limit
= time(NULL
) - 60 * 60 * 24 * value
;
1859 localtime_r(&limit
, &tm
);
1860 if (criteria
== IMAP_SEARCH_CRITERIA_AGE_GREATER
) {
1861 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_SENTBEFORE
;
1862 sk_sentbefore
= mailimap_date_new(tm
.tm_mday
, tm
.tm_mon
, tm
.tm_year
+ 1900);
1864 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_SENTSINCE
;
1865 sk_sentsince
= mailimap_date_new(tm
.tm_mday
, tm
.tm_mon
, tm
.tm_year
+ 1900);
1870 case IMAP_SEARCH_CRITERIA_BODY
:
1871 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_BODY
;
1872 sk_body
= strdup(expr
);
1875 case IMAP_SEARCH_CRITERIA_MESSAGE
:
1876 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_TEXT
;
1877 sk_text
= strdup(expr
);
1880 case IMAP_SEARCH_CRITERIA_HEADER
:
1881 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_HEADER
;
1882 sk_header_name
= strdup(header
);
1883 sk_header_value
= strdup(expr
);
1886 case IMAP_SEARCH_CRITERIA_FROM
:
1887 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_FROM
;
1888 sk_from
= strdup(expr
);
1891 case IMAP_SEARCH_CRITERIA_SIZE_GREATER
:
1892 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_LARGER
;
1896 case IMAP_SEARCH_CRITERIA_SIZE_SMALLER
:
1897 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_SMALLER
;
1905 return mailimap_search_key_new(etpan_matcher_type
,
1906 sk_bcc
, sk_before
, sk_body
, sk_cc
, sk_from
, sk_keyword
,
1907 sk_on
, sk_since
, sk_subject
, sk_text
, sk_to
,
1908 sk_unkeyword
, sk_header_name
,sk_header_value
, sk_larger
,
1909 sk_not
, sk_or1
, sk_or2
, sk_sentbefore
, sk_senton
,
1910 sk_sentsince
, sk_smaller
, sk_uid
, sk_set
, sk_multiple
);
1913 IMAPSearchKey
* imap_search_not(IMAPSearchKey
* key
)
1915 return mailimap_search_key_new_not(key
);
1918 IMAPSearchKey
* imap_search_or(IMAPSearchKey
* l
, IMAPSearchKey
* r
)
1920 return mailimap_search_key_new_or(l
, r
);
1923 IMAPSearchKey
* imap_search_and(IMAPSearchKey
* l
, IMAPSearchKey
* r
)
1925 IMAPSearchKey
* result
= mailimap_search_key_new_multiple_empty();
1926 mailimap_search_key_multiple_add(result
, l
);
1927 mailimap_search_key_multiple_add(result
, r
);
1932 void imap_search_free(IMAPSearchKey
* key
)
1937 mailimap_search_key_free(key
);
1942 static int imap_get_msg_att_info(struct mailimap_msg_att
* msg_att
,
1946 struct mailimap_msg_att_dynamic
** patt_dyn
);
1949 result_to_uid_list(clist
* fetch_result
, carray
** result
)
1951 clistiter
* cur
= NULL
;
1956 tab
= carray_new(128);
1958 res
= MAILIMAP_ERROR_MEMORY
;
1963 cur
= clist_begin(fetch_result
);
1965 for(; cur
!= NULL
; cur
= clist_next(cur
)) {
1966 struct mailimap_msg_att
* msg_att
;
1970 msg_att
= clist_content(cur
);
1973 imap_get_msg_att_info(msg_att
, &uid
, NULL
, NULL
, NULL
);
1975 puid
= malloc(sizeof(* puid
));
1977 res
= MAILIMAP_ERROR_MEMORY
;
1982 r
= carray_add(tab
, puid
, NULL
);
1985 res
= MAILIMAP_ERROR_MEMORY
;
1992 return MAILIMAP_NO_ERROR
;
1995 imap_fetch_uid_list_free(tab
);
2000 static int imap_get_messages_list(mailimap
* imap
,
2001 uint32_t first_index
,
2006 struct mailimap_fetch_att
* fetch_att
;
2007 struct mailimap_fetch_type
* fetch_type
;
2008 struct mailimap_set
* set
;
2009 clist
* fetch_result
;
2012 set
= mailimap_set_new_interval(first_index
, 0);
2014 res
= MAILIMAP_ERROR_MEMORY
;
2018 fetch_type
= mailimap_fetch_type_new_fetch_att_list_empty();
2019 if (fetch_type
== NULL
) {
2020 res
= MAILIMAP_ERROR_MEMORY
;
2024 fetch_att
= mailimap_fetch_att_new_uid();
2025 if (fetch_att
== NULL
) {
2026 res
= MAILIMAP_ERROR_MEMORY
;
2027 goto free_fetch_type
;
2030 r
= mailimap_fetch_type_new_fetch_att_list_add(fetch_type
, fetch_att
);
2031 if (r
!= MAILIMAP_NO_ERROR
) {
2032 mailimap_fetch_att_free(fetch_att
);
2033 res
= MAILIMAP_ERROR_MEMORY
;
2034 goto free_fetch_type
;
2037 mailstream_logger
= imap_logger_fetch
;
2039 r
= mailimap_uid_fetch(imap
, set
,
2040 fetch_type
, &fetch_result
);
2042 mailstream_logger
= imap_logger_cmd
;
2043 mailimap_fetch_type_free(fetch_type
);
2044 mailimap_set_free(set
);
2046 if (r
!= MAILIMAP_NO_ERROR
) {
2052 r
= result_to_uid_list(fetch_result
, &env_list
);
2053 mailimap_fetch_list_free(fetch_result
);
2055 * result
= env_list
;
2057 return MAILIMAP_NO_ERROR
;
2060 mailimap_fetch_type_free(fetch_type
);
2062 mailimap_set_free(set
);
2070 struct fetch_uid_param
{
2072 uint32_t first_index
;
2075 struct fetch_uid_result
{
2077 carray
* fetch_result
;
2080 static void fetch_uid_run(struct etpan_thread_op
* op
)
2082 struct fetch_uid_param
* param
;
2083 struct fetch_uid_result
* result
;
2084 carray
* fetch_result
;
2088 result
= op
->result
;
2092 fetch_result
= NULL
;
2093 mailstream_logger
= imap_logger_noop
;
2094 log_print(LOG_PROTOCOL
, "IMAP- [fetching UIDs...]\n");
2096 r
= imap_get_messages_list(param
->imap
, param
->first_index
,
2099 mailstream_logger
= imap_logger_cmd
;
2102 result
->fetch_result
= fetch_result
;
2103 debug_print("imap fetch_uid run - end %i\n", r
);
2106 int imap_threaded_fetch_uid(Folder
* folder
, uint32_t first_index
,
2107 carray
** fetch_result
)
2109 struct fetch_uid_param param
;
2110 struct fetch_uid_result result
;
2113 debug_print("imap fetch_uid - begin\n");
2115 imap
= get_imap(folder
);
2117 param
.first_index
= first_index
;
2119 threaded_run(folder
, ¶m
, &result
, fetch_uid_run
);
2121 if (result
.error
!= MAILIMAP_NO_ERROR
)
2122 return result
.error
;
2124 debug_print("imap fetch_uid - end\n");
2126 * fetch_result
= result
.fetch_result
;
2128 return result
.error
;
2132 void imap_fetch_uid_list_free(carray
* uid_list
)
2136 for(i
= 0 ; i
< carray_count(uid_list
) ; i
++) {
2139 puid
= carray_get(uid_list
, i
);
2142 carray_free(uid_list
);
2148 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic
* att_dyn
, GSList
**tags
);
2151 result_to_uid_flags_list(clist
* fetch_result
, carray
** result
)
2153 clistiter
* cur
= NULL
;
2157 GSList
*tags
= NULL
;
2159 tab
= carray_new(128);
2161 res
= MAILIMAP_ERROR_MEMORY
;
2166 cur
= clist_begin(fetch_result
);
2168 for(; cur
!= NULL
; cur
= clist_next(cur
)) {
2169 struct mailimap_msg_att
* msg_att
;
2172 struct mailimap_msg_att_dynamic
* att_dyn
;
2178 msg_att
= clist_content(cur
);
2182 imap_get_msg_att_info(msg_att
, &uid
, NULL
, NULL
, &att_dyn
);
2185 if (att_dyn
== NULL
)
2188 flags
= imap_flags_to_flags(att_dyn
, &tags
);
2190 puid
= malloc(sizeof(* puid
));
2192 res
= MAILIMAP_ERROR_MEMORY
;
2197 r
= carray_add(tab
, puid
, NULL
);
2200 res
= MAILIMAP_ERROR_MEMORY
;
2203 pflags
= malloc(sizeof(* pflags
));
2204 if (pflags
== NULL
) {
2205 res
= MAILIMAP_ERROR_MEMORY
;
2209 r
= carray_add(tab
, pflags
, NULL
);
2212 res
= MAILIMAP_ERROR_MEMORY
;
2215 r
= carray_add(tab
, tags
, NULL
);
2218 res
= MAILIMAP_ERROR_MEMORY
;
2225 return MAILIMAP_NO_ERROR
;
2228 imap_fetch_uid_flags_list_free(tab
);
2229 slist_free_strings_full(tags
);
2234 static int imap_get_messages_flags_list(mailimap
* imap
,
2235 uint32_t first_index
,
2240 struct mailimap_fetch_att
* fetch_att
;
2241 struct mailimap_fetch_type
* fetch_type
;
2242 struct mailimap_set
* set
;
2243 clist
* fetch_result
;
2246 set
= mailimap_set_new_interval(first_index
, 0);
2248 res
= MAILIMAP_ERROR_MEMORY
;
2252 fetch_type
= mailimap_fetch_type_new_fetch_att_list_empty();
2253 if (fetch_type
== NULL
) {
2254 res
= MAILIMAP_ERROR_MEMORY
;
2258 fetch_att
= mailimap_fetch_att_new_flags();
2259 if (fetch_att
== NULL
) {
2260 res
= MAILIMAP_ERROR_MEMORY
;
2261 goto free_fetch_type
;
2264 r
= mailimap_fetch_type_new_fetch_att_list_add(fetch_type
, fetch_att
);
2265 if (r
!= MAILIMAP_NO_ERROR
) {
2266 mailimap_fetch_att_free(fetch_att
);
2267 res
= MAILIMAP_ERROR_MEMORY
;
2268 goto free_fetch_type
;
2271 fetch_att
= mailimap_fetch_att_new_uid();
2272 if (fetch_att
== NULL
) {
2273 res
= MAILIMAP_ERROR_MEMORY
;
2274 goto free_fetch_type
;
2277 r
= mailimap_fetch_type_new_fetch_att_list_add(fetch_type
, fetch_att
);
2278 if (r
!= MAILIMAP_NO_ERROR
) {
2279 mailimap_fetch_att_free(fetch_att
);
2280 res
= MAILIMAP_ERROR_MEMORY
;
2281 goto free_fetch_type
;
2284 mailstream_logger
= imap_logger_fetch
;
2286 r
= mailimap_uid_fetch(imap
, set
,
2287 fetch_type
, &fetch_result
);
2289 mailstream_logger
= imap_logger_cmd
;
2290 mailimap_fetch_type_free(fetch_type
);
2291 mailimap_set_free(set
);
2293 if (r
!= MAILIMAP_NO_ERROR
) {
2299 r
= result_to_uid_flags_list(fetch_result
, &env_list
);
2300 mailimap_fetch_list_free(fetch_result
);
2302 * result
= env_list
;
2304 return MAILIMAP_NO_ERROR
;
2307 mailimap_fetch_type_free(fetch_type
);
2309 mailimap_set_free(set
);
2316 static void fetch_uid_flags_run(struct etpan_thread_op
* op
)
2318 struct fetch_uid_param
* param
;
2319 struct fetch_uid_result
* result
;
2320 carray
* fetch_result
;
2324 result
= op
->result
;
2328 fetch_result
= NULL
;
2329 r
= imap_get_messages_flags_list(param
->imap
, param
->first_index
,
2333 result
->fetch_result
= fetch_result
;
2334 debug_print("imap fetch_uid run - end %i\n", r
);
2337 int imap_threaded_fetch_uid_flags(Folder
* folder
, uint32_t first_index
,
2338 carray
** fetch_result
)
2340 struct fetch_uid_param param
;
2341 struct fetch_uid_result result
;
2344 debug_print("imap fetch_uid - begin\n");
2346 imap
= get_imap(folder
);
2348 param
.first_index
= first_index
;
2350 mailstream_logger
= imap_logger_noop
;
2351 log_print(LOG_PROTOCOL
, "IMAP- [fetching flags...]\n");
2353 threaded_run(folder
, ¶m
, &result
, fetch_uid_flags_run
);
2355 mailstream_logger
= imap_logger_cmd
;
2358 if (result
.error
!= MAILIMAP_NO_ERROR
)
2359 return result
.error
;
2361 debug_print("imap fetch_uid - end\n");
2363 * fetch_result
= result
.fetch_result
;
2365 return result
.error
;
2369 void imap_fetch_uid_flags_list_free(carray
* uid_flags_list
)
2373 for(i
= 0 ; i
< carray_count(uid_flags_list
) ; i
+= 3) {
2376 data
= carray_get(uid_flags_list
, i
);
2378 data
= carray_get(uid_flags_list
, i
+ 1);
2381 carray_free(uid_flags_list
);
2386 static int imap_fetch(mailimap
* imap
,
2389 size_t * result_len
)
2392 struct mailimap_set
* set
;
2393 struct mailimap_fetch_att
* fetch_att
;
2394 struct mailimap_fetch_type
* fetch_type
;
2395 clist
* fetch_result
;
2396 struct mailimap_msg_att
* msg_att
;
2397 struct mailimap_msg_att_item
* msg_att_item
;
2402 struct mailimap_section
* section
;
2404 set
= mailimap_set_new_single(msg_index
);
2406 res
= MAILIMAP_ERROR_MEMORY
;
2410 section
= mailimap_section_new(NULL
);
2411 if (section
== NULL
) {
2412 res
= MAILIMAP_ERROR_MEMORY
;
2416 fetch_att
= mailimap_fetch_att_new_body_peek_section(section
);
2417 if (fetch_att
== NULL
) {
2418 mailimap_section_free(section
);
2419 res
= MAILIMAP_ERROR_MEMORY
;
2423 fetch_type
= mailimap_fetch_type_new_fetch_att(fetch_att
);
2424 if (fetch_type
== NULL
) {
2425 res
= MAILIMAP_ERROR_MEMORY
;
2426 goto free_fetch_att
;
2429 mailstream_logger
= imap_logger_fetch
;
2431 r
= mailimap_uid_fetch(imap
, set
,
2432 fetch_type
, &fetch_result
);
2434 mailstream_logger
= imap_logger_cmd
;
2436 mailimap_fetch_type_free(fetch_type
);
2437 mailimap_set_free(set
);
2440 case MAILIMAP_NO_ERROR
:
2446 if (fetch_result
== NULL
|| clist_begin(fetch_result
) == NULL
) {
2447 mailimap_fetch_list_free(fetch_result
);
2448 return MAILIMAP_ERROR_FETCH
;
2451 msg_att
= clist_begin(fetch_result
)->data
;
2456 if (msg_att
->att_list
)
2457 cur
= clist_begin(msg_att
->att_list
);
2461 for(; cur
!= NULL
; cur
= clist_next(cur
)) {
2462 msg_att_item
= clist_content(cur
);
2464 if (msg_att_item
->att_type
== MAILIMAP_MSG_ATT_ITEM_STATIC
) {
2465 if (msg_att_item
->att_data
.att_static
->att_type
==
2466 MAILIMAP_MSG_ATT_BODY_SECTION
) {
2467 text
= msg_att_item
->att_data
.att_static
->att_data
.att_body_section
->sec_body_part
;
2469 msg_att_item
->att_data
.att_static
->att_data
.att_body_section
->sec_body_part
= NULL
;
2471 msg_att_item
->att_data
.att_static
->att_data
.att_body_section
->sec_length
;
2476 mailimap_fetch_list_free(fetch_result
);
2479 return MAILIMAP_ERROR_FETCH
;
2482 * result_len
= text_length
;
2484 return MAILIMAP_NO_ERROR
;
2487 mailimap_fetch_att_free(fetch_att
);
2489 mailimap_set_free(set
);
2494 static int imap_fetch_header(mailimap
* imap
,
2497 size_t * result_len
)
2500 struct mailimap_set
* set
;
2501 struct mailimap_fetch_att
* fetch_att
;
2502 struct mailimap_fetch_type
* fetch_type
;
2503 clist
* fetch_result
;
2504 struct mailimap_msg_att
* msg_att
;
2505 struct mailimap_msg_att_item
* msg_att_item
;
2510 struct mailimap_section
* section
;
2512 set
= mailimap_set_new_single(msg_index
);
2514 res
= MAILIMAP_ERROR_MEMORY
;
2518 section
= mailimap_section_new_header();
2519 if (section
== NULL
) {
2520 res
= MAILIMAP_ERROR_MEMORY
;
2524 fetch_att
= mailimap_fetch_att_new_body_peek_section(section
);
2525 if (fetch_att
== NULL
) {
2526 mailimap_section_free(section
);
2527 res
= MAILIMAP_ERROR_MEMORY
;
2531 fetch_type
= mailimap_fetch_type_new_fetch_att(fetch_att
);
2532 if (fetch_type
== NULL
) {
2533 res
= MAILIMAP_ERROR_MEMORY
;
2534 goto free_fetch_att
;
2537 mailstream_logger
= imap_logger_fetch
;
2539 r
= mailimap_uid_fetch(imap
, set
, fetch_type
, &fetch_result
);
2541 mailstream_logger
= imap_logger_cmd
;
2542 mailimap_fetch_type_free(fetch_type
);
2543 mailimap_set_free(set
);
2546 case MAILIMAP_NO_ERROR
:
2552 if (fetch_result
== NULL
|| clist_begin(fetch_result
) == NULL
) {
2553 mailimap_fetch_list_free(fetch_result
);
2554 return MAILIMAP_ERROR_FETCH
;
2557 msg_att
= clist_begin(fetch_result
)->data
;
2562 if (msg_att
->att_list
)
2563 cur
= clist_begin(msg_att
->att_list
);
2567 for(; cur
!= NULL
; cur
= clist_next(cur
)) {
2568 msg_att_item
= clist_content(cur
);
2570 if (msg_att_item
->att_type
== MAILIMAP_MSG_ATT_ITEM_STATIC
) {
2571 if (msg_att_item
->att_data
.att_static
->att_type
==
2572 MAILIMAP_MSG_ATT_BODY_SECTION
) {
2573 text
= msg_att_item
->att_data
.att_static
->att_data
.att_body_section
->sec_body_part
;
2574 msg_att_item
->att_data
.att_static
->att_data
.att_body_section
->sec_body_part
= NULL
;
2576 msg_att_item
->att_data
.att_static
->att_data
.att_body_section
->sec_length
;
2581 mailimap_fetch_list_free(fetch_result
);
2584 return MAILIMAP_ERROR_FETCH
;
2587 * result_len
= text_length
;
2589 return MAILIMAP_NO_ERROR
;
2592 mailimap_fetch_att_free(fetch_att
);
2594 mailimap_set_free(set
);
2601 struct fetch_content_param
{
2604 const char * filename
;
2608 struct fetch_content_result
{
2612 static void fetch_content_run(struct etpan_thread_op
* op
)
2614 struct fetch_content_param
* param
;
2615 struct fetch_content_result
* result
;
2617 size_t content_size
;
2623 result
= op
->result
;
2629 if (param
->with_body
)
2630 r
= imap_fetch(param
->imap
, param
->msg_index
,
2631 &content
, &content_size
);
2633 r
= imap_fetch_header(param
->imap
, param
->msg_index
,
2634 &content
, &content_size
);
2638 if (r
== MAILIMAP_NO_ERROR
) {
2639 fd
= g_open(param
->filename
, O_RDWR
| O_CREAT
, 0600);
2641 result
->error
= MAILIMAP_ERROR_FETCH
;
2645 f
= claws_fdopen(fd
, "wb");
2647 result
->error
= MAILIMAP_ERROR_FETCH
;
2651 r
= claws_fwrite(content
, 1, content_size
, f
);
2652 if (r
< content_size
) {
2653 result
->error
= MAILIMAP_ERROR_FETCH
;
2657 r
= claws_safe_fclose(f
);
2659 result
->error
= MAILIMAP_ERROR_FETCH
;
2670 if (claws_unlink(param
->filename
) < 0)
2671 FILE_OP_ERROR(param
->filename
, "claws_unlink");
2674 /* mmap_string_unref is a simple free in libetpan
2675 * when it has MMAP_UNAVAILABLE defined */
2676 if (mmap_string_unref(content
) != 0)
2680 debug_print("imap fetch_content run - end %i\n", result
->error
);
2683 int imap_threaded_fetch_content(Folder
* folder
, uint32_t msg_index
,
2685 const char * filename
)
2687 struct fetch_content_param param
;
2688 struct fetch_content_result result
;
2691 debug_print("imap fetch_content - begin\n");
2693 imap
= get_imap(folder
);
2695 param
.msg_index
= msg_index
;
2696 param
.filename
= filename
;
2697 param
.with_body
= with_body
;
2699 threaded_run(folder
, ¶m
, &result
, fetch_content_run
);
2701 if (result
.error
!= MAILIMAP_NO_ERROR
)
2702 return result
.error
;
2704 debug_print("imap fetch_content - end\n");
2706 return result
.error
;
2711 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic
* att_dyn
, GSList
**s_tags
)
2716 GSList
*tags
= NULL
;
2720 flag_list
= att_dyn
->att_list
;
2721 if (flag_list
== NULL
)
2724 for(cur
= clist_begin(flag_list
) ; cur
!= NULL
;
2725 cur
= clist_next(cur
)) {
2726 struct mailimap_flag_fetch
* flag_fetch
;
2728 flag_fetch
= clist_content(cur
);
2729 if (flag_fetch
->fl_type
== MAILIMAP_FLAG_FETCH_RECENT
)
2732 switch (flag_fetch
->fl_flag
->fl_type
) {
2733 case MAILIMAP_FLAG_ANSWERED
:
2734 flags
|= MSG_REPLIED
;
2736 case MAILIMAP_FLAG_FLAGGED
:
2737 flags
|= MSG_MARKED
;
2739 case MAILIMAP_FLAG_DELETED
:
2740 flags
|= MSG_DELETED
;
2742 case MAILIMAP_FLAG_SEEN
:
2743 flags
&= ~MSG_UNREAD
;
2746 case MAILIMAP_FLAG_KEYWORD
:
2747 if (!strcasecmp(flag_fetch
->fl_flag
->fl_data
.fl_keyword
, RTAG_FORWARDED
))
2748 flags
|= MSG_FORWARDED
;
2749 else if (!strcasecmp(flag_fetch
->fl_flag
->fl_data
.fl_keyword
, RTAG_JUNK
))
2751 else if (!strcasecmp(flag_fetch
->fl_flag
->fl_data
.fl_keyword
, RTAG_NON_JUNK
) ||
2752 !strcasecmp(flag_fetch
->fl_flag
->fl_data
.fl_keyword
, RTAG_NO_JUNK
) ||
2753 !strcasecmp(flag_fetch
->fl_flag
->fl_data
.fl_keyword
, RTAG_NOT_JUNK
))
2756 tags
= g_slist_prepend(tags
, g_strdup(flag_fetch
->fl_flag
->fl_data
.fl_keyword
));
2766 static int imap_get_msg_att_info(struct mailimap_msg_att
* msg_att
,
2770 struct mailimap_msg_att_dynamic
** patt_dyn
)
2772 clistiter
* item_cur
;
2776 struct mailimap_msg_att_dynamic
* att_dyn
;
2783 if (msg_att
->att_list
)
2784 item_cur
= clist_begin(msg_att
->att_list
);
2787 for(; item_cur
!= NULL
; item_cur
= clist_next(item_cur
)) {
2788 struct mailimap_msg_att_item
* item
;
2790 item
= clist_content(item_cur
);
2792 switch (item
->att_type
) {
2793 case MAILIMAP_MSG_ATT_ITEM_STATIC
:
2794 switch (item
->att_data
.att_static
->att_type
) {
2795 case MAILIMAP_MSG_ATT_UID
:
2796 uid
= item
->att_data
.att_static
->att_data
.att_uid
;
2799 case MAILIMAP_MSG_ATT_BODY_SECTION
:
2800 if (headers
== NULL
) {
2801 headers
= item
->att_data
.att_static
->att_data
.att_body_section
->sec_body_part
;
2804 case MAILIMAP_MSG_ATT_RFC822_SIZE
:
2805 ref_size
= item
->att_data
.att_static
->att_data
.att_rfc822_size
;
2810 case MAILIMAP_MSG_ATT_ITEM_DYNAMIC
:
2811 if (att_dyn
== NULL
) {
2812 att_dyn
= item
->att_data
.att_dyn
;
2820 if (pheaders
!= NULL
)
2821 * pheaders
= headers
;
2822 if (pref_size
!= NULL
)
2823 * pref_size
= ref_size
;
2824 if (patt_dyn
!= NULL
)
2825 * patt_dyn
= att_dyn
;
2827 return MAIL_NO_ERROR
;
2830 static struct imap_fetch_env_info
*
2831 fetch_to_env_info(struct mailimap_msg_att
* msg_att
, GSList
**tags
)
2833 struct imap_fetch_env_info
* info
;
2837 struct mailimap_msg_att_dynamic
* att_dyn
;
2839 imap_get_msg_att_info(msg_att
, &uid
, &headers
, &size
,
2844 info
= malloc(sizeof(* info
));
2846 info
->headers
= strdup(headers
);
2848 info
->flags
= imap_flags_to_flags(att_dyn
, tags
);
2854 imap_fetch_result_to_envelop_list(clist
* fetch_result
,
2855 carray
** p_env_list
)
2861 env_list
= carray_new(16);
2863 for(cur
= clist_begin(fetch_result
) ; cur
!= NULL
;
2864 cur
= clist_next(cur
)) {
2865 struct mailimap_msg_att
* msg_att
;
2866 struct imap_fetch_env_info
* env_info
;
2867 GSList
*tags
= NULL
;
2869 msg_att
= clist_content(cur
);
2871 env_info
= fetch_to_env_info(msg_att
, &tags
);
2873 || carray_add(env_list
, env_info
, NULL
) != 0
2874 || carray_add(env_list
, tags
, NULL
) != 0) {
2875 carray_free(env_list
);
2876 return MAILIMAP_ERROR_MEMORY
;
2879 * p_env_list
= env_list
;
2881 * p_env_list
= NULL
;
2884 return MAIL_NO_ERROR
;
2887 static int imap_add_envelope_fetch_att(struct mailimap_fetch_type
* fetch_type
)
2889 struct mailimap_fetch_att
* fetch_att
;
2893 struct mailimap_header_list
* imap_hdrlist
;
2894 struct mailimap_section
* section
;
2896 "Date", "From", "To", "Cc", "Subject", "Message-ID",
2897 "References", "In-Reply-To", NULL
2900 hdrlist
= clist_new();
2902 return MAIL_ERROR_MEMORY
;
2904 while (headers
[i
] != NULL
) {
2905 header
= strdup(headers
[i
]);
2906 if (header
== NULL
|| clist_append(hdrlist
, header
) != 0) {
2907 clist_free(hdrlist
);
2908 return MAIL_ERROR_MEMORY
;
2913 imap_hdrlist
= mailimap_header_list_new(hdrlist
);
2914 section
= mailimap_section_new_header_fields(imap_hdrlist
);
2915 fetch_att
= mailimap_fetch_att_new_body_peek_section(section
);
2916 mailimap_fetch_type_new_fetch_att_list_add(fetch_type
, fetch_att
);
2918 return MAIL_NO_ERROR
;
2921 static int imap_add_header_fetch_att(struct mailimap_fetch_type
* fetch_type
)
2923 struct mailimap_fetch_att
* fetch_att
;
2924 struct mailimap_section
* section
;
2926 section
= mailimap_section_new_header();
2927 fetch_att
= mailimap_fetch_att_new_body_peek_section(section
);
2928 mailimap_fetch_type_new_fetch_att_list_add(fetch_type
, fetch_att
);
2930 return MAIL_NO_ERROR
;
2934 imap_get_envelopes_list(mailimap
* imap
, struct mailimap_set
* set
,
2935 carray
** p_env_list
)
2937 struct mailimap_fetch_att
* fetch_att
;
2938 struct mailimap_fetch_type
* fetch_type
;
2940 clist
* fetch_result
;
2942 carray
* env_list
= NULL
;
2946 fetch_type
= mailimap_fetch_type_new_fetch_att_list_empty();
2949 fetch_att
= mailimap_fetch_att_new_uid();
2950 r
= mailimap_fetch_type_new_fetch_att_list_add(fetch_type
, fetch_att
);
2953 fetch_att
= mailimap_fetch_att_new_flags();
2954 r
= mailimap_fetch_type_new_fetch_att_list_add(fetch_type
, fetch_att
);
2957 fetch_att
= mailimap_fetch_att_new_rfc822_size();
2958 r
= mailimap_fetch_type_new_fetch_att_list_add(fetch_type
, fetch_att
);
2962 key
.len
= sizeof(imap
);
2963 r
= chash_get(courier_workaround_hash
, &key
, &value
);
2965 r
= imap_add_envelope_fetch_att(fetch_type
);
2967 r
= imap_add_header_fetch_att(fetch_type
);
2969 if (r
!= MAILIMAP_NO_ERROR
) {
2970 debug_print("add fetch attr: %d\n", r
);
2974 mailstream_logger
= imap_logger_fetch
;
2976 r
= mailimap_uid_fetch(imap
, set
, fetch_type
, &fetch_result
);
2978 mailstream_logger
= imap_logger_cmd
;
2980 case MAILIMAP_NO_ERROR
:
2983 mailimap_fetch_type_free(fetch_type
);
2984 debug_print("uid_fetch: %d\n", r
);
2988 if (fetch_result
== NULL
|| clist_begin(fetch_result
) == NULL
) {
2989 res
= MAILIMAP_ERROR_FETCH
;
2990 debug_print("clist_begin = NULL\n");
2994 r
= imap_fetch_result_to_envelop_list(fetch_result
, &env_list
);
2995 mailimap_fetch_list_free(fetch_result
);
2997 if (r
!= MAILIMAP_NO_ERROR
) {
2998 mailimap_fetch_type_free(fetch_type
);
2999 res
= MAILIMAP_ERROR_MEMORY
;
3000 debug_print("fetch_result_to_envelop_list: %d\n", res
);
3004 mailimap_fetch_type_free(fetch_type
);
3006 * p_env_list
= env_list
;
3008 return MAILIMAP_NO_ERROR
;
3014 struct fetch_env_param
{
3016 struct mailimap_set
* set
;
3019 struct fetch_env_result
{
3020 carray
* fetch_env_result
;
3024 static void fetch_env_run(struct etpan_thread_op
* op
)
3026 struct fetch_env_param
* param
;
3027 struct fetch_env_result
* result
;
3032 result
= op
->result
;
3037 r
= imap_get_envelopes_list(param
->imap
, param
->set
,
3041 result
->fetch_env_result
= env_list
;
3043 debug_print("imap fetch_env run - end %i\n", r
);
3046 int imap_threaded_fetch_env(Folder
* folder
, struct mailimap_set
* set
,
3047 carray
** p_env_list
)
3049 struct fetch_env_param param
;
3050 struct fetch_env_result result
;
3053 debug_print("imap fetch_env - begin\n");
3055 imap
= get_imap(folder
);
3059 if (threaded_run(folder
, ¶m
, &result
, fetch_env_run
))
3060 return MAILIMAP_ERROR_INVAL
;
3062 if (result
.error
!= MAILIMAP_NO_ERROR
) {
3068 key
.len
= sizeof(imap
);
3069 r
= chash_get(courier_workaround_hash
, &key
, &value
);
3073 chash_set(courier_workaround_hash
, &key
, &value
, NULL
);
3075 threaded_run(folder
, ¶m
, &result
, fetch_env_run
);
3079 if (result
.error
!= MAILIMAP_NO_ERROR
)
3080 return result
.error
;
3082 debug_print("imap fetch_env - end\n");
3084 * p_env_list
= result
.fetch_env_result
;
3086 return result
.error
;
3089 void imap_fetch_env_free(carray
* env_list
)
3093 for(i
= 0 ; i
< carray_count(env_list
) ; i
+= 2) {
3094 struct imap_fetch_env_info
* env_info
;
3096 env_info
= carray_get(env_list
, i
);
3097 free(env_info
->headers
);
3100 carray_free(env_list
);
3107 struct append_param
{
3109 const char * mailbox
;
3110 const char * filename
;
3111 struct mailimap_flag_list
* flag_list
;
3114 struct append_result
{
3119 static void append_run(struct etpan_thread_op
* op
)
3121 struct append_param
* param
;
3122 struct append_result
* result
;
3127 struct stat stat_buf
;
3130 guint32 uid
= 0, val
= 0;
3133 result
= op
->result
;
3138 r
= stat(param
->filename
, &stat_buf
);
3140 result
->error
= MAILIMAP_ERROR_APPEND
;
3143 size
= stat_buf
.st_size
;
3145 fd
= g_open(param
->filename
, O_RDONLY
, 0);
3147 result
->error
= MAILIMAP_ERROR_APPEND
;
3151 data
= mmap(NULL
, size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
3152 if (data
== (void *) MAP_FAILED
) {
3154 result
->error
= MAILIMAP_ERROR_APPEND
;
3158 data
= file_read_to_str_no_recode(param
->filename
);
3160 result
->error
= MAILIMAP_ERROR_APPEND
;
3163 size
= strlen(data
);
3165 mailstream_logger
= imap_logger_append
;
3167 r
= mailimap_uidplus_append(param
->imap
, param
->mailbox
,
3168 param
->flag_list
, NULL
,
3169 data
, size
, &val
, &uid
);
3171 mailstream_logger
= imap_logger_cmd
;
3182 debug_print("imap append run - end %i uid %d\n", r
, uid
);
3185 int imap_threaded_append(Folder
* folder
, const char * mailbox
,
3186 const char * filename
,
3187 struct mailimap_flag_list
* flag_list
,
3190 struct append_param param
;
3191 struct append_result result
;
3194 debug_print("imap append - begin\n");
3196 imap
= get_imap(folder
);
3198 param
.mailbox
= mailbox
;
3199 param
.filename
= filename
;
3200 param
.flag_list
= flag_list
;
3202 threaded_run(folder
, ¶m
, &result
, append_run
);
3204 if (result
.error
!= MAILIMAP_NO_ERROR
)
3205 return result
.error
;
3207 debug_print("imap append - end\n");
3211 return result
.error
;
3217 struct expunge_param
{
3221 struct expunge_result
{
3225 static void expunge_run(struct etpan_thread_op
* op
)
3227 struct expunge_param
* param
;
3228 struct expunge_result
* result
;
3232 result
= op
->result
;
3236 r
= mailimap_expunge(param
->imap
);
3239 debug_print("imap expunge run - end %i\n", r
);
3242 int imap_threaded_expunge(Folder
* folder
)
3244 struct expunge_param param
;
3245 struct expunge_result result
;
3247 debug_print("imap expunge - begin\n");
3249 param
.imap
= get_imap(folder
);
3251 threaded_run(folder
, ¶m
, &result
, expunge_run
);
3253 debug_print("imap expunge - end\n");
3255 return result
.error
;
3261 struct mailimap_set
* set
;
3265 struct copy_result
{
3267 struct mailimap_set
*source
;
3268 struct mailimap_set
*dest
;
3271 static void copy_run(struct etpan_thread_op
* op
)
3273 struct copy_param
* param
;
3274 struct copy_result
* result
;
3277 struct mailimap_set
*source
= NULL
, *dest
= NULL
;
3280 result
= op
->result
;
3284 r
= mailimap_uidplus_uid_copy(param
->imap
, param
->set
, param
->mb
,
3285 &val
, &source
, &dest
);
3289 result
->source
= source
;
3290 result
->dest
= dest
;
3292 result
->source
= NULL
;
3293 result
->dest
= NULL
;
3295 debug_print("imap copy run - end %i\n", r
);
3298 int imap_threaded_copy(Folder
* folder
, struct mailimap_set
* set
,
3299 const char * mb
, struct mailimap_set
**source
,
3300 struct mailimap_set
**dest
)
3302 struct copy_param param
;
3303 struct copy_result result
;
3306 debug_print("imap copy - begin\n");
3308 imap
= get_imap(folder
);
3313 threaded_run(folder
, ¶m
, &result
, copy_run
);
3317 if (result
.error
!= MAILIMAP_NO_ERROR
)
3318 return result
.error
;
3320 *source
= result
.source
;
3321 *dest
= result
.dest
;
3323 debug_print("imap copy - end\n");
3325 return result
.error
;
3330 struct store_param
{
3332 struct mailimap_set
* set
;
3333 struct mailimap_store_att_flags
* store_att_flags
;
3336 struct store_result
{
3340 static void store_run(struct etpan_thread_op
* op
)
3342 struct store_param
* param
;
3343 struct store_result
* result
;
3347 result
= op
->result
;
3351 r
= mailimap_uid_store(param
->imap
, param
->set
,
3352 param
->store_att_flags
);
3356 debug_print("imap store run - end %i\n", r
);
3359 int imap_threaded_store(Folder
* folder
, struct mailimap_set
* set
,
3360 struct mailimap_store_att_flags
* store_att_flags
)
3362 struct store_param param
;
3363 struct store_result result
;
3366 debug_print("imap store - begin\n");
3368 imap
= get_imap(folder
);
3371 param
.store_att_flags
= store_att_flags
;
3373 threaded_run(folder
, ¶m
, &result
, store_run
);
3375 if (result
.error
!= MAILIMAP_NO_ERROR
)
3376 return result
.error
;
3378 debug_print("imap store - end\n");
3380 return result
.error
;
3385 static void do_exec_command(int fd
, const char * command
,
3386 const char * servername
, uint16_t port
)
3391 /* Fork again to become a child of init rather than
3392 the etpan client. */
3397 g_setenv("ETPANSERVER", servername
, TRUE
);
3399 g_unsetenv("ETPANSERVER");
3404 snprintf(porttext
, sizeof(porttext
), "%d", port
);
3405 g_setenv("ETPANPORT", porttext
, TRUE
);
3408 g_unsetenv("ETPANPORT");
3411 /* Not a lot we can do if there's an error other than bail. */
3412 if (dup2(fd
, 0) == -1)
3414 if (dup2(fd
, 1) == -1)
3417 /* Should we close stderr and reopen /dev/null? */
3419 maxopen
= sysconf(_SC_OPEN_MAX
);
3420 for (i
=3; i
< maxopen
; i
++)
3424 /* Detach from the controlling tty if we have one. Otherwise,
3425 SSH might do something stupid like trying to use it instead
3426 of running $SSH_ASKPASS. Doh. */
3427 fd
= g_open("/dev/tty", O_RDONLY
, 0);
3429 ioctl(fd
, TIOCNOTTY
, NULL
);
3432 #endif /* TIOCNOTTY */
3434 execl("/bin/sh", "/bin/sh", "-c", command
, NULL
);
3436 /* Eep. Shouldn't reach this */
3440 static int subcommand_connect(const char *command
,
3441 const char *servername
, uint16_t port
)
3443 /* SEB unsupported on Windows */
3447 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, sockfds
))
3452 do_exec_command(sockfds
[1], command
, servername
, port
);
3454 else if (childpid
== -1) {
3462 /* Reap child, leaving grandchild process to run */
3463 waitpid(childpid
, NULL
, 0);
3468 static int socket_connect_cmd(mailimap
* imap
, const char * command
,
3469 const char * server
, int port
)
3475 fd
= subcommand_connect(command
, server
, port
);
3477 return MAILIMAP_ERROR_STREAM
;
3479 s
= mailstream_socket_open(fd
);
3482 return MAILIMAP_ERROR_STREAM
;
3485 r
= mailimap_connect(imap
, s
);
3486 if (r
!= MAILIMAP_NO_ERROR_AUTHENTICATED
3487 && r
!= MAILIMAP_NO_ERROR_NON_AUTHENTICATED
) {
3488 mailstream_close(s
);
3490 imap
->imap_stream
= NULL
;
3499 struct connect_cmd_param
{
3501 const char * command
;
3502 const char * server
;
3506 struct connect_cmd_result
{
3510 static void connect_cmd_run(struct etpan_thread_op
* op
)
3513 struct connect_cmd_param
* param
;
3514 struct connect_cmd_result
* result
;
3517 result
= op
->result
;
3521 r
= socket_connect_cmd(param
->imap
, param
->command
,
3522 param
->server
, param
->port
);
3528 int imap_threaded_connect_cmd(Folder
* folder
, const char * command
,
3529 const char * server
, int port
)
3531 struct connect_cmd_param param
;
3532 struct connect_cmd_result result
;
3535 mailimap
* imap
, * oldimap
;
3537 oldimap
= get_imap(folder
);
3539 imap
= mailimap_new(0, NULL
);
3542 debug_print("deleting old imap %p\n", oldimap
);
3543 delete_imap(folder
, oldimap
);
3547 key
.len
= sizeof(folder
);
3550 chash_set(session_hash
, &key
, &value
, NULL
);
3553 param
.command
= command
;
3554 param
.server
= server
;
3557 threaded_run(folder
, ¶m
, &result
, connect_cmd_run
);
3559 debug_print("connect_cmd ok %i with imap %p\n", result
.error
, imap
);
3561 return result
.error
;
3563 #endif /* G_OS_WIN32 */
3565 void imap_threaded_cancel(Folder
* folder
)
3569 imap
= get_imap(folder
);
3570 if (imap
&& imap
->imap_stream
!= NULL
)
3571 mailstream_cancel(imap
->imap_stream
);
3576 void imap_main_init(void)
3579 void imap_main_done(gboolean have_connectivity
)
3582 void imap_main_set_timeout(int sec
)
3586 void imap_threaded_cancel(Folder
* folder
);