2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2002 Hiroyuki Yamamoto
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 2 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, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
44 #include "procheader.h"
46 #include "prefs_account.h"
49 #include "inputdialog.h"
52 #define IMAP4_PORT 143
54 #define IMAPS_PORT 993
57 #define QUOTE_IF_REQUIRED(out, str) \
59 if (*str != '"' && strpbrk(str, " \t(){}%*") != NULL) { \
63 len = strlen(str) + 3; \
64 Xalloca(__tmp, len, return IMAP_ERROR); \
65 g_snprintf(__tmp, len, "\"%s\"", str); \
68 Xstrdup_a(out, str, return IMAP_ERROR); \
72 struct _IMAPFolderItem
80 static GList
*session_list
= NULL
;
82 static gint imap_cmd_count
= 0;
84 static void imap_folder_init (Folder
*folder
,
88 static FolderItem
*imap_folder_item_new (Folder
*folder
);
89 static void imap_folder_item_destroy (Folder
*folder
,
92 static IMAPSession
*imap_session_get (Folder
*folder
);
94 static gint
imap_scan_tree_recursive (IMAPSession
*session
,
96 static GSList
*imap_parse_list (Folder
*folder
,
98 const gchar
*real_path
,
101 static void imap_create_missing_folders (Folder
*folder
);
102 static FolderItem
*imap_create_special_folder
104 SpecialFolderItemType stype
,
107 static gint
imap_do_copy (Folder
*folder
,
110 gboolean remove_source
);
111 static gint
imap_do_copy_msgs_with_dest (Folder
*folder
,
114 gboolean remove_source
);
116 static GSList
*imap_get_uncached_messages (IMAPSession
*session
,
120 static GSList
*imap_delete_cached_messages (GSList
*mlist
,
124 static void imap_delete_all_cached_messages (FolderItem
*item
);
127 static SockInfo
*imap_open (const gchar
*server
,
131 static SockInfo
*imap_open (const gchar
*server
,
136 static SockInfo
*imap_open_tunnel(const gchar
*server
,
137 const gchar
*tunnelcmd
,
140 static SockInfo
*imap_open_tunnel(const gchar
*server
,
141 const gchar
*tunnelcmd
);
145 static SockInfo
*imap_init_sock(SockInfo
*sock
, SSLType ssl_type
);
147 static SockInfo
*imap_init_sock(SockInfo
*sock
);
150 static gint
imap_set_message_flags (IMAPSession
*session
,
155 static gint
imap_select (IMAPSession
*session
,
161 guint32
*uid_validity
);
162 static gint
imap_get_uid (IMAPSession
*session
,
165 static gint
imap_status (IMAPSession
*session
,
171 guint32
*uid_validity
,
174 static void imap_parse_namespace (IMAPSession
*session
,
176 static void imap_get_namespace_by_list (IMAPSession
*session
,
178 static IMAPNameSpace
*imap_find_namespace (IMAPFolder
*folder
,
180 static gchar
imap_get_path_separator (IMAPFolder
*folder
,
182 static gchar
*imap_get_real_path (IMAPFolder
*folder
,
185 static gchar
*imap_parse_atom (SockInfo
*sock
,
190 static MsgFlags
imap_parse_flags (const gchar
*flag_str
);
191 static MsgInfo
*imap_parse_envelope (SockInfo
*sock
,
194 static gint
imap_greeting (SockInfo
*sock
,
195 gboolean
*is_preauth
);
197 /* low-level IMAP4rev1 commands */
198 static gint
imap_cmd_login (SockInfo
*sock
,
201 static gint
imap_cmd_logout (SockInfo
*sock
);
202 static gint
imap_cmd_noop (SockInfo
*sock
);
203 static gint
imap_cmd_starttls (SockInfo
*sock
);
204 static gint
imap_cmd_namespace (SockInfo
*sock
,
206 static gint
imap_cmd_list (SockInfo
*sock
,
208 const gchar
*mailbox
,
210 static gint
imap_cmd_do_select (SockInfo
*sock
,
216 guint32
*uid_validity
);
217 static gint
imap_cmd_select (SockInfo
*sock
,
222 guint32
*uid_validity
);
223 static gint
imap_cmd_examine (SockInfo
*sock
,
228 guint32
*uid_validity
);
229 static gint
imap_cmd_create (SockInfo
*sock
,
230 const gchar
*folder
);
231 static gint
imap_cmd_rename (SockInfo
*sock
,
232 const gchar
*oldfolder
,
233 const gchar
*newfolder
);
234 static gint
imap_cmd_delete (SockInfo
*sock
,
235 const gchar
*folder
);
236 static gint
imap_cmd_envelope (SockInfo
*sock
,
240 static gint
imap_cmd_search (SockInfo
*sock
,
243 static gint
imap_cmd_fetch (SockInfo
*sock
,
245 const gchar
*filename
);
246 static gint
imap_cmd_append (SockInfo
*sock
,
247 const gchar
*destfolder
,
249 static gint
imap_cmd_copy (SockInfo
*sock
,
251 const gchar
*destfolder
);
252 static gint
imap_cmd_store (SockInfo
*sock
,
256 static gint
imap_cmd_expunge (SockInfo
*sock
);
258 static gint
imap_cmd_ok (SockInfo
*sock
,
260 static void imap_cmd_gen_send (SockInfo
*sock
,
261 const gchar
*format
, ...);
262 static gint
imap_cmd_gen_recv (SockInfo
*sock
,
266 /* misc utility functions */
267 static gchar
*strchr_cpy (const gchar
*src
,
271 static gchar
*get_quoted (const gchar
*src
,
275 static gchar
*search_array_contain_str (GPtrArray
*array
,
277 static gchar
*search_array_str (GPtrArray
*array
,
279 static gchar
*search_array_starts (GPtrArray
*array
,
281 static void imap_path_separator_subst (gchar
*str
,
284 static gchar
*imap_modified_utf7_to_locale (const gchar
*mutf7_str
);
285 static gchar
*imap_locale_to_modified_utf7 (const gchar
*from
);
287 static gboolean
imap_rename_folder_func (GNode
*node
,
289 gint
imap_get_num_list (Folder
*folder
,
292 MsgInfo
*imap_get_msginfo (Folder
*folder
,
295 gboolean
imap_check_msgnum_validity (Folder
*folder
,
298 Folder
*imap_folder_new(const gchar
*name
, const gchar
*path
)
302 folder
= (Folder
*)g_new0(IMAPFolder
, 1);
303 imap_folder_init(folder
, name
, path
);
308 void imap_folder_destroy(Folder
*folder
)
312 dir
= folder_get_path(folder
);
313 if (is_dir_exist(dir
))
314 remove_dir_recursive(dir
);
317 folder_remote_folder_destroy(REMOTE_FOLDER(folder
));
320 static void imap_folder_init(Folder
*folder
, const gchar
*name
,
323 folder
->type
= F_IMAP
;
325 folder_remote_folder_init((Folder
*)folder
, name
, path
);
328 folder->get_msg_list = imap_get_msg_list;
330 folder
->item_new
= imap_folder_item_new
;
331 folder
->item_destroy
= imap_folder_item_destroy
;
332 folder
->fetch_msg
= imap_fetch_msg
;
333 folder
->add_msg
= imap_add_msg
;
334 folder
->move_msg
= imap_move_msg
;
335 folder
->move_msgs_with_dest
= imap_move_msgs_with_dest
;
336 folder
->copy_msg
= imap_copy_msg
;
337 folder
->copy_msgs_with_dest
= imap_copy_msgs_with_dest
;
338 folder
->remove_msg
= imap_remove_msg
;
339 folder
->remove_msgs
= imap_remove_msgs
;
340 folder
->remove_all_msg
= imap_remove_all_msg
;
341 folder
->is_msg_changed
= imap_is_msg_changed
;
343 folder->scan = imap_scan_folder;
345 folder
->scan_tree
= imap_scan_tree
;
346 folder
->create_tree
= imap_create_tree
;
347 folder
->create_folder
= imap_create_folder
;
348 folder
->rename_folder
= imap_rename_folder
;
349 folder
->remove_folder
= imap_remove_folder
;
350 folder
->destroy
= imap_folder_destroy
;
351 folder
->check_msgnum_validity
= imap_check_msgnum_validity
;
353 folder
->get_num_list
= imap_get_num_list
;
354 folder
->get_msginfo
= imap_get_msginfo
;
357 static FolderItem
*imap_folder_item_new(Folder
*folder
)
359 IMAPFolderItem
*item
;
361 item
= g_new0(IMAPFolderItem
, 1);
363 item
->uid_list
= NULL
;
365 return (FolderItem
*)item
;
368 static void imap_folder_item_destroy(Folder
*folder
, FolderItem
*_item
)
370 IMAPFolderItem
*item
= (IMAPFolderItem
*)_item
;
372 g_return_if_fail(item
!= NULL
);
373 g_slist_free(item
->uid_list
);
378 static gboolean
imap_reset_uid_lists_func(GNode
*node
, gpointer data
)
380 IMAPFolderItem
*item
= (IMAPFolderItem
*)node
->data
;
383 g_slist_free(item
->uid_list
);
384 item
->uid_list
= NULL
;
389 static void imap_reset_uid_lists(Folder
*folder
)
391 if(folder
->node
== NULL
)
394 /* Destroy all uid lists and rest last uid */
395 g_node_traverse(folder
->node
, G_IN_ORDER
, G_TRAVERSE_ALL
, -1, imap_reset_uid_lists_func
, NULL
);
398 static IMAPSession
*imap_session_get(Folder
*folder
)
400 RemoteFolder
*rfolder
= REMOTE_FOLDER(folder
);
401 Session
*session
= NULL
;
404 g_return_val_if_fail(folder
!= NULL
, NULL
);
405 g_return_val_if_fail(folder
->type
== F_IMAP
, NULL
);
406 g_return_val_if_fail(folder
->account
!= NULL
, NULL
);
409 port
= folder
->account
->set_imapport
? folder
->account
->imapport
410 : folder
->account
->ssl_imap
== SSL_TUNNEL
411 ? IMAPS_PORT
: IMAP4_PORT
;
413 port
= folder
->account
->set_imapport
? folder
->account
->imapport
417 /* Make sure we have a session */
418 if (rfolder
->session
!= NULL
) {
419 session
= rfolder
->session
;
421 imap_reset_uid_lists(folder
);
422 session
= imap_session_new(folder
->account
);
423 session
->last_access_time
= time(NULL
);
429 /* Make sure session is authenticated */
430 if (!IMAP_SESSION(session
)->authenticated
)
431 imap_session_authenticate(IMAP_SESSION(session
), folder
->account
);
432 if (!IMAP_SESSION(session
)->authenticated
) {
433 session_destroy(session
);
434 rfolder
->session
= NULL
;
438 /* Make sure we have parsed the IMAP namespace */
439 imap_parse_namespace(IMAP_SESSION(session
),
440 IMAP_FOLDER(folder
));
442 /* I think the point of this code is to avoid sending a
443 * keepalive if we've used the session recently and therefore
444 * think it's still alive. Unfortunately, most of the code
445 * does not yet check for errors on the socket, and so if the
446 * connection drops we don't notice until the timeout expires.
447 * A better solution than sending a NOOP every time would be
448 * for every command to be prepared to retry until it is
449 * successfully sent. -- mbp */
450 if (time(NULL
) - session
->last_access_time
> SESSION_TIMEOUT
) {
451 /* verify that the session is still alive */
452 if (imap_cmd_noop(session
->sock
) != IMAP_SUCCESS
) {
453 /* Check if this is the first try to establish a
454 connection, if yes we don't try to reconnect */
455 if (rfolder
->session
== NULL
) {
456 log_warning(_("Connecting %s:%d failed"),
457 folder
->account
->recv_server
, port
);
458 session_destroy(session
);
461 log_warning(_("IMAP4 connection to %s:%d has been"
462 " disconnected. Reconnecting...\n"),
463 folder
->account
->recv_server
, port
);
464 session_destroy(session
);
465 /* Clear folders session to make imap_session_get create
466 a new session, because of rfolder->session == NULL
467 it will not try to reconnect again and so avoid an
469 rfolder
->session
= NULL
;
470 session
= SESSION(imap_session_get(folder
));
475 rfolder
->session
= session
;
477 session
->last_access_time
= time(NULL
);
479 return IMAP_SESSION(session
);
482 Session
*imap_session_new(const PrefsAccount
*account
)
484 IMAPSession
*session
;
490 /* FIXME: IMAP over SSL only... */
493 port
= account
->set_imapport
? account
->imapport
494 : account
->ssl_imap
? IMAPS_PORT
: IMAP4_PORT
;
495 ssl_type
= account
->ssl_imap
? TRUE
: FALSE
;
497 port
= account
->set_imapport
? account
->imapport
501 if (account
->set_tunnelcmd
) {
502 log_message(_("creating tunneled IMAP4 connection\n"));
504 if ((imap_sock
= imap_open_tunnel(account
->recv_server
,
508 if ((imap_sock
= imap_open_tunnel(account
->recv_server
,
509 account
->tunnelcmd
)) == NULL
)
513 g_return_val_if_fail(account
->recv_server
!= NULL
, NULL
);
515 log_message(_("creating IMAP4 connection to %s:%d ...\n"),
516 account
->recv_server
, port
);
519 if ((imap_sock
= imap_open(account
->recv_server
, port
,
522 if ((imap_sock
= imap_open(account
->recv_server
, port
)) == NULL
)
527 /* Only need to log in if the connection was not PREAUTH */
528 if (imap_greeting(imap_sock
, &is_preauth
) != IMAP_SUCCESS
) {
529 sock_close(imap_sock
);
532 log_message("IMAP connection is %s-authenticated\n",
533 (is_preauth
) ? "pre" : "un");
535 session
= g_new(IMAPSession
, 1);
536 SESSION(session
)->type
= SESSION_IMAP
;
537 SESSION(session
)->server
= g_strdup(account
->recv_server
);
538 SESSION(session
)->sock
= imap_sock
;
539 SESSION(session
)->connected
= TRUE
;
540 SESSION(session
)->phase
= SESSION_READY
;
541 SESSION(session
)->last_access_time
= time(NULL
);
542 SESSION(session
)->data
= NULL
;
544 SESSION(session
)->destroy
= imap_session_destroy
;
546 session
->mbox
= NULL
;
547 session
->authenticated
= is_preauth
;
549 session_list
= g_list_append(session_list
, session
);
551 return SESSION(session
);
554 void imap_session_authenticate(IMAPSession
*session
, const PrefsAccount
*account
)
558 g_return_if_fail(account
->userid
!= NULL
);
560 pass
= account
->passwd
;
563 tmp_pass
= input_dialog_query_password(account
->recv_server
, account
->userid
);
566 Xstrdup_a(pass
, tmp_pass
, {g_free(tmp_pass
); return;});
570 if (imap_cmd_login(SESSION(session
)->sock
, account
->userid
, pass
) != IMAP_SUCCESS
) {
571 imap_cmd_logout(SESSION(session
)->sock
);
575 session
->authenticated
= TRUE
;
578 void imap_session_destroy(Session
*session
)
580 sock_close(session
->sock
);
581 session
->sock
= NULL
;
583 g_free(IMAP_SESSION(session
)->mbox
);
585 session_list
= g_list_remove(session_list
, session
);
588 void imap_session_destroy_all(void)
590 while (session_list
!= NULL
) {
591 IMAPSession
*session
= (IMAPSession
*)session_list
->data
;
593 imap_cmd_logout(SESSION(session
)->sock
);
594 session_destroy(SESSION(session
));
598 #define THROW goto catch
600 GSList
*imap_get_msg_list(Folder
*folder
, FolderItem
*item
, gboolean use_cache
)
602 GSList
*mlist
= NULL
;
603 IMAPSession
*session
;
604 gint ok
, exists
= 0, recent
= 0, unseen
= 0;
605 guint32 uid_validity
= 0;
606 guint32 first_uid
= 0, last_uid
= 0, begin
;
608 g_return_val_if_fail(folder
!= NULL
, NULL
);
609 g_return_val_if_fail(item
!= NULL
, NULL
);
610 g_return_val_if_fail(folder
->type
== F_IMAP
, NULL
);
611 g_return_val_if_fail(folder
->account
!= NULL
, NULL
);
613 session
= imap_session_get(folder
);
616 mlist
= procmsg_read_cache(item
, FALSE
);
617 item
->last_num
= procmsg_get_last_num_in_msg_list(mlist
);
618 procmsg_set_flags(mlist
, item
);
622 ok
= imap_select(session
, IMAP_FOLDER(folder
), item
->path
,
623 &exists
, &recent
, &unseen
, &uid_validity
);
624 if (ok
!= IMAP_SUCCESS
) THROW
;
626 ok
= imap_get_uid(session
, 1, &first_uid
);
627 if (ok
!= IMAP_SUCCESS
) THROW
;
629 ok
= imap_get_uid(session
, exists
, &last_uid
);
630 if (ok
!= IMAP_SUCCESS
) THROW
;
632 last_uid
= first_uid
;
634 imap_delete_all_cached_messages(item
);
641 mlist
= procmsg_read_cache(item
, FALSE
);
642 procmsg_set_flags(mlist
, item
);
643 cache_last
= procmsg_get_last_num_in_msg_list(mlist
);
645 /* calculating the range of envelope to get */
646 if (item
->mtime
!= uid_validity
) {
647 /* mailbox is changed (get all) */
649 } else if (last_uid
< cache_last
) {
650 /* mailbox is changed (get all) */
652 } else if (last_uid
== cache_last
) {
653 /* mailbox unchanged (get none)*/
656 begin
= cache_last
+ 1;
659 item
->mtime
= uid_validity
;
661 if (first_uid
> 0 && last_uid
> 0) {
662 mlist
= imap_delete_cached_messages(mlist
, item
,
664 mlist
= imap_delete_cached_messages(mlist
, item
,
669 mlist
= imap_delete_cached_messages(mlist
, item
,
672 imap_delete_all_cached_messages(item
);
676 if (begin
> 0 && begin
<= last_uid
) {
678 newlist
= imap_get_uncached_messages(session
, item
,
680 mlist
= g_slist_concat(mlist
, newlist
);
683 item
->last_num
= last_uid
;
691 gchar
*imap_fetch_msg(Folder
*folder
, FolderItem
*item
, gint uid
)
693 gchar
*path
, *filename
;
694 IMAPSession
*session
;
697 g_return_val_if_fail(folder
!= NULL
, NULL
);
698 g_return_val_if_fail(item
!= NULL
, NULL
);
700 path
= folder_item_get_path(item
);
701 if (!is_dir_exist(path
))
703 filename
= g_strconcat(path
, G_DIR_SEPARATOR_S
, itos(uid
), NULL
);
706 if (is_file_exist(filename
)) {
707 debug_print("message %d has been already cached.\n", uid
);
711 session
= imap_session_get(folder
);
717 ok
= imap_select(session
, IMAP_FOLDER(folder
), item
->path
,
718 NULL
, NULL
, NULL
, NULL
);
719 if (ok
!= IMAP_SUCCESS
) {
720 g_warning("can't select mailbox %s\n", item
->path
);
725 debug_print("getting message %d...\n", uid
);
726 ok
= imap_cmd_fetch(SESSION(session
)->sock
, (guint32
)uid
, filename
);
728 if (ok
!= IMAP_SUCCESS
) {
729 g_warning("can't fetch message %d\n", uid
);
737 gint
imap_add_msg(Folder
*folder
, FolderItem
*dest
, const gchar
*file
,
738 gboolean remove_source
)
741 IMAPSession
*session
;
742 gint messages
, recent
, unseen
;
743 guint32 uid_next
, uid_validity
;
746 g_return_val_if_fail(folder
!= NULL
, -1);
747 g_return_val_if_fail(dest
!= NULL
, -1);
748 g_return_val_if_fail(file
!= NULL
, -1);
750 session
= imap_session_get(folder
);
751 if (!session
) return -1;
753 ok
= imap_status(session
, IMAP_FOLDER(folder
), dest
->path
,
754 &messages
, &recent
, &uid_next
, &uid_validity
, &unseen
);
755 if (ok
!= IMAP_SUCCESS
) {
756 g_warning("can't append message %s\n", file
);
760 destdir
= imap_get_real_path(IMAP_FOLDER(folder
), dest
->path
);
761 ok
= imap_cmd_append(SESSION(session
)->sock
, destdir
, file
);
764 if (ok
!= IMAP_SUCCESS
) {
765 g_warning("can't append message %s\n", file
);
770 if (unlink(file
) < 0)
771 FILE_OP_ERROR(file
, "unlink");
777 static gint
imap_do_copy(Folder
*folder
, FolderItem
*dest
, MsgInfo
*msginfo
,
778 gboolean remove_source
)
781 IMAPSession
*session
;
782 gint messages
, recent
, unseen
;
783 guint32 uid_next
, uid_validity
;
786 g_return_val_if_fail(folder
!= NULL
, -1);
787 g_return_val_if_fail(folder
->type
== F_IMAP
, -1);
788 g_return_val_if_fail(dest
!= NULL
, -1);
789 g_return_val_if_fail(msginfo
!= NULL
, -1);
791 session
= imap_session_get(folder
);
792 if (!session
) return -1;
794 if (msginfo
->folder
== dest
) {
795 g_warning("the src folder is identical to the dest.\n");
799 ok
= imap_status(session
, IMAP_FOLDER(folder
), dest
->path
,
800 &messages
, &recent
, &uid_next
, &uid_validity
, &unseen
);
801 if (ok
!= IMAP_SUCCESS
) {
802 g_warning("can't copy message\n");
806 destdir
= imap_get_real_path(IMAP_FOLDER(folder
), dest
->path
);
808 /* ensure source folder selected */
809 ok
= imap_select(session
, IMAP_FOLDER(folder
), msginfo
->folder
->path
,
810 NULL
, NULL
, NULL
, NULL
);
811 if (ok
!= IMAP_SUCCESS
)
815 debug_print("Moving message %s%c%d to %s ...\n",
816 msginfo
->folder
->path
, G_DIR_SEPARATOR
,
817 msginfo
->msgnum
, destdir
);
819 debug_print("Copying message %s%c%d to %s ...\n",
820 msginfo
->folder
->path
, G_DIR_SEPARATOR
,
821 msginfo
->msgnum
, destdir
);
823 ok
= imap_cmd_copy(SESSION(session
)->sock
, msginfo
->msgnum
, destdir
);
825 if (ok
== IMAP_SUCCESS
&& remove_source
) {
826 imap_set_message_flags(session
, msginfo
->msgnum
, msginfo
->msgnum
,
827 IMAP_FLAG_DELETED
, TRUE
);
828 ok
= imap_cmd_expunge(SESSION(session
)->sock
);
833 if (ok
== IMAP_SUCCESS
)
839 static gint
imap_do_copy_msgs_with_dest(Folder
*folder
, FolderItem
*dest
,
841 gboolean remove_source
)
846 IMAPSession
*session
;
847 gint ok
= IMAP_SUCCESS
;
849 g_return_val_if_fail(folder
!= NULL
, -1);
850 g_return_val_if_fail(dest
!= NULL
, -1);
851 g_return_val_if_fail(msglist
!= NULL
, -1);
853 session
= imap_session_get(folder
);
854 if (!session
) return -1;
856 destdir
= imap_get_real_path(IMAP_FOLDER(folder
), dest
->path
);
858 for (cur
= msglist
; cur
!= NULL
; cur
= cur
->next
) {
859 msginfo
= (MsgInfo
*)cur
->data
;
861 if (msginfo
->folder
== dest
) {
862 g_warning("the src folder is identical to the dest.\n");
866 /* ensure source folder selected */
867 ok
= imap_select(session
, IMAP_FOLDER(folder
),
868 msginfo
->folder
->path
, NULL
, NULL
, NULL
, NULL
);
871 debug_print("Moving message %s%c%d to %s ...\n",
872 msginfo
->folder
->path
, G_DIR_SEPARATOR
,
873 msginfo
->msgnum
, destdir
);
875 debug_print("Copying message %s%c%d to %s ...\n",
876 msginfo
->folder
->path
, G_DIR_SEPARATOR
,
877 msginfo
->msgnum
, destdir
);
879 ok
= imap_cmd_copy(SESSION(session
)->sock
, msginfo
->msgnum
,
882 if (ok
== IMAP_SUCCESS
&& remove_source
) {
883 imap_set_message_flags
884 (session
, msginfo
->msgnum
, msginfo
->msgnum
,
885 IMAP_FLAG_DELETED
, TRUE
);
890 ok
= imap_cmd_expunge(SESSION(session
)->sock
);
894 if (ok
== IMAP_SUCCESS
)
900 gint
imap_move_msg(Folder
*folder
, FolderItem
*dest
, MsgInfo
*msginfo
)
905 g_return_val_if_fail(folder
!= NULL
, -1);
906 g_return_val_if_fail(dest
!= NULL
, -1);
907 g_return_val_if_fail(msginfo
!= NULL
, -1);
908 g_return_val_if_fail(msginfo
->folder
!= NULL
, -1);
910 if (folder
== msginfo
->folder
->folder
)
911 return imap_do_copy(folder
, dest
, msginfo
, TRUE
);
913 srcfile
= procmsg_get_message_file(msginfo
);
914 if (!srcfile
) return -1;
916 ret
= imap_add_msg(folder
, dest
, srcfile
, FALSE
);
920 if(folder_item_remove_msg(msginfo
->folder
, msginfo
->msgnum
)) {
928 gint
imap_move_msgs_with_dest(Folder
*folder
, FolderItem
*dest
,
935 g_return_val_if_fail(folder
!= NULL
, -1);
936 g_return_val_if_fail(dest
!= NULL
, -1);
937 g_return_val_if_fail(msglist
!= NULL
, -1);
939 msginfo
= (MsgInfo
*)msglist
->data
;
940 if (folder
== msginfo
->folder
->folder
)
941 return imap_do_copy_msgs_with_dest(folder
, dest
, msglist
, TRUE
);
943 for (cur
= msglist
; cur
!= NULL
; cur
= cur
->next
) {
944 msginfo
= (MsgInfo
*)cur
->data
;
945 ret
= imap_move_msg(folder
, dest
, msginfo
);
946 if (ret
== -1) break;
952 gint
imap_copy_msg(Folder
*folder
, FolderItem
*dest
, MsgInfo
*msginfo
)
957 g_return_val_if_fail(folder
!= NULL
, -1);
958 g_return_val_if_fail(dest
!= NULL
, -1);
959 g_return_val_if_fail(msginfo
!= NULL
, -1);
960 g_return_val_if_fail(msginfo
->folder
!= NULL
, -1);
962 if (folder
== msginfo
->folder
->folder
)
963 return imap_do_copy(folder
, dest
, msginfo
, FALSE
);
965 srcfile
= procmsg_get_message_file(msginfo
);
966 if (!srcfile
) return -1;
968 ret
= imap_add_msg(folder
, dest
, srcfile
, FALSE
);
975 gint
imap_copy_msgs_with_dest(Folder
*folder
, FolderItem
*dest
,
982 g_return_val_if_fail(folder
!= NULL
, -1);
983 g_return_val_if_fail(dest
!= NULL
, -1);
984 g_return_val_if_fail(msglist
!= NULL
, -1);
986 msginfo
= (MsgInfo
*)msglist
->data
;
987 if (folder
== msginfo
->folder
->folder
)
988 return imap_do_copy_msgs_with_dest
989 (folder
, dest
, msglist
, FALSE
);
991 for (cur
= msglist
; cur
!= NULL
; cur
= cur
->next
) {
992 msginfo
= (MsgInfo
*)cur
->data
;
993 ret
= imap_copy_msg(folder
, dest
, msginfo
);
994 if (ret
== -1) break;
1000 gint
imap_remove_msg(Folder
*folder
, FolderItem
*item
, gint uid
)
1003 IMAPSession
*session
;
1006 g_return_val_if_fail(folder
!= NULL
, -1);
1007 g_return_val_if_fail(folder
->type
== F_IMAP
, -1);
1008 g_return_val_if_fail(item
!= NULL
, -1);
1010 session
= imap_session_get(folder
);
1011 if (!session
) return -1;
1013 ok
= imap_select(session
, IMAP_FOLDER(folder
), item
->path
,
1014 NULL
, NULL
, NULL
, NULL
);
1015 if (ok
!= IMAP_SUCCESS
)
1018 ok
= imap_set_message_flags
1019 (IMAP_SESSION(REMOTE_FOLDER(folder
)->session
),
1020 (guint32
)uid
, (guint32
)uid
, IMAP_FLAG_DELETED
, TRUE
);
1021 if (ok
!= IMAP_SUCCESS
) {
1022 log_warning(_("can't set deleted flags: %d\n"), uid
);
1026 ok
= imap_cmd_expunge(SESSION(session
)->sock
);
1027 if (ok
!= IMAP_SUCCESS
) {
1028 log_warning(_("can't expunge\n"));
1032 dir
= folder_item_get_path(item
);
1033 if (is_dir_exist(dir
))
1034 remove_numbered_files(dir
, uid
, uid
);
1037 return IMAP_SUCCESS
;
1040 gint
imap_remove_msgs(Folder
*folder
, FolderItem
*item
, GSList
*msglist
)
1043 IMAPSession
*session
;
1049 g_return_val_if_fail(folder
!= NULL
, -1);
1050 g_return_val_if_fail(folder
->type
== F_IMAP
, -1);
1051 g_return_val_if_fail(item
!= NULL
, -1);
1052 g_return_val_if_fail(msglist
!= NULL
, -1);
1054 session
= imap_session_get(folder
);
1055 if (!session
) return -1;
1057 ok
= imap_select(session
, IMAP_FOLDER(folder
), item
->path
,
1058 NULL
, NULL
, NULL
, NULL
);
1059 if (ok
!= IMAP_SUCCESS
)
1062 for (cur
= msglist
; cur
!= NULL
; cur
= cur
->next
) {
1063 msginfo
= (MsgInfo
*)cur
->data
;
1064 uid
= msginfo
->msgnum
;
1065 ok
= imap_set_message_flags
1066 (IMAP_SESSION(REMOTE_FOLDER(folder
)->session
),
1067 uid
, uid
, IMAP_FLAG_DELETED
, TRUE
);
1068 if (ok
!= IMAP_SUCCESS
) {
1069 log_warning(_("can't set deleted flags: %d\n"), uid
);
1074 ok
= imap_cmd_expunge(SESSION(session
)->sock
);
1075 if (ok
!= IMAP_SUCCESS
) {
1076 log_warning(_("can't expunge\n"));
1080 dir
= folder_item_get_path(item
);
1081 if (is_dir_exist(dir
)) {
1082 for (cur
= msglist
; cur
!= NULL
; cur
= cur
->next
) {
1083 msginfo
= (MsgInfo
*)cur
->data
;
1084 uid
= msginfo
->msgnum
;
1085 remove_numbered_files(dir
, uid
, uid
);
1090 return IMAP_SUCCESS
;
1093 gint
imap_remove_all_msg(Folder
*folder
, FolderItem
*item
)
1095 gint exists
, recent
, unseen
;
1096 guint32 uid_validity
;
1098 IMAPSession
*session
;
1101 g_return_val_if_fail(folder
!= NULL
, -1);
1102 g_return_val_if_fail(item
!= NULL
, -1);
1104 session
= imap_session_get(folder
);
1105 if (!session
) return -1;
1107 ok
= imap_select(session
, IMAP_FOLDER(folder
), item
->path
,
1108 &exists
, &recent
, &unseen
, &uid_validity
);
1109 if (ok
!= IMAP_SUCCESS
)
1112 return IMAP_SUCCESS
;
1114 imap_cmd_gen_send(SESSION(session
)->sock
,
1115 "STORE 1:%d +FLAGS (\\Deleted)", exists
);
1116 ok
= imap_cmd_ok(SESSION(session
)->sock
, NULL
);
1117 if (ok
!= IMAP_SUCCESS
) {
1118 log_warning(_("can't set deleted flags: 1:%d\n"), exists
);
1122 ok
= imap_cmd_expunge(SESSION(session
)->sock
);
1123 if (ok
!= IMAP_SUCCESS
) {
1124 log_warning(_("can't expunge\n"));
1128 dir
= folder_item_get_path(item
);
1129 if (is_dir_exist(dir
))
1130 remove_all_numbered_files(dir
);
1133 return IMAP_SUCCESS
;
1136 gboolean
imap_is_msg_changed(Folder
*folder
, FolderItem
*item
, MsgInfo
*msginfo
)
1138 /* TODO: properly implement this method */
1142 gint
imap_scan_folder(Folder
*folder
, FolderItem
*item
)
1144 IMAPSession
*session
;
1145 gint messages
, recent
, unseen
;
1146 guint32 uid_next
, uid_validity
;
1149 g_return_val_if_fail(folder
!= NULL
, -1);
1150 g_return_val_if_fail(item
!= NULL
, -1);
1152 session
= imap_session_get(folder
);
1153 if (!session
) return -1;
1155 ok
= imap_status(session
, IMAP_FOLDER(folder
), item
->path
,
1156 &messages
, &recent
, &uid_next
, &uid_validity
, &unseen
);
1157 if (ok
!= IMAP_SUCCESS
) return -1;
1159 item
->new = unseen
> 0 ? recent
: 0;
1160 item
->unread
= unseen
;
1161 item
->total
= messages
;
1162 item
->last_num
= (messages
> 0 && uid_next
> 0) ? uid_next
- 1 : 0;
1163 /* item->mtime = uid_validity; */
1168 void imap_scan_tree(Folder
*folder
)
1171 IMAPSession
*session
;
1172 gchar
*root_folder
= NULL
;
1174 g_return_if_fail(folder
!= NULL
);
1175 g_return_if_fail(folder
->account
!= NULL
);
1177 session
= imap_session_get(folder
);
1179 if (!folder
->node
) {
1180 folder_tree_destroy(folder
);
1181 item
= folder_item_new(folder
, folder
->name
, NULL
);
1182 item
->folder
= folder
;
1183 folder
->node
= g_node_new(item
);
1188 if (folder
->account
->imap_dir
&& *folder
->account
->imap_dir
) {
1189 Xstrdup_a(root_folder
, folder
->account
->imap_dir
, return);
1190 strtailchomp(root_folder
, '/');
1191 debug_print("IMAP root directory: %s\n", root_folder
);
1194 item
= folder_item_new(folder
, folder
->name
, root_folder
);
1195 item
->folder
= folder
;
1196 item
->no_select
= TRUE
;
1197 folder
->node
= g_node_new(item
);
1199 imap_scan_tree_recursive(session
, item
);
1201 imap_create_missing_folders(folder
);
1204 static gint
imap_scan_tree_recursive(IMAPSession
*session
, FolderItem
*item
)
1207 IMAPFolder
*imapfolder
;
1208 FolderItem
*new_item
;
1209 GSList
*item_list
, *cur
;
1211 gchar
*wildcard_path
;
1215 g_return_val_if_fail(item
!= NULL
, -1);
1216 g_return_val_if_fail(item
->folder
!= NULL
, -1);
1217 g_return_val_if_fail(item
->no_sub
== FALSE
, -1);
1219 folder
= FOLDER(item
->folder
);
1220 imapfolder
= IMAP_FOLDER(folder
);
1222 separator
= imap_get_path_separator(imapfolder
, item
->path
);
1224 if (item
->folder
->ui_func
)
1225 item
->folder
->ui_func(folder
, item
, folder
->ui_func_data
);
1228 wildcard
[0] = separator
;
1231 real_path
= imap_get_real_path(imapfolder
, item
->path
);
1235 real_path
= g_strdup("");
1238 Xstrcat_a(wildcard_path
, real_path
, wildcard
,
1239 {g_free(real_path
); return IMAP_ERROR
;});
1240 QUOTE_IF_REQUIRED(wildcard_path
, wildcard_path
);
1242 imap_cmd_gen_send(SESSION(session
)->sock
, "LIST \"\" %s",
1245 strtailchomp(real_path
, separator
);
1246 item_list
= imap_parse_list(folder
, session
, real_path
, NULL
);
1249 for (cur
= item_list
; cur
!= NULL
; cur
= cur
->next
) {
1250 new_item
= cur
->data
;
1251 if (!strcmp(new_item
->path
, "INBOX")) {
1252 if (!folder
->inbox
) {
1253 new_item
->stype
= F_INBOX
;
1254 item
->folder
->inbox
= new_item
;
1256 folder_item_destroy(new_item
);
1259 } else if (!item
->parent
|| item
->stype
== F_INBOX
) {
1262 base
= g_basename(new_item
->path
);
1264 if (!folder
->outbox
&& !strcasecmp(base
, "Sent")) {
1265 new_item
->stype
= F_OUTBOX
;
1266 folder
->outbox
= new_item
;
1267 } else if (!folder
->draft
&& !strcasecmp(base
, "Drafts")) {
1268 new_item
->stype
= F_DRAFT
;
1269 folder
->draft
= new_item
;
1270 } else if (!folder
->queue
&& !strcasecmp(base
, "Queue")) {
1271 new_item
->stype
= F_QUEUE
;
1272 folder
->queue
= new_item
;
1273 } else if (!folder
->trash
&& !strcasecmp(base
, "Trash")) {
1274 new_item
->stype
= F_TRASH
;
1275 folder
->trash
= new_item
;
1278 folder_item_append(item
, new_item
);
1279 if (new_item
->no_select
== FALSE
)
1280 imap_scan_folder(folder
, new_item
);
1281 if (new_item
->no_sub
== FALSE
)
1282 imap_scan_tree_recursive(session
, new_item
);
1285 return IMAP_SUCCESS
;
1288 static GSList
*imap_parse_list(Folder
*folder
, IMAPSession
*session
,
1289 const gchar
*real_path
, gchar
*separator
)
1291 gchar buf
[IMAPBUFSIZE
];
1293 gchar separator_str
[16];
1296 gchar
*loc_name
, *loc_path
;
1297 GSList
*item_list
= NULL
;
1299 FolderItem
*new_item
;
1301 debug_print("getting list of %s ...\n",
1302 *real_path
? real_path
: "\"\"");
1304 str
= g_string_new(NULL
);
1307 if (sock_gets(SESSION(session
)->sock
, buf
, sizeof(buf
)) <= 0) {
1308 log_warning(_("error occured while getting LIST.\n"));
1312 if (buf
[0] != '*' || buf
[1] != ' ') {
1313 log_print("IMAP4< %s\n", buf
);
1316 debug_print("IMAP4< %s\n", buf
);
1318 g_string_assign(str
, buf
);
1320 if (strncmp(p
, "LIST ", 5) != 0) continue;
1323 if (*p
!= '(') continue;
1325 p
= strchr_cpy(p
, ')', flags
, sizeof(flags
));
1327 while (*p
== ' ') p
++;
1329 p
= strchr_cpy(p
, ' ', separator_str
, sizeof(separator_str
));
1331 extract_quote(separator_str
, '"');
1332 if (!strcmp(separator_str
, "NIL"))
1333 separator_str
[0] = '\0';
1335 *separator
= separator_str
[0];
1338 while (*p
== ' ') p
++;
1339 if (*p
== '{' || *p
== '"')
1340 p
= imap_parse_atom(SESSION(session
)->sock
, p
,
1341 buf
, sizeof(buf
), str
);
1343 strncpy2(buf
, p
, sizeof(buf
));
1344 strtailchomp(buf
, separator_str
[0]);
1345 if (buf
[0] == '\0') continue;
1346 if (!strcmp(buf
, real_path
)) continue;
1348 if (separator_str
[0] != '\0')
1349 subst_char(buf
, separator_str
[0], '/');
1350 name
= g_basename(buf
);
1351 if (name
[0] == '.') continue;
1353 loc_name
= imap_modified_utf7_to_locale(name
);
1354 loc_path
= imap_modified_utf7_to_locale(buf
);
1355 new_item
= folder_item_new(folder
, loc_name
, loc_path
);
1356 if (strcasestr(flags
, "\\Noinferiors") != NULL
)
1357 new_item
->no_sub
= TRUE
;
1358 if (strcmp(buf
, "INBOX") != 0 &&
1359 strcasestr(flags
, "\\Noselect") != NULL
)
1360 new_item
->no_select
= TRUE
;
1362 item_list
= g_slist_append(item_list
, new_item
);
1364 debug_print("folder %s has been added.\n", loc_path
);
1369 g_string_free(str
, TRUE
);
1374 gint
imap_create_tree(Folder
*folder
)
1376 g_return_val_if_fail(folder
!= NULL
, -1);
1377 g_return_val_if_fail(folder
->node
!= NULL
, -1);
1378 g_return_val_if_fail(folder
->node
->data
!= NULL
, -1);
1379 g_return_val_if_fail(folder
->account
!= NULL
, -1);
1381 imap_scan_tree(folder
);
1382 imap_create_missing_folders(folder
);
1387 static void imap_create_missing_folders(Folder
*folder
)
1389 g_return_if_fail(folder
!= NULL
);
1392 folder
->inbox
= imap_create_special_folder
1393 (folder
, F_INBOX
, "INBOX");
1395 if (!folder
->outbox
)
1396 folder
->outbox
= imap_create_special_folder
1397 (folder
, F_OUTBOX
, "Sent");
1399 folder
->draft
= imap_create_special_folder
1400 (folder
, F_DRAFT
, "Drafts");
1402 folder
->queue
= imap_create_special_folder
1403 (folder
, F_QUEUE
, "Queue");
1406 folder
->trash
= imap_create_special_folder
1407 (folder
, F_TRASH
, "Trash");
1410 static FolderItem
*imap_create_special_folder(Folder
*folder
,
1411 SpecialFolderItemType stype
,
1415 FolderItem
*new_item
;
1417 g_return_val_if_fail(folder
!= NULL
, NULL
);
1418 g_return_val_if_fail(folder
->node
!= NULL
, NULL
);
1419 g_return_val_if_fail(folder
->node
->data
!= NULL
, NULL
);
1420 g_return_val_if_fail(folder
->account
!= NULL
, NULL
);
1421 g_return_val_if_fail(name
!= NULL
, NULL
);
1423 item
= FOLDER_ITEM(folder
->node
->data
);
1424 new_item
= imap_create_folder(folder
, item
, name
);
1427 g_warning("Can't create '%s'\n", name
);
1428 if (!folder
->inbox
) return NULL
;
1430 new_item
= imap_create_folder(folder
, folder
->inbox
, name
);
1432 g_warning("Can't create '%s' under INBOX\n", name
);
1434 new_item
->stype
= stype
;
1436 new_item
->stype
= stype
;
1441 FolderItem
*imap_create_folder(Folder
*folder
, FolderItem
*parent
,
1444 gchar
*dirpath
, *imap_path
;
1445 IMAPSession
*session
;
1446 FolderItem
*new_item
;
1452 g_return_val_if_fail(folder
!= NULL
, NULL
);
1453 g_return_val_if_fail(folder
->account
!= NULL
, NULL
);
1454 g_return_val_if_fail(parent
!= NULL
, NULL
);
1455 g_return_val_if_fail(name
!= NULL
, NULL
);
1457 session
= imap_session_get(folder
);
1458 if (!session
) return NULL
;
1460 if (!parent
->parent
&& strcmp(name
, "INBOX") == 0)
1461 dirpath
= g_strdup(name
);
1462 else if (parent
->path
)
1463 dirpath
= g_strconcat(parent
->path
, "/", name
, NULL
);
1464 else if ((p
= strchr(name
, '/')) != NULL
&& *(p
+ 1) != '\0')
1465 dirpath
= g_strdup(name
);
1466 else if (folder
->account
->imap_dir
&& *folder
->account
->imap_dir
) {
1469 Xstrdup_a(imap_dir
, folder
->account
->imap_dir
, return NULL
);
1470 strtailchomp(imap_dir
, '/');
1471 dirpath
= g_strconcat(imap_dir
, "/", name
, NULL
);
1473 dirpath
= g_strdup(name
);
1475 /* keep trailing directory separator to create a folder that contains
1477 imap_path
= imap_locale_to_modified_utf7(dirpath
);
1478 strtailchomp(dirpath
, '/');
1479 Xstrdup_a(new_name
, name
, {g_free(dirpath
); return NULL
;});
1480 strtailchomp(new_name
, '/');
1481 separator
= imap_get_path_separator(IMAP_FOLDER(folder
), imap_path
);
1482 imap_path_separator_subst(imap_path
, separator
);
1483 subst_char(new_name
, '/', separator
);
1485 if (strcmp(name
, "INBOX") != 0) {
1488 gboolean exist
= FALSE
;
1490 argbuf
= g_ptr_array_new();
1491 ok
= imap_cmd_list(SESSION(session
)->sock
, NULL
, imap_path
,
1493 if (ok
!= IMAP_SUCCESS
) {
1494 log_warning(_("can't create mailbox: LIST failed\n"));
1497 g_ptr_array_free(argbuf
, TRUE
);
1501 for (i
= 0; i
< argbuf
->len
; i
++) {
1503 str
= g_ptr_array_index(argbuf
, i
);
1504 if (!strncmp(str
, "LIST ", 5)) {
1509 g_ptr_array_free(argbuf
, TRUE
);
1512 ok
= imap_cmd_create(SESSION(session
)->sock
, imap_path
);
1513 if (ok
!= IMAP_SUCCESS
) {
1514 log_warning(_("can't create mailbox\n"));
1522 new_item
= folder_item_new(folder
, new_name
, dirpath
);
1523 folder_item_append(parent
, new_item
);
1527 dirpath
= folder_item_get_path(new_item
);
1528 if (!is_dir_exist(dirpath
))
1529 make_dir_hier(dirpath
);
1535 gint
imap_rename_folder(Folder
*folder
, FolderItem
*item
, const gchar
*name
)
1539 gchar
*real_oldpath
;
1540 gchar
*real_newpath
;
1543 gchar
*old_cache_dir
;
1544 gchar
*new_cache_dir
;
1545 IMAPSession
*session
;
1548 gint exists
, recent
, unseen
;
1549 guint32 uid_validity
;
1551 g_return_val_if_fail(folder
!= NULL
, -1);
1552 g_return_val_if_fail(item
!= NULL
, -1);
1553 g_return_val_if_fail(item
->path
!= NULL
, -1);
1554 g_return_val_if_fail(name
!= NULL
, -1);
1556 session
= imap_session_get(folder
);
1557 if (!session
) return -1;
1559 real_oldpath
= imap_get_real_path(IMAP_FOLDER(folder
), item
->path
);
1561 g_free(session
->mbox
);
1562 session
->mbox
= NULL
;
1563 ok
= imap_cmd_examine(SESSION(session
)->sock
, "INBOX",
1564 &exists
, &recent
, &unseen
, &uid_validity
);
1565 if (ok
!= IMAP_SUCCESS
) {
1566 g_free(real_oldpath
);
1570 separator
= imap_get_path_separator(IMAP_FOLDER(folder
), item
->path
);
1571 if (strchr(item
->path
, G_DIR_SEPARATOR
)) {
1572 dirpath
= g_dirname(item
->path
);
1573 newpath
= g_strconcat(dirpath
, G_DIR_SEPARATOR_S
, name
, NULL
);
1576 newpath
= g_strdup(name
);
1578 real_newpath
= imap_locale_to_modified_utf7(newpath
);
1579 imap_path_separator_subst(real_newpath
, separator
);
1581 ok
= imap_cmd_rename(SESSION(session
)->sock
, real_oldpath
, real_newpath
);
1582 if (ok
!= IMAP_SUCCESS
) {
1583 log_warning(_("can't rename mailbox: %s to %s\n"),
1584 real_oldpath
, real_newpath
);
1585 g_free(real_oldpath
);
1587 g_free(real_newpath
);
1592 item
->name
= g_strdup(name
);
1594 old_cache_dir
= folder_item_get_path(item
);
1596 node
= g_node_find(item
->folder
->node
, G_PRE_ORDER
, G_TRAVERSE_ALL
,
1598 paths
[0] = g_strdup(item
->path
);
1600 g_node_traverse(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, -1,
1601 imap_rename_folder_func
, paths
);
1603 if (is_dir_exist(old_cache_dir
)) {
1604 new_cache_dir
= folder_item_get_path(item
);
1605 if (rename(old_cache_dir
, new_cache_dir
) < 0) {
1606 FILE_OP_ERROR(old_cache_dir
, "rename");
1608 g_free(new_cache_dir
);
1611 g_free(old_cache_dir
);
1614 g_free(real_oldpath
);
1615 g_free(real_newpath
);
1620 gint
imap_remove_folder(Folder
*folder
, FolderItem
*item
)
1623 IMAPSession
*session
;
1626 gint exists
, recent
, unseen
;
1627 guint32 uid_validity
;
1629 g_return_val_if_fail(folder
!= NULL
, -1);
1630 g_return_val_if_fail(item
!= NULL
, -1);
1631 g_return_val_if_fail(item
->path
!= NULL
, -1);
1633 session
= imap_session_get(folder
);
1634 if (!session
) return -1;
1636 path
= imap_get_real_path(IMAP_FOLDER(folder
), item
->path
);
1638 ok
= imap_cmd_examine(SESSION(session
)->sock
, "INBOX",
1639 &exists
, &recent
, &unseen
, &uid_validity
);
1640 if (ok
!= IMAP_SUCCESS
) {
1645 ok
= imap_cmd_delete(SESSION(session
)->sock
, path
);
1646 if (ok
!= IMAP_SUCCESS
) {
1647 log_warning(_("can't delete mailbox\n"));
1653 cache_dir
= folder_item_get_path(item
);
1654 if (is_dir_exist(cache_dir
) && remove_dir_recursive(cache_dir
) < 0)
1655 g_warning("can't remove directory '%s'\n", cache_dir
);
1657 folder_item_remove(item
);
1662 static GSList
*imap_get_uncached_messages(IMAPSession
*session
,
1664 guint32 first_uid
, guint32 last_uid
)
1667 GSList
*newlist
= NULL
;
1668 GSList
*llast
= NULL
;
1672 g_return_val_if_fail(session
!= NULL
, NULL
);
1673 g_return_val_if_fail(item
!= NULL
, NULL
);
1674 g_return_val_if_fail(item
->folder
!= NULL
, NULL
);
1675 g_return_val_if_fail(item
->folder
->type
== F_IMAP
, NULL
);
1676 g_return_val_if_fail(first_uid
<= last_uid
, NULL
);
1678 if (imap_cmd_envelope(SESSION(session
)->sock
, first_uid
, last_uid
)
1680 log_warning(_("can't get envelope\n"));
1684 str
= g_string_new(NULL
);
1687 if ((tmp
= sock_getline(SESSION(session
)->sock
)) == NULL
) {
1688 log_warning(_("error occurred while getting envelope.\n"));
1689 g_string_free(str
, TRUE
);
1693 if (tmp
[0] != '*' || tmp
[1] != ' ') {
1694 log_print("IMAP4< %s\n", tmp
);
1698 if (strstr(tmp
, "FETCH") == NULL
) {
1699 log_print("IMAP4< %s\n", tmp
);
1703 log_print("IMAP4< %s\n", tmp
);
1704 g_string_assign(str
, tmp
);
1707 msginfo
= imap_parse_envelope
1708 (SESSION(session
)->sock
, item
, str
);
1710 log_warning(_("can't parse envelope: %s\n"), str
->str
);
1713 if (item
->stype
== F_QUEUE
) {
1714 MSG_SET_TMP_FLAGS(msginfo
->flags
, MSG_QUEUED
);
1715 } else if (item
->stype
== F_DRAFT
) {
1716 MSG_SET_TMP_FLAGS(msginfo
->flags
, MSG_DRAFT
);
1719 msginfo
->folder
= item
;
1722 llast
= newlist
= g_slist_append(newlist
, msginfo
);
1724 llast
= g_slist_append(llast
, msginfo
);
1725 llast
= llast
->next
;
1729 g_string_free(str
, TRUE
);
1734 static GSList
*imap_delete_cached_messages(GSList
*mlist
, FolderItem
*item
,
1735 guint32 first_uid
, guint32 last_uid
)
1741 g_return_val_if_fail(item
!= NULL
, mlist
);
1742 g_return_val_if_fail(item
->folder
!= NULL
, mlist
);
1743 g_return_val_if_fail(item
->folder
->type
== F_IMAP
, mlist
);
1745 debug_print("Deleting cached messages %u - %u ... ",
1746 first_uid
, last_uid
);
1748 dir
= folder_item_get_path(item
);
1749 if (is_dir_exist(dir
))
1750 remove_numbered_files(dir
, first_uid
, last_uid
);
1753 for (cur
= mlist
; cur
!= NULL
; ) {
1756 msginfo
= (MsgInfo
*)cur
->data
;
1757 if (msginfo
!= NULL
&& first_uid
<= msginfo
->msgnum
&&
1758 msginfo
->msgnum
<= last_uid
) {
1759 procmsg_msginfo_free(msginfo
);
1760 mlist
= g_slist_remove(mlist
, msginfo
);
1766 debug_print("done.\n");
1771 static void imap_delete_all_cached_messages(FolderItem
*item
)
1775 g_return_if_fail(item
!= NULL
);
1776 g_return_if_fail(item
->folder
!= NULL
);
1777 g_return_if_fail(item
->folder
->type
== F_IMAP
);
1779 debug_print("Deleting all cached messages...\n");
1781 dir
= folder_item_get_path(item
);
1782 if (is_dir_exist(dir
))
1783 remove_all_numbered_files(dir
);
1786 debug_print("done.\n");
1790 static SockInfo
*imap_open_tunnel(const gchar
*server
,
1791 const gchar
*tunnelcmd
,
1794 static SockInfo
*imap_open_tunnel(const gchar
*server
,
1795 const gchar
*tunnelcmd
)
1800 if ((sock
= sock_connect_cmd(server
, tunnelcmd
)) == NULL
)
1801 log_warning(_("Can't establish IMAP4 session with: %s\n"),
1805 return imap_init_sock(sock
, ssl_type
);
1807 return imap_init_sock(sock
);
1813 static SockInfo
*imap_open(const gchar
*server
, gushort port
,
1816 static SockInfo
*imap_open(const gchar
*server
, gushort port
)
1821 if ((sock
= sock_connect(server
, port
)) == NULL
) {
1822 log_warning(_("Can't connect to IMAP4 server: %s:%d\n"),
1828 if (ssl_type
== SSL_TUNNEL
&& !ssl_init_socket(sock
)) {
1829 log_warning(_("Can't establish IMAP4 session with: %s:%d\n"),
1834 return imap_init_sock(sock
, ssl_type
);
1836 return imap_init_sock(sock
);
1841 static SockInfo
*imap_init_sock(SockInfo
*sock
, SSLType ssl_type
)
1843 static SockInfo
*imap_init_sock(SockInfo
*sock
)
1848 if (ssl_type
== SSL_STARTTLS
) {
1851 ok
= imap_cmd_starttls(sock
);
1852 if (ok
!= IMAP_SUCCESS
) {
1853 log_warning(_("Can't start TLS session.\n"));
1857 if (!ssl_init_socket_with_method(sock
, SSL_METHOD_TLSv1
)) {
1864 if (imap_cmd_noop(sock
) != IMAP_SUCCESS
) {
1865 log_warning(_("Can't establish IMAP4 session.\n"));
1873 static GList
*imap_parse_namespace_str(gchar
*str
)
1878 IMAPNameSpace
*namespace;
1879 GList
*ns_list
= NULL
;
1881 while (*p
!= '\0') {
1882 /* parse ("#foo" "/") */
1884 while (*p
&& *p
!= '(') p
++;
1885 if (*p
== '\0') break;
1888 while (*p
&& *p
!= '"') p
++;
1889 if (*p
== '\0') break;
1893 while (*p
&& *p
!= '"') p
++;
1894 if (*p
== '\0') break;
1898 while (*p
&& isspace(*p
)) p
++;
1899 if (*p
== '\0') break;
1900 if (strncmp(p
, "NIL", 3) == 0)
1902 else if (*p
== '"') {
1905 while (*p
&& *p
!= '"') p
++;
1906 if (*p
== '\0') break;
1911 while (*p
&& *p
!= ')') p
++;
1912 if (*p
== '\0') break;
1915 namespace = g_new(IMAPNameSpace
, 1);
1916 namespace->name
= g_strdup(name
);
1917 namespace->separator
= separator
? separator
[0] : '\0';
1918 ns_list
= g_list_append(ns_list
, namespace);
1924 static void imap_parse_namespace(IMAPSession
*session
, IMAPFolder
*folder
)
1929 g_return_if_fail(session
!= NULL
);
1930 g_return_if_fail(folder
!= NULL
);
1932 if (folder
->ns_personal
!= NULL
||
1933 folder
->ns_others
!= NULL
||
1934 folder
->ns_shared
!= NULL
)
1937 if (imap_cmd_namespace(SESSION(session
)->sock
, &ns_str
)
1939 log_warning(_("can't get namespace\n"));
1940 imap_get_namespace_by_list(session
, folder
);
1944 str_array
= strsplit_parenthesis(ns_str
, '(', ')', 3);
1946 folder
->ns_personal
= imap_parse_namespace_str(str_array
[0]);
1947 if (str_array
[0] && str_array
[1])
1948 folder
->ns_others
= imap_parse_namespace_str(str_array
[1]);
1949 if (str_array
[0] && str_array
[1] && str_array
[2])
1950 folder
->ns_shared
= imap_parse_namespace_str(str_array
[2]);
1951 g_strfreev(str_array
);
1955 static void imap_get_namespace_by_list(IMAPSession
*session
, IMAPFolder
*folder
)
1957 GSList
*item_list
, *cur
;
1958 gchar separator
= '\0';
1959 IMAPNameSpace
*namespace;
1961 g_return_if_fail(session
!= NULL
);
1962 g_return_if_fail(folder
!= NULL
);
1964 if (folder
->ns_personal
!= NULL
||
1965 folder
->ns_others
!= NULL
||
1966 folder
->ns_shared
!= NULL
)
1969 imap_cmd_gen_send(SESSION(session
)->sock
, "LIST \"\" \"\"");
1970 item_list
= imap_parse_list(NULL
, session
, "", &separator
);
1971 for (cur
= item_list
; cur
!= NULL
; cur
= cur
->next
)
1972 folder_item_destroy(FOLDER_ITEM(cur
->data
));
1973 g_slist_free(item_list
);
1975 namespace = g_new(IMAPNameSpace
, 1);
1976 namespace->name
= g_strdup("");
1977 namespace->separator
= separator
;
1978 folder
->ns_personal
= g_list_append(NULL
, namespace);
1981 static IMAPNameSpace
*imap_find_namespace_from_list(GList
*ns_list
,
1984 IMAPNameSpace
*namespace = NULL
;
1985 gchar
*tmp_path
, *name
;
1987 if (!path
) path
= "";
1989 Xstrcat_a(tmp_path
, path
, "/", return NULL
);
1991 for (; ns_list
!= NULL
; ns_list
= ns_list
->next
) {
1992 IMAPNameSpace
*tmp_ns
= ns_list
->data
;
1994 Xstrdup_a(name
, tmp_ns
->name
, return namespace);
1995 if (tmp_ns
->separator
&& tmp_ns
->separator
!= '/')
1996 subst_char(name
, tmp_ns
->separator
, '/');
1997 if (strncmp(tmp_path
, name
, strlen(name
)) == 0)
2004 static IMAPNameSpace
*imap_find_namespace(IMAPFolder
*folder
,
2007 IMAPNameSpace
*namespace;
2009 g_return_val_if_fail(folder
!= NULL
, NULL
);
2011 namespace = imap_find_namespace_from_list(folder
->ns_personal
, path
);
2012 if (namespace) return namespace;
2013 namespace = imap_find_namespace_from_list(folder
->ns_others
, path
);
2014 if (namespace) return namespace;
2015 namespace = imap_find_namespace_from_list(folder
->ns_shared
, path
);
2016 if (namespace) return namespace;
2021 static gchar
imap_get_path_separator(IMAPFolder
*folder
, const gchar
*path
)
2023 IMAPNameSpace
*namespace;
2024 gchar separator
= '/';
2026 namespace = imap_find_namespace(folder
, path
);
2027 if (namespace && namespace->separator
)
2028 separator
= namespace->separator
;
2033 static gchar
*imap_get_real_path(IMAPFolder
*folder
, const gchar
*path
)
2038 g_return_val_if_fail(folder
!= NULL
, NULL
);
2039 g_return_val_if_fail(path
!= NULL
, NULL
);
2041 real_path
= imap_locale_to_modified_utf7(path
);
2042 separator
= imap_get_path_separator(folder
, path
);
2043 imap_path_separator_subst(real_path
, separator
);
2048 static gchar
*imap_parse_atom(SockInfo
*sock
, gchar
*src
,
2049 gchar
*dest
, gint dest_len
, GString
*str
)
2051 gchar
*cur_pos
= src
;
2054 g_return_val_if_fail(str
!= NULL
, cur_pos
);
2056 /* read the next line if the current response buffer is empty */
2057 while (isspace(*cur_pos
)) cur_pos
++;
2058 while (*cur_pos
== '\0') {
2059 if ((nextline
= sock_getline(sock
)) == NULL
)
2061 g_string_assign(str
, nextline
);
2063 strretchomp(nextline
);
2064 /* log_print("IMAP4< %s\n", nextline); */
2065 debug_print("IMAP4< %s\n", nextline
);
2068 while (isspace(*cur_pos
)) cur_pos
++;
2071 if (!strncmp(cur_pos
, "NIL", 3)) {
2074 } else if (*cur_pos
== '\"') {
2077 p
= get_quoted(cur_pos
, '\"', dest
, dest_len
);
2078 cur_pos
= p
? p
: cur_pos
+ 2;
2079 } else if (*cur_pos
== '{') {
2084 cur_pos
= strchr_cpy(cur_pos
+ 1, '}', buf
, sizeof(buf
));
2087 g_string_truncate(str
, 0);
2091 if ((nextline
= sock_getline(sock
)) == NULL
)
2093 line_len
+= strlen(nextline
);
2094 g_string_append(str
, nextline
);
2096 strretchomp(nextline
);
2097 /* log_print("IMAP4< %s\n", nextline); */
2098 debug_print("IMAP4< %s\n", nextline
);
2100 } while (line_len
< len
);
2102 memcpy(dest
, cur_pos
, MIN(len
, dest_len
- 1));
2103 dest
[MIN(len
, dest_len
- 1)] = '\0';
2110 static gchar
*imap_get_header(SockInfo
*sock
, gchar
*cur_pos
, gchar
**headers
,
2120 g_return_val_if_fail(str
!= NULL
, cur_pos
);
2122 while (isspace(*cur_pos
)) cur_pos
++;
2124 g_return_val_if_fail(*cur_pos
== '{', cur_pos
);
2126 cur_pos
= strchr_cpy(cur_pos
+ 1, '}', buf
, sizeof(buf
));
2129 g_string_truncate(str
, 0);
2133 if ((nextline
= sock_getline(sock
)) == NULL
)
2135 block_len
+= strlen(nextline
);
2136 g_string_append(str
, nextline
);
2138 strretchomp(nextline
);
2139 /* debug_print("IMAP4< %s\n", nextline); */
2141 } while (block_len
< len
);
2143 debug_print("IMAP4< [contents of RFC822.HEADER]\n");
2145 *headers
= g_strndup(cur_pos
, len
);
2148 while (isspace(*cur_pos
)) cur_pos
++;
2149 while (*cur_pos
== '\0') {
2150 if ((nextline
= sock_getline(sock
)) == NULL
)
2152 g_string_assign(str
, nextline
);
2154 strretchomp(nextline
);
2155 debug_print("IMAP4< %s\n", nextline
);
2158 while (isspace(*cur_pos
)) cur_pos
++;
2164 static MsgFlags
imap_parse_flags(const gchar
*flag_str
)
2166 const gchar
*p
= flag_str
;
2167 MsgFlags flags
= {0, 0};
2169 flags
.perm_flags
= MSG_UNREAD
;
2171 while ((p
= strchr(p
, '\\')) != NULL
) {
2174 if (g_strncasecmp(p
, "Recent", 6) == 0 && MSG_IS_UNREAD(flags
)) {
2175 MSG_SET_PERM_FLAGS(flags
, MSG_NEW
);
2176 } else if (g_strncasecmp(p
, "Seen", 4) == 0) {
2177 MSG_UNSET_PERM_FLAGS(flags
, MSG_NEW
|MSG_UNREAD
);
2178 } else if (g_strncasecmp(p
, "Deleted", 7) == 0) {
2179 MSG_SET_PERM_FLAGS(flags
, MSG_DELETED
);
2180 } else if (g_strncasecmp(p
, "Flagged", 7) == 0) {
2181 MSG_SET_PERM_FLAGS(flags
, MSG_MARKED
);
2182 } else if (g_strncasecmp(p
, "Answered", 8) == 0) {
2183 MSG_SET_PERM_FLAGS(flags
, MSG_REPLIED
);
2190 static MsgInfo
*imap_parse_envelope(SockInfo
*sock
, FolderItem
*item
,
2193 gchar buf
[IMAPBUFSIZE
];
2194 MsgInfo
*msginfo
= NULL
;
2199 MsgFlags flags
= {0, 0}, imap_flags
= {0, 0};
2201 g_return_val_if_fail(line_str
!= NULL
, NULL
);
2202 g_return_val_if_fail(line_str
->str
[0] == '*' &&
2203 line_str
->str
[1] == ' ', NULL
);
2205 MSG_SET_TMP_FLAGS(flags
, MSG_IMAP
);
2206 if (item
->stype
== F_QUEUE
) {
2207 MSG_SET_TMP_FLAGS(flags
, MSG_QUEUED
);
2208 } else if (item
->stype
== F_DRAFT
) {
2209 MSG_SET_TMP_FLAGS(flags
, MSG_DRAFT
);
2212 cur_pos
= line_str
->str
+ 2;
2214 #define PARSE_ONE_ELEMENT(ch) \
2216 cur_pos = strchr_cpy(cur_pos, ch, buf, sizeof(buf)); \
2217 if (cur_pos == NULL) { \
2218 g_warning("cur_pos == NULL\n"); \
2219 procmsg_msginfo_free(msginfo); \
2224 PARSE_ONE_ELEMENT(' ');
2227 PARSE_ONE_ELEMENT(' ');
2228 g_return_val_if_fail(!strcmp(buf
, "FETCH"), NULL
);
2230 g_return_val_if_fail(*cur_pos
== '(', NULL
);
2233 while (*cur_pos
!= '\0' && *cur_pos
!= ')') {
2234 while (*cur_pos
== ' ') cur_pos
++;
2236 if (!strncmp(cur_pos
, "UID ", 4)) {
2238 uid
= strtoul(cur_pos
, &cur_pos
, 10);
2239 } else if (!strncmp(cur_pos
, "FLAGS ", 6)) {
2241 if (*cur_pos
!= '(') {
2242 g_warning("*cur_pos != '('\n");
2243 procmsg_msginfo_free(msginfo
);
2247 PARSE_ONE_ELEMENT(')');
2248 imap_flags
= imap_parse_flags(buf
);
2249 } else if (!strncmp(cur_pos
, "RFC822.SIZE ", 12)) {
2251 size
= strtol(cur_pos
, &cur_pos
, 10);
2252 } else if (!strncmp(cur_pos
, "RFC822.HEADER ", 14)) {
2256 cur_pos
= imap_get_header(sock
, cur_pos
, &headers
,
2258 msginfo
= procheader_parse_str(headers
, flags
, FALSE
, FALSE
);
2261 g_warning("invalid FETCH response: %s\n", cur_pos
);
2267 msginfo
->msgnum
= uid
;
2268 msginfo
->size
= size
;
2269 msginfo
->flags
.tmp_flags
|= imap_flags
.tmp_flags
;
2270 msginfo
->flags
.perm_flags
= imap_flags
.perm_flags
;
2276 gint
imap_msg_set_perm_flags(MsgInfo
*msginfo
, MsgPermFlags flags
)
2279 IMAPSession
*session
;
2280 IMAPFlags iflags
= 0;
2281 gint ok
= IMAP_SUCCESS
;
2283 g_return_val_if_fail(msginfo
!= NULL
, -1);
2284 g_return_val_if_fail(MSG_IS_IMAP(msginfo
->flags
), -1);
2285 g_return_val_if_fail(msginfo
->folder
!= NULL
, -1);
2286 g_return_val_if_fail(msginfo
->folder
->folder
!= NULL
, -1);
2288 folder
= msginfo
->folder
->folder
;
2289 g_return_val_if_fail(folder
->type
== F_IMAP
, -1);
2291 session
= imap_session_get(folder
);
2292 if (!session
) return -1;
2294 if (flags
& MSG_MARKED
) iflags
|= IMAP_FLAG_FLAGGED
;
2295 if (flags
& MSG_REPLIED
) iflags
|= IMAP_FLAG_ANSWERED
;
2297 ok
= imap_set_message_flags(session
, msginfo
->msgnum
,
2298 msginfo
->msgnum
, iflags
, TRUE
);
2299 if (ok
!= IMAP_SUCCESS
) return ok
;
2302 if (flags
& MSG_UNREAD
)
2303 ok
= imap_set_message_flags(session
, msginfo
->msgnum
,
2304 msginfo
->msgnum
, IMAP_FLAG_SEEN
,
2309 gint
imap_msg_unset_perm_flags(MsgInfo
*msginfo
, MsgPermFlags flags
)
2312 IMAPSession
*session
;
2313 IMAPFlags iflags
= 0;
2314 gint ok
= IMAP_SUCCESS
;
2316 g_return_val_if_fail(msginfo
!= NULL
, -1);
2317 g_return_val_if_fail(MSG_IS_IMAP(msginfo
->flags
), -1);
2318 g_return_val_if_fail(msginfo
->folder
!= NULL
, -1);
2319 g_return_val_if_fail(msginfo
->folder
->folder
!= NULL
, -1);
2321 folder
= msginfo
->folder
->folder
;
2322 g_return_val_if_fail(folder
->type
== F_IMAP
, -1);
2324 session
= imap_session_get(folder
);
2325 if (!session
) return -1;
2327 if (flags
& MSG_MARKED
) iflags
|= IMAP_FLAG_FLAGGED
;
2328 if (flags
& MSG_REPLIED
) iflags
|= IMAP_FLAG_ANSWERED
;
2330 ok
= imap_set_message_flags(session
, msginfo
->msgnum
,
2331 msginfo
->msgnum
, iflags
, FALSE
);
2332 if (ok
!= IMAP_SUCCESS
) return ok
;
2335 if (flags
& MSG_UNREAD
)
2336 ok
= imap_set_message_flags(session
, msginfo
->msgnum
,
2337 msginfo
->msgnum
, IMAP_FLAG_SEEN
,
2342 static gint
imap_set_message_flags(IMAPSession
*session
,
2351 buf
= g_string_new(is_set
? "+FLAGS (" : "-FLAGS (");
2353 if (IMAP_IS_SEEN(flags
)) g_string_append(buf
, "\\Seen ");
2354 if (IMAP_IS_ANSWERED(flags
)) g_string_append(buf
, "\\Answered ");
2355 if (IMAP_IS_FLAGGED(flags
)) g_string_append(buf
, "\\Flagged ");
2356 if (IMAP_IS_DELETED(flags
)) g_string_append(buf
, "\\Deleted ");
2357 if (IMAP_IS_DRAFT(flags
)) g_string_append(buf
, "\\Draft");
2359 if (buf
->str
[buf
->len
- 1] == ' ')
2360 g_string_truncate(buf
, buf
->len
- 1);
2362 g_string_append_c(buf
, ')');
2364 ok
= imap_cmd_store(SESSION(session
)->sock
, first_uid
, last_uid
,
2366 g_string_free(buf
, TRUE
);
2371 static gint
imap_select(IMAPSession
*session
, IMAPFolder
*folder
,
2373 gint
*exists
, gint
*recent
, gint
*unseen
,
2374 guint32
*uid_validity
)
2378 gint exists_
, recent_
, unseen_
, uid_validity_
;
2380 if (!exists
|| !recent
|| !unseen
|| !uid_validity
) {
2381 if (session
->mbox
&& strcmp(session
->mbox
, path
) == 0)
2382 return IMAP_SUCCESS
;
2386 uid_validity
= &uid_validity_
;
2389 g_free(session
->mbox
);
2390 session
->mbox
= NULL
;
2392 real_path
= imap_get_real_path(folder
, path
);
2393 ok
= imap_cmd_select(SESSION(session
)->sock
, real_path
,
2394 exists
, recent
, unseen
, uid_validity
);
2395 if (ok
!= IMAP_SUCCESS
)
2396 log_warning(_("can't select folder: %s\n"), real_path
);
2398 session
->mbox
= g_strdup(path
);
2404 #define THROW(err) { ok = err; goto catch; }
2406 static gint
imap_get_uid(IMAPSession
*session
, gint msgnum
, guint32
*uid
)
2414 argbuf
= g_ptr_array_new();
2416 imap_cmd_gen_send(SESSION(session
)->sock
, "FETCH %d (UID)", msgnum
);
2417 if ((ok
= imap_cmd_ok(SESSION(session
)->sock
, argbuf
)) != IMAP_SUCCESS
)
2420 str
= search_array_contain_str(argbuf
, "FETCH");
2421 if (!str
) THROW(IMAP_ERROR
);
2423 if (sscanf(str
, "%d FETCH (UID %d)", &num
, uid
) != 2 ||
2425 g_warning("imap_get_uid(): invalid FETCH line.\n");
2430 ptr_array_free_strings(argbuf
);
2431 g_ptr_array_free(argbuf
, TRUE
);
2436 static gint
imap_status(IMAPSession
*session
, IMAPFolder
*folder
,
2438 gint
*messages
, gint
*recent
,
2439 guint32
*uid_next
, guint32
*uid_validity
,
2448 *messages
= *recent
= *uid_next
= *uid_validity
= *unseen
= 0;
2450 argbuf
= g_ptr_array_new();
2452 real_path
= imap_get_real_path(folder
, path
);
2453 QUOTE_IF_REQUIRED(real_path_
, real_path
);
2454 imap_cmd_gen_send(SESSION(session
)->sock
, "STATUS %s "
2455 "(MESSAGES RECENT UIDNEXT UIDVALIDITY UNSEEN)",
2458 ok
= imap_cmd_ok(SESSION(session
)->sock
, argbuf
);
2459 if (ok
!= IMAP_SUCCESS
) THROW(ok
);
2461 str
= search_array_str(argbuf
, "STATUS");
2462 if (!str
) THROW(IMAP_ERROR
);
2464 str
= strchr(str
, '(');
2465 if (!str
) THROW(IMAP_ERROR
);
2467 while (*str
!= '\0' && *str
!= ')') {
2468 while (*str
== ' ') str
++;
2470 if (!strncmp(str
, "MESSAGES ", 9)) {
2472 *messages
= strtol(str
, &str
, 10);
2473 } else if (!strncmp(str
, "RECENT ", 7)) {
2475 *recent
= strtol(str
, &str
, 10);
2476 } else if (!strncmp(str
, "UIDNEXT ", 8)) {
2478 *uid_next
= strtoul(str
, &str
, 10);
2479 } else if (!strncmp(str
, "UIDVALIDITY ", 12)) {
2481 *uid_validity
= strtoul(str
, &str
, 10);
2482 } else if (!strncmp(str
, "UNSEEN ", 7)) {
2484 *unseen
= strtol(str
, &str
, 10);
2486 g_warning("invalid STATUS response: %s\n", str
);
2493 ptr_array_free_strings(argbuf
);
2494 g_ptr_array_free(argbuf
, TRUE
);
2502 /* low-level IMAP4rev1 commands */
2504 static gint
imap_cmd_login(SockInfo
*sock
,
2505 const gchar
*user
, const gchar
*pass
)
2507 gchar
*user_
, *pass_
;
2510 QUOTE_IF_REQUIRED(user_
, user
);
2511 QUOTE_IF_REQUIRED(pass_
, pass
);
2512 imap_cmd_gen_send(sock
, "LOGIN %s %s", user_
, pass_
);
2514 ok
= imap_cmd_ok(sock
, NULL
);
2515 if (ok
!= IMAP_SUCCESS
)
2516 log_warning(_("IMAP4 login failed.\n"));
2521 static gint
imap_cmd_logout(SockInfo
*sock
)
2523 imap_cmd_gen_send(sock
, "LOGOUT");
2524 return imap_cmd_ok(sock
, NULL
);
2527 /* Send a NOOP, and examine the server's response to see whether this
2528 * connection is pre-authenticated or not. */
2529 static gint
imap_greeting(SockInfo
*sock
, gboolean
*is_preauth
)
2534 imap_cmd_gen_send(sock
, "NOOP");
2535 argbuf
= g_ptr_array_new(); /* will hold messages sent back */
2536 r
= imap_cmd_ok(sock
, argbuf
);
2537 *is_preauth
= search_array_starts(argbuf
, "PREAUTH") != NULL
;
2542 static gint
imap_cmd_noop(SockInfo
*sock
)
2544 imap_cmd_gen_send(sock
, "NOOP");
2545 return imap_cmd_ok(sock
, NULL
);
2548 static gint
imap_cmd_starttls(SockInfo
*sock
)
2550 imap_cmd_gen_send(sock
, "STARTTLS");
2551 return imap_cmd_ok(sock
, NULL
);
2554 #define THROW(err) { ok = err; goto catch; }
2556 static gint
imap_cmd_namespace(SockInfo
*sock
, gchar
**ns_str
)
2562 argbuf
= g_ptr_array_new();
2564 imap_cmd_gen_send(sock
, "NAMESPACE");
2565 if ((ok
= imap_cmd_ok(sock
, argbuf
)) != IMAP_SUCCESS
) THROW(ok
);
2567 str
= search_array_str(argbuf
, "NAMESPACE");
2568 if (!str
) THROW(IMAP_ERROR
);
2570 *ns_str
= g_strdup(str
);
2573 ptr_array_free_strings(argbuf
);
2574 g_ptr_array_free(argbuf
, TRUE
);
2581 static gint
imap_cmd_list(SockInfo
*sock
, const gchar
*ref
,
2582 const gchar
*mailbox
, GPtrArray
*argbuf
)
2584 gchar
*ref_
, *mailbox_
;
2586 if (!ref
) ref
= "\"\"";
2587 if (!mailbox
) mailbox
= "\"\"";
2589 QUOTE_IF_REQUIRED(ref_
, ref
);
2590 QUOTE_IF_REQUIRED(mailbox_
, mailbox
);
2591 imap_cmd_gen_send(sock
, "LIST %s %s", ref_
, mailbox_
);
2593 return imap_cmd_ok(sock
, argbuf
);
2596 #define THROW goto catch
2598 static gint
imap_cmd_do_select(SockInfo
*sock
, const gchar
*folder
,
2600 gint
*exists
, gint
*recent
, gint
*unseen
,
2601 guint32
*uid_validity
)
2609 *exists
= *recent
= *unseen
= *uid_validity
= 0;
2610 argbuf
= g_ptr_array_new();
2613 select_cmd
= "EXAMINE";
2615 select_cmd
= "SELECT";
2617 QUOTE_IF_REQUIRED(folder_
, folder
);
2618 imap_cmd_gen_send(sock
, "%s %s", select_cmd
, folder_
);
2620 if ((ok
= imap_cmd_ok(sock
, argbuf
)) != IMAP_SUCCESS
) THROW
;
2622 resp_str
= search_array_contain_str(argbuf
, "EXISTS");
2624 if (sscanf(resp_str
,"%d EXISTS", exists
) != 1) {
2625 g_warning("imap_cmd_select(): invalid EXISTS line.\n");
2630 resp_str
= search_array_contain_str(argbuf
, "RECENT");
2632 if (sscanf(resp_str
, "%d RECENT", recent
) != 1) {
2633 g_warning("imap_cmd_select(): invalid RECENT line.\n");
2638 resp_str
= search_array_contain_str(argbuf
, "UIDVALIDITY");
2640 if (sscanf(resp_str
, "OK [UIDVALIDITY %u] ", uid_validity
)
2642 g_warning("imap_cmd_select(): invalid UIDVALIDITY line.\n");
2647 resp_str
= search_array_contain_str(argbuf
, "UNSEEN");
2649 if (sscanf(resp_str
, "OK [UNSEEN %d] ", unseen
) != 1) {
2650 g_warning("imap_cmd_select(): invalid UNSEEN line.\n");
2656 ptr_array_free_strings(argbuf
);
2657 g_ptr_array_free(argbuf
, TRUE
);
2662 static gint
imap_cmd_select(SockInfo
*sock
, const gchar
*folder
,
2663 gint
*exists
, gint
*recent
, gint
*unseen
,
2664 guint32
*uid_validity
)
2666 return imap_cmd_do_select(sock
, folder
, FALSE
,
2667 exists
, recent
, unseen
, uid_validity
);
2670 static gint
imap_cmd_examine(SockInfo
*sock
, const gchar
*folder
,
2671 gint
*exists
, gint
*recent
, gint
*unseen
,
2672 guint32
*uid_validity
)
2674 return imap_cmd_do_select(sock
, folder
, TRUE
,
2675 exists
, recent
, unseen
, uid_validity
);
2680 static gint
imap_cmd_create(SockInfo
*sock
, const gchar
*folder
)
2684 QUOTE_IF_REQUIRED(folder_
, folder
);
2685 imap_cmd_gen_send(sock
, "CREATE %s", folder_
);
2687 return imap_cmd_ok(sock
, NULL
);
2690 static gint
imap_cmd_rename(SockInfo
*sock
, const gchar
*old_folder
,
2691 const gchar
*new_folder
)
2693 gchar
*old_folder_
, *new_folder_
;
2695 QUOTE_IF_REQUIRED(old_folder_
, old_folder
);
2696 QUOTE_IF_REQUIRED(new_folder_
, new_folder
);
2697 imap_cmd_gen_send(sock
, "RENAME %s %s", old_folder_
, new_folder_
);
2699 return imap_cmd_ok(sock
, NULL
);
2702 static gint
imap_cmd_delete(SockInfo
*sock
, const gchar
*folder
)
2706 QUOTE_IF_REQUIRED(folder_
, folder
);
2707 imap_cmd_gen_send(sock
, "DELETE %s", folder_
);
2709 return imap_cmd_ok(sock
, NULL
);
2712 static gint
imap_cmd_fetch(SockInfo
*sock
, guint32 uid
, const gchar
*filename
)
2715 gchar buf
[IMAPBUFSIZE
];
2720 g_return_val_if_fail(filename
!= NULL
, IMAP_ERROR
);
2722 imap_cmd_gen_send(sock
, "UID FETCH %d BODY[]", uid
);
2724 while ((ok
= imap_cmd_gen_recv(sock
, buf
, sizeof(buf
)))
2726 if (buf
[0] != '*' || buf
[1] != ' ')
2728 if (strstr(buf
, "FETCH") != NULL
)
2731 if (ok
!= IMAP_SUCCESS
)
2734 cur_pos
= strchr(buf
, '{');
2735 g_return_val_if_fail(cur_pos
!= NULL
, IMAP_ERROR
);
2736 cur_pos
= strchr_cpy(cur_pos
+ 1, '}', size_str
, sizeof(size_str
));
2737 g_return_val_if_fail(cur_pos
!= NULL
, IMAP_ERROR
);
2738 size_num
= atol(size_str
);
2740 if (*cur_pos
!= '\0') return IMAP_ERROR
;
2742 if (recv_bytes_write_to_file(sock
, size_num
, filename
) != 0)
2745 if (imap_cmd_gen_recv(sock
, buf
, sizeof(buf
)) != IMAP_SUCCESS
)
2748 if (buf
[0] == '\0' || buf
[strlen(buf
) - 1] != ')')
2751 ok
= imap_cmd_ok(sock
, NULL
);
2756 static gint
imap_cmd_append(SockInfo
*sock
, const gchar
*destfolder
,
2762 gchar buf
[BUFFSIZE
];
2765 g_return_val_if_fail(file
!= NULL
, IMAP_ERROR
);
2767 size
= get_file_size_as_crlf(file
);
2768 if ((fp
= fopen(file
, "rb")) == NULL
) {
2769 FILE_OP_ERROR(file
, "fopen");
2772 QUOTE_IF_REQUIRED(destfolder_
, destfolder
);
2773 imap_cmd_gen_send(sock
, "APPEND %s (\\Seen) {%d}", destfolder_
, size
);
2775 ok
= imap_cmd_gen_recv(sock
, buf
, sizeof(buf
));
2776 if (ok
!= IMAP_SUCCESS
|| buf
[0] != '+' || buf
[1] != ' ') {
2777 log_warning(_("can't append %s to %s\n"), file
, destfolder_
);
2782 log_print("IMAP4> %s\n", _("(sending file...)"));
2784 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
2786 if (sock_puts(sock
, buf
) < 0) {
2794 FILE_OP_ERROR(file
, "fgets");
2800 sock_puts(sock
, "");
2803 return imap_cmd_ok(sock
, NULL
);
2806 static gint
imap_cmd_copy(SockInfo
*sock
, guint32 uid
, const gchar
*destfolder
)
2811 g_return_val_if_fail(destfolder
!= NULL
, IMAP_ERROR
);
2813 QUOTE_IF_REQUIRED(destfolder_
, destfolder
);
2814 imap_cmd_gen_send(sock
, "UID COPY %d %s", uid
, destfolder_
);
2816 ok
= imap_cmd_ok(sock
, NULL
);
2817 if (ok
!= IMAP_SUCCESS
) {
2818 log_warning(_("can't copy %d to %s\n"), uid
, destfolder_
);
2825 gint
imap_cmd_envelope(SockInfo
*sock
, guint32 first_uid
, guint32 last_uid
)
2828 (sock
, "UID FETCH %d:%d (UID FLAGS RFC822.SIZE RFC822.HEADER)",
2829 first_uid
, last_uid
);
2831 return IMAP_SUCCESS
;
2834 static gint
imap_cmd_store(SockInfo
*sock
, guint32 first_uid
, guint32 last_uid
,
2839 imap_cmd_gen_send(sock
, "UID STORE %d:%d %s",
2840 first_uid
, last_uid
, sub_cmd
);
2842 if ((ok
= imap_cmd_ok(sock
, NULL
)) != IMAP_SUCCESS
) {
2843 log_warning(_("error while imap command: STORE %d:%d %s\n"),
2844 first_uid
, last_uid
, sub_cmd
);
2848 return IMAP_SUCCESS
;
2851 static gint
imap_cmd_expunge(SockInfo
*sock
)
2855 imap_cmd_gen_send(sock
, "EXPUNGE");
2856 if ((ok
= imap_cmd_ok(sock
, NULL
)) != IMAP_SUCCESS
) {
2857 log_warning(_("error while imap command: EXPUNGE\n"));
2861 return IMAP_SUCCESS
;
2864 static gint
imap_cmd_ok(SockInfo
*sock
, GPtrArray
*argbuf
)
2867 gchar buf
[IMAPBUFSIZE
];
2869 gchar cmd_status
[IMAPBUFSIZE
];
2871 while ((ok
= imap_cmd_gen_recv(sock
, buf
, sizeof(buf
)))
2873 if (buf
[0] == '*' && buf
[1] == ' ') {
2875 g_ptr_array_add(argbuf
, g_strdup(buf
+ 2));
2879 if (sscanf(buf
, "%d %s", &cmd_num
, cmd_status
) < 2)
2881 else if (cmd_num
== imap_cmd_count
&&
2882 !strcmp(cmd_status
, "OK")) {
2884 g_ptr_array_add(argbuf
, g_strdup(buf
));
2885 return IMAP_SUCCESS
;
2893 static void imap_cmd_gen_send(SockInfo
*sock
, const gchar
*format
, ...)
2895 gchar buf
[IMAPBUFSIZE
];
2896 gchar tmp
[IMAPBUFSIZE
];
2900 va_start(args
, format
);
2901 g_vsnprintf(tmp
, sizeof(tmp
), format
, args
);
2906 g_snprintf(buf
, sizeof(buf
), "%d %s\r\n", imap_cmd_count
, tmp
);
2907 if (!strncasecmp(tmp
, "LOGIN ", 6) && (p
= strchr(tmp
+ 6, ' '))) {
2909 log_print("IMAP4> %d %s ********\n", imap_cmd_count
, tmp
);
2911 log_print("IMAP4> %d %s\n", imap_cmd_count
, tmp
);
2913 sock_write(sock
, buf
, strlen(buf
));
2916 static gint
imap_cmd_gen_recv(SockInfo
*sock
, gchar
*buf
, gint size
)
2918 if (sock_gets(sock
, buf
, size
) == -1)
2923 log_print("IMAP4< %s\n", buf
);
2925 return IMAP_SUCCESS
;
2929 /* misc utility functions */
2931 static gchar
*strchr_cpy(const gchar
*src
, gchar ch
, gchar
*dest
, gint len
)
2936 tmp
= strchr(src
, ch
);
2940 memcpy(dest
, src
, MIN(tmp
- src
, len
- 1));
2941 dest
[MIN(tmp
- src
, len
- 1)] = '\0';
2946 static gchar
*get_quoted(const gchar
*src
, gchar ch
, gchar
*dest
, gint len
)
2948 const gchar
*p
= src
;
2951 g_return_val_if_fail(*p
== ch
, NULL
);
2956 while (*p
!= '\0' && *p
!= ch
) {
2958 if (*p
== '\\' && *(p
+ 1) != '\0')
2967 return (gchar
*)(*p
== ch
? p
+ 1 : p
);
2970 static gchar
*search_array_starts(GPtrArray
*array
, const gchar
*str
)
2975 g_return_val_if_fail(str
!= NULL
, NULL
);
2977 for (i
= 0; i
< array
->len
; i
++) {
2979 tmp
= g_ptr_array_index(array
, i
);
2980 if (strncmp(tmp
, str
, len
) == 0)
2986 static gchar
*search_array_contain_str(GPtrArray
*array
, gchar
*str
)
2990 for (i
= 0; i
< array
->len
; i
++) {
2993 tmp
= g_ptr_array_index(array
, i
);
2994 if (strstr(tmp
, str
) != NULL
)
3001 static gchar
*search_array_str(GPtrArray
*array
, gchar
*str
)
3008 for (i
= 0; i
< array
->len
; i
++) {
3011 tmp
= g_ptr_array_index(array
, i
);
3012 if (!strncmp(tmp
, str
, len
))
3019 static void imap_path_separator_subst(gchar
*str
, gchar separator
)
3022 gboolean in_escape
= FALSE
;
3024 if (!separator
|| separator
== '/') return;
3026 for (p
= str
; *p
!= '\0'; p
++) {
3027 if (*p
== '/' && !in_escape
)
3029 else if (*p
== '&' && *(p
+ 1) != '-' && !in_escape
)
3031 else if (*p
== '-' && in_escape
)
3036 static gchar
*imap_modified_utf7_to_locale(const gchar
*mutf7_str
)
3039 return g_strdup(mutf7_str
);
3041 static iconv_t cd
= (iconv_t
)-1;
3042 static gboolean iconv_ok
= TRUE
;
3045 size_t norm_utf7_len
;
3047 gchar
*to_str
, *to_p
;
3049 gboolean in_escape
= FALSE
;
3051 if (!iconv_ok
) return g_strdup(mutf7_str
);
3053 if (cd
== (iconv_t
)-1) {
3054 cd
= iconv_open(conv_get_current_charset_str(), "UTF-7");
3055 if (cd
== (iconv_t
)-1) {
3056 g_warning("iconv cannot convert UTF-7 to %s\n",
3057 conv_get_current_charset_str());
3059 return g_strdup(mutf7_str
);
3063 norm_utf7
= g_string_new(NULL
);
3065 for (p
= mutf7_str
; *p
!= '\0'; p
++) {
3066 /* replace: '&' -> '+',
3068 escaped ',' -> '/' */
3069 if (!in_escape
&& *p
== '&') {
3070 if (*(p
+ 1) != '-') {
3071 g_string_append_c(norm_utf7
, '+');
3074 g_string_append_c(norm_utf7
, '&');
3077 } else if (in_escape
&& *p
== ',') {
3078 g_string_append_c(norm_utf7
, '/');
3079 } else if (in_escape
&& *p
== '-') {
3080 g_string_append_c(norm_utf7
, '-');
3083 g_string_append_c(norm_utf7
, *p
);
3087 norm_utf7_p
= norm_utf7
->str
;
3088 norm_utf7_len
= norm_utf7
->len
;
3089 to_len
= strlen(mutf7_str
) * 5;
3090 to_p
= to_str
= g_malloc(to_len
+ 1);
3092 if (iconv(cd
, &norm_utf7_p
, &norm_utf7_len
, &to_p
, &to_len
) == -1) {
3093 g_warning("iconv cannot convert UTF-7 to %s\n",
3094 conv_get_current_charset_str());
3095 g_string_free(norm_utf7
, TRUE
);
3097 return g_strdup(mutf7_str
);
3100 /* second iconv() call for flushing */
3101 iconv(cd
, NULL
, NULL
, &to_p
, &to_len
);
3102 g_string_free(norm_utf7
, TRUE
);
3106 #endif /* !HAVE_LIBJCONV */
3109 static gchar
*imap_locale_to_modified_utf7(const gchar
*from
)
3112 return g_strdup(from
);
3114 static iconv_t cd
= (iconv_t
)-1;
3115 static gboolean iconv_ok
= TRUE
;
3116 gchar
*norm_utf7
, *norm_utf7_p
;
3117 size_t from_len
, norm_utf7_len
;
3119 gchar
*from_tmp
, *to
, *p
;
3120 gboolean in_escape
= FALSE
;
3122 if (!iconv_ok
) return g_strdup(from
);
3124 if (cd
== (iconv_t
)-1) {
3125 cd
= iconv_open("UTF-7", conv_get_current_charset_str());
3126 if (cd
== (iconv_t
)-1) {
3127 g_warning("iconv cannot convert %s to UTF-7\n",
3128 conv_get_current_charset_str());
3130 return g_strdup(from
);
3134 Xstrdup_a(from_tmp
, from
, return g_strdup(from
));
3135 from_len
= strlen(from
);
3136 norm_utf7_len
= from_len
* 5;
3137 Xalloca(norm_utf7
, norm_utf7_len
+ 1, return g_strdup(from
));
3138 norm_utf7_p
= norm_utf7
;
3140 #define IS_PRINT(ch) (isprint(ch) && isascii(ch))
3142 while (from_len
> 0) {
3143 if (IS_PRINT(*from_tmp
)) {
3144 /* printable ascii char */
3145 *norm_utf7_p
= *from_tmp
;
3152 /* unprintable char: convert to UTF-7 */
3154 !IS_PRINT(from_tmp
[mblen
]) && mblen
< from_len
;
3158 if (iconv(cd
, &from_tmp
, &mblen
,
3159 &norm_utf7_p
, &norm_utf7_len
) == -1) {
3160 g_warning("iconv cannot convert %s to UTF-7\n",
3161 conv_get_current_charset_str());
3162 return g_strdup(from
);
3165 /* second iconv() call for flushing */
3166 iconv(cd
, NULL
, NULL
, &norm_utf7_p
, &norm_utf7_len
);
3172 *norm_utf7_p
= '\0';
3173 to_str
= g_string_new(NULL
);
3174 for (p
= norm_utf7
; p
< norm_utf7_p
; p
++) {
3175 /* replace: '&' -> "&-",
3177 escaped '/' -> ',' */
3178 if (!in_escape
&& *p
== '&') {
3179 g_string_append(to_str
, "&-");
3180 } else if (!in_escape
&& *p
== '+') {
3181 g_string_append_c(to_str
, '&');
3183 } else if (in_escape
&& *p
== '/') {
3184 g_string_append_c(to_str
, ',');
3185 } else if (in_escape
&& *p
== '-') {
3187 g_string_append_c(to_str
, '-');
3189 g_string_append_c(to_str
, *p
);
3195 g_string_append_c(to_str
, '-');
3199 g_string_free(to_str
, FALSE
);
3205 static gboolean
imap_rename_folder_func(GNode
*node
, gpointer data
)
3207 FolderItem
*item
= node
->data
;
3208 gchar
**paths
= data
;
3209 const gchar
*oldpath
= paths
[0];
3210 const gchar
*newpath
= paths
[1];
3212 gchar
*new_itempath
;
3215 oldpathlen
= strlen(oldpath
);
3216 if (strncmp(oldpath
, item
->path
, oldpathlen
) != 0) {
3217 g_warning("path doesn't match: %s, %s\n", oldpath
, item
->path
);
3221 base
= item
->path
+ oldpathlen
;
3222 while (*base
== G_DIR_SEPARATOR
) base
++;
3224 new_itempath
= g_strdup(newpath
);
3226 new_itempath
= g_strconcat(newpath
, G_DIR_SEPARATOR_S
, base
,
3229 item
->path
= new_itempath
;
3234 gint
imap_get_num_list(Folder
*folder
, FolderItem
*_item
, GSList
**msgnum_list
)
3236 IMAPFolderItem
*item
= (IMAPFolderItem
*)_item
;
3237 IMAPSession
*session
;
3238 gint ok
, i
, lastuid_old
, nummsgs
= 0;
3240 gchar
*cmdbuf
= NULL
;
3243 g_return_val_if_fail(folder
!= NULL
, -1);
3244 g_return_val_if_fail(item
!= NULL
, -1);
3245 g_return_val_if_fail(item
->item
.path
!= NULL
, -1);
3246 g_return_val_if_fail(folder
->type
== F_IMAP
, -1);
3247 g_return_val_if_fail(folder
->account
!= NULL
, -1);
3249 session
= imap_session_get(folder
);
3250 g_return_val_if_fail(session
!= NULL
, -1);
3252 ok
= imap_select(session
, IMAP_FOLDER(folder
), item
->item
.path
,
3253 NULL
, NULL
, NULL
, NULL
);
3254 if (ok
!= IMAP_SUCCESS
)
3257 argbuf
= g_ptr_array_new();
3259 cmdbuf
= g_strdup_printf("UID FETCH %d:* (UID)", (item
->lastuid
+ 1));
3261 cmdbuf
= g_strdup("FETCH 1:* (UID)");
3263 imap_cmd_gen_send(SESSION(session
)->sock
, cmdbuf
);
3265 ok
= imap_cmd_ok(SESSION(session
)->sock
, argbuf
);
3266 if (ok
!= IMAP_SUCCESS
) {
3267 ptr_array_free_strings(argbuf
);
3268 g_ptr_array_free(argbuf
, TRUE
);
3272 lastuid_old
= item
->lastuid
;
3273 *msgnum_list
= g_slist_copy(item
->uid_list
);
3274 debug_print("Got %d uids from cache\n", g_slist_length(item
->uid_list
));
3275 for(i
= 0; i
< argbuf
->len
; i
++) {
3276 int ret
, msgidx
, msgnum
;
3278 if((ret
= sscanf(g_ptr_array_index(argbuf
, i
), "%d FETCH (UID %d)", &msgidx
, &msgnum
)) == 2) {
3279 if(msgnum
> lastuid_old
) {
3280 *msgnum_list
= g_slist_prepend(*msgnum_list
, GINT_TO_POINTER(msgnum
));
3281 item
->uid_list
= g_slist_prepend(item
->uid_list
, GINT_TO_POINTER(msgnum
));
3284 if(msgnum
> item
->lastuid
)
3285 item
->lastuid
= msgnum
;
3290 dir
= folder_item_get_path((FolderItem
*)item
);
3291 debug_print("removing old messages from %s\n", dir
);
3292 remove_numbered_files_not_in_list(dir
, *msgnum_list
);
3298 static MsgInfo
*imap_parse_msg(const gchar
*file
, FolderItem
*item
)
3303 flags
.perm_flags
= MSG_NEW
|MSG_UNREAD
;
3304 flags
.tmp_flags
= 0;
3306 g_return_val_if_fail(item
!= NULL
, NULL
);
3307 g_return_val_if_fail(file
!= NULL
, NULL
);
3309 if (item
->stype
== F_QUEUE
) {
3310 MSG_SET_TMP_FLAGS(flags
, MSG_QUEUED
);
3311 } else if (item
->stype
== F_DRAFT
) {
3312 MSG_SET_TMP_FLAGS(flags
, MSG_DRAFT
);
3315 msginfo
= procheader_parse_file(file
, flags
, FALSE
, FALSE
);
3316 if (!msginfo
) return NULL
;
3318 msginfo
->folder
= item
;
3324 MsgInfo
*imap_get_msginfo(Folder
*folder
, FolderItem
*item
, gint uid
)
3326 IMAPSession
*session
;
3327 MsgInfo
*msginfo
= NULL
;
3329 g_return_val_if_fail(folder
!= NULL
, NULL
);
3330 g_return_val_if_fail(item
!= NULL
, NULL
);
3332 session
= imap_session_get(folder
);
3333 g_return_val_if_fail(session
!= NULL
, NULL
);
3335 if (!(item
->stype
== F_QUEUE
|| item
->stype
== F_DRAFT
)) {
3338 list
= imap_get_uncached_messages(session
, item
, uid
, uid
);
3340 msginfo
= (MsgInfo
*)list
->data
;
3343 procmsg_msg_list_free(list
);
3347 file
= imap_fetch_msg(folder
, item
, uid
);
3349 msginfo
= imap_parse_msg(file
, item
);
3350 if (msginfo
!= NULL
)
3351 msginfo
->msgnum
= uid
;
3359 gboolean
imap_check_msgnum_validity(Folder
*folder
, FolderItem
*_item
)
3361 IMAPSession
*session
;
3362 IMAPFolderItem
*item
= (IMAPFolderItem
*)_item
;
3363 gint ok
, exists
= 0, recent
= 0, unseen
= 0;
3364 guint32 uid_next
, uid_validity
= 0;
3366 g_return_val_if_fail(folder
!= NULL
, FALSE
);
3367 g_return_val_if_fail(item
!= NULL
, FALSE
);
3368 g_return_val_if_fail(item
->item
.folder
!= NULL
, FALSE
);
3369 g_return_val_if_fail(item
->item
.folder
->type
== F_IMAP
, FALSE
);
3371 session
= imap_session_get(folder
);
3372 g_return_val_if_fail(session
!= NULL
, FALSE
);
3374 ok
= imap_status(session
, IMAP_FOLDER(folder
), item
->item
.path
,
3375 &exists
, &recent
, &uid_next
, &uid_validity
, &unseen
);
3376 if (ok
!= IMAP_SUCCESS
)
3379 if(item
->item
.mtime
== uid_validity
)
3382 debug_print("Freeing imap uid cache");
3384 g_slist_free(item
->uid_list
);
3385 item
->uid_list
= NULL
;
3387 item
->item
.mtime
= uid_validity
;
3389 imap_delete_all_cached_messages((FolderItem
*)item
);