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
);
100 static int do_mailimap_ssl_connect_with_callback(mailimap
* imap
, const char * server
,
102 void (* callback
)(struct mailstream_ssl_context
* ssl_context
, void * data
),
104 ProxyInfo
*proxy_info
)
110 return mailimap_ssl_connect_with_callback(imap
, server
,
111 port
, callback
, data
);
116 sock
= sock_connect(proxy_info
->proxy_host
, proxy_info
->proxy_port
);
119 debug_print("Can not connect to proxy %s:%d\n",
120 proxy_info
->proxy_host
, proxy_info
->proxy_port
);
121 return MAILIMAP_ERROR_CONNECTION_REFUSED
;
124 if (proxy_connect(sock
, server
, port
, proxy_info
) < 0) {
125 debug_print("Can not make proxy connection via %s:%d\n",
126 proxy_info
->proxy_host
, proxy_info
->proxy_port
);
127 sock_close(sock
, TRUE
);
128 return MAILIMAP_ERROR_CONNECTION_REFUSED
;
131 stream
= mailstream_ssl_open_with_callback_timeout(sock
->sock
,
132 imap
->imap_timeout
, callback
, data
);
133 if (stream
== NULL
) {
134 sock_close(sock
, TRUE
);
135 return MAILIMAP_ERROR_SSL
;
138 /* Libetpan now has the socket fd, and we're not interested in
139 * rest of the SockInfo struct. Let's free it, while not touching
140 * the socket itself. */
141 sock_close(sock
, FALSE
);
143 return mailimap_connect(imap
, stream
);
146 static gboolean
thread_manager_event(GIOChannel
* source
,
147 GIOCondition condition
,
154 if (condition
& G_IO_IN
)
155 g_io_channel_read_chars(source
, &ch
, 1, &bytes_read
, NULL
);
157 etpan_thread_manager_loop(thread_manager
);
162 static void imap_logger_noop(int direction
, const char * str
, size_t size
)
164 /* inhibit logging */
167 static void imap_logger_cmd(int direction
, const char * str
, size_t size
)
174 log_print(LOG_PROTOCOL
, "IMAP%c [CMD data - %"G_GSIZE_FORMAT
" bytes]\n", direction
?'>':'<', size
);
177 buf
= malloc(size
+1);
178 memset(buf
, 0, size
+1);
179 strncpy(buf
, str
, size
);
182 if (!strncmp(buf
, "<<<<<<<", 7)
183 || !strncmp(buf
, ">>>>>>>", 7)) {
187 while (strstr(buf
, "\r"))
188 *strstr(buf
, "\r") = ' ';
189 while (strlen(buf
) > 0 && buf
[strlen(buf
)-1] == '\n')
190 buf
[strlen(buf
)-1] = '\0';
192 lines
= g_strsplit(buf
, "\n", -1);
194 while (lines
[i
] && *lines
[i
]) {
195 log_print(LOG_PROTOCOL
, "IMAP%c %s\n", direction
?'>':'<', lines
[i
]);
202 static void imap_logger_fetch(int direction
, const char * str
, size_t size
)
208 if (size
> 128 && !direction
) {
209 log_print(LOG_PROTOCOL
, "IMAP%c [FETCH data - %"G_GSIZE_FORMAT
" bytes]\n", direction
?'>':'<', size
);
213 buf
= malloc(size
+1);
214 memset(buf
, 0, size
+1);
215 strncpy(buf
, str
, size
);
217 if (!strncmp(buf
, "<<<<<<<", 7)
218 || !strncmp(buf
, ">>>>>>>", 7)) {
222 while (strstr(buf
, "\r"))
223 *strstr(buf
, "\r") = ' ';
224 while (strlen(buf
) > 0 && buf
[strlen(buf
)-1] == '\n')
225 buf
[strlen(buf
)-1] = '\0';
227 lines
= g_strsplit(buf
, "\n", -1);
229 if (direction
!= 0 || (buf
[0] == '*' && buf
[1] == ' ') || size
< 32) {
230 while (lines
[i
] && *lines
[i
]) {
231 log_print(LOG_PROTOCOL
, "IMAP%c %s\n", direction
?'>':'<', lines
[i
]);
235 log_print(LOG_PROTOCOL
, "IMAP%c [data - %"G_GSIZE_FORMAT
" bytes]\n", direction
?'>':'<', size
);
241 static void imap_logger_uid(int direction
, const char * str
, size_t size
)
248 log_print(LOG_PROTOCOL
, "IMAP%c [UID data - %"G_GSIZE_FORMAT
" bytes]\n", direction
?'>':'<', size
);
251 buf
= malloc(size
+1);
252 memset(buf
, 0, size
+1);
253 strncpy(buf
, str
, size
);
255 if (!strncmp(buf
, "<<<<<<<", 7)
256 || !strncmp(buf
, ">>>>>>>", 7)) {
260 while (strstr(buf
, "\r"))
261 *strstr(buf
, "\r") = ' ';
262 while (strlen(buf
) > 0 && buf
[strlen(buf
)-1] == '\n')
263 buf
[strlen(buf
)-1] = '\0';
265 lines
= g_strsplit(buf
, "\n", -1);
267 while (lines
[i
] && *lines
[i
]) {
268 int llen
= strlen(lines
[i
]);
270 log_print(LOG_PROTOCOL
, "IMAP%c %s\n", direction
?'>':'<', lines
[i
]);
273 strncpy2(tmp
, lines
[i
], 63);
274 log_print(LOG_PROTOCOL
, "IMAP%c %s[... - %d bytes more]\n", direction
?'>':'<', tmp
,
283 static void imap_logger_append(int direction
, const char * str
, size_t size
)
290 log_print(LOG_PROTOCOL
, "IMAP%c [APPEND data - %"G_GSIZE_FORMAT
" bytes]\n", direction
?'>':'<', size
);
292 } else if (direction
== 0 && size
> 64) {
293 log_print(LOG_PROTOCOL
, "IMAP%c [APPEND data - %"G_GSIZE_FORMAT
" bytes]\n", direction
?'>':'<', size
);
296 buf
= malloc(size
+1);
297 memset(buf
, 0, size
+1);
298 strncpy(buf
, str
, size
);
300 if (!strncmp(buf
, "<<<<<<<", 7)
301 || !strncmp(buf
, ">>>>>>>", 7)) {
305 while (strstr(buf
, "\r"))
306 *strstr(buf
, "\r") = ' ';
307 while (strlen(buf
) > 0 && buf
[strlen(buf
)-1] == '\n')
308 buf
[strlen(buf
)-1] = '\0';
310 lines
= g_strsplit(buf
, "\n", -1);
312 if (direction
== 0 || (buf
[0] == '*' && buf
[1] == ' ') || size
< 64) {
313 while (lines
[i
] && *lines
[i
]) {
314 log_print(LOG_PROTOCOL
, "IMAP%c %s\n", direction
?'>':'<', lines
[i
]);
318 log_print(LOG_PROTOCOL
, "IMAP%c [data - %"G_GSIZE_FORMAT
" bytes]\n", direction
?'>':'<', size
);
324 #define ETPAN_DEFAULT_NETWORK_TIMEOUT 60
325 gboolean etpan_skip_ssl_cert_check
= FALSE
;
326 extern void mailsasl_ref(void);
328 void imap_main_init(gboolean skip_ssl_cert_check
)
330 int fd_thread_manager
;
332 etpan_skip_ssl_cert_check
= skip_ssl_cert_check
;
333 mailstream_network_delay
.tv_sec
= ETPAN_DEFAULT_NETWORK_TIMEOUT
;
334 mailstream_network_delay
.tv_usec
= 0;
336 mailstream_debug
= 1;
337 mailstream_logger
= imap_logger_cmd
;
340 imap_hash
= chash_new(CHASH_COPYKEY
, CHASH_DEFAULTSIZE
);
341 session_hash
= chash_new(CHASH_COPYKEY
, CHASH_DEFAULTSIZE
);
342 courier_workaround_hash
= chash_new(CHASH_COPYKEY
, CHASH_DEFAULTSIZE
);
344 thread_manager
= etpan_thread_manager_new();
346 fd_thread_manager
= etpan_thread_manager_get_fd(thread_manager
);
349 io_channel
= g_io_channel_unix_new(fd_thread_manager
);
351 io_channel
= g_io_channel_win32_new_fd(fd_thread_manager
);
353 thread_manager_signal
= g_io_add_watch_full(io_channel
, 0, G_IO_IN
,
354 thread_manager_event
,
359 void imap_main_set_timeout(int sec
)
361 mailstream_network_delay
.tv_sec
= sec
;
362 mailstream_network_delay
.tv_usec
= 0;
365 void imap_main_done(gboolean have_connectivity
)
367 imap_disconnect_all(have_connectivity
);
368 etpan_thread_manager_stop(thread_manager
);
369 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
372 etpan_thread_manager_join(thread_manager
);
374 g_source_remove(thread_manager_signal
);
375 g_io_channel_unref(io_channel
);
377 etpan_thread_manager_free(thread_manager
);
379 chash_free(courier_workaround_hash
);
380 chash_free(session_hash
);
381 chash_free(imap_hash
);
384 void imap_init(Folder
* folder
)
386 struct etpan_thread
* thread
;
390 thread
= etpan_thread_manager_get_thread(thread_manager
);
393 key
.len
= sizeof(folder
);
397 chash_set(imap_hash
, &key
, &value
, NULL
);
400 void imap_done(Folder
* folder
)
402 struct etpan_thread
* thread
;
408 key
.len
= sizeof(folder
);
410 r
= chash_get(imap_hash
, &key
, &value
);
416 etpan_thread_unbind(thread
);
418 chash_delete(imap_hash
, &key
, NULL
);
420 debug_print("remove thread\n");
423 static struct etpan_thread
* get_thread(Folder
* folder
)
425 struct etpan_thread
* thread
;
431 key
.len
= sizeof(folder
);
433 r
= chash_get(imap_hash
, &key
, &value
);
442 static mailimap
* get_imap(Folder
* folder
)
450 key
.len
= sizeof(folder
);
452 r
= chash_get(session_hash
, &key
, &value
);
457 debug_print("found imap %p\n", imap
);
461 static gboolean
cb_show_error(gpointer data
)
463 mainwindow_show_error();
467 static void generic_cb(int cancelled
, void * result
, void * callback_data
)
469 struct etpan_thread_op
* op
;
471 op
= (struct etpan_thread_op
*) callback_data
;
473 debug_print("generic_cb\n");
474 if (op
->imap
&& op
->imap
->imap_response_info
&&
475 op
->imap
->imap_response_info
->rsp_alert
) {
476 log_error(LOG_PROTOCOL
, "IMAP< Alert: %s\n",
477 op
->imap
->imap_response_info
->rsp_alert
);
478 g_timeout_add(10, cb_show_error
, NULL
);
483 /* Please do *not* blindly use imap pointers after this function returns,
484 * someone may have deleted it while this function was waiting for completion.
485 * Check return value to see if imap is still valid.
486 * Run get_imap(folder) again to get a fresh and valid pointer.
488 static int threaded_run(Folder
* folder
, void * param
, void * result
,
489 void (* func
)(struct etpan_thread_op
* ))
491 struct etpan_thread_op
* op
;
492 struct etpan_thread
* thread
;
493 struct mailimap
* imap
= get_imap(folder
);
495 imap_folder_ref(folder
);
497 op
= etpan_thread_op_new();
504 op
->callback
= generic_cb
;
505 op
->callback_data
= op
;
507 thread
= get_thread(folder
);
508 etpan_thread_op_schedule(thread
, op
);
510 while (!op
->finished
) {
511 gtk_main_iteration();
514 etpan_thread_op_free(op
);
516 imap_folder_unref(folder
);
518 if (imap
!= get_imap(folder
)) {
519 g_warning("returning from operation on a stale imap %p", imap
);
529 struct connect_param
{
531 PrefsAccount
*account
;
534 ProxyInfo
* proxy_info
;
537 struct connect_result
{
541 #define CHECK_IMAP() { \
542 if (!param->imap) { \
543 result->error = MAILIMAP_ERROR_BAD_STATE; \
549 static void delete_imap_run(struct etpan_thread_op
* op
)
551 mailimap
* imap
= op
->imap
;
553 /* we don't want libetpan to logout */
554 if (imap
->imap_stream
) {
555 mailstream_close(imap
->imap_stream
);
556 imap
->imap_stream
= NULL
;
562 static void threaded_delete_imap(Folder
*folder
, mailimap
*imap
)
564 struct etpan_thread_op
* op
;
566 /* No need to wait for completion, threaded_run() won't work here. */
567 op
= etpan_thread_op_new();
569 op
->run
= delete_imap_run
;
570 op
->cleanup
= etpan_thread_op_free
;
572 etpan_thread_op_schedule(get_thread(folder
), op
);
574 debug_print("threaded delete imap posted\n");
577 static void delete_imap(Folder
*folder
, mailimap
*imap
)
582 key
.len
= sizeof(folder
);
583 chash_delete(session_hash
, &key
, NULL
);
588 key
.len
= sizeof(imap
);
589 chash_delete(courier_workaround_hash
, &key
, NULL
);
590 /* We can't just free imap here as there may be ops on it pending
591 * in the thread. Posting freeing as an op will synchronize against
592 * existing jobs and as imap is already removed from session_hash
593 * we are sure no new ops can be posted. */
594 threaded_delete_imap(folder
, imap
);
597 static void connect_run(struct etpan_thread_op
* op
)
600 struct connect_param
* param
;
601 struct connect_result
* result
;
608 r
= do_mailimap_socket_connect(param
->imap
,
609 param
->server
, param
->port
, param
->proxy_info
);
615 int imap_threaded_connect(Folder
* folder
, const char * server
, int port
, ProxyInfo
*proxy_info
)
617 struct connect_param param
;
618 struct connect_result result
;
621 mailimap
* imap
, * oldimap
;
623 oldimap
= get_imap(folder
);
625 imap
= mailimap_new(0, NULL
);
628 debug_print("deleting old imap %p\n", oldimap
);
629 delete_imap(folder
, oldimap
);
633 key
.len
= sizeof(folder
);
636 chash_set(session_hash
, &key
, &value
, NULL
);
639 param
.server
= server
;
641 param
.proxy_info
= proxy_info
;
644 threaded_run(folder
, ¶m
, &result
, connect_run
);
646 debug_print("connect ok %i with imap %p\n", result
.error
, imap
);
651 static void connect_ssl_run(struct etpan_thread_op
* op
)
654 struct connect_param
* param
;
655 struct connect_result
* result
;
662 r
= do_mailimap_ssl_connect_with_callback(param
->imap
,
663 param
->server
, param
->port
,
664 etpan_connect_ssl_context_cb
, param
->account
,
669 int imap_threaded_connect_ssl(Folder
* folder
, const char * server
, int port
, ProxyInfo
*proxy_info
)
671 struct connect_param param
;
672 struct connect_result result
;
675 mailimap
* imap
, * oldimap
;
676 gboolean accept_if_valid
= FALSE
;
678 oldimap
= get_imap(folder
);
680 imap
= mailimap_new(0, NULL
);
683 debug_print("deleting old imap %p\n", oldimap
);
684 delete_imap(folder
, oldimap
);
688 key
.len
= sizeof(folder
);
691 chash_set(session_hash
, &key
, &value
, NULL
);
694 param
.server
= server
;
696 param
.account
= folder
->account
;
697 param
.proxy_info
= proxy_info
;
700 accept_if_valid
= folder
->account
->ssl_certs_auto_accept
;
703 if (threaded_run(folder
, ¶m
, &result
, connect_ssl_run
))
704 return MAILIMAP_ERROR_INVAL
;
706 if ((result
.error
== MAILIMAP_NO_ERROR_AUTHENTICATED
||
707 result
.error
== MAILIMAP_NO_ERROR_NON_AUTHENTICATED
) && !etpan_skip_ssl_cert_check
) {
708 if (etpan_certificate_check(imap
->imap_stream
, server
, port
,
709 accept_if_valid
) != TRUE
)
710 result
.error
= MAILIMAP_ERROR_SSL
;
712 debug_print("connect %d with imap %p\n", result
.error
, imap
);
723 struct mailimap_capability_data
*caps
;
726 static void capability_run(struct etpan_thread_op
* op
)
729 struct capa_param
* param
;
730 struct capa_result
* result
;
731 struct mailimap_capability_data
*caps
;
738 r
= mailimap_capability(param
->imap
, &caps
);
741 result
->caps
= (r
== 0 ? caps
: NULL
);
745 int imap_threaded_capability(Folder
*folder
, struct mailimap_capability_data
** caps
)
747 struct capa_param param
;
748 struct capa_result result
;
751 imap
= get_imap(folder
);
755 threaded_run(folder
, ¶m
, &result
, capability_run
);
757 debug_print("capa %d\n", result
.error
);
759 if (result
.error
== MAILIMAP_NO_ERROR
)
766 struct disconnect_param
{
770 struct disconnect_result
{
774 static void disconnect_run(struct etpan_thread_op
* op
)
777 struct disconnect_param
* param
;
778 struct disconnect_result
* result
;
785 r
= mailimap_logout(param
->imap
);
790 void imap_threaded_disconnect(Folder
* folder
)
792 struct connect_param param
;
793 struct connect_result result
;
796 imap
= get_imap(folder
);
798 debug_print("was disconnected\n");
804 if (threaded_run(folder
, ¶m
, &result
, disconnect_run
)) {
805 debug_print("imap already deleted %p\n", imap
);
807 debug_print("deleting old imap %p\n", imap
);
808 delete_imap(folder
, imap
);
811 debug_print("disconnect ok\n");
818 const char * wildcard
;
827 static void list_run(struct etpan_thread_op
* op
)
829 struct list_param
* param
;
830 struct list_result
* result
;
841 if (param
->base
== NULL
|| param
->wildcard
== NULL
) {
844 debug_print("no base or wildcard (%p %p)\n", param
->base
, param
->wildcard
);
848 r
= mailimap_lsub(param
->imap
, param
->base
,
849 param
->wildcard
, &list
);
851 r
= mailimap_list(param
->imap
, param
->base
,
852 param
->wildcard
, &list
);
855 debug_print("imap list run - end\n");
858 int imap_threaded_list(Folder
* folder
, const char * base
,
859 const char * wildcard
,
862 struct list_param param
;
863 struct list_result result
;
865 debug_print("imap list - begin\n");
867 param
.imap
= get_imap(folder
);
869 param
.wildcard
= wildcard
;
870 param
.sub_only
= FALSE
;
872 threaded_run(folder
, ¶m
, &result
, list_run
);
874 * p_result
= result
.list
;
876 debug_print("imap list - end %p\n", result
.list
);
881 int imap_threaded_lsub(Folder
* folder
, const char * base
,
882 const char * wildcard
,
885 struct list_param param
;
886 struct list_result result
;
888 debug_print("imap lsub - begin\n");
890 param
.imap
= get_imap(folder
);
892 param
.wildcard
= wildcard
;
893 param
.sub_only
= TRUE
;
895 threaded_run(folder
, ¶m
, &result
, list_run
);
897 * p_result
= result
.list
;
899 debug_print("imap lsub - end %p\n", result
.list
);
904 struct subscribe_param
{
910 struct subscribe_result
{
914 static void subscribe_run(struct etpan_thread_op
* op
)
916 struct subscribe_param
* param
;
917 struct subscribe_result
* result
;
925 if (param
->mb
== NULL
) {
927 debug_print("no mb\n");
930 if (param
->subscribe
)
931 r
= mailimap_subscribe(param
->imap
, param
->mb
);
933 r
= mailimap_unsubscribe(param
->imap
, param
->mb
);
935 debug_print("imap %ssubscribe run - end %d\n", param
->subscribe
?"":"un", r
);
938 int imap_threaded_subscribe(Folder
* folder
, const char * mb
,
941 struct subscribe_param param
;
942 struct subscribe_result result
;
944 debug_print("imap list - begin\n");
946 param
.imap
= get_imap(folder
);
948 param
.subscribe
= subscribe
;
950 threaded_run(folder
, ¶m
, &result
, subscribe_run
);
958 const char * password
;
963 struct login_result
{
967 static void login_run(struct etpan_thread_op
* op
)
969 struct login_param
* param
;
970 struct login_result
* result
;
972 #ifdef DISABLE_LOG_DURING_LOGIN
981 #ifdef DISABLE_LOG_DURING_LOGIN
982 old_debug
= mailstream_debug
;
983 mailstream_debug
= 0;
985 if (!strcmp(param
->type
, "plaintext"))
986 r
= mailimap_login(param
->imap
,
987 param
->login
, param
->password
);
988 else if (!strcmp(param
->type
, "GSSAPI"))
989 r
= mailimap_authenticate(param
->imap
,
990 param
->type
, param
->server
, NULL
, NULL
,
991 param
->login
, param
->login
,
992 param
->password
, NULL
);
993 else if (!strcmp(param
->type
, "SCRAM-SHA-1"))
994 /* 7th argument has to be NULL here, to stop libetpan sending the
995 * a= attribute in its initial SCRAM-SHA-1 message to server. At least
996 * Dovecot 2.2 doesn't seem to like that, and will not authenticate
998 r
= mailimap_authenticate(param
->imap
,
999 param
->type
, NULL
, NULL
, NULL
,
1001 param
->password
, NULL
);
1003 else if (!strcmp(param
->type
, "XOAUTH2"))
1004 r
= mailimap_oauth2_authenticate(param
->imap
, param
->login
, param
->password
);
1007 r
= mailimap_authenticate(param
->imap
,
1008 param
->type
, NULL
, NULL
, NULL
,
1009 param
->login
, param
->login
,
1010 param
->password
, NULL
);
1011 #ifdef DISABLE_LOG_DURING_LOGIN
1012 mailstream_debug
= old_debug
;
1016 if (param
->imap
->imap_response
)
1017 imap_logger_cmd(0, param
->imap
->imap_response
, strlen(param
->imap
->imap_response
));
1018 debug_print("imap login run - end %i\n", r
);
1021 int imap_threaded_login(Folder
* folder
,
1022 const char * login
, const char * password
,
1025 struct login_param param
;
1026 struct login_result result
;
1028 debug_print("imap login - begin\n");
1031 return MAILIMAP_ERROR_INVAL
;
1033 param
.imap
= get_imap(folder
);
1034 param
.login
= login
;
1035 param
.password
= password
;
1037 if (folder
&& folder
->account
)
1038 param
.server
= folder
->account
->recv_server
;
1040 param
.server
= NULL
;
1042 threaded_run(folder
, ¶m
, &result
, login_run
);
1044 debug_print("imap login - end\n");
1046 return result
.error
;
1050 struct status_param
{
1053 struct mailimap_status_att_list
* status_att_list
;
1056 struct status_result
{
1058 struct mailimap_mailbox_data_status
* data_status
;
1061 static void status_run(struct etpan_thread_op
* op
)
1063 struct status_param
* param
;
1064 struct status_result
* result
;
1068 result
= op
->result
;
1072 r
= mailimap_status(param
->imap
, param
->mb
,
1073 param
->status_att_list
,
1074 &result
->data_status
);
1077 debug_print("imap status run - end %i\n", r
);
1080 int imap_threaded_status(Folder
* folder
, const char * mb
,
1081 struct mailimap_mailbox_data_status
** data_status
,
1084 struct status_param param
;
1085 struct status_result result
;
1086 struct mailimap_status_att_list
* status_att_list
;
1088 debug_print("imap status - begin\n");
1090 status_att_list
= mailimap_status_att_list_new_empty();
1091 if (mask
& 1 << 0) {
1092 mailimap_status_att_list_add(status_att_list
,
1093 MAILIMAP_STATUS_ATT_MESSAGES
);
1095 if (mask
& 1 << 1) {
1096 mailimap_status_att_list_add(status_att_list
,
1097 MAILIMAP_STATUS_ATT_RECENT
);
1099 if (mask
& 1 << 2) {
1100 mailimap_status_att_list_add(status_att_list
,
1101 MAILIMAP_STATUS_ATT_UIDNEXT
);
1103 if (mask
& 1 << 3) {
1104 mailimap_status_att_list_add(status_att_list
,
1105 MAILIMAP_STATUS_ATT_UIDVALIDITY
);
1107 if (mask
& 1 << 4) {
1108 mailimap_status_att_list_add(status_att_list
,
1109 MAILIMAP_STATUS_ATT_UNSEEN
);
1111 param
.imap
= get_imap(folder
);
1113 param
.status_att_list
= status_att_list
;
1115 threaded_run(folder
, ¶m
, &result
, status_run
);
1117 debug_print("imap status - end\n");
1119 * data_status
= result
.data_status
;
1121 mailimap_status_att_list_free(status_att_list
);
1123 return result
.error
;
1132 struct noop_result
{
1136 static void noop_run(struct etpan_thread_op
* op
)
1138 struct noop_param
* param
;
1139 struct noop_result
* result
;
1143 result
= op
->result
;
1147 r
= mailimap_noop(param
->imap
);
1150 debug_print("imap noop run - end %i\n", r
);
1153 int imap_threaded_noop(Folder
* folder
, unsigned int * p_exists
,
1154 unsigned int *p_recent
,
1155 unsigned int *p_expunge
,
1156 unsigned int *p_unseen
,
1157 unsigned int *p_uidnext
,
1158 unsigned int *p_uidval
)
1160 struct noop_param param
;
1161 struct noop_result result
;
1164 debug_print("imap noop - begin\n");
1166 imap
= get_imap(folder
);
1169 if (threaded_run(folder
, ¶m
, &result
, noop_run
))
1170 return MAILIMAP_ERROR_INVAL
;
1172 if (result
.error
== 0 && imap
&& imap
->imap_selection_info
!= NULL
) {
1173 * p_exists
= imap
->imap_selection_info
->sel_exists
;
1174 * p_recent
= imap
->imap_selection_info
->sel_recent
;
1175 * p_unseen
= imap
->imap_selection_info
->sel_unseen
;
1176 * p_uidnext
= imap
->imap_selection_info
->sel_uidnext
;
1177 * p_uidval
= imap
->imap_selection_info
->sel_uidvalidity
;
1185 if (result
.error
== 0 && imap
&& imap
->imap_response_info
!= NULL
&&
1186 imap
->imap_response_info
->rsp_expunged
!= NULL
) {
1187 * p_expunge
= clist_count(imap
->imap_response_info
->rsp_expunged
);
1191 debug_print("imap noop - end [EXISTS %d RECENT %d EXPUNGE %d UNSEEN %d UIDNEXT %d UIDVAL %d]\n",
1192 *p_exists
, *p_recent
, *p_expunge
, *p_unseen
,
1193 *p_uidnext
, *p_uidval
);
1195 return result
.error
;
1199 struct starttls_result
{
1203 static void starttls_run(struct etpan_thread_op
* op
)
1205 struct connect_param
* param
;
1206 struct starttls_result
* result
;
1210 result
= op
->result
;
1214 r
= mailimap_starttls(param
->imap
);
1217 debug_print("imap STARTTLS run - end %i\n", r
);
1220 mailimap
*imap
= param
->imap
;
1221 mailstream_low
*plain_low
= NULL
;
1222 mailstream_low
*tls_low
= NULL
;
1225 plain_low
= mailstream_get_low(imap
->imap_stream
);
1226 fd
= mailstream_low_get_fd(plain_low
);
1228 debug_print("imap STARTTLS run - can't get fd\n");
1229 result
->error
= MAILIMAP_ERROR_STREAM
;
1233 tls_low
= mailstream_low_tls_open_with_callback(fd
, etpan_connect_ssl_context_cb
, param
->account
);
1234 if (tls_low
== NULL
) {
1235 debug_print("imap STARTTLS run - can't tls_open\n");
1236 result
->error
= MAILIMAP_ERROR_STREAM
;
1239 mailstream_low_free(plain_low
);
1240 mailstream_set_low(imap
->imap_stream
, tls_low
);
1244 int imap_threaded_starttls(Folder
* folder
, const gchar
*host
, int port
)
1246 struct connect_param param
;
1247 struct starttls_result result
;
1248 gboolean accept_if_valid
= FALSE
;
1250 debug_print("imap STARTTLS - begin\n");
1252 param
.imap
= get_imap(folder
);
1253 param
.server
= host
;
1255 param
.account
= folder
->account
;
1257 if (folder
->account
)
1258 accept_if_valid
= folder
->account
->ssl_certs_auto_accept
;
1260 if (threaded_run(folder
, ¶m
, &result
, starttls_run
))
1261 return MAILIMAP_ERROR_INVAL
;
1263 debug_print("imap STARTTLS - end\n");
1265 if (result
.error
== 0 && param
.imap
&& !etpan_skip_ssl_cert_check
) {
1266 if (etpan_certificate_check(param
.imap
->imap_stream
, host
, port
,
1267 accept_if_valid
) != TRUE
)
1268 return MAILIMAP_ERROR_SSL
;
1270 return result
.error
;
1274 struct create_param
{
1279 struct create_result
{
1283 static void create_run(struct etpan_thread_op
* op
)
1285 struct create_param
* param
;
1286 struct create_result
* result
;
1290 result
= op
->result
;
1294 r
= mailimap_create(param
->imap
, param
->mb
);
1297 debug_print("imap create run - end %i\n", r
);
1300 int imap_threaded_create(Folder
* folder
, const char * mb
)
1302 struct create_param param
;
1303 struct create_result result
;
1305 debug_print("imap create - begin\n");
1307 param
.imap
= get_imap(folder
);
1310 threaded_run(folder
, ¶m
, &result
, create_run
);
1312 debug_print("imap create - end\n");
1314 return result
.error
;
1320 struct rename_param
{
1323 const char * new_name
;
1326 struct rename_result
{
1330 static void rename_run(struct etpan_thread_op
* op
)
1332 struct rename_param
* param
;
1333 struct rename_result
* result
;
1337 result
= op
->result
;
1341 r
= mailimap_rename(param
->imap
, param
->mb
, param
->new_name
);
1344 debug_print("imap rename run - end %i\n", r
);
1347 int imap_threaded_rename(Folder
* folder
,
1348 const char * mb
, const char * new_name
)
1350 struct rename_param param
;
1351 struct rename_result result
;
1353 debug_print("imap rename - begin\n");
1355 param
.imap
= get_imap(folder
);
1357 param
.new_name
= new_name
;
1359 threaded_run(folder
, ¶m
, &result
, rename_run
);
1361 debug_print("imap rename - end\n");
1363 return result
.error
;
1369 struct delete_param
{
1374 struct delete_result
{
1378 static void delete_run(struct etpan_thread_op
* op
)
1380 struct delete_param
* param
;
1381 struct delete_result
* result
;
1385 result
= op
->result
;
1389 r
= mailimap_delete(param
->imap
, param
->mb
);
1392 debug_print("imap delete run - end %i\n", r
);
1395 int imap_threaded_delete(Folder
* folder
, const char * mb
)
1397 struct delete_param param
;
1398 struct delete_result result
;
1400 debug_print("imap delete - begin\n");
1402 param
.imap
= get_imap(folder
);
1405 threaded_run(folder
, ¶m
, &result
, delete_run
);
1407 debug_print("imap delete - end\n");
1409 return result
.error
;
1414 struct select_param
{
1419 struct select_result
{
1423 static void select_run(struct etpan_thread_op
* op
)
1425 struct select_param
* param
;
1426 struct select_result
* result
;
1430 result
= op
->result
;
1434 r
= mailimap_select(param
->imap
, param
->mb
);
1437 debug_print("imap select run - end %i\n", r
);
1440 int imap_threaded_select(Folder
* folder
, const char * mb
,
1441 gint
* exists
, gint
* recent
, gint
* unseen
,
1442 guint32
* uid_validity
,gint
*can_create_flags
,
1445 struct select_param param
;
1446 struct select_result result
;
1449 debug_print("imap select - begin\n");
1451 imap
= get_imap(folder
);
1455 if (threaded_run(folder
, ¶m
, &result
, select_run
))
1456 return MAILIMAP_ERROR_INVAL
;
1458 if (result
.error
!= MAILIMAP_NO_ERROR
)
1459 return result
.error
;
1461 if (!imap
|| imap
->imap_selection_info
== NULL
)
1462 return MAILIMAP_ERROR_PARSE
;
1464 * exists
= imap
->imap_selection_info
->sel_exists
;
1465 * recent
= imap
->imap_selection_info
->sel_recent
;
1466 * unseen
= imap
->imap_selection_info
->sel_unseen
;
1467 * uid_validity
= imap
->imap_selection_info
->sel_uidvalidity
;
1468 * can_create_flags
= FALSE
;
1470 if (imap
->imap_selection_info
->sel_perm_flags
) {
1471 GSList
*t_flags
= NULL
;
1472 clistiter
*cur
= NULL
;
1473 if (imap
->imap_selection_info
->sel_perm_flags
)
1474 cur
= clist_begin(imap
->imap_selection_info
->sel_perm_flags
);
1476 for (; cur
; cur
= clist_next(cur
)) {
1477 struct mailimap_flag_perm
*flag
= (struct mailimap_flag_perm
*)clist_content(cur
);
1478 if (flag
->fl_type
== MAILIMAP_FLAG_PERM_ALL
)
1479 *can_create_flags
= TRUE
;
1480 else if (flag
->fl_flag
&&
1481 flag
->fl_flag
->fl_type
== 6 &&
1482 !strcmp(flag
->fl_flag
->fl_data
.fl_extension
, "*"))
1483 *can_create_flags
= TRUE
;
1484 if (flag
->fl_flag
&& ok_flags
) {
1485 MsgPermFlags c_flag
= 0;
1486 switch (flag
->fl_flag
->fl_type
) {
1487 case MAILIMAP_FLAG_ANSWERED
:
1488 c_flag
= IMAP_FLAG_ANSWERED
;
1490 case MAILIMAP_FLAG_FLAGGED
:
1491 c_flag
= IMAP_FLAG_FLAGGED
;
1493 case MAILIMAP_FLAG_DELETED
:
1494 c_flag
= IMAP_FLAG_DELETED
;
1496 case MAILIMAP_FLAG_DRAFT
:
1497 c_flag
= IMAP_FLAG_DRAFT
;
1499 case MAILIMAP_FLAG_SEEN
:
1500 c_flag
= IMAP_FLAG_SEEN
;
1502 case MAILIMAP_FLAG_KEYWORD
:
1503 if (!strcasecmp(flag
->fl_flag
->fl_data
.fl_keyword
, RTAG_FORWARDED
))
1504 c_flag
= IMAP_FLAG_FORWARDED
;
1505 if (!strcasecmp(flag
->fl_flag
->fl_data
.fl_keyword
, RTAG_JUNK
))
1506 c_flag
= IMAP_FLAG_SPAM
;
1507 if (!strcasecmp(flag
->fl_flag
->fl_data
.fl_keyword
, RTAG_NON_JUNK
) ||
1508 !strcasecmp(flag
->fl_flag
->fl_data
.fl_keyword
, RTAG_NO_JUNK
) ||
1509 !strcasecmp(flag
->fl_flag
->fl_data
.fl_keyword
, RTAG_NOT_JUNK
))
1510 c_flag
= IMAP_FLAG_HAM
;
1516 t_flags
= g_slist_prepend(t_flags
,
1517 GUINT_TO_POINTER(c_flag
));
1522 *ok_flags
= t_flags
;
1524 debug_print("imap select - end\n");
1526 return result
.error
;
1529 static void close_run(struct etpan_thread_op
* op
)
1531 struct select_param
* param
;
1532 struct select_result
* result
;
1536 result
= op
->result
;
1540 r
= mailimap_close(param
->imap
);
1543 debug_print("imap close run - end %i\n", r
);
1546 int imap_threaded_close(Folder
* folder
)
1548 struct select_param param
;
1549 struct select_result result
;
1552 debug_print("imap close - begin\n");
1554 imap
= get_imap(folder
);
1557 threaded_run(folder
, ¶m
, &result
, close_run
);
1559 if (result
.error
!= MAILIMAP_NO_ERROR
)
1560 return result
.error
;
1562 debug_print("imap close - end\n");
1564 return result
.error
;
1567 struct examine_param
{
1572 struct examine_result
{
1576 static void examine_run(struct etpan_thread_op
* op
)
1578 struct examine_param
* param
;
1579 struct examine_result
* result
;
1583 result
= op
->result
;
1587 r
= mailimap_examine(param
->imap
, param
->mb
);
1590 debug_print("imap examine run - end %i\n", r
);
1593 int imap_threaded_examine(Folder
* folder
, const char * mb
,
1594 gint
* exists
, gint
* recent
, gint
* unseen
,
1595 guint32
* uid_validity
)
1597 struct examine_param param
;
1598 struct examine_result result
;
1601 debug_print("imap examine - begin\n");
1603 imap
= get_imap(folder
);
1607 if (threaded_run(folder
, ¶m
, &result
, examine_run
))
1608 return MAILIMAP_ERROR_INVAL
;
1610 if (result
.error
!= MAILIMAP_NO_ERROR
)
1611 return result
.error
;
1613 if (!imap
|| imap
->imap_selection_info
== NULL
)
1614 return MAILIMAP_ERROR_PARSE
;
1616 * exists
= imap
->imap_selection_info
->sel_exists
;
1617 * recent
= imap
->imap_selection_info
->sel_recent
;
1618 * unseen
= imap
->imap_selection_info
->sel_unseen
;
1619 * uid_validity
= imap
->imap_selection_info
->sel_uidvalidity
;
1621 debug_print("imap examine - end\n");
1623 return result
.error
;
1629 struct search_param
{
1632 const char *charset
;
1633 struct mailimap_set
* set
;
1637 struct search_result
{
1639 clist
* search_result
;
1642 static struct mailimap_set_item
*sc_mailimap_set_item_copy(struct mailimap_set_item
*orig
)
1644 return mailimap_set_item_new(orig
->set_first
, orig
->set_last
);
1647 static struct mailimap_set
*sc_mailimap_set_copy(struct mailimap_set
*orig
)
1649 clist
*list
= orig
? orig
->set_list
: NULL
;
1656 newlist
= clist_new();
1660 for (cur
= clist_begin(list
); cur
; cur
= clist_next(cur
)) {
1661 if (clist_append(newlist
,
1662 sc_mailimap_set_item_copy(
1663 (struct mailimap_set_item
*)clist_content(cur
))) != 0) {
1664 clist_free(newlist
);
1668 return mailimap_set_new(newlist
);
1671 static void search_run(struct etpan_thread_op
* op
)
1673 struct search_param
* param
;
1674 struct search_result
* result
;
1676 struct mailimap_search_key
* key
= NULL
;
1677 struct mailimap_search_key
* uid_key
= NULL
;
1678 struct mailimap_search_key
* search_type_key
= NULL
;
1679 clist
* search_result
;
1682 result
= op
->result
;
1686 /* we copy the mailimap_set because freeing the key is recursive */
1687 if (param
->set
!= NULL
) {
1688 uid_key
= mailimap_search_key_new_uid(sc_mailimap_set_copy(param
->set
));
1689 } else if (param
->type
== IMAP_SEARCH_TYPE_SIMPLE
) {
1690 uid_key
= mailimap_search_key_new_all();
1692 switch (param
->type
) {
1693 case IMAP_SEARCH_TYPE_SIMPLE
:
1694 search_type_key
= NULL
;
1696 case IMAP_SEARCH_TYPE_SEEN
:
1697 search_type_key
= imap_search_new(IMAP_SEARCH_CRITERIA_READ
, NULL
, NULL
, 0);
1699 case IMAP_SEARCH_TYPE_UNSEEN
:
1700 search_type_key
= imap_search_new(IMAP_SEARCH_CRITERIA_UNREAD
, NULL
, NULL
, 0);
1702 case IMAP_SEARCH_TYPE_ANSWERED
:
1703 search_type_key
= imap_search_new(IMAP_SEARCH_CRITERIA_REPLIED
, NULL
, NULL
, 0);
1705 case IMAP_SEARCH_TYPE_FLAGGED
:
1706 search_type_key
= imap_search_new(IMAP_SEARCH_CRITERIA_MARKED
, NULL
, NULL
, 0);
1708 case IMAP_SEARCH_TYPE_DELETED
:
1709 search_type_key
= imap_search_new(IMAP_SEARCH_CRITERIA_DELETED
, NULL
, NULL
, 0);
1711 case IMAP_SEARCH_TYPE_FORWARDED
:
1712 search_type_key
= imap_search_new(IMAP_SEARCH_CRITERIA_TAG
, NULL
, RTAG_FORWARDED
, 0);
1714 case IMAP_SEARCH_TYPE_SPAM
:
1715 search_type_key
= imap_search_new(IMAP_SEARCH_CRITERIA_TAG
, NULL
, RTAG_JUNK
, 0);
1717 case IMAP_SEARCH_TYPE_KEYED
:
1718 search_type_key
= param
->key
;
1722 if (search_type_key
!= NULL
) {
1723 if (param
->set
!= NULL
) {
1724 key
= mailimap_search_key_new_multiple_empty();
1725 mailimap_search_key_multiple_add(key
, search_type_key
);
1726 mailimap_search_key_multiple_add(key
, uid_key
);
1728 key
= search_type_key
;
1730 } else if (uid_key
!= NULL
) {
1735 g_warning("no key!");
1736 result
= op
->result
;
1738 result
->search_result
= NULL
;
1740 mailstream_logger
= imap_logger_uid
;
1742 r
= mailimap_uid_search(param
->imap
, param
->charset
, key
, &search_result
);
1744 mailstream_logger
= imap_logger_cmd
;
1746 /* free the key (with the imapset) */
1747 mailimap_search_key_free(key
);
1750 result
->search_result
= search_result
;
1752 debug_print("imap search run - end %i\n", result
->error
);
1755 int imap_threaded_search(Folder
* folder
, int search_type
, IMAPSearchKey
* key
,
1756 const char *charset
, struct mailimap_set
* set
,
1757 clist
** search_result
)
1759 struct search_param param
;
1760 struct search_result result
;
1763 debug_print("imap search - begin\n");
1765 imap
= get_imap(folder
);
1768 param
.charset
= charset
;
1769 param
.type
= search_type
;
1772 threaded_run(folder
, ¶m
, &result
, search_run
);
1774 if (result
.error
!= MAILIMAP_NO_ERROR
)
1775 return result
.error
;
1777 debug_print("imap search - end\n");
1779 * search_result
= result
.search_result
;
1781 return result
.error
;
1785 struct _IMAPSearchKey
{
1786 struct mailimap_search_key
* key
;
1789 IMAPSearchKey
* imap_search_new(gint criteria
,
1790 const gchar
*header
,
1794 char* sk_bcc
= NULL
;
1795 struct mailimap_date
* sk_before
= NULL
;
1796 char* sk_body
= NULL
;
1798 char* sk_from
= NULL
;
1799 char* sk_keyword
= NULL
;
1800 struct mailimap_date
* sk_on
= NULL
;
1801 struct mailimap_date
* sk_since
= NULL
;
1802 char* sk_subject
= NULL
;
1803 char* sk_text
= NULL
;
1805 char* sk_unkeyword
= NULL
;
1806 char* sk_header_name
= NULL
;
1807 char* sk_header_value
= NULL
;
1808 uint32_t sk_larger
= 0;
1809 struct mailimap_search_key
* sk_not
= NULL
;
1810 struct mailimap_search_key
* sk_or1
= NULL
;
1811 struct mailimap_search_key
* sk_or2
= NULL
;
1812 struct mailimap_date
* sk_sentbefore
= NULL
;
1813 struct mailimap_date
* sk_senton
= NULL
;
1814 struct mailimap_date
* sk_sentsince
= NULL
;
1815 uint32_t sk_smaller
= 0;
1816 struct mailimap_set
* sk_uid
= NULL
;
1817 struct mailimap_set
* sk_set
= NULL
;
1818 clist
* sk_multiple
= NULL
;
1819 int etpan_matcher_type
;
1822 case IMAP_SEARCH_CRITERIA_ALL
: etpan_matcher_type
= MAILIMAP_SEARCH_KEY_ALL
; break;
1823 case IMAP_SEARCH_CRITERIA_READ
: etpan_matcher_type
= MAILIMAP_SEARCH_KEY_SEEN
; break;
1824 case IMAP_SEARCH_CRITERIA_UNREAD
: etpan_matcher_type
= MAILIMAP_SEARCH_KEY_UNSEEN
; break;
1825 case IMAP_SEARCH_CRITERIA_NEW
: etpan_matcher_type
= MAILIMAP_SEARCH_KEY_NEW
; break;
1826 case IMAP_SEARCH_CRITERIA_MARKED
: etpan_matcher_type
= MAILIMAP_SEARCH_KEY_FLAGGED
; break;
1827 case IMAP_SEARCH_CRITERIA_REPLIED
: etpan_matcher_type
= MAILIMAP_SEARCH_KEY_ANSWERED
; break;
1828 case IMAP_SEARCH_CRITERIA_DELETED
: etpan_matcher_type
= MAILIMAP_SEARCH_KEY_DELETED
; break;
1830 case IMAP_SEARCH_CRITERIA_TAG
:
1831 sk_keyword
= strdup(expr
);
1832 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_KEYWORD
;
1835 case IMAP_SEARCH_CRITERIA_SUBJECT
:
1836 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_SUBJECT
;
1837 sk_subject
= strdup(expr
);
1840 case IMAP_SEARCH_CRITERIA_TO
:
1841 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_TO
;
1842 sk_to
= strdup(expr
);
1845 case IMAP_SEARCH_CRITERIA_CC
:
1846 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_CC
;
1847 sk_cc
= strdup(expr
);
1850 case IMAP_SEARCH_CRITERIA_AGE_GREATER
:
1851 case IMAP_SEARCH_CRITERIA_AGE_LOWER
:
1854 time_t limit
= time(NULL
) - 60 * 60 * 24 * value
;
1857 localtime_r(&limit
, &tm
);
1858 if (criteria
== IMAP_SEARCH_CRITERIA_AGE_GREATER
) {
1859 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_SENTBEFORE
;
1860 sk_sentbefore
= mailimap_date_new(tm
.tm_mday
, tm
.tm_mon
, tm
.tm_year
+ 1900);
1862 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_SENTSINCE
;
1863 sk_sentsince
= mailimap_date_new(tm
.tm_mday
, tm
.tm_mon
, tm
.tm_year
+ 1900);
1868 case IMAP_SEARCH_CRITERIA_BODY
:
1869 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_BODY
;
1870 sk_body
= strdup(expr
);
1873 case IMAP_SEARCH_CRITERIA_MESSAGE
:
1874 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_TEXT
;
1875 sk_text
= strdup(expr
);
1878 case IMAP_SEARCH_CRITERIA_HEADER
:
1879 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_HEADER
;
1880 sk_header_name
= strdup(header
);
1881 sk_header_value
= strdup(expr
);
1884 case IMAP_SEARCH_CRITERIA_FROM
:
1885 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_FROM
;
1886 sk_from
= strdup(expr
);
1889 case IMAP_SEARCH_CRITERIA_SIZE_GREATER
:
1890 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_LARGER
;
1894 case IMAP_SEARCH_CRITERIA_SIZE_SMALLER
:
1895 etpan_matcher_type
= MAILIMAP_SEARCH_KEY_SMALLER
;
1903 return mailimap_search_key_new(etpan_matcher_type
,
1904 sk_bcc
, sk_before
, sk_body
, sk_cc
, sk_from
, sk_keyword
,
1905 sk_on
, sk_since
, sk_subject
, sk_text
, sk_to
,
1906 sk_unkeyword
, sk_header_name
,sk_header_value
, sk_larger
,
1907 sk_not
, sk_or1
, sk_or2
, sk_sentbefore
, sk_senton
,
1908 sk_sentsince
, sk_smaller
, sk_uid
, sk_set
, sk_multiple
);
1911 IMAPSearchKey
* imap_search_not(IMAPSearchKey
* key
)
1913 return mailimap_search_key_new_not(key
);
1916 IMAPSearchKey
* imap_search_or(IMAPSearchKey
* l
, IMAPSearchKey
* r
)
1918 return mailimap_search_key_new_or(l
, r
);
1921 IMAPSearchKey
* imap_search_and(IMAPSearchKey
* l
, IMAPSearchKey
* r
)
1923 IMAPSearchKey
* result
= mailimap_search_key_new_multiple_empty();
1924 mailimap_search_key_multiple_add(result
, l
);
1925 mailimap_search_key_multiple_add(result
, r
);
1930 void imap_search_free(IMAPSearchKey
* key
)
1935 mailimap_search_key_free(key
);
1940 static int imap_get_msg_att_info(struct mailimap_msg_att
* msg_att
,
1944 struct mailimap_msg_att_dynamic
** patt_dyn
);
1947 result_to_uid_list(clist
* fetch_result
, carray
** result
)
1949 clistiter
* cur
= NULL
;
1954 tab
= carray_new(128);
1956 res
= MAILIMAP_ERROR_MEMORY
;
1961 cur
= clist_begin(fetch_result
);
1963 for(; cur
!= NULL
; cur
= clist_next(cur
)) {
1964 struct mailimap_msg_att
* msg_att
;
1968 msg_att
= clist_content(cur
);
1971 imap_get_msg_att_info(msg_att
, &uid
, NULL
, NULL
, NULL
);
1973 puid
= malloc(sizeof(* puid
));
1975 res
= MAILIMAP_ERROR_MEMORY
;
1980 r
= carray_add(tab
, puid
, NULL
);
1983 res
= MAILIMAP_ERROR_MEMORY
;
1990 return MAILIMAP_NO_ERROR
;
1993 imap_fetch_uid_list_free(tab
);
1998 static int imap_get_messages_list(mailimap
* imap
,
1999 uint32_t first_index
,
2004 struct mailimap_fetch_att
* fetch_att
;
2005 struct mailimap_fetch_type
* fetch_type
;
2006 struct mailimap_set
* set
;
2007 clist
* fetch_result
;
2010 set
= mailimap_set_new_interval(first_index
, 0);
2012 res
= MAILIMAP_ERROR_MEMORY
;
2016 fetch_type
= mailimap_fetch_type_new_fetch_att_list_empty();
2017 if (fetch_type
== NULL
) {
2018 res
= MAILIMAP_ERROR_MEMORY
;
2022 fetch_att
= mailimap_fetch_att_new_uid();
2023 if (fetch_att
== NULL
) {
2024 res
= MAILIMAP_ERROR_MEMORY
;
2025 goto free_fetch_type
;
2028 r
= mailimap_fetch_type_new_fetch_att_list_add(fetch_type
, fetch_att
);
2029 if (r
!= MAILIMAP_NO_ERROR
) {
2030 mailimap_fetch_att_free(fetch_att
);
2031 res
= MAILIMAP_ERROR_MEMORY
;
2032 goto free_fetch_type
;
2035 mailstream_logger
= imap_logger_fetch
;
2037 r
= mailimap_uid_fetch(imap
, set
,
2038 fetch_type
, &fetch_result
);
2040 mailstream_logger
= imap_logger_cmd
;
2041 mailimap_fetch_type_free(fetch_type
);
2042 mailimap_set_free(set
);
2044 if (r
!= MAILIMAP_NO_ERROR
) {
2050 r
= result_to_uid_list(fetch_result
, &env_list
);
2051 mailimap_fetch_list_free(fetch_result
);
2053 * result
= env_list
;
2055 return MAILIMAP_NO_ERROR
;
2058 mailimap_fetch_type_free(fetch_type
);
2060 mailimap_set_free(set
);
2068 struct fetch_uid_param
{
2070 uint32_t first_index
;
2073 struct fetch_uid_result
{
2075 carray
* fetch_result
;
2078 static void fetch_uid_run(struct etpan_thread_op
* op
)
2080 struct fetch_uid_param
* param
;
2081 struct fetch_uid_result
* result
;
2082 carray
* fetch_result
;
2086 result
= op
->result
;
2090 fetch_result
= NULL
;
2091 mailstream_logger
= imap_logger_noop
;
2092 log_print(LOG_PROTOCOL
, "IMAP- [fetching UIDs...]\n");
2094 r
= imap_get_messages_list(param
->imap
, param
->first_index
,
2097 mailstream_logger
= imap_logger_cmd
;
2100 result
->fetch_result
= fetch_result
;
2101 debug_print("imap fetch_uid run - end %i\n", r
);
2104 int imap_threaded_fetch_uid(Folder
* folder
, uint32_t first_index
,
2105 carray
** fetch_result
)
2107 struct fetch_uid_param param
;
2108 struct fetch_uid_result result
;
2111 debug_print("imap fetch_uid - begin\n");
2113 imap
= get_imap(folder
);
2115 param
.first_index
= first_index
;
2117 threaded_run(folder
, ¶m
, &result
, fetch_uid_run
);
2119 if (result
.error
!= MAILIMAP_NO_ERROR
)
2120 return result
.error
;
2122 debug_print("imap fetch_uid - end\n");
2124 * fetch_result
= result
.fetch_result
;
2126 return result
.error
;
2130 void imap_fetch_uid_list_free(carray
* uid_list
)
2134 for(i
= 0 ; i
< carray_count(uid_list
) ; i
++) {
2137 puid
= carray_get(uid_list
, i
);
2140 carray_free(uid_list
);
2146 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic
* att_dyn
, GSList
**tags
);
2149 result_to_uid_flags_list(clist
* fetch_result
, carray
** result
)
2151 clistiter
* cur
= NULL
;
2155 GSList
*tags
= NULL
;
2157 tab
= carray_new(128);
2159 res
= MAILIMAP_ERROR_MEMORY
;
2164 cur
= clist_begin(fetch_result
);
2166 for(; cur
!= NULL
; cur
= clist_next(cur
)) {
2167 struct mailimap_msg_att
* msg_att
;
2170 struct mailimap_msg_att_dynamic
* att_dyn
;
2176 msg_att
= clist_content(cur
);
2180 imap_get_msg_att_info(msg_att
, &uid
, NULL
, NULL
, &att_dyn
);
2183 if (att_dyn
== NULL
)
2186 flags
= imap_flags_to_flags(att_dyn
, &tags
);
2188 puid
= malloc(sizeof(* puid
));
2190 res
= MAILIMAP_ERROR_MEMORY
;
2195 r
= carray_add(tab
, puid
, NULL
);
2198 res
= MAILIMAP_ERROR_MEMORY
;
2201 pflags
= malloc(sizeof(* pflags
));
2202 if (pflags
== NULL
) {
2203 res
= MAILIMAP_ERROR_MEMORY
;
2207 r
= carray_add(tab
, pflags
, NULL
);
2210 res
= MAILIMAP_ERROR_MEMORY
;
2213 r
= carray_add(tab
, tags
, NULL
);
2216 res
= MAILIMAP_ERROR_MEMORY
;
2223 return MAILIMAP_NO_ERROR
;
2226 imap_fetch_uid_flags_list_free(tab
);
2227 slist_free_strings_full(tags
);
2232 static int imap_get_messages_flags_list(mailimap
* imap
,
2233 uint32_t first_index
,
2238 struct mailimap_fetch_att
* fetch_att
;
2239 struct mailimap_fetch_type
* fetch_type
;
2240 struct mailimap_set
* set
;
2241 clist
* fetch_result
;
2244 set
= mailimap_set_new_interval(first_index
, 0);
2246 res
= MAILIMAP_ERROR_MEMORY
;
2250 fetch_type
= mailimap_fetch_type_new_fetch_att_list_empty();
2251 if (fetch_type
== NULL
) {
2252 res
= MAILIMAP_ERROR_MEMORY
;
2256 fetch_att
= mailimap_fetch_att_new_flags();
2257 if (fetch_att
== NULL
) {
2258 res
= MAILIMAP_ERROR_MEMORY
;
2259 goto free_fetch_type
;
2262 r
= mailimap_fetch_type_new_fetch_att_list_add(fetch_type
, fetch_att
);
2263 if (r
!= MAILIMAP_NO_ERROR
) {
2264 mailimap_fetch_att_free(fetch_att
);
2265 res
= MAILIMAP_ERROR_MEMORY
;
2266 goto free_fetch_type
;
2269 fetch_att
= mailimap_fetch_att_new_uid();
2270 if (fetch_att
== NULL
) {
2271 res
= MAILIMAP_ERROR_MEMORY
;
2272 goto free_fetch_type
;
2275 r
= mailimap_fetch_type_new_fetch_att_list_add(fetch_type
, fetch_att
);
2276 if (r
!= MAILIMAP_NO_ERROR
) {
2277 mailimap_fetch_att_free(fetch_att
);
2278 res
= MAILIMAP_ERROR_MEMORY
;
2279 goto free_fetch_type
;
2282 mailstream_logger
= imap_logger_fetch
;
2284 r
= mailimap_uid_fetch(imap
, set
,
2285 fetch_type
, &fetch_result
);
2287 mailstream_logger
= imap_logger_cmd
;
2288 mailimap_fetch_type_free(fetch_type
);
2289 mailimap_set_free(set
);
2291 if (r
!= MAILIMAP_NO_ERROR
) {
2297 r
= result_to_uid_flags_list(fetch_result
, &env_list
);
2298 mailimap_fetch_list_free(fetch_result
);
2300 * result
= env_list
;
2302 return MAILIMAP_NO_ERROR
;
2305 mailimap_fetch_type_free(fetch_type
);
2307 mailimap_set_free(set
);
2314 static void fetch_uid_flags_run(struct etpan_thread_op
* op
)
2316 struct fetch_uid_param
* param
;
2317 struct fetch_uid_result
* result
;
2318 carray
* fetch_result
;
2322 result
= op
->result
;
2326 fetch_result
= NULL
;
2327 r
= imap_get_messages_flags_list(param
->imap
, param
->first_index
,
2331 result
->fetch_result
= fetch_result
;
2332 debug_print("imap fetch_uid run - end %i\n", r
);
2335 int imap_threaded_fetch_uid_flags(Folder
* folder
, uint32_t first_index
,
2336 carray
** fetch_result
)
2338 struct fetch_uid_param param
;
2339 struct fetch_uid_result result
;
2342 debug_print("imap fetch_uid - begin\n");
2344 imap
= get_imap(folder
);
2346 param
.first_index
= first_index
;
2348 mailstream_logger
= imap_logger_noop
;
2349 log_print(LOG_PROTOCOL
, "IMAP- [fetching flags...]\n");
2351 threaded_run(folder
, ¶m
, &result
, fetch_uid_flags_run
);
2353 mailstream_logger
= imap_logger_cmd
;
2356 if (result
.error
!= MAILIMAP_NO_ERROR
)
2357 return result
.error
;
2359 debug_print("imap fetch_uid - end\n");
2361 * fetch_result
= result
.fetch_result
;
2363 return result
.error
;
2367 void imap_fetch_uid_flags_list_free(carray
* uid_flags_list
)
2371 for(i
= 0 ; i
< carray_count(uid_flags_list
) ; i
+= 3) {
2374 data
= carray_get(uid_flags_list
, i
);
2376 data
= carray_get(uid_flags_list
, i
+ 1);
2379 carray_free(uid_flags_list
);
2384 static int imap_fetch(mailimap
* imap
,
2387 size_t * result_len
)
2390 struct mailimap_set
* set
;
2391 struct mailimap_fetch_att
* fetch_att
;
2392 struct mailimap_fetch_type
* fetch_type
;
2393 clist
* fetch_result
;
2394 struct mailimap_msg_att
* msg_att
;
2395 struct mailimap_msg_att_item
* msg_att_item
;
2400 struct mailimap_section
* section
;
2402 set
= mailimap_set_new_single(msg_index
);
2404 res
= MAILIMAP_ERROR_MEMORY
;
2408 section
= mailimap_section_new(NULL
);
2409 if (section
== NULL
) {
2410 res
= MAILIMAP_ERROR_MEMORY
;
2414 fetch_att
= mailimap_fetch_att_new_body_peek_section(section
);
2415 if (fetch_att
== NULL
) {
2416 mailimap_section_free(section
);
2417 res
= MAILIMAP_ERROR_MEMORY
;
2421 fetch_type
= mailimap_fetch_type_new_fetch_att(fetch_att
);
2422 if (fetch_type
== NULL
) {
2423 res
= MAILIMAP_ERROR_MEMORY
;
2424 goto free_fetch_att
;
2427 mailstream_logger
= imap_logger_fetch
;
2429 r
= mailimap_uid_fetch(imap
, set
,
2430 fetch_type
, &fetch_result
);
2432 mailstream_logger
= imap_logger_cmd
;
2434 mailimap_fetch_type_free(fetch_type
);
2435 mailimap_set_free(set
);
2438 case MAILIMAP_NO_ERROR
:
2444 if (fetch_result
== NULL
|| clist_begin(fetch_result
) == NULL
) {
2445 mailimap_fetch_list_free(fetch_result
);
2446 return MAILIMAP_ERROR_FETCH
;
2449 msg_att
= clist_begin(fetch_result
)->data
;
2454 if (msg_att
->att_list
)
2455 cur
= clist_begin(msg_att
->att_list
);
2459 for(; cur
!= NULL
; cur
= clist_next(cur
)) {
2460 msg_att_item
= clist_content(cur
);
2462 if (msg_att_item
->att_type
== MAILIMAP_MSG_ATT_ITEM_STATIC
) {
2463 if (msg_att_item
->att_data
.att_static
->att_type
==
2464 MAILIMAP_MSG_ATT_BODY_SECTION
) {
2465 text
= msg_att_item
->att_data
.att_static
->att_data
.att_body_section
->sec_body_part
;
2467 msg_att_item
->att_data
.att_static
->att_data
.att_body_section
->sec_body_part
= NULL
;
2469 msg_att_item
->att_data
.att_static
->att_data
.att_body_section
->sec_length
;
2474 mailimap_fetch_list_free(fetch_result
);
2477 return MAILIMAP_ERROR_FETCH
;
2480 * result_len
= text_length
;
2482 return MAILIMAP_NO_ERROR
;
2485 mailimap_fetch_att_free(fetch_att
);
2487 mailimap_set_free(set
);
2492 static int imap_fetch_header(mailimap
* imap
,
2495 size_t * result_len
)
2498 struct mailimap_set
* set
;
2499 struct mailimap_fetch_att
* fetch_att
;
2500 struct mailimap_fetch_type
* fetch_type
;
2501 clist
* fetch_result
;
2502 struct mailimap_msg_att
* msg_att
;
2503 struct mailimap_msg_att_item
* msg_att_item
;
2508 struct mailimap_section
* section
;
2510 set
= mailimap_set_new_single(msg_index
);
2512 res
= MAILIMAP_ERROR_MEMORY
;
2516 section
= mailimap_section_new_header();
2517 if (section
== NULL
) {
2518 res
= MAILIMAP_ERROR_MEMORY
;
2522 fetch_att
= mailimap_fetch_att_new_body_peek_section(section
);
2523 if (fetch_att
== NULL
) {
2524 mailimap_section_free(section
);
2525 res
= MAILIMAP_ERROR_MEMORY
;
2529 fetch_type
= mailimap_fetch_type_new_fetch_att(fetch_att
);
2530 if (fetch_type
== NULL
) {
2531 res
= MAILIMAP_ERROR_MEMORY
;
2532 goto free_fetch_att
;
2535 mailstream_logger
= imap_logger_fetch
;
2537 r
= mailimap_uid_fetch(imap
, set
, fetch_type
, &fetch_result
);
2539 mailstream_logger
= imap_logger_cmd
;
2540 mailimap_fetch_type_free(fetch_type
);
2541 mailimap_set_free(set
);
2544 case MAILIMAP_NO_ERROR
:
2550 if (fetch_result
== NULL
|| clist_begin(fetch_result
) == NULL
) {
2551 mailimap_fetch_list_free(fetch_result
);
2552 return MAILIMAP_ERROR_FETCH
;
2555 msg_att
= clist_begin(fetch_result
)->data
;
2560 if (msg_att
->att_list
)
2561 cur
= clist_begin(msg_att
->att_list
);
2565 for(; cur
!= NULL
; cur
= clist_next(cur
)) {
2566 msg_att_item
= clist_content(cur
);
2568 if (msg_att_item
->att_type
== MAILIMAP_MSG_ATT_ITEM_STATIC
) {
2569 if (msg_att_item
->att_data
.att_static
->att_type
==
2570 MAILIMAP_MSG_ATT_BODY_SECTION
) {
2571 text
= msg_att_item
->att_data
.att_static
->att_data
.att_body_section
->sec_body_part
;
2572 msg_att_item
->att_data
.att_static
->att_data
.att_body_section
->sec_body_part
= NULL
;
2574 msg_att_item
->att_data
.att_static
->att_data
.att_body_section
->sec_length
;
2579 mailimap_fetch_list_free(fetch_result
);
2582 return MAILIMAP_ERROR_FETCH
;
2585 * result_len
= text_length
;
2587 return MAILIMAP_NO_ERROR
;
2590 mailimap_fetch_att_free(fetch_att
);
2592 mailimap_set_free(set
);
2599 struct fetch_content_param
{
2602 const char * filename
;
2606 struct fetch_content_result
{
2610 static void fetch_content_run(struct etpan_thread_op
* op
)
2612 struct fetch_content_param
* param
;
2613 struct fetch_content_result
* result
;
2615 size_t content_size
;
2621 result
= op
->result
;
2627 if (param
->with_body
)
2628 r
= imap_fetch(param
->imap
, param
->msg_index
,
2629 &content
, &content_size
);
2631 r
= imap_fetch_header(param
->imap
, param
->msg_index
,
2632 &content
, &content_size
);
2636 if (r
== MAILIMAP_NO_ERROR
) {
2637 fd
= g_open(param
->filename
, O_RDWR
| O_CREAT
, 0600);
2639 result
->error
= MAILIMAP_ERROR_FETCH
;
2643 f
= claws_fdopen(fd
, "wb");
2645 result
->error
= MAILIMAP_ERROR_FETCH
;
2649 r
= claws_fwrite(content
, 1, content_size
, f
);
2650 if (r
< content_size
) {
2651 result
->error
= MAILIMAP_ERROR_FETCH
;
2655 r
= claws_safe_fclose(f
);
2657 result
->error
= MAILIMAP_ERROR_FETCH
;
2668 if (claws_unlink(param
->filename
) < 0)
2669 FILE_OP_ERROR(param
->filename
, "claws_unlink");
2672 /* mmap_string_unref is a simple free in libetpan
2673 * when it has MMAP_UNAVAILABLE defined */
2674 if (mmap_string_unref(content
) != 0)
2678 debug_print("imap fetch_content run - end %i\n", result
->error
);
2681 int imap_threaded_fetch_content(Folder
* folder
, uint32_t msg_index
,
2683 const char * filename
)
2685 struct fetch_content_param param
;
2686 struct fetch_content_result result
;
2689 debug_print("imap fetch_content - begin\n");
2691 imap
= get_imap(folder
);
2693 param
.msg_index
= msg_index
;
2694 param
.filename
= filename
;
2695 param
.with_body
= with_body
;
2697 threaded_run(folder
, ¶m
, &result
, fetch_content_run
);
2699 if (result
.error
!= MAILIMAP_NO_ERROR
)
2700 return result
.error
;
2702 debug_print("imap fetch_content - end\n");
2704 return result
.error
;
2709 static int imap_flags_to_flags(struct mailimap_msg_att_dynamic
* att_dyn
, GSList
**s_tags
)
2714 GSList
*tags
= NULL
;
2718 flag_list
= att_dyn
->att_list
;
2719 if (flag_list
== NULL
)
2722 for(cur
= clist_begin(flag_list
) ; cur
!= NULL
;
2723 cur
= clist_next(cur
)) {
2724 struct mailimap_flag_fetch
* flag_fetch
;
2726 flag_fetch
= clist_content(cur
);
2727 if (flag_fetch
->fl_type
== MAILIMAP_FLAG_FETCH_RECENT
)
2730 switch (flag_fetch
->fl_flag
->fl_type
) {
2731 case MAILIMAP_FLAG_ANSWERED
:
2732 flags
|= MSG_REPLIED
;
2734 case MAILIMAP_FLAG_FLAGGED
:
2735 flags
|= MSG_MARKED
;
2737 case MAILIMAP_FLAG_DELETED
:
2738 flags
|= MSG_DELETED
;
2740 case MAILIMAP_FLAG_SEEN
:
2741 flags
&= ~MSG_UNREAD
;
2744 case MAILIMAP_FLAG_KEYWORD
:
2745 if (!strcasecmp(flag_fetch
->fl_flag
->fl_data
.fl_keyword
, RTAG_FORWARDED
))
2746 flags
|= MSG_FORWARDED
;
2747 else if (!strcasecmp(flag_fetch
->fl_flag
->fl_data
.fl_keyword
, RTAG_JUNK
))
2749 else if (!strcasecmp(flag_fetch
->fl_flag
->fl_data
.fl_keyword
, RTAG_NON_JUNK
) ||
2750 !strcasecmp(flag_fetch
->fl_flag
->fl_data
.fl_keyword
, RTAG_NO_JUNK
) ||
2751 !strcasecmp(flag_fetch
->fl_flag
->fl_data
.fl_keyword
, RTAG_NOT_JUNK
))
2754 tags
= g_slist_prepend(tags
, g_strdup(flag_fetch
->fl_flag
->fl_data
.fl_keyword
));
2764 static int imap_get_msg_att_info(struct mailimap_msg_att
* msg_att
,
2768 struct mailimap_msg_att_dynamic
** patt_dyn
)
2770 clistiter
* item_cur
;
2774 struct mailimap_msg_att_dynamic
* att_dyn
;
2781 if (msg_att
->att_list
)
2782 item_cur
= clist_begin(msg_att
->att_list
);
2785 for(; item_cur
!= NULL
; item_cur
= clist_next(item_cur
)) {
2786 struct mailimap_msg_att_item
* item
;
2788 item
= clist_content(item_cur
);
2790 switch (item
->att_type
) {
2791 case MAILIMAP_MSG_ATT_ITEM_STATIC
:
2792 switch (item
->att_data
.att_static
->att_type
) {
2793 case MAILIMAP_MSG_ATT_UID
:
2794 uid
= item
->att_data
.att_static
->att_data
.att_uid
;
2797 case MAILIMAP_MSG_ATT_BODY_SECTION
:
2798 if (headers
== NULL
) {
2799 headers
= item
->att_data
.att_static
->att_data
.att_body_section
->sec_body_part
;
2802 case MAILIMAP_MSG_ATT_RFC822_SIZE
:
2803 ref_size
= item
->att_data
.att_static
->att_data
.att_rfc822_size
;
2808 case MAILIMAP_MSG_ATT_ITEM_DYNAMIC
:
2809 if (att_dyn
== NULL
) {
2810 att_dyn
= item
->att_data
.att_dyn
;
2818 if (pheaders
!= NULL
)
2819 * pheaders
= headers
;
2820 if (pref_size
!= NULL
)
2821 * pref_size
= ref_size
;
2822 if (patt_dyn
!= NULL
)
2823 * patt_dyn
= att_dyn
;
2825 return MAIL_NO_ERROR
;
2828 static struct imap_fetch_env_info
*
2829 fetch_to_env_info(struct mailimap_msg_att
* msg_att
, GSList
**tags
)
2831 struct imap_fetch_env_info
* info
;
2835 struct mailimap_msg_att_dynamic
* att_dyn
;
2837 imap_get_msg_att_info(msg_att
, &uid
, &headers
, &size
,
2842 info
= malloc(sizeof(* info
));
2844 info
->headers
= strdup(headers
);
2846 info
->flags
= imap_flags_to_flags(att_dyn
, tags
);
2852 imap_fetch_result_to_envelop_list(clist
* fetch_result
,
2853 carray
** p_env_list
)
2859 env_list
= carray_new(16);
2861 for(cur
= clist_begin(fetch_result
) ; cur
!= NULL
;
2862 cur
= clist_next(cur
)) {
2863 struct mailimap_msg_att
* msg_att
;
2864 struct imap_fetch_env_info
* env_info
;
2865 GSList
*tags
= NULL
;
2867 msg_att
= clist_content(cur
);
2869 env_info
= fetch_to_env_info(msg_att
, &tags
);
2871 || carray_add(env_list
, env_info
, NULL
) != 0
2872 || carray_add(env_list
, tags
, NULL
) != 0) {
2873 carray_free(env_list
);
2874 return MAILIMAP_ERROR_MEMORY
;
2877 * p_env_list
= env_list
;
2879 * p_env_list
= NULL
;
2882 return MAIL_NO_ERROR
;
2885 static int imap_add_envelope_fetch_att(struct mailimap_fetch_type
* fetch_type
)
2887 struct mailimap_fetch_att
* fetch_att
;
2891 struct mailimap_header_list
* imap_hdrlist
;
2892 struct mailimap_section
* section
;
2894 "Date", "From", "To", "Cc", "Subject", "Message-ID",
2895 "References", "In-Reply-To", NULL
2898 hdrlist
= clist_new();
2900 return MAIL_ERROR_MEMORY
;
2902 while (headers
[i
] != NULL
) {
2903 header
= strdup(headers
[i
]);
2904 if (header
== NULL
|| clist_append(hdrlist
, header
) != 0) {
2905 clist_free(hdrlist
);
2906 return MAIL_ERROR_MEMORY
;
2911 imap_hdrlist
= mailimap_header_list_new(hdrlist
);
2912 section
= mailimap_section_new_header_fields(imap_hdrlist
);
2913 fetch_att
= mailimap_fetch_att_new_body_peek_section(section
);
2914 mailimap_fetch_type_new_fetch_att_list_add(fetch_type
, fetch_att
);
2916 return MAIL_NO_ERROR
;
2919 static int imap_add_header_fetch_att(struct mailimap_fetch_type
* fetch_type
)
2921 struct mailimap_fetch_att
* fetch_att
;
2922 struct mailimap_section
* section
;
2924 section
= mailimap_section_new_header();
2925 fetch_att
= mailimap_fetch_att_new_body_peek_section(section
);
2926 mailimap_fetch_type_new_fetch_att_list_add(fetch_type
, fetch_att
);
2928 return MAIL_NO_ERROR
;
2932 imap_get_envelopes_list(mailimap
* imap
, struct mailimap_set
* set
,
2933 carray
** p_env_list
)
2935 struct mailimap_fetch_att
* fetch_att
;
2936 struct mailimap_fetch_type
* fetch_type
;
2938 clist
* fetch_result
;
2940 carray
* env_list
= NULL
;
2944 fetch_type
= mailimap_fetch_type_new_fetch_att_list_empty();
2947 fetch_att
= mailimap_fetch_att_new_uid();
2948 r
= mailimap_fetch_type_new_fetch_att_list_add(fetch_type
, fetch_att
);
2951 fetch_att
= mailimap_fetch_att_new_flags();
2952 r
= mailimap_fetch_type_new_fetch_att_list_add(fetch_type
, fetch_att
);
2955 fetch_att
= mailimap_fetch_att_new_rfc822_size();
2956 r
= mailimap_fetch_type_new_fetch_att_list_add(fetch_type
, fetch_att
);
2960 key
.len
= sizeof(imap
);
2961 r
= chash_get(courier_workaround_hash
, &key
, &value
);
2963 r
= imap_add_envelope_fetch_att(fetch_type
);
2965 r
= imap_add_header_fetch_att(fetch_type
);
2967 if (r
!= MAILIMAP_NO_ERROR
) {
2968 debug_print("add fetch attr: %d\n", r
);
2972 mailstream_logger
= imap_logger_fetch
;
2974 r
= mailimap_uid_fetch(imap
, set
, fetch_type
, &fetch_result
);
2976 mailstream_logger
= imap_logger_cmd
;
2978 case MAILIMAP_NO_ERROR
:
2981 mailimap_fetch_type_free(fetch_type
);
2982 debug_print("uid_fetch: %d\n", r
);
2986 if (fetch_result
== NULL
|| clist_begin(fetch_result
) == NULL
) {
2987 res
= MAILIMAP_ERROR_FETCH
;
2988 debug_print("clist_begin = NULL\n");
2992 r
= imap_fetch_result_to_envelop_list(fetch_result
, &env_list
);
2993 mailimap_fetch_list_free(fetch_result
);
2995 if (r
!= MAILIMAP_NO_ERROR
) {
2996 mailimap_fetch_type_free(fetch_type
);
2997 res
= MAILIMAP_ERROR_MEMORY
;
2998 debug_print("fetch_result_to_envelop_list: %d\n", res
);
3002 mailimap_fetch_type_free(fetch_type
);
3004 * p_env_list
= env_list
;
3006 return MAILIMAP_NO_ERROR
;
3012 struct fetch_env_param
{
3014 struct mailimap_set
* set
;
3017 struct fetch_env_result
{
3018 carray
* fetch_env_result
;
3022 static void fetch_env_run(struct etpan_thread_op
* op
)
3024 struct fetch_env_param
* param
;
3025 struct fetch_env_result
* result
;
3030 result
= op
->result
;
3035 r
= imap_get_envelopes_list(param
->imap
, param
->set
,
3039 result
->fetch_env_result
= env_list
;
3041 debug_print("imap fetch_env run - end %i\n", r
);
3044 int imap_threaded_fetch_env(Folder
* folder
, struct mailimap_set
* set
,
3045 carray
** p_env_list
)
3047 struct fetch_env_param param
;
3048 struct fetch_env_result result
;
3051 debug_print("imap fetch_env - begin\n");
3053 imap
= get_imap(folder
);
3057 if (threaded_run(folder
, ¶m
, &result
, fetch_env_run
))
3058 return MAILIMAP_ERROR_INVAL
;
3060 if (result
.error
!= MAILIMAP_NO_ERROR
) {
3066 key
.len
= sizeof(imap
);
3067 r
= chash_get(courier_workaround_hash
, &key
, &value
);
3071 chash_set(courier_workaround_hash
, &key
, &value
, NULL
);
3073 threaded_run(folder
, ¶m
, &result
, fetch_env_run
);
3077 if (result
.error
!= MAILIMAP_NO_ERROR
)
3078 return result
.error
;
3080 debug_print("imap fetch_env - end\n");
3082 * p_env_list
= result
.fetch_env_result
;
3084 return result
.error
;
3087 void imap_fetch_env_free(carray
* env_list
)
3091 for(i
= 0 ; i
< carray_count(env_list
) ; i
+= 2) {
3092 struct imap_fetch_env_info
* env_info
;
3094 env_info
= carray_get(env_list
, i
);
3095 free(env_info
->headers
);
3098 carray_free(env_list
);
3105 struct append_param
{
3107 const char * mailbox
;
3108 const char * filename
;
3109 struct mailimap_flag_list
* flag_list
;
3112 struct append_result
{
3117 static void append_run(struct etpan_thread_op
* op
)
3119 struct append_param
* param
;
3120 struct append_result
* result
;
3125 struct stat stat_buf
;
3128 guint32 uid
= 0, val
= 0;
3131 result
= op
->result
;
3136 r
= stat(param
->filename
, &stat_buf
);
3138 result
->error
= MAILIMAP_ERROR_APPEND
;
3141 size
= stat_buf
.st_size
;
3143 fd
= g_open(param
->filename
, O_RDONLY
, 0);
3145 result
->error
= MAILIMAP_ERROR_APPEND
;
3149 data
= mmap(NULL
, size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
3150 if (data
== (void *) MAP_FAILED
) {
3152 result
->error
= MAILIMAP_ERROR_APPEND
;
3156 data
= file_read_to_str_no_recode(param
->filename
);
3158 result
->error
= MAILIMAP_ERROR_APPEND
;
3161 size
= strlen(data
);
3163 mailstream_logger
= imap_logger_append
;
3165 r
= mailimap_uidplus_append(param
->imap
, param
->mailbox
,
3166 param
->flag_list
, NULL
,
3167 data
, size
, &val
, &uid
);
3169 mailstream_logger
= imap_logger_cmd
;
3180 debug_print("imap append run - end %i uid %d\n", r
, uid
);
3183 int imap_threaded_append(Folder
* folder
, const char * mailbox
,
3184 const char * filename
,
3185 struct mailimap_flag_list
* flag_list
,
3188 struct append_param param
;
3189 struct append_result result
;
3192 debug_print("imap append - begin\n");
3194 imap
= get_imap(folder
);
3196 param
.mailbox
= mailbox
;
3197 param
.filename
= filename
;
3198 param
.flag_list
= flag_list
;
3200 threaded_run(folder
, ¶m
, &result
, append_run
);
3202 if (result
.error
!= MAILIMAP_NO_ERROR
)
3203 return result
.error
;
3205 debug_print("imap append - end\n");
3209 return result
.error
;
3215 struct expunge_param
{
3219 struct expunge_result
{
3223 static void expunge_run(struct etpan_thread_op
* op
)
3225 struct expunge_param
* param
;
3226 struct expunge_result
* result
;
3230 result
= op
->result
;
3234 r
= mailimap_expunge(param
->imap
);
3237 debug_print("imap expunge run - end %i\n", r
);
3240 int imap_threaded_expunge(Folder
* folder
)
3242 struct expunge_param param
;
3243 struct expunge_result result
;
3245 debug_print("imap expunge - begin\n");
3247 param
.imap
= get_imap(folder
);
3249 threaded_run(folder
, ¶m
, &result
, expunge_run
);
3251 debug_print("imap expunge - end\n");
3253 return result
.error
;
3259 struct mailimap_set
* set
;
3263 struct copy_result
{
3265 struct mailimap_set
*source
;
3266 struct mailimap_set
*dest
;
3269 static void copy_run(struct etpan_thread_op
* op
)
3271 struct copy_param
* param
;
3272 struct copy_result
* result
;
3275 struct mailimap_set
*source
= NULL
, *dest
= NULL
;
3278 result
= op
->result
;
3282 r
= mailimap_uidplus_uid_copy(param
->imap
, param
->set
, param
->mb
,
3283 &val
, &source
, &dest
);
3287 result
->source
= source
;
3288 result
->dest
= dest
;
3290 result
->source
= NULL
;
3291 result
->dest
= NULL
;
3293 debug_print("imap copy run - end %i\n", r
);
3296 int imap_threaded_copy(Folder
* folder
, struct mailimap_set
* set
,
3297 const char * mb
, struct mailimap_set
**source
,
3298 struct mailimap_set
**dest
)
3300 struct copy_param param
;
3301 struct copy_result result
;
3304 debug_print("imap copy - begin\n");
3306 imap
= get_imap(folder
);
3311 threaded_run(folder
, ¶m
, &result
, copy_run
);
3315 if (result
.error
!= MAILIMAP_NO_ERROR
)
3316 return result
.error
;
3318 *source
= result
.source
;
3319 *dest
= result
.dest
;
3321 debug_print("imap copy - end\n");
3323 return result
.error
;
3328 struct store_param
{
3330 struct mailimap_set
* set
;
3331 struct mailimap_store_att_flags
* store_att_flags
;
3334 struct store_result
{
3338 static void store_run(struct etpan_thread_op
* op
)
3340 struct store_param
* param
;
3341 struct store_result
* result
;
3345 result
= op
->result
;
3349 r
= mailimap_uid_store(param
->imap
, param
->set
,
3350 param
->store_att_flags
);
3354 debug_print("imap store run - end %i\n", r
);
3357 int imap_threaded_store(Folder
* folder
, struct mailimap_set
* set
,
3358 struct mailimap_store_att_flags
* store_att_flags
)
3360 struct store_param param
;
3361 struct store_result result
;
3364 debug_print("imap store - begin\n");
3366 imap
= get_imap(folder
);
3369 param
.store_att_flags
= store_att_flags
;
3371 threaded_run(folder
, ¶m
, &result
, store_run
);
3373 if (result
.error
!= MAILIMAP_NO_ERROR
)
3374 return result
.error
;
3376 debug_print("imap store - end\n");
3378 return result
.error
;
3383 static void do_exec_command(int fd
, const char * command
,
3384 const char * servername
, uint16_t port
)
3389 /* Fork again to become a child of init rather than
3390 the etpan client. */
3395 g_setenv("ETPANSERVER", servername
, TRUE
);
3397 g_unsetenv("ETPANSERVER");
3402 snprintf(porttext
, sizeof(porttext
), "%d", port
);
3403 g_setenv("ETPANPORT", porttext
, TRUE
);
3406 g_unsetenv("ETPANPORT");
3409 /* Not a lot we can do if there's an error other than bail. */
3410 if (dup2(fd
, 0) == -1)
3412 if (dup2(fd
, 1) == -1)
3415 /* Should we close stderr and reopen /dev/null? */
3417 maxopen
= sysconf(_SC_OPEN_MAX
);
3418 for (i
=3; i
< maxopen
; i
++)
3422 /* Detach from the controlling tty if we have one. Otherwise,
3423 SSH might do something stupid like trying to use it instead
3424 of running $SSH_ASKPASS. Doh. */
3425 fd
= g_open("/dev/tty", O_RDONLY
, 0);
3427 ioctl(fd
, TIOCNOTTY
, NULL
);
3430 #endif /* TIOCNOTTY */
3432 execl("/bin/sh", "/bin/sh", "-c", command
, NULL
);
3434 /* Eep. Shouldn't reach this */
3438 static int subcommand_connect(const char *command
,
3439 const char *servername
, uint16_t port
)
3441 /* SEB unsupported on Windows */
3445 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, sockfds
))
3450 do_exec_command(sockfds
[1], command
, servername
, port
);
3452 else if (childpid
== -1) {
3460 /* Reap child, leaving grandchild process to run */
3461 waitpid(childpid
, NULL
, 0);
3466 static int socket_connect_cmd(mailimap
* imap
, const char * command
,
3467 const char * server
, int port
)
3473 fd
= subcommand_connect(command
, server
, port
);
3475 return MAILIMAP_ERROR_STREAM
;
3477 s
= mailstream_socket_open(fd
);
3480 return MAILIMAP_ERROR_STREAM
;
3483 r
= mailimap_connect(imap
, s
);
3484 if (r
!= MAILIMAP_NO_ERROR_AUTHENTICATED
3485 && r
!= MAILIMAP_NO_ERROR_NON_AUTHENTICATED
) {
3486 mailstream_close(s
);
3488 imap
->imap_stream
= NULL
;
3497 struct connect_cmd_param
{
3499 const char * command
;
3500 const char * server
;
3504 struct connect_cmd_result
{
3508 static void connect_cmd_run(struct etpan_thread_op
* op
)
3511 struct connect_cmd_param
* param
;
3512 struct connect_cmd_result
* result
;
3515 result
= op
->result
;
3519 r
= socket_connect_cmd(param
->imap
, param
->command
,
3520 param
->server
, param
->port
);
3526 int imap_threaded_connect_cmd(Folder
* folder
, const char * command
,
3527 const char * server
, int port
)
3529 struct connect_cmd_param param
;
3530 struct connect_cmd_result result
;
3533 mailimap
* imap
, * oldimap
;
3535 oldimap
= get_imap(folder
);
3537 imap
= mailimap_new(0, NULL
);
3540 debug_print("deleting old imap %p\n", oldimap
);
3541 delete_imap(folder
, oldimap
);
3545 key
.len
= sizeof(folder
);
3548 chash_set(session_hash
, &key
, &value
, NULL
);
3551 param
.command
= command
;
3552 param
.server
= server
;
3555 threaded_run(folder
, ¶m
, &result
, connect_cmd_run
);
3557 debug_print("connect_cmd ok %i with imap %p\n", result
.error
, imap
);
3559 return result
.error
;
3561 #endif /* G_OS_WIN32 */
3563 void imap_threaded_cancel(Folder
* folder
)
3567 imap
= get_imap(folder
);
3568 if (imap
&& imap
->imap_stream
!= NULL
)
3569 mailstream_cancel(imap
->imap_stream
);
3574 void imap_main_init(void)
3577 void imap_main_done(gboolean have_connectivity
)
3580 void imap_main_set_timeout(int sec
)
3584 void imap_threaded_cancel(Folder
* folder
);